"""Menu objects for the MUFF Engine"""
-# Copyright (c) 2005 mudpy, Jeremy Stanley <fungi@yuggoth.org>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
+# Copyright (c) 2005 mudpy, Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
+# Licensed per terms in the LICENSE file distributed with this software.
+# muff uses menu data stored in ini-style files supported by ConfigParser
import ConfigParser
+
+# os.listdir is needed to get a file listing from a config directory
import os
+
+# re.match is used to find menu options based on the choice_ prefix
import re
-import string
+# hack to load all modules in the muff package
import muff
for module in muff.__all__:
exec("import " + module)
+# see if the menupath can be retrieved from muffconf
try:
- if muffconf.config_data.get("general", "menu_path"):
- pass
+ if muffconf.config_data.get("files", "menus"): pass
+
+# otherwise, reload muffconf
except AttributeError:
reload(muffconf)
+# build a list of files in the menus directory
menu_files = []
-menu_path = muffconf.config_data.get("general", "menu_path")
+menu_path = muffconf.config_data.get("files", "menus")
for each_file in os.listdir(menu_path):
menu_files.append(menu_path + "/" + each_file)
+
+# read the menu files
menu_data = ConfigParser.SafeConfigParser()
menu_data.read(menu_files)
def get_default(user):
+ """Return the default choice for a menu."""
return menu_data.get(user.state, "default")
def get_menu(user):
+ """Show the correct menu text to a user."""
+
+ # the menu hasn't been shown yet since the user's last input
if not user.menu_seen:
+
+ # echo is currently on for the user, so don't add an extra eol
if user.echoing:
spacer = ""
+
+ # echo is currently off for the user, so add an extra eol
else:
spacer = "$(eol)"
+
+ # if the user has echo on and the menu specifies it should be
+ # turned off, send: iac + will + echo + null
try:
if menu_data.get(user.state, "echo") == "off" and user.echoing:
echo = chr(255) + chr(251) + chr(1) + chr(0)
user.echoing = False
else:
echo = ""
+
+ # if echo is not set to off in the menu and the user curently
+ # has echo off, send: iac + wont + echo + null
except:
if not user.echoing:
echo = chr(255) + chr(252) + chr(1) + chr(0)
user.echoing = True
else:
echo = ""
+
+ # and error condition was raised by the handler
if user.error:
+
+ # try to get an error message matching the condition
+ # and current state
try:
description = "$(red)" + menu_data.get(user.state, "error_" + user.error) + "$(nrm)$(eol)$(eol)"
+
+ # otherwise, use a generic one
except:
description = "$(red)That is not a valid choice...$(nrm)$(eol)$(eol)"
+
+ # now clear the error condition
user.error = ""
+
+ # there was no error condition raised by the handler
else:
+
+ # try to get a menu description for the current state
try:
description = menu_data.get(user.state, "description") + "$(eol)$(eol)"
+
+ # otherwise, leave it blank
except:
description = ""
+
+ # try to get menu choices for the current state
try:
+
+ # build a dict of choice:meaning
choices = {}
for option in menu_data.options(user.state):
if re.match("choice_", option):
choices[option.split("_")[1]] = menu_data.get(user.state, option)
+
+ # make a sorted list of choices
choice_keys = choices.keys()
choice_keys.sort()
+
+ # concatenate them all into a list for display
choicestring = ""
for choice in choice_keys:
choicestring += " [$(red)" + choice + "$(nrm)] " + choices[choice] + "$(eol)"
+
+ # throw in an additional blank line after the choices,
+ # if there were any
if choicestring:
choicestring += "$(eol)"
+
+ # there were no choices, so leave them blank
except:
choicestring = ""
+
+ # try to get a prompt, if it was defined
try:
prompt = menu_data.get(user.state, "prompt") + " "
+
+ # otherwise, leave it blank
except:
prompt = ""
+
+ # throw in the default choice, if it exists
try:
default = "[$(red)" + menu_data.get(user.state, "default") + "$(nrm)] "
+
+ # otherwise, leave it blank
except:
default = ""
+
+ # echo is on, so don't display a message about it
if user.echoing:
echoing = ""
+
+ # echo is off, so let the user know
else:
echoing = "(won't echo) "
+
+ # assemble and send the various strings defined above
user.send(echo + spacer + description + choicestring + prompt + default + echoing, "")
+
+ # flag that the menu has now been displayed
user.menu_seen = True