Imported from archive.
[mudpy.git] / lib / muff / muffmenu.py
1 """Menu objects for the MUFF Engine"""
2
3 # Copyright (c) 2005 mudpy, Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
4 # Licensed per terms in the LICENSE file distributed with this software.
5
6 # muff uses menu data stored in ini-style files supported by ConfigParser
7 import ConfigParser
8
9 # hack to load all modules in the muff package
10 import muff
11 for module in muff.__all__:
12         exec("import " + module)
13
14 # see if the menupath can be retrieved from muffconf
15 try:
16         if muffconf.get("files", "menus"): pass
17
18 # otherwise, reload muffconf
19 except AttributeError:
20         reload(muffconf)
21
22 # now we can safely nab the menu path setting and build a list of data files
23 menu_path = muffconf.get("files", "menus")
24 menu_files_index = ConfigParser.SafeConfigParser()
25 menu_files_index.read(menu_path + "/index")
26 menu_files = []
27 for each_file in menu_files_index.get("index", "files").split():
28         menu_files.append(menu_path + "/" + each_file)
29
30 # read the menu files
31 menu_data = ConfigParser.SafeConfigParser()
32 menu_data.read(menu_files)
33
34 def get_menu(state, error=None, echoing=True, choices={}):
35         """Show the correct menu text to a user."""
36
37         # begin with a telnet echo command sequence if needed
38         message = get_echo_sequence(state, echoing)
39
40         # get the description or error text
41         message += get_menu_description(state, error)
42
43         # get menu choices for the current state
44         message += get_formatted_menu_choices(state, choices)
45
46         # try to get a prompt, if it was defined
47         message += get_menu_prompt(state)
48
49         # throw in the default choice, if it exists
50         message += get_formatted_default_menu_choice(state)
51
52         # display a message indicating if echo is off
53         message += get_echo_message(state)
54
55         # return the assembly of various strings defined above
56         return message
57
58 def menu_echo_on(state):
59         """True if echo is on, false if it is off."""
60         try:
61                 return menu_data.getboolean(state, "echo")
62         except:
63                 return True
64
65 def get_echo_sequence(state, echoing):
66         """Build the appropriate IAC ECHO sequence as needed."""
67
68         # if the user has echo on and the menu specifies it should be turned
69         # off, send: iac + will + echo + null
70         if echoing and not menu_echo_on(state): return chr(255) + chr(251) + chr(1) + chr(0)
71
72         # if echo is not set to off in the menu and the user curently has echo
73         # off, send: iac + wont + echo + null
74         elif not echoing and menu_echo_on(state): return chr(255) + chr(252) + chr(1) + chr(0)
75
76         # default is not to send an echo control sequence at all
77         else: return ""
78
79 def get_echo_message(state):
80         """Return a message indicating that echo is off."""
81         if menu_echo_on(state): return ""
82         else: return "(won't echo) "
83
84 def get_default_menu_choice(state):
85         """Return the default choice for a menu."""
86         try:
87                 return menu_data.get(state, "default")
88         except:
89                 return ""
90 def get_formatted_default_menu_choice(state):
91         """Default menu choice foratted for inclusion in a prompt string."""
92         default = get_default_menu_choice(state)
93         if default: return "[$(red)" + default + "$(nrm)] "
94         else: return ""
95
96 def get_menu_description(state, error):
97         """Get the description or error text."""
98
99         # an error condition was raised by the handler
100         if error:
101
102                 # try to get an error message matching the condition
103                 # and current state
104                 try:
105                         return "$(red)" + menu_data.get(state, "error_" + error) + "$(nrm)$(eol)$(eol)"
106
107                 # otherwise, use a generic one
108                 except:
109                         return "$(red)That is not a valid choice...$(nrm)$(eol)$(eol)"
110
111         # there was no error condition
112         else:
113
114                 # try to get a menu description for the current state
115                 try:
116                         return menu_data.get(state, "description") + "$(eol)$(eol)"
117
118                 # otherwise, leave it blank
119                 except:
120                         return ""
121
122 def get_menu_prompt(state):
123         """Try to get a prompt, if it was defined."""
124         try:
125                 return menu_data.get(state, "prompt") + " "
126         except:
127                 return ""
128
129 def get_menu_choices(user):
130         """Return a dict of choice:meaning."""
131         choices = {}
132         for option in menu_data.options(user.state):
133                 if option.startswith("choice_"):
134                         choices[option.split("_", 2)[1]] = menu_data.get(user.state, option)
135                 elif option.startswith("create_"):
136                         choices[option.split("_", 2)[1]] = eval(menu_data.get(user.state, option))
137         return choices
138
139 def get_formatted_menu_choices(state, choices):
140         """Returns a formatted string of menu choices."""
141         choice_output = ""
142         choice_keys = choices.keys()
143         choice_keys.sort()
144         for choice in choice_keys:
145                 choice_output += "   [$(red)" + choice + "$(nrm)]  " + choices[choice] + "$(eol)"
146         if choice_output: choice_output += "$(eol)"
147         return choice_output
148
149 def get_menu_branches(state):
150         """Return a dict of choice:branch."""
151         branches = {}
152         try:
153                 for option in menu_data.options(state):
154                         if option.startswith("branch_"):
155                                 branches[option.split("_", 2)[1]] = menu_data.get(state, option)
156         except:
157                 pass
158         return branches
159
160 def get_default_branch(state):
161         """Return the default branch."""
162         try:
163                 return menu_data.get(state, "branch")
164         except:
165                 return ""
166
167 def get_choice_branch(user, choice):
168         """Returns the new state matching the given choice."""
169         branches = get_menu_branches(user.state)
170         if not choice: choice = get_default_menu_choice(user.state)
171         if choice in branches.keys(): return branches[choice]
172         elif choice in user.menu_choices.keys(): return get_default_branch(user.state)
173         else: return ""
174
175 def get_menu_actions(state):
176         """Return a dict of choice:branch."""
177         actions = {}
178         try:
179                 for option in menu_data.options(state):
180                         if option.startswith("action_"):
181                                 actions[option.split("_", 2)[1]] = menu_data.get(state, option)
182         except:
183                 pass
184         return actions
185
186 def get_default_action(state):
187         """Return the default action."""
188         try:
189                 return menu_data.get(state, "action")
190         except:
191                 return ""
192
193 def get_choice_action(user, choice):
194         """Run any indicated script for the given choice."""
195         actions = get_menu_actions(user.state)
196         if not choice: choice = get_default_menu_choice(user.state)
197         if choice in actions.keys(): return actions[choice]
198         elif choice in user.menu_choices.keys(): return get_default_action(user.state)
199         else: return ""
200