Welcome to HBH! If you had an account on hellboundhacker.org you will need to reset your password using the Lost Password system before you will be able to login.
Console Application Menu Module - Python Code Bank
Console Application Menu Module
Well, it bothers me to build menus for every shell application that needs one.
So, I've written a module to handle that, like in the good old turbo pascal times.
Here it is, the module comments are pretty explanatory, I think, and the sample usage if run as script should enlighten the concept.
Use it, give comments, improvements, have fun...
Cheers and Happy coding
import string
from textwrap import wrap
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
class Console_App_Menu():
"""Console Application Menu module.
It implements basic menu and dialogs on a console window."""
def __init__(self, title='Console Application Menu', size=(80, 25), border='#', log_title='Log Output:'):
"""The class initialization takes as optional arguments:
- title: title text of the menu
- size: the size in characteres of the console window menu
- border: character to be printed as border for the menu and dialogs
- log_title: title text of the log window"""
self.__width = size[0]
self.__height = size[1] - 1
self.__line = lambda(x): x * self.__width
self.__ruler = lambda((x, l)): (x / 2) - (l / 2)
self.__content = StringIO()
self.__content.write((' ' * self.__width) * self.__height)
self.__border = border[0]
self.__log_title = log_title
self.__log = ['', '', '', '']
self.__draw_border()
self.__writeline(3, title)
self.__log_box()
def __draw_border(self):
self.__content.seek(0)
self.__content.write(self.__border * self.__width)
for i in range (1, self.__height):
self.__content.seek(self.__line(i))
self.__content.write(self.__border)
self.__content.seek(self.__line(i + 1) - 1)
self.__content.write(self.__border)
self.__content.seek(self.__line(i))
self.__content.write(self.__border * self.__width)
def __writeline(self, line_n, text):
self.__content.seek(self.__line(line_n) + self.__ruler((self.__width, len(text))))
self.__content.write(text)
def __log_box(self):
self.__content.seek(self.__line(self.__height - 8) + 10)
self.__content.write(self.__border + self.__border + self.__log_title)
self.__content.write(self.__border * (self.__width - 22 - len(self.__log_title)))
for i in reversed(range(4, 8)):
self.__content.seek(self.__line(self.__height - i) + 10)
self.__content.write(self.__border)
self.__content.seek(self.__line(self.__height - (i - 1)) - 11)
self.__content.write(self.__border)
self.__content.seek(self.__line(self.__height - 3) + 10)
self.__content.write(self.__border * (self.__width - 20))
def __update_display(self):
print self.__content.getvalue(),
print self.__question
def __log_write(self, output):
for i in range(len(self.__log)):
if self.__log[i] == '':
self.__log[i] = output
break
else:
self.__log.pop(0)
self.__log.append(output)
ylines = 7
self.__content.seek(self.__line(self.__height - ylines) + 12)
for i in range(len(self.__log)):
self.__content.write(self.__log[i] + (' ' * (self.__width - 24 - len(self.__log[i]))))
ylines -= 1
self.__content.seek(self.__line(self.__height - ylines) + 12)
def __dialog(self, dlg_type, dlg_text):
scr_buffer = self.__content.getvalue()
dlg_types = 'error', 'info', 'query_str', 'query_int', 'query_bool'
dlg_titles = 'Error:', 'Information:', 'Question:', 'Question:', 'Question:'
line = (self.__height / 2) - 3
self.__content.seek(self.__line(line) + (self.__width / 4) - 1)
self.__content.write(' ' * ((self.__width / 2) + 2))
line += 1
self.__content.seek(self.__line(line) + (self.__width / 4) - 1)
self.__content.write(' ' + self.__border + self.__border + dlg_titles[dlg_types.index(dlg_type)])
self.__content.write(self.__border * ((self.__width / 2) - len(dlg_titles[dlg_types.index(dlg_type)])) + ' ')
for i in range(1, 4):
self.__content.seek(self.__line(line + i) + (self.__width / 4) - 1)
self.__content.write(' ' + self.__border + (' ' * (self.__width / 2) + self.__border + ' '))
self.__content.seek(self.__line(line + 4) + (self.__width / 4) - 1)
self.__content.write(' ' + (self.__border * ((self.__width / 2) + 2)) + ' ')
self.__content.seek(self.__line(line + 2) + (self.__width / 4) + 1)
self.__content.write((' ' * ((self.__width / 4) - (len(dlg_text) / 2) - 1)) + dlg_text + (' ' * ((self.__width / 4) - (len(dlg_text) / 2))))
print self.__content.getvalue(),
if dlg_type in ('error', 'info'):
raw_input('Press Enter to continue... ')
self.__content.seek(0)
self.__content.write(scr_buffer)
self.__update_display()
elif dlg_type == 'query_str':
value = raw_input('Enter string: ')
self.__content.seek(0)
self.__content.write(scr_buffer)
return value
elif dlg_type == 'query_int':
while True:
value = raw_input('Enter number: ')
try:
value = int(value)
self.__content.seek(0)
self.__content.write(scr_buffer)
return value
except:
self.__content.seek(0)
self.__content.write(scr_buffer)
return self.__dialog(dlg_type, dlg_text)
elif dlg_type == 'query_bool':
while True:
value = raw_input('Enter \'Y(y)...\' or \'N(n)...\': ')
if value:
if value[0].lower() == 'y':
self.__content.seek(0)
self.__content.write(scr_buffer)
return True
elif value[0].lower() == 'n':
self.__content.seek(0)
self.__content.write(scr_buffer)
return None
self.__content.seek(0)
self.__content.write(scr_buffer)
return self.__dialog(dlg_type, dlg_text)
def set_options(self, index_type, options_list, separator=') ', question='Insert option: '):
"""Sets menu options. It takes as arguments:
- index type: 'numbers', 'low' and 'caps'
- options: list of menu options
and as optional arguments:
- separator: characteres between the index and option
- question: text following the menu
Usage: Console_App_Menu.set_options(index, options)"""
self.__separator = separator
self.__question = question
lenght = len(options_list)
start = self.__ruler((self.__height - (self.__height / 4), lenght))
string_size = max([len(item) for item in options_list])
self.__options_list = [string.ljust(item, string_size) for item in options_list]
if index_type == 'numbers':
self.__indexs = string.digits
elif index_type == 'low':
self.__indexs = string.lowercase
elif index_type == 'caps':
self.__indexs = string.uppercase
else:
print 'Invalid Index Type'
self.__valids = []
index = 0
for i in range(start, start + lenght):
self.__writeline(i, self.__indexs[index] + self.__separator + self.__options_list[index])
self.__valids.append(self.__indexs[index])
index += 1
def option(self):
"""Returns user selected menu option as a tuple containing:
- the option index order
- the option index character
- the option text
Usage: option = Console_App_Menu.option()"""
print self.__content.getvalue(),
selected = raw_input(self.__question)
if selected not in self.__valids:
self.__dialog('error', 'Invalid Option Selected!!!')
return self.option()
else:
return (self.__valids.index(selected), selected, self.__options_list[self.__valids.index(selected)].strip())
def log(self, output):
"""Prints given text to the log window.
Usage: Console_App_Menu.log(text)"""
if len(output) > 56:
list_output = wrap(output, 56)
for output in list_output:
self.__log_write(output)
self.__update_display()
else:
self.__log_write(output)
self.__update_display()
def info(self, text):
"""Displays a information dialog with the given text.
Usage: Console_App_Menu.info(text)"""
self.__dialog('info', text[0:37])
def error(self, text):
"""Displays a error dialog with the given text.
Usage: Console_App_Menu.error(text)"""
self.__dialog('error', text[0:37])
def query(self, input_type, text):
"""Displays a query dialog with the given text and can return
three different types of data:
- an integer: Console_App_Menu.query('int', text)
- a string: Console_App_Menu.query('str', text)
- a boolean: Console_App_Menu.query('bool', text)
Usage: input = Console_App_Menu.query(type, text)"""
if input_type in ('int', 'str', 'bool'):
return self.__dialog('query_' + input_type, text[0:37])
if __name__ == '__main__':
menu = Console_App_Menu(title='Console Application Menu Calculator Demo')
menu.set_options('low', ('Add x to y', 'Subtract x to y', 'Multiply x by y', 'Divide x by y', 'Help', 'Exit'))
menu.log('Welcome, please select an option to continue...')
exit_flag = None
while not exit_flag:
selected = menu.option()
if selected == (0, 'a', 'Add x to y'):
x = menu.query('int', 'Insert number x')
y = menu.query('int', 'Insert number y')
menu.log('The result of adding %s to %s is %s.' % (x, y, (x + y)))
elif selected[0] == 1:
x = menu.query('int', 'Insert number x')
y = menu.query('int', 'Insert number y')
menu.log('The result of subtracting %s to %s is %s.' % (x, y, (y - x)))
elif selected[1] == 'c':
x = menu.query('int', 'Insert number x')
y = menu.query('int', 'Insert number y')
menu.log('The result of multiplying %s by %s is %s.' % (x, y, (x * y)))
elif selected[0] == 3:
x = menu.query('int', 'Insert number x')
y = menu.query('int', 'Insert number y')
menu.log('The result of dividing %s by %s is %s.' % (x, y, (x / y)))
elif selected[2] == 'Help':
menu.log('Select a calculation option. The numbers will be asked, the calculation is done and the result will be displayed on this log window.')
elif selected[2] == 'Exit':
if menu.query('bool', 'Are you sure you want to exit?'):
exit_flag = True
else:
name = menu.query('str', 'Insert your name')
menu.info('Bye, %s!' % name)
Comments
Sorry but there are no comments to display