From 3d58f3f0ffc9041ad6f87364e0b209c0b0a8cdb3 Mon Sep 17 00:00:00 2001 From: Dpk3062 Date: Mon, 06 Jul 2009 03:48:30 +0000 Subject: * Now using Curses for text display * 'Main Menu' working * 'Change Player' menu working * Putting constants and strings in utils.strs.py * Added class 'Profile' * Renamed class 'LevelInfo' to 'Level' Note: paths still hard coded for main developer's machine --- diff --git a/src/setup/__init__.py b/src/setup/__init__.py index e69de29..a003759 100644 --- a/src/setup/__init__.py +++ b/src/setup/__init__.py @@ -0,0 +1 @@ +# this is a package diff --git a/src/setup/config.py b/src/setup/config.py new file mode 100644 index 0000000..696c039 --- /dev/null +++ b/src/setup/config.py @@ -0,0 +1,122 @@ +''' + +''' + +import os +from lxml import etree # using lxml for XML processing +from utils import strs # string constants +from utils import utils # some XML utilities +from profile import Profile +from level import Level + +# setup logging +import logging +logging.basicConfig(filename=strs.LoggingFile,level=logging.DEBUG) +log = logging.getLogger('setup.config') + + +# ----------------------------------------------------------------------------- +# Some Getters +# ----------------------------------------------------------------------------- + +# TODO refactor to remove duplicated code logic: should have the two getXXX() going to findFiles() -> findFolders() -> find() + +def getLevelDescriptors(): + '''Returns a list of Levels representing all known levels''' + # get all the level descriptor files + files = findLevelFiles() + + # convert them all into objects + levels = [] + for file in files: + level = Level(path) + levels.append(level) + return files + +def getProfiles(): + '''Returns a list of Profiles representing all known profiles''' + # get all the profile files + files = findProfileFiles() + + # convert the files into Profile objects + profiles = [] + for file in files: + profile = Profile(file) + profiles.append(profile) + return profiles + +# ----------------------------------------------------------------------------- +# File related methods +# ----------------------------------------------------------------------------- + +def getLastProfileName(): + '''Returns the name of the last loaded profile''' + name = find(strs.XP_LastProfileName)[0] + return name + +def findLevelFiles(): + '''Returns the list of found level descriptor files''' + folders = findLevelFolders() + files = findFiles(folders, strs.Ext_Level) + log.debug('Found ' + str(len(files)) + ' level files') + return files + +def findProfileFiles(): + '''Returns the list of found profile files''' + folders = findProfileFolders() + files = findFiles(folders, strs.Ext_Profile) + log.debug('Found ' + str(len(files)) + ' profile files') + return files + +def findFiles(folders, extension): + '''Returns a list of all files with the given extension directly inside the given folders''' + files = [] + + for dir in folders: + contents = os.listdir(dir) + for item in contents: + item = dir + '/' + item # must convert the file/folder name into its complete path + + # only want files with the given extension + if not os.path.isfile(item): + continue + if not item.endswith(extension): + continue + + files.append(item) + return files + +# ----------------------------------------------------------------------------- +# Folder related methods +# ----------------------------------------------------------------------------- + +def findLevelFolders(): + '''Returns the list of known level folders''' + folders = find(strs.XP_LevelFolderLocation) + log.debug('Found ' + str(len(folders)) + ' level folders') + return folders + pass + +def findProfileFolders(): + '''Returns the list of known profile folders''' + folders = find(strs.XP_ProfileFolderLocation) + log.debug('Found ' + str(len(folders)) + ' profile folders') + return folders + +# ----------------------------------------------------------------------------- +# General methods +# ----------------------------------------------------------------------------- + +def find(xpath): + ''' Returns the result of applying the given xpath onto the config file''' + config = utils.getXMLRoot(strs.ConfigFile) + return config.xpath(xpath) + +# ----------------------------------------------------------------------------- +# Some Setters +# ----------------------------------------------------------------------------- + +def setLastProfileName(name): + ''' ''' + # TODO fill in this stub + pass diff --git a/src/setup/level.py b/src/setup/level.py index 907d8bd..193e8f7 100644 --- a/src/setup/level.py +++ b/src/setup/level.py @@ -1,10 +1,12 @@ ''' ''' -from lxml import etree -from utils import utils +from lxml import etree # using lxml for XML processing +from utils import strs # string constants +from utils import utils # some XML utilities -class LevelInfo(object): + +class Level(object): ''' ''' @@ -15,16 +17,17 @@ class LevelInfo(object): #open up the mlvl file and read in its basic properties root = utils.getXMLRoot(path) - self.name = root.xpath('//level-info/@name')[0] - self.description = root.xpath('//level-info/@description')[0] + self.name = root.xpath(strs.XP_LevelName)[0] + self.description = root.xpath(strs.XP_LevelName)[0] + self.path = path pass def getName(self): - '''Gets the name of this level''' + '''Returns the name of this level''' return self.name def getDescription(self): - '''Gets the description of this level''' + '''Returns the description of this level''' return self.description diff --git a/src/setup/main.py b/src/setup/main.py index 1f05f10..c88cb46 100644 --- a/src/setup/main.py +++ b/src/setup/main.py @@ -2,60 +2,26 @@ ''' +#why? if __name__ == '__main__': pass -import os - -# using lxml for XML processing -from lxml import etree -from level import LevelInfo -from utils import utils - -# constants -ConfigFile = '/home/doug/workspace/Muthris/docs/examples/config.xml' -LevelExt = '.mlvl' - -# load the configuration file -config = utils.getXMLRoot(ConfigFile) - -#for each level folder, scan for and process any Muthris level files (.mlvl) -levels = [] -folders = config.xpath('//level-folders/folder/@location') -for folder in folders: - #search for files in the level folder - list = os.listdir(folder) - print(list) - for path in list: - #make sure path is not just the filename, as isfile() would fail if it was - path = folder + '/' + path - - #only want level files - if not os.path.isfile(path): - continue - if not path.endswith(LevelExt): - continue - - #create a level object for this level file - level = LevelInfo( path ) - levels.append( level ) - -print( config ) -print( folders ) - - - -# find all the level folders - -# load all the level folders -# start the menus +import sys +sys.path.append('/home/doug/workspace/Muthris/src/') -print( 'done' ) +import menus +from utils import strs +# setup logging +import logging +logging.basicConfig(filename=strs.LoggingFile,level=logging.DEBUG) +log = logging.getLogger('setup.main') -def processLevelFile( file ): - ''' ''' - pass +# start the menus + +menus.begin() + +print( 'done' ) diff --git a/src/setup/menus.py b/src/setup/menus.py new file mode 100644 index 0000000..e229277 --- /dev/null +++ b/src/setup/menus.py @@ -0,0 +1,191 @@ +''' + +''' + +import curses +import config +from utils import strs + +# setup logging +import logging +logging.basicConfig(filename=strs.LoggingFile,level=logging.DEBUG) +log = logging.getLogger('setup.menus') + +# ----------------------------------------------------------------------------- +# +# ----------------------------------------------------------------------------- + +class MenuData(object): + '''Holds data used by the menu system''' + + def __init__(self): + ''' + Constructor + ''' + self.levels = [] + self.profiles = [] + self.profile = None + self.screen = None + + +# ----------------------------------------------------------------------------- +# Menu display functions +# ----------------------------------------------------------------------------- + +# Warning: the menu system uses recursion to move about. Excessive bad input (tested to crash at 979 bad inputs to the main menu) or moving between menus will case a stack overflow. When the menu system exits (such as when actually playing a game), we need to make sure all of the menu's function calls unwind +# TODO: improve the menu system so it doesn't use recursion + +def mainMenu(data): + ''' ''' + + # we use the current profile, so make sure there is one + if (data.profile == None) | (data.profile == ''): + changePlayerMenu(data) + return + + # configure the screen for our needs + data.screen.erase() + curses.cbreak() + curses.echo() + + # display the title + title = strs.Title_Main + strs.Title_Seperator + (data.profile or '[No Player]') + displayTitle(data.screen, title) + + # display the menu options + lines = ('1) Play Game', + '2) Join Game - Stubbed', + '3) Options - Stubbed', + '', + 'c) Change Player', + 'e) Exit') + displayOptions(data.screen, lines, 1) + + # display the input prompt + lines = ('', 'Pick [1,c,e]: ') + displayPrompt(data.screen, lines, 7) + + # refresh the screen + data.screen.refresh() + + # store the current cursor location, so we can keep it here when the user types + y, x = data.screen.getyx() + log.debug('Y,X are at: ' + str(y) + ' ' + str(x)) + + # wait for user input + c = data.screen.getch() + + # keep the cursor in the same spot + data.screen.move(y, x) + + # process input + if c == ord('1'): playGameMenu(data) + #elif c == ord('2'): curses.beep() + #elif c == ord('3'): curses.beep() + elif c == ord('c'): changePlayerMenu(data) + elif c == ord('e'): pass + else: + mainMenu(data) + +def changePlayerMenu(data): + ''' ''' + + # create a list of players + profiles = config.getProfiles() + players = [] + for profile in profiles: + players.append(profile.getName()) + + # configure the screen for our needs + data.screen.erase() + curses.nocbreak() + curses.echo() + + # display the title + title = strs.Title_ChangePlayer + strs.Title_Seperator + (data.profile or '[No Player]') + displayTitle(data.screen, title) + + # display the menu options + lines = ['', 'Known Players:'] + for player in players: + lines.append(' * ' + player) + displayOptions(data.screen, lines, 1) + + # display the input prompt + offset = len(lines) + 1 + lines = ('','Enter your player\'s name: ') + displayPrompt(data.screen, lines, offset) + + # refresh and wait for valid user input + data.screen.refresh() + name = data.screen.getstr() + + # process input + # Note: if the player's profile doesn't exist, it will be created whenever the player does something that needs to be saved to a profile + data.profile = name + + # always head back to the main menu after changing the profile + mainMenu(data) + +def playGameMenu(data): + ''' ''' + + # check for required vars + # clear the screen and display the title + # display the menu + # refresh the screen + # wait for input + # process input + + pass + +def levelOptionsMenu(data): + ''' ''' + pass + +def skillLevelMenu(data): + ''' ''' + pass + +def numberOfPlayersMenu(data): + ''' ''' + pass + +# ----------------------------------------------------------------------------- +# Common functions +# ----------------------------------------------------------------------------- + +def displayTitle(screen, title): + '''Displays the given title as the title of the given stdscr''' + screen.addstr(0,strs.Indent_Title, title, curses.A_REVERSE) + +def displayOptions(screen, options, offset=0): + '''Displays the given list of options on the given stdscr with the given vertical offset''' + for index, line in enumerate(options): + screen.addstr(index+1+offset,strs.Indent_Options, line) + +def displayPrompt(screen, lines, offset=0): + '''Displays the given list of textual prompt lines on the given stdscr with the given vertical offset''' + for index, line in enumerate(lines): + screen.addstr(index+1+offset,strs.Indent_Prompt, line) + +# ----------------------------------------------------------------------------- +# Menu setup functions +# ----------------------------------------------------------------------------- + +def init(stdscr): + ''' ''' + + # create the menu's data + data = MenuData() + data.screen = stdscr + + # set the last used values + data.profile = config.getLastProfileName() + + mainMenu(data) + +def begin(): + ''' ''' + curses.wrapper(init) + diff --git a/src/setup/profile.py b/src/setup/profile.py new file mode 100644 index 0000000..0aceea3 --- /dev/null +++ b/src/setup/profile.py @@ -0,0 +1,30 @@ +''' + +''' + +from lxml import etree # using lxml for XML processing +from utils import strs # string constants +from utils import utils # some XML utilities + + + +class Profile(object): + ''' + ''' + + def __init__(self, path): + ''' + Constructor + ''' + + #open up the mpro file and read in its basic properties + root = utils.getXMLRoot(path) + self.name = root.xpath(strs.XP_ProfileName)[0] + self.path = path + pass + + def getName(self): + '''Returns the name of the profile's user''' + return self.name + + diff --git a/src/setup/profiles.py b/src/setup/profiles.py new file mode 100644 index 0000000..3282a62 --- /dev/null +++ b/src/setup/profiles.py @@ -0,0 +1,31 @@ +''' + +''' + +import os # file path support +from lxml import etree # using lxml for XML processing +from utils import utils # some XML utilities +from utils import strs # string constants + +# setup logging +import logging # logging support +logging.basicConfig(level=logging.DEBUG) +log = logging.getLogger('setup.profiles') + + + +def findAllProfiles(): + ''' ''' + pass + +def getLastUsedProfile(): + ''' ''' + pass + +def createNewProfile(): + ''' ''' + pass + + + + diff --git a/src/utils/__init__.py b/src/utils/__init__.py index e69de29..a003759 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -0,0 +1 @@ +# this is a package diff --git a/src/utils/strs.py b/src/utils/strs.py new file mode 100644 index 0000000..4059bbf --- /dev/null +++ b/src/utils/strs.py @@ -0,0 +1,35 @@ +''' +Created on Jul 5, 2009 + +@author: doug +''' + +# files +ConfigFile = '/home/doug/workspace/Muthris/docs/examples/config.xml' +LoggingFile = '/tmp/muthris-dev.log' + +# file extensions +Ext_Level = '.mlvl' +Ext_Profile = '.mpro' + +# XML locations +XP_LevelFolderLocation = '/muthris/config/level-folders/folder/@location' +XP_ProfileFolderLocation = '/muthris/config/profile-folders/folder/@location' +XP_LastProfileName = '/muthris/config/last/profile/@name' +XP_LevelName = '/muthris/level/@name' +XP_LevelDescription = '/muthris/level/@description' +XP_ProfileName = '/muthris/profile/@name' + +# menu titles +Title_Main = 'Main Menu' +Title_ChangePlayer = 'Change Player' +Title_PlayGame = 'Play Game' +# Title_LevelOptions = '' # title uses the name of the level +Title_SkillLevel = 'Skill Level' +Title_NumberOfPlayers = 'Number of Players' +Title_Seperator = ' - ' + +# indent spacing for curses +Indent_Title = 25 +Indent_Options = 10 +Indent_Prompt = 5 \ No newline at end of file -- cgit v0.9.1