// -*- C++ -*-
// $RCSfile: menuDef.h,v $
// $Revision: 1.8 $
// $Author: langer $
// $Date: 2003/10/30 21:33:05 $
/* This software was produced by NIST, an agency of the U.S. government,
* and by statute is not subject to copyright in the United States.
* Recipients of this software assume all responsibilities associated
* with its operation, modification and maintenance. However, to
* facilitate maintenance we ask that before distributing modifed
* versions of this software, you first contact the authors at
* oof_manager@ctcms.nist.gov.
*/
#ifndef MENUDEF_H
#define MENUDEF_H
typedef void CommandFn;
class Command0;
class Command;
class CommandM;
class CommandS;
class Menu;
class MenuOption;
class SubMenu;
class TextWaiter;
class Variable;
class Waiter;
#ifdef MENUGFX
class FormWaiter;
#endif
class LoopCommand;
#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include "charstring.h"
#include "menuform.h"
#include "menuinterrupt.h"
#include "menustream.h"
#include "tocharstring.h"
#include "truefalse.h"
#include "varobjects.h"
#include "vec.h"
#include "word.h"
#ifdef DONT_HAVE_STRSTREAM_H
#include <strstream>
using namespace std;
#else
#include <strstream.h>
#endif
//---------------------------------------------//
// Attributes of menu items. A separate class is used, instead of a
// simple enum, so that the result of operator| can be the same class
// (instead of an int, which is the result of enum|enum).
class MenuAttribute {
private:
int flag;
public:
MenuAttribute(int f) : flag(f) {}
int operator()(const MenuAttribute &q) const { return flag & q.flag; }
friend MenuAttribute operator|(const MenuAttribute &a, const MenuAttribute&b)
{
return MenuAttribute(a.flag|b.flag);
}
};
extern const MenuAttribute MOPT_NORMAL;
extern const MenuAttribute MOPT_NOLOG; // doesn't appear in log files
extern const MenuAttribute MOPT_SECRET; // doesn't appear in menu listings
extern const MenuAttribute MOPT_NOPRINT;// isn't printed via Menu::print
//----------------------------------------------//
class Menu {
friend class TextWaiter;
friend class CommandM;
friend class Variable;
private:
CharString prompt;
Vec<MenuOption*> option;
void execute(const CharString &word, TextWaiter &w);
int help(const CharString&, TextWaiter&) const;
public:
Menu(const CharString &prmpt);
virtual ~Menu();
//Menu(const Menu&);
Menu* AddSubMenu(const CharString &nm, const CharString &help,
const CharString &prmpt = "",
const MenuAttribute& = MOPT_NORMAL);
Menu* AddSubMenu(const CharString &nm, const CharString &help,
Menu* submenu, const MenuAttribute& = MOPT_NORMAL);
void AddCommand(const CharString &nm, const CharString &help,
CommandFn (*func)(), const MenuAttribute& = MOPT_NORMAL);
void AddCommand(Command*, const MenuAttribute& = MOPT_NORMAL);
void RemoveOption(const CharString &);
void RemoveOption(const MenuOption &);
bool RenameOption(const CharString&, const CharString&);
void update_forms();
void highlight(const CharString &); // highlight an entry
void highlight_only(const CharString &); // ... and unhighlight others
void unhighlight(const CharString &); // remove highlight
void unhighlight(void); // ... from all entries
void print(FILE *file, const TrueFalse &recursive=TF_TRUE) const;
void print(FILE *file, CharString, const TrueFalse &recursive=TF_TRUE) const;
void print(ostream &os, const TrueFalse &recursive=TF_TRUE) const;
void print(ostream &os, CharString, const TrueFalse &recursive=TF_TRUE) const;
void AddOption(MenuOption* newopt);
// would be private, but is used by template functions
#ifdef MENUGFX
friend class FormWaiter;
friend class MenuForm;
friend class CommandMForm;
private:
Vec<MenuForm*> form;
#endif // MENUGFX
};
class MenuOption { // Item in a menu (virtual)
friend class Menu;
friend class TextWaiter;
friend class SubMenu;
friend class Variable;
friend class CommandM;
friend class Command0;
friend int getcnum(const CharString&, const Vec<MenuOption*>&);
friend int getcnum(const CharString&, const Vec<Variable*>&);
public:
CharString name;
MenuAttribute attribute; // should be protected, but a template needs access
void rename(const CharString &aka) { name = aka; }
private:
virtual void execute(TextWaiter&) = 0;
protected:
char tag; // [*=/] --- indicates type of option in listings
CharString helpstring;
int active; // is it actually being executed right now?
int drawactive; // is it lit up in the menus?
int highlighted; // is it marked? (by Menu::highlight, etc)
Menu* menu; // menu containing this option
CharString browserline(void) const;
virtual int help(TextWaiter&) const;
MenuOption(const CharString &nm, const CharString &hs, char t,
const MenuAttribute &att);
MenuOption()
: active(0),
highlighted(0),
drawactive(0),
attribute(MOPT_NORMAL)
{}
virtual ~MenuOption() {}
virtual void print(FILE *file, CharString path, const TrueFalse &recursive)
const = 0;
virtual void print(ostream &os, CharString path, const TrueFalse &recursive)
const = 0;
#ifdef MENUGFX
friend class Form;
friend class MenuForm;
friend class CommandForm;
friend class Command0Form;
friend class CommandMForm;
private:
virtual void AddToForm(MenuForm*) = 0;
#endif // MENUGFX
};
class Command : public MenuOption {
friend class Waiter;
friend class Menu;
protected:
#ifndef MENUGFX
Command(const CharString &nm, const CharString &hs,
const MenuAttribute &att = MOPT_NORMAL)
: MenuOption(nm, hs, '*', att)
{}
#else // MENUGFX
friend class MenuForm;
friend class CommandForm;
friend class CommandSForm;
friend class CommandZeroForm;
Command(const CharString &nm, const CharString &hs,
const MenuAttribute &att = MOPT_NORMAL)
: MenuOption(nm, hs, '*', att),
form(0)
{}
virtual void AddToForm(MenuForm*);
virtual CommandForm *makecmdform(const WordList&) = 0;
virtual void print(FILE*, CharString, const TrueFalse&) const {}
virtual void print(ostream &, CharString, const TrueFalse&) const {}
CommandForm *form;
#endif // MENUGFX
/* execute is a virtual function that handles all kinds of
* menu options for TextWaiters. pronto performs commands only,
* but is independent of the type of Waiter.
*/
virtual void execute(TextWaiter&) = 0;
virtual void pronto(Waiter &, const WordList&) = 0;
public:
virtual ~Command();
};
class CommandM : public Command { // command w/ multiple args in a Menu
friend class Waiter;
friend class TextWaiter;
friend class ScriptWaiter;
friend class Menu;
private:
void koko(TextWaiter&, int); // the lord high executioner
CommandM *duplicate() const; // make a copy of this command.
Vec<CommandM*> *clonelist;
int ismaster;
protected:
virtual CommandFn func() = 0;
virtual void execute(TextWaiter &);
virtual void pronto(Waiter &w, const WordList&);
virtual CommandM *clone() const = 0;// make a copy of derived parts
CommandM(const CharString &nm, const CharString &hs,
const MenuAttribute &att = MOPT_NORMAL)
: Command(nm, hs, att),
arg(0),
ismaster(1),
clonelist(new Vec<CommandM*>)
{}
CommandM(const CommandM &cmd);
public:
virtual ~CommandM();
// argstring() returns a string with the args of the cmd.
CharString argstring() const;
// this is public only because it's needed in the AddArgument templates
Vec<Variable*> arg;
#ifdef MENUGFX
friend class CommandMForm;
friend class CommandForm;
virtual CommandForm *makecmdform(const WordList&);
#endif // MENUGFX
};
class Command0 : public Command { // command w/out args
friend class Waiter;
friend class Menu;
private:
CommandFn (*func)();
virtual void execute(TextWaiter &);
virtual void pronto(Waiter &w, const WordList&);
Command0(const CharString &nm, const CharString &hs, CommandFn (*fn)(),
const MenuAttribute &att)
: Command(nm, hs, att), func(fn)
{}
public:
virtual ~Command0() {}
#ifdef MENUGFX
friend class CommandForm;
friend class Command0Form;
private:
virtual CommandForm *makecmdform(const WordList&);
#endif // MENUGFX
};
class CommandS : public Command { // command that executes a string
private:
CharString script;
Menu *menu;
virtual void pronto(Waiter&, const WordList&);
virtual void execute(TextWaiter&);
virtual int help(TextWaiter&) const;
public:
CommandS(const CharString &nm, CharString &scr, Menu *m)
: script(scr), menu(m), Command(nm, "execute macro " + nm) {}
virtual ~CommandS() {}
#ifdef MENUGFX
friend class CommandSForm;
private:
virtual CommandForm *makecmdform(const WordList&);
#endif // MENUGFX
};
class SubMenu : public MenuOption {
friend class Menu;
friend class Waiter;
private:
Menu* menu;
virtual void execute(TextWaiter& w);
virtual int help(TextWaiter&) const;
#ifndef MENUGFX
SubMenu(const CharString &nm, const CharString &hs,
const MenuAttribute &att = MOPT_NORMAL)
: MenuOption(nm, hs, '/', att),
menu(0)
{}
#else // MENUGFX
friend class MenuForm;
private:
SubMenu(const CharString &nm, const CharString &hs,
const MenuAttribute &att = MOPT_NORMAL)
: MenuOption(nm, hs, '/', att),
menu(0),
form(0)
{}
virtual void AddToForm(MenuForm*);
virtual void print(FILE *file, CharString path, const TrueFalse &recursive)
const;
virtual void print(ostream &os, CharString path, const TrueFalse &recursive)
const;
MenuForm *form; // form representing the submenu
#endif // MENUGFX
};
// Interactively settable variables in a menu.
class Variable : public MenuOption {
public:
void *address; // would be private if templates could be friends
virtual CharString tostring() const = 0;
protected:
void (*hook)(const CharString&); // fn called when variable is set
Variable(const CharString &nm, const CharString &hs, void *x,
void (*f)(const CharString&)=0,
const MenuAttribute& = MOPT_NORMAL);
Variable();
virtual ~Variable();
void *oldvalue;
virtual void execute(TextWaiter&);
CharString printstr() const;
virtual int fromstring(const CharString&, Waiter&) const = 0;
virtual void fromstring(TextWaiter&) const = 0;
virtual void copyvalue(const Variable*) = 0;
virtual void savevalue() = 0;
virtual void restorevalue() = 0;
void update_forms();
virtual int help(TextWaiter&) const;
virtual void print(FILE *file, CharString path,
const TrueFalse &recursive) const;
virtual void print(ostream &os, CharString path,
const TrueFalse &recursive) const;
friend class TextWaiter;
friend class CommandM;
friend class VariableRegistry;
#ifdef MENUGFX
friend class Form;
friend class MenuForm;
friend class CommandMForm;
protected:
virtual void AddToForm(MenuForm*);
virtual VarObject* create_varobject(Variable*, Form*, VarObjectType,
int, int, int, int)=0;
VarObject *varobj;
#endif // MENUGFX
};
// When a variable is added to a Menu with AddVariable, a new Variable
// is created. Each Variable is in only one menu, but each variable
// (small v) can be in more than one. Changes in one Variable should
// be reflected in the others. This is only a problem in the graphics
// interface, when both Variables may be on the screen at the same
// time. The VariableRegistry keeps track of Variables corresponding
// to the same variable, and allows functions to be applied to all of
// them together.
class VariableRegistry {
private:
VariableRegistry() {}
~VariableRegistry();
Vec<Vec<Variable*>*> varlist;
// add a new Variable to the registry
void add_variable(Variable *);
public:
// The constructor is private, but this function is used to allocate
// a single instance of the class:
static VariableRegistry &vr();
// Call a function on each Variable corresponding to the given
// Variable. Don't call it for the specified Variable, since the
// calling function can do that easily if it wants to.
void call_function(const Variable *, void (Variable::*)()) const;
friend class Variable;
};
template <class TYPE>
class Var : public Variable {
public:
Var(const CharString &nm, const CharString &hs, TYPE &x,
void (*f)(const CharString&));
Var(const CharString &nm, const CharString &hs, TYPE &x,
void (*f)(const CharString&), const MenuAttribute&);
Var(const CharString &nm, const CharString &hs, TYPE &x);
Var(const CharString &nm, const CharString &hs, TYPE &x,
const MenuAttribute&);
Var(const CharString &nm, TYPE &x); // for arguments
Var(const CharString &nm, TYPE &x, const MenuAttribute&); // for arguments
Var() {}; // so that dummy instances can be made in kludge.C
virtual ~Var();
virtual CharString tostring() const;
protected:
virtual int fromstring(const CharString &str, Waiter&) const;
virtual void fromstring(TextWaiter&) const;
virtual void copyvalue(const Variable*);
virtual void savevalue();
virtual void restorevalue();
friend class TextWaiter;
friend class CommandM;
#ifdef MENUGFX
protected:
virtual VarObject *create_varobject(Variable*, Form*, VarObjectType,
int, int, int, int);
friend class Form;
friend class MenuForm;
friend class CommandMForm;
#endif // MENUGFX
};
// declare specializations
template <> int Var<double>::fromstring(const CharString&, Waiter&) const;
template <> void Var<double>::fromstring(TextWaiter&) const;
template <> int Var<float>::fromstring(const CharString&, Waiter&) const;
template <> void Var<float>::fromstring(TextWaiter&) const;
template <> int Var<int>::fromstring(const CharString&, Waiter&) const;
template <> void Var<int>::fromstring(TextWaiter&) const;
template <> int Var<CharString>::fromstring(const CharString&, Waiter&) const;
template <> void Var<CharString>::fromstring(TextWaiter&) const;
template <> CharString Var<CharString>::tostring() const;
template <> VarObject*
Var<TrueFalse>::create_varobject(Variable*, Form*,
VarObjectType, int, int, int, int);
template <> CharString Var<char>::tostring() const;
template <class TYPE, class NTYPE, class HTYPE>
void AddVariable(Menu *m, NTYPE nm, HTYPE help,
TYPE &x, void (*f)(const CharString&));
template <class TYPE, class NTYPE, class HTYPE>
void AddVariable(Menu *m, NTYPE nm, HTYPE help, TYPE &x);
template <class TYPE, class NTYPE, class HTYPE>
void AddVariable(Menu *m, NTYPE nm, HTYPE help,
TYPE &x, void (*f)(const CharString&),
const MenuAttribute &att);
template <class TYPE, class NTYPE, class HTYPE>
void AddVariable(Menu *m, NTYPE nm, HTYPE help, TYPE &x,
const MenuAttribute &att);
template <class TYPE, class NTYPE>
void AddArgument(CommandM *cmd, NTYPE nm, TYPE &x);
template <class TYPE, class NTYPE>
void AddArgument(CommandM *cmd, NTYPE nm, TYPE &x, const MenuAttribute &att);
// -------------------------------------------------------------- //
/* Waiter classes.
* Pointers to the base waiter class are passed to the Commands. Otherwise,
* there's no reason to have the TextWaiter and FormWaiter classed be
* derived from a common base class.
*/
const int wbufsiz = 1024;
class Waiter {
friend class Menu;
friend class Command;
friend class Command0;
friend class CommandS;
friend class CommandM;
friend class Variable;
friend class MenuOption;
friend class VarToggle;
friend Waiter *garcon();
protected:
CharString makeprompt(const char *); // constructs prompt from promptfmt
CharString promptfmt; // format for prompts
void saywhat(const char*); // bad input, error message
void makecurrent(); // label this one the current waiter
WordList path; // path to currently executing cmd, set by pronto
CharString args; // set by commands so that user fns can unparse args
CharString errhm; // sort of clearing the throat to get attention
Menu *rootmenu; // the menu for the last order()
int (*quitcmd)(); // Command to call when quitting
// stuff for defining macros
int macromode;
Menu *macromenu;
CharString macrostring;
WordList macropath;
int macrocount;
void startmacro(Menu *m, const WordList &pth) {
macromenu = m;
macromode = 1;
macrostring = "";
macropath = pth;
}
void record(const CharString &s) { macrostring += s; }
void recorddelim();
void endmacro();
void definemacro(const CharString &); // put it in the menu
void trashmacro() { macromode = 0; macrostring = ""; }
virtual CharString getmacroname() = 0;
CharString defaultmacroname();
TrueFalse logging_;
int inhibit_logging_; // to temporarily disable logging
ofstream *logfile;
static TrueFalse logdirty_;
static Vec<CharString*> logbook;
public:
Waiter(MenuStream&);
Waiter(MenuStream*);
virtual ~Waiter();
virtual void order(Menu*) = 0; // take orders
void setprompt(const char *); // set format for prompts
CharString get_command(int=0) const; // get part of command path
int get_depth() const; // get depth of command path
CharString get_path() const { return path.concat(); }
CharString get_path(int n, int m) const {// path skipping n at start, m at end
return path.concat(n, m);
}
const CharString &get_args() const { return args; }
MenuStream &msout; // output stream
TrueFalse echo; // echo inputs?
// allows functions to read data embedded in scripts, but may return
// 0 for Waiters for which this doesn't make sense
virtual istream *inputstream() { return 0; }
virtual void quiet() { echo = 0;}
virtual void talkative() { echo = 1;}
// read text input from a file
void runfile(FILE*, Menu*, int, bool (*stp)()=0);
void runfile(istream&, Menu*, int, bool (*stp)()=0);
// ask the user for a string
virtual CharString getstring(const CharString&, const CharString&) = 0;
// ask a yes/no question
virtual int question(const CharString&, int) = 0;
// wait a bit
static CommandFn pause();
void loadmacros(FILE*);
void showmacros(FILE*);
void showmacros(ostream&);
TrueFalse logging() const { return logging_; } // log
void startlog(const CharString&, const TrueFalse &append=TF_FALSE);
void stoplog();
void log(const CharString &);
void inhibit_logging() { ++inhibit_logging_; }
void disinhibit_logging() { --inhibit_logging_; }
void printlog(ostream&) const;
void readlog(istream&);
TrueFalse logdirty() const { return logdirty_; }
// direct output to a file as well as to the screen
// "mode" is the second argument to fopen()
int tee(const CharString &file, const char *mode) {
return msout.tee(file, mode);
}
void teestop() { msout.teestop(); } // stop doing so
// choose which kinds of output get teed
void tee_normal(int on) { msout.tee_normal(on); }
void tee_errors(int on) { msout.tee_error(on); }
void tee_prompt(int on) { msout.tee_prompt(on); }
void tee_inform(int on) { msout.tee_info(on); }
// set fn to be called when quitting. returns 1 if really should quit.
void quitcommand(int (*f)()) { quitcmd = f; }
int graphics(); // is graphics being used?
// (ie has a FormWaiter been invoked?)
#ifdef MENUGFX
friend class MenuForm;
friend class CommandMForm;
friend class Command0Form;
public:
// stuff that's only meaningful for FormWaiter, but is defined as no-op
// for all waiters for convenience
virtual void graphics_off() {} // suppress graphics output
virtual void graphics_on() {} // restore graphics output
virtual void set_cursor(int) {}
#endif // MENUGFX
};
class TextWaiter : public Waiter { // waiters handle menus
friend class Menu;
friend class CommandM;
friend class Command0;
friend class CommandS;
friend class Variable;
friend class SubMenu;
friend class MenuOption;
friend class Waiter;
protected:
void twstartup(); // used by constructors
FILE *infile; // typed input
CharString buffer; // current input line
int repeatword; // repeat last word read?
int grouplevel; // parenthesis depth
int eoffound; // was end-of-file encountered?
TrueFalse showprompts; // print prompts?
CommandFn (*eolfn)(); // function called at end-of-line;
// methods called by Menu...
void order1(Menu*); // take a single order
CharString word(void); // get next word of input
// prompt for next word of input
CharString inputword(const CharString &prompt);
// prompt for next line of input
virtual CharString getline(const CharString &prompt);
CharString argword(void); // get word from arg list
void listoptions(const Menu*); // print choices
void trashline(); // discard rest of input
int help(Menu* menu);
char *(*inputhandler)(const CharString&, MenuStream&, FILE*);
int getvar(const Variable*); // ask for variable value
void echovar(const Variable*); // print variable value and path
int setargs(Vec<Variable*> &); // set args for commands
virtual void do_cmdm(CommandM*);
virtual CharString getmacroname();
WordList cmdlist; // for keeping track of calling sequence
Menu *currentmenu;
bool (*stop)(); // returns 1 when it's time to stop taking orders
static char *defaultinputhandler(const CharString&, MenuStream&, FILE*);
// This is really ugly. The TextWaiter has to be able to return an
// istream for the inputstream() method, but it only has a FILE*. So
// if it needs to it creates an istream and stores it here. The
// ugliness is that the StreamWaiter class is derived from
// TextWaiter, but the StreamWaiter doesn't need to construct an
// istream; it has one already. StreamWaiter should *not* be
// derived from TextWaiter; it should *be* TextWaiter, and we
// shouldn't use FILEs at all!
istream *inputstrm_;
public:
TextWaiter(bool (*stop)()=0);
TextWaiter(FILE* ifile, FILE *pfile, bool (*stop)()=0);
TextWaiter(char *(*ih)(const CharString&, MenuStream&, FILE*),
bool (*stop)()=0);
TextWaiter(FILE* ifile, FILE *pfile,
char *(*ih)(const CharString&, MenuStream&, FILE*),
bool (*stop)()=0);
TextWaiter(MenuStream &ms, FILE* ifile = stdin,
char *(*ih)(const CharString&,
MenuStream&,FILE*)=defaultinputhandler,
bool (*stop)()=0);
TextWaiter(MenuStream &ms, FILE* ifile, bool (*stop)());
virtual ~TextWaiter();
virtual istream *inputstream();
virtual void order(Menu*); // perform an action from menu
virtual void quiet() { echo = 0; showprompts = 0;}
virtual void talkative() { echo = 1; showprompts = 1;}
virtual int question(const CharString &, int);
void set_eolfn(CommandFn (*)()); // set end-of-line function
// check for end-of-file on input
int eof() {return eoffound;}
virtual CharString getstring(const CharString&, const CharString&);
/* inbuf would be protected if templates could be friends */
istrstream *inbuf; // for reading current input line
};
class ScriptWaiter : public TextWaiter {
private:
CharString script;
int already_read;
virtual CharString getline(const CharString&);
virtual void do_cmdm(CommandM*);
public:
ScriptWaiter(const CharString&, MenuStream&, bool (*stop)()=0);
virtual void talkative() { echo = 1; showprompts = 0;}
};
class StreamWaiter : public TextWaiter {
// use an existing istream for input, without any inputhandler for now.
private:
virtual CharString getline(const CharString&);
istream &inputstream_;
public:
StreamWaiter(MenuStream &output, istream &input,
bool (*stop)()=0);
virtual istream *inputstream() { return &inputstream_; }
};
#ifdef MENUGFX
class FormWaiter : public Waiter {
friend class Menu;
friend class Command;
friend class Variable;
friend class SubMenu;
friend class MenuOption;
friend class VarToggle;
private:
virtual CharString getmacroname();
MenuForm *rootform;
public:
FormWaiter(int*, char*[], XrmOptionDescList = 0, int = 0);
~FormWaiter() {}
virtual void order(Menu*);
virtual void graphics_off();
virtual void graphics_on();
virtual void set_cursor(int);
void show_homeform() const;
virtual CharString getstring(const CharString&, const CharString&);
virtual int question(const CharString &, int);
};
#endif
extern Waiter *garcon(); // pointer to current Waiter
class LoopCommand : public CommandM {
private:
CharString script, beginscript, endscript;
int iterations;
Menu *loopmenu;
int fixscripts; // are scripts not to appear in argument list?
public:
LoopCommand(const CharString&, const CharString&, Menu*,
const CharString&, const CharString& = "", const CharString& = "",
int=1);
virtual CommandFn func();
virtual CommandM *clone() const;
void setscript(const CharString &s) { script = s; }
};
class LoadMacroCmd : public CommandM {
private:
CharString filename;
CharString cmdname;
public:
LoadMacroCmd(const CharString &cname);
virtual CommandFn func();
virtual CommandM *clone() const;
};
class SaveMacroCmd : public CommandM {
private:
CharString filename;
CharString cmdname;
public:
SaveMacroCmd(const CharString &cname);
virtual CommandFn func();
virtual CommandM *clone() const;
};
// ------------------------------------------------------- //
#include "menuDef.C"
#endif /* MENUDEF_H */
syntax highlighted by Code2HTML, v. 0.9.1