Gave EvMenu a 'persistent' option (False by default). This makes the menu survive a server reboot, including remembering its last node. Use with caution during debugging. Changed the EvMenu API so allow_exit is now auto_exit, which better describes its functionality. Also added auto_look and auto_help flags for turning off the respective automatic options (Resolves #949)."

This commit is contained in:
Griatch 2016-04-16 23:57:05 +02:00
parent 3b8142201d
commit 74a339574a

View file

@ -14,7 +14,7 @@ To start the menu, just import the EvMenu class from this module,
EvMenu(caller, menu_module_path, EvMenu(caller, menu_module_path,
startnode="node1", startnode="node1",
cmdset_mergetype="Replace", cmdset_priority=1, cmdset_mergetype="Replace", cmdset_priority=1,
allow_quit=True, cmd_on_quit="look") auto_quit=True, cmd_on_exit="look")
``` ```
Where `caller` is the Object to use the menu on - it will get a new Where `caller` is the Object to use the menu on - it will get a new
@ -195,6 +195,17 @@ class CmdEvMenuNode(Command):
""" """
caller = self.caller caller = self.caller
menu = caller.ndb._menutree or self.session.ndb._menutree menu = caller.ndb._menutree or self.session.ndb._menutree
if not menu:
# check if there is a saved menu available
saved_options = caller.attributes.get("_menutree_saved")
if saved_options:
startnode = caller.attributes.get("_menutree_saved_startnode")
if startnode:
saved_options[1]["startnode"] = startnode
# this will create a completely new menu call
EvMenu(caller, *saved_options[0], **saved_options[1])
return
if not menu: if not menu:
err = "Menu object not found as %s.ndb._menutree!" % (caller) err = "Menu object not found as %s.ndb._menutree!" % (caller)
@ -326,18 +337,17 @@ def evtable_parse_input(menuobject, raw_string, caller):
the menu. the menu.
""" """
cmd = raw_string.strip().lower() cmd = raw_string.strip().lower()
allow_quit = menuobject.allow_quit
if cmd in menuobject.options: if cmd in menuobject.options:
# this will take precedence over the default commands # this will take precedence over the default commands
# below # below
goto, callback = menuobject.options[cmd] goto, callback = menuobject.options[cmd]
menuobject.callback_goto(callback, goto, raw_string) menuobject.callback_goto(callback, goto, raw_string)
elif cmd in ("look", "l"): elif menuobject.auto_look and cmd in ("look", "l"):
menuobject.display_nodetext() menuobject.display_nodetext()
elif cmd in ("help", "h"): elif menuobject.auto_help and cmd in ("help", "h"):
menuobject.display_helptext() menuobject.display_helptext()
elif allow_quit and cmd in ("quit", "q", "exit"): elif menuobject.auto_quit and cmd in ("quit", "q", "exit"):
menuobject.close_menu() menuobject.close_menu()
elif menuobject.default: elif menuobject.default:
goto, callback = menuobject.default goto, callback = menuobject.default
@ -363,7 +373,8 @@ class EvMenu(object):
""" """
def __init__(self, caller, menudata, startnode="start", def __init__(self, caller, menudata, startnode="start",
cmdset_mergetype="Replace", cmdset_priority=1, cmdset_mergetype="Replace", cmdset_priority=1,
allow_quit=True, cmd_on_quit="look", auto_quit=True, auto_look=True, auto_help=True,
cmd_on_exit="look", persistent=False,
nodetext_formatter=dedent_strip_nodetext_formatter, nodetext_formatter=dedent_strip_nodetext_formatter,
options_formatter=evtable_options_formatter, options_formatter=evtable_options_formatter,
node_formatter=underline_node_formatter, node_formatter=underline_node_formatter,
@ -394,16 +405,28 @@ class EvMenu(object):
cmdset_priority (int, optional): The merge priority for the cmdset_priority (int, optional): The merge priority for the
menu command set. The default (1) is usually enough for most menu command set. The default (1) is usually enough for most
types of menus. types of menus.
allow_quit (bool, optional): Allow user to use quit or auto_quit (bool, optional): Allow user to use "q", "quit" or
exit to leave the menu at any point. Recommended during "exit" to leave the menu at any point. Recommended during
development! development!
cmd_on_quit (callable, str or None, optional): When exiting the menu auto_look (bool, optional): Automatically make "looK" or "l" to
re-show the last node. Turning this off means you have to handle
re-showing nodes yourself, but may be useful if you need to
use "l" for some other purpose.
auto_help (bool, optional): Automatically make "help" or "h" show
the current help entry for the node. If turned off, eventual
help must be handled manually, but it may be useful if you
need 'h' for some other purpose, for example.
cmd_on_exit (callable, str or None, optional): When exiting the menu
(either by reaching a node with no options or by using the (either by reaching a node with no options or by using the
in-built quit command (activated with `allow_quit`), this in-built quit command (activated with `allow_quit`), this
callback function or command string will be executed. callback function or command string will be executed.
The callback function takes two parameters, the caller then the The callback function takes two parameters, the caller then the
EvMenu object. This is called after cleanup is complete. EvMenu object. This is called after cleanup is complete.
Set to None to not call any command. Set to None to not call any command.
persistent (bool, optional): Make the Menu persistent (i.e. it will
survive a reload. This will make the Menu cmdset persistent. Use
with caution - if your menu is buggy you may end up in a state
you can't get out of!
nodetext_formatter (callable, optional): This callable should be on nodetext_formatter (callable, optional): This callable should be on
the form `function(nodetext, has_options, caller=None)`, where `nodetext` is the the form `function(nodetext, has_options, caller=None)`, where `nodetext` is the
node text string and `has_options` a boolean specifying if there node text string and `has_options` a boolean specifying if there
@ -448,6 +471,7 @@ class EvMenu(object):
self._options_formatter = options_formatter self._options_formatter = options_formatter
self._node_formatter = node_formatter self._node_formatter = node_formatter
self._input_parser = input_parser self._input_parser = input_parser
self._persistent = persistent
if startnode not in self._menutree: if startnode not in self._menutree:
raise EvMenuError("Start node '%s' not in menu tree!" % startnode) raise EvMenuError("Start node '%s' not in menu tree!" % startnode)
@ -455,19 +479,20 @@ class EvMenu(object):
# public variables made available to the command # public variables made available to the command
self.caller = caller self.caller = caller
self.allow_quit = allow_quit self.auto_quit = auto_quit
if isinstance(cmd_on_quit, str): self.auto_look = auto_look
self.cmd_on_quit = lambda caller, menu: caller.execute_cmd(cmd_on_quit) self.auto_help = auto_help
elif callable(cmd_on_quit): if isinstance(cmd_on_exit, str):
self.cmd_on_quit = cmd_on_quit self.cmd_on_exit = lambda caller, menu: caller.execute_cmd(cmd_on_exit)
elif callable(cmd_on_exit):
self.cmd_on_exit = cmd_on_exit
else: else:
self.cmd_on_quit = None self.cmd_on_exit = None
self.default = None self.default = None
self.nodetext = None self.nodetext = None
self.helptext = None self.helptext = None
self.options = None self.options = None
# store ourself on the object # store ourself on the object
self.caller.ndb._menutree = self self.caller.ndb._menutree = self
@ -475,7 +500,19 @@ class EvMenu(object):
menu_cmdset = EvMenuCmdSet() menu_cmdset = EvMenuCmdSet()
menu_cmdset.mergetype = str(cmdset_mergetype).lower().capitalize() or "Replace" menu_cmdset.mergetype = str(cmdset_mergetype).lower().capitalize() or "Replace"
menu_cmdset.priority = int(cmdset_priority) menu_cmdset.priority = int(cmdset_priority)
self.caller.cmdset.add(menu_cmdset) self.caller.cmdset.add(menu_cmdset, permanent=persistent)
if persistent:
caller.attributes.add("_menutree_saved",
((menudata, ),
{"startnode": startnode,
"cmdset_mergetype": cmdset_mergetype,
"cmdset_priority": cmdset_priority,
"auto_quit": auto_quit, "auto_look": auto_look, "auto_help": auto_help,
"cmd_on_exit": cmd_on_exit, "persistent": persistent,
"nodetext_formatter": nodetext_formatter, "options_formatter": options_formatter,
"node_formatter": node_formatter, "input_parser": input_parser}))
caller.attributes.add("_menutree_saved_startnode", startnode)
# start the menu # start the menu
self.goto(self._startnode, "") self.goto(self._startnode, "")
@ -633,6 +670,9 @@ class EvMenu(object):
except EvMenuError: except EvMenuError:
return return
if self._persistent:
self.caller.attributes.add("_menutree_saved_startnode", nodename)
# validation of the node return values # validation of the node return values
helptext = "" helptext = ""
if hasattr(nodetext, "__iter__"): if hasattr(nodetext, "__iter__"):
@ -674,20 +714,23 @@ class EvMenu(object):
if helptext: if helptext:
self.helptext = helptext self.helptext = helptext
elif options: elif options:
self.helptext = _HELP_FULL if self.allow_quit else _HELP_NO_QUIT self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT
else: else:
self.helptext = _HELP_NO_OPTIONS if self.allow_quit else _HELP_NO_OPTIONS_NO_QUIT self.helptext = _HELP_NO_OPTIONS if self.auto_quit else _HELP_NO_OPTIONS_NO_QUIT
self.display_nodetext() self.display_nodetext()
def close_menu(self): def close_menu(self):
""" """
Shutdown menu; occurs when reaching the end node. Shutdown menu; occurs when reaching the end node or using the quit command.
""" """
self.caller.cmdset.remove(EvMenuCmdSet) self.caller.cmdset.remove(EvMenuCmdSet)
del self.caller.ndb._menutree del self.caller.ndb._menutree
if self.cmd_on_quit is not None: if self._persistent:
self.cmd_on_quit(self.caller, self) self.caller.attributes.remove("_menutree_saved")
self.caller.attributes.remove("_menutree_saved_startnode")
if self.cmd_on_exit is not None:
self.cmd_on_exit(self.caller, self)
# ------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------
@ -894,4 +937,4 @@ class CmdTestMenu(Command):
self.caller.msg("Usage: testmenu menumodule") self.caller.msg("Usage: testmenu menumodule")
return return
# start menu # start menu
EvMenu(self.caller, self.args.strip(), startnode="test_start_node", cmdset_mergetype="Replace") EvMenu(self.caller, self.args.strip(), startnode="test_start_node", persistent=True, cmdset_mergetype="Replace")