source: branches/active/character_customization/game/parpg/gui/hud.py @ 796

Revision 796, 19.5 KB checked in by aspidites, 9 years ago (diff)

Patch by Aspdites:

  • changed PlaySounds? references to EnableSound? for consistency
  • changed optionButton references to settingsButton for consistency
  • changed hud pause menu "Options" to "Settings" for consistency
  • Property svn:eol-style set to native
RevLine 
[143]1#   This file is part of PARPG.
2
3#   PARPG is free software: you can redistribute it and/or modify
4#   it under the terms of the GNU General Public License as published by
5#   the Free Software Foundation, either version 3 of the License, or
6#   (at your option) any later version.
7
8#   PARPG is distributed in the hope that it will be useful,
9#   but WITHOUT ANY WARRANTY; without even the implied warranty of
10#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#   GNU General Public License for more details.
12
13#   You should have received a copy of the GNU General Public License
14#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
15
[473]16from fife.extensions import pychan
17from fife.extensions.pychan.tools import callbackWithArguments as cbwa
18
[736]19from parpg.gui.filebrowser import FileBrowser
[767]20from parpg.gui.menus import ContextMenu, SettingsMenu
[736]21from parpg.gui import inventorygui
22from parpg.gui.popups import ExaminePopup
23from parpg.gui.containergui import ContainerGUI
24from parpg.gui.dialoguegui import DialogueGUI
25from parpg.gui import drag_drop_data as data_drag
[653]26from actionsbox import ActionsBox
[74]27
[261]28class Hud(object):
[143]29    """Main Hud class"""
[568]30    def __init__(self, controller, settings, callbacks):
[143]31        """Initialise the instance.
[568]32           @type controller: Class derived from ControllerBase
33           @param controller: The current controller
[143]34           @type settings: settings.Setting
[553]35           @param settings: The settings
[270]36           @type inv_model: dict
37           @type callbacks: dict
38           @param callbacks: a dict of callbacks
39               saveGame: called when the user clicks on Save
40               loadGame: called when the user clicks on Load
41               quitGame: called when the user clicks on Quit
[143]42           @return: None"""
[261]43
[143]44        # TODO: perhaps this should not be hard-coded here
[653]45        pychan.registerWidget(ActionsBox)
[74]46        self.hud = pychan.loadXML("gui/hud.xml")
[568]47        self.controller = controller
48        self.engine = controller.engine
49        self.model = controller.model
[76]50        self.settings = settings
[424]51        self.inventory = None
[693]52        self.character_screen = None
[270]53
[313]54        self.save_game_callback = callbacks['saveGame']
55        self.load_game_callback = callbacks['loadGame']
[326]56        self.quit_callback      = callbacks['quitGame']
[270]57
[277]58        self.box_container = None
59        self.examine_box = None
[553]60        self.context_menu = None
61        self.help_dialog = None
62        self.events_to_map = None
63        self.main_menu = None
64        self.menu_events = None
65        self.quit_window = None
[621]66        self.bottom_panel = self.hud.findChild(name="mainHudWindow")
[553]67       
[313]68        self.actions_box = self.hud.findChild(name="actionsBox")
[74]69        self.menu_displayed = False
[444]70        self.inventory_storage = None
[80]71        self.initializeHud()
72        self.initializeMainMenu()
[261]73        self.initializeContextMenu()
[97]74        self.initializeHelpMenu()
[261]75        self.initializeEvents()
[294]76        self.initializeQuitDialog()
[765]77        self.initializeSettingsMenu()
[639]78   
79    def _getEnabled(self):
80        """"Returns whether the gui widget is enabled or not"""
81        return self.hud.real_widget.isEnabled()
82   
83    def _setEnabled(self, enabled):
84        """"Sets whether the gui widget is enabled or not"""
85        self.hud.real_widget.setEnabled(enabled)
86        childs = self.hud.getNamedChildren()
87        for child_list in childs.itervalues():
88            for child in child_list:
89                child.real_widget.setEnabled(enabled)
90   
91    enabled = property(_getEnabled, _setEnabled)
92       
[80]93    def initializeHud(self):
[143]94        """Initialize and show the main HUD
95           @return: None"""
[553]96        self.events_to_map = {"menuButton":self.displayMenu, }
[74]97        self.hud.mapEvents(self.events_to_map) 
[348]98        # set HUD size according to screen size
[541]99        screen_width = self.engine.getSettings().getScreenWidth()
[80]100        self.hud.findChild(name="mainHudWindow").size = (screen_width, 65)
[313]101        self.hud.findChild(name="inventoryButton").position = \
102                                                    (screen_width-59, 7)
[143]103        # add ready slots
[106]104        ready1 = self.hud.findChild(name='hudReady1')
105        ready2 = self.hud.findChild(name='hudReady2')
106        ready3 = self.hud.findChild(name='hudReady3')
107        ready4 = self.hud.findChild(name='hudReady4')
[466]108
[268]109        if (screen_width <=800) :
110            gap = 0
111        else :
112            gap = 40
113        ready1.position = (160+gap, 7)
114        ready2.position = (220+gap, 7)
115        ready3.position = (screen_width-180-gap, 7)
116        ready4.position = (screen_width-120-gap, 7)
[653]117        self.actions_box.position = (280+gap, 5)
[268]118        actions_width = screen_width - 470 - 2*gap
119
[653]120        self.actions_box.ContentBox.min_width = actions_width
121        self.actions_box.ContentBox.max_width = actions_width
[572]122       
[143]123        # and finally add an actions box
[653]124        self.actions_box.min_size = (actions_width, 55)
125        self.actions_box.max_size = (actions_width, 55)
[143]126        # now it should be OK to display it all
[632]127        self.showHUD()
[621]128       
[112]129    def addAction(self, action):
[143]130        """Add an action to the actions box.
[600]131           @type action: (unicode) string
[167]132           @param action: The text that you want to display in the actions box
[653]133           @return: None"""   
134        self.actions_box.addAction(action)
[112]135
136    def showHUD(self):
[143]137        """Show the HUD.
138           @return: None"""
[112]139        self.hud.show()
[632]140        self.enabled = True
[112]141
142    def hideHUD(self):
[143]143        """Hide the HUD.
144           @return: None"""
[112]145        self.hud.hide()
[632]146        self.enabled = False
[261]147
[424]148    def initializeInventory(self):
[553]149        """Initialize the inventory"""
[726]150        if not self.inventory:
[568]151            self.inventory = inventorygui.InventoryGUI(self.controller,
[726]152                                                       None,
153                                                       None)
154#        inv_callbacks = {
155#            'refreshReadyImages': self.refreshReadyImages,
156#            'toggleInventoryButton': self.toggleInventoryButton,
157#        }
158#        self.inventory_storage = \
159#            self.model.game_state.player_character.inventory
160#        if self.inventory == None:
161#            self.inventory = inventorygui.InventoryGUI(self.controller,
162#                                                       self.inventory_storage,
163#                                                       inv_callbacks)
164#        else:
165#            self.inventory.inventory_storage = self.inventory_storage
166#        self.refreshReadyImages()
[693]167   
168    def initializeCharacterScreen(self):
169        """Initialize the character screen."""
170        # TODO Technomage 2010-12-24:
171        if not self.character_screen:
172            self.character_screen = pychan.loadXML('gui/character_screen.xml')
173       
174   
[261]175    def initializeContextMenu(self):
176        """Initialize the Context Menu
177           @return: None"""
[553]178        self.context_menu = ContextMenu (self.engine, [], (0, 0))
[261]179
180    def showContextMenu(self, data, pos):
[553]181        """Display the Context Menu with model at pos
182           @type model: list
183           @param model: model to pass to context menu
[261]184           @type pos: tuple
185           @param pos: tuple of x and y coordinates
186           @return: None"""
187        self.context_menu = ContextMenu(self.engine, data, pos)
[767]188        self.context_menu.show()
[261]189
[270]190    def hideContextMenu(self):
191        """Hides the context menu
192           @return: None"""
193        self.context_menu.hide()
194
[80]195    def initializeMainMenu(self):
[143]196        """Initalize the main menu.
197           @return: None"""
[648]198        self.main_menu = pychan.loadXML("gui/hud_pause_menu.xml")
[754]199        #TODO: find more suitalbe place for onOptilonsPress implementation
200        self.menu_events = {"resumeButton": self.hideMenu, 
[796]201                            "settingsButton": self.displaySettings,
[754]202                            "helpButton": self.displayHelp}
[74]203        self.main_menu.mapEvents(self.menu_events)
204
[112]205    def displayMenu(self):
[143]206        """Displays the main in-game menu.
207           @return: None"""
[630]208        self.stopActions()
[112]209        if (self.menu_displayed == False):
210            self.main_menu.show()
211            self.menu_displayed = True
[632]212            self.model.pause(True)
[640]213            self.controller.pause(True)
214            self.enabled = False
[112]215        elif (self.menu_displayed == True):
216            self.hideMenu()
217
218    def hideMenu(self):
[143]219        """Hides the main in-game menu.
220           @return: None"""
[112]221        self.main_menu.hide()
222        self.menu_displayed = False
[632]223        self.model.pause(False)
[640]224        self.controller.pause(False)
225        self.enabled = True
[112]226
[767]227    def initializeSettingsMenu(self):
228        self.settings_menu = SettingsMenu(self.settings)
[765]229
[763]230    def displaySettings(self):
231        self.settings_menu.show()
[287]232
[97]233    def initializeHelpMenu(self):
[143]234        """Initialize the help menu
235           @return: None"""
[97]236        self.help_dialog = pychan.loadXML("gui/help.xml")
237        help_events = {"closeButton":self.help_dialog.hide}
238        self.help_dialog.mapEvents(help_events)
[261]239        main_help_text = u"Welcome to Post-Apocalyptic RPG or PARPG![br][br]"\
[313]240        "This game is still in development, so please expect for there to be "\
241        "bugs and[br]feel free to tell us about them at "\
242        "http://www.forums.parpg.net.[br]This game uses a "\
243        "\"Point 'N' Click\" interface, which means that to move around,[br]"\
244        "just click where you would like to go and your character will move "\
245        "there.[br]PARPG also utilizes a context menu. To access this, just "\
246        "right click anywhere[br]on the screen and a menu will come up. This "\
247        "menu will change depending on[br]what you have clicked on, hence "\
248        "it's name \"context menu\".[br][br]"
[182]249       
[261]250        k_text = u" Keybindings" 
[313]251        k_text += "[br] A : Add a test action to the actions display"
252        k_text += "[br] I : Toggle the inventory screen"
253        k_text += "[br] F5 : Take a screenshot"
254        k_text += "[br]      (saves to <parpg>/screenshots/)"
[446]255        k_text += "[br] F10 : Toggle console"
256        k_text += "[br] PAUSE : (Un)Pause the game"
[313]257        k_text += "[br] Q : Quit the game"
[97]258        self.help_dialog.distributeInitialData({
259                "MainHelpText":main_help_text,
[143]260                "KeybindText":k_text
[97]261                })
262
[112]263    def displayHelp(self):
[143]264        """Display the help screen.
265           @return: None"""
[112]266        self.help_dialog.show()
267
[261]268    def saveGame(self):
269        """ Called when the user wants to save the game.
270            @return: None"""
[630]271        self.stopActions()
[303]272        save_browser = FileBrowser(self.engine,
[313]273                                   self.save_game_callback,
[640]274                                   self.loadsave_close,
[313]275                                   save_file=True,
276                                   gui_xml_path="gui/savebrowser.xml",
[261]277                                   extensions = ('.dat'))
278        save_browser.showBrowser()
[640]279        self.controller.pause(True)
[632]280        self.model.pause(True)
[640]281        self.enabled = False
[630]282
283    def stopActions(self):
[639]284        """This method stops/resets actions that are currently performed
285        like dragging an item.
286        This is done to be able to savely perform other actions that might
287        interfere with current running ones."""
[630]288        #Reset dragging - move item back to its old container
289        if data_drag.dragging:
290            data_drag.source_container.placeItem(data_drag.dragged_item)
291            data_drag.dragging = False
[632]292            data_drag.dragged_item = None
293        if self.inventory:
294            self.inventory.closeInventory()
[630]295       
[261]296    def newGame(self):
297        """Called when user request to start a new game.
298           @return: None"""
[630]299        self.stopActions()
[261]300        print 'new game'
[640]301   
302    def loadsave_close(self):
303        """Called when the load/save filebrowser was closed without a file selected"""
304        if not self.menu_displayed:
305            self.enabled = True
306            self.model.pause(False)
307            self.controller.pause(False)
308           
[261]309    def loadGame(self):
310        """ Called when the user wants to load a game.
311            @return: None"""
[630]312        self.stopActions()
[303]313        load_browser = FileBrowser(self.engine,
[313]314                                   self.load_game_callback,
[648]315                                   close_callback = self.loadsave_close,
[313]316                                   save_file=False,
317                                   gui_xml_path='gui/loadbrowser.xml',
[261]318                                   extensions=('.dat'))
319        load_browser.showBrowser()
[640]320        self.model.pause(True)
321        self.controller.pause(True)
322        self.enabled = False
[294]323   
324    def initializeQuitDialog(self):
325        """Creates the quit confirmation dialog
[261]326           @return: None"""
[313]327        self.quit_window = pychan.widgets.Window(title=unicode("Quit?"), \
328                                                 min_size=(200,0))
[261]329
330        hbox = pychan.widgets.HBox()
331        are_you_sure = "Are you sure you want to quit?"
332        label = pychan.widgets.Label(text=unicode(are_you_sure))
333        yes_button = pychan.widgets.Button(name="yes_button", 
[294]334                                           text=unicode("Yes"),
335                                           min_size=(90,20),
336                                           max_size=(90,20))
[261]337        no_button = pychan.widgets.Button(name="no_button",
[294]338                                          text=unicode("No"),
339                                          min_size=(90,20),
340                                          max_size=(90,20))
[261]341
[313]342        self.quit_window.addChild(label)
[261]343        hbox.addChild(yes_button)
344        hbox.addChild(no_button)
[313]345        self.quit_window.addChild(hbox)
[261]346
[313]347        events_to_map = { "yes_button": self.quit_callback,
348                          "no_button":  self.quit_window.hide }
[261]349       
[313]350        self.quit_window.mapEvents(events_to_map)
[261]351
[294]352
353    def quitGame(self):
354        """Called when user requests to quit game.
355           @return: None"""
[630]356        self.stopActions()
[313]357        self.quit_window.show()
[294]358
[261]359    def toggleInventoryButton(self):
360        """Manually toggles the inventory button.
361           @return: None"""
362        button = self.hud.findChild(name="inventoryButton")
[270]363        if button.toggled == 0:
[261]364            button.toggled = 1
365        else:
366            button.toggled = 0
367
[553]368    def toggleInventory(self, toggle_image=True):
[445]369        """Displays the inventory screen
[261]370           @return: None"""
[424]371        if self.inventory == None:
372            self.initializeInventory()
[553]373        self.inventory.toggleInventory(toggle_image)
[693]374   
375    def toggleCharacterScreen(self):
376        if not self.character_screen:
377            self.initializeCharacterScreen()
378        if not self.character_screen.isVisible():
379            self.character_screen.show()
380        else:
381            self.character_screen.hide()
382   
[261]383    def refreshReadyImages(self):
384        """Make the Ready slot images on the HUD be the same as those
385           on the inventory
386           @return: None"""
[553]387        for ready in range(1, 5):
[444]388            button = self.hud.findChild(name=("hudReady%d" % ready))
389            if self.inventory_storage == None :
390                origin = None
391            else:
[553]392                origin = self.inventory_storage.getItemsInSlot('ready', ready-1)
[444]393            if origin == None:
[553]394                self.setImages(button, 
395                               self.inventory.slot_empty_images['ready'])
[444]396            else:
[553]397                self.setImages(button, origin.getInventoryThumbnail())
[270]398
[261]399    def setImages(self, widget, image):
400        """Set the up, down, and hover images of an Imagebutton.
401           @type widget: pychan.widget
402           @param widget: widget to set
403           @type image: string
404           @param image: image to use
405           @return: None"""
406        widget.up_image = image
407        widget.down_image = image
408        widget.hover_image = image
409
410    def initializeEvents(self):
411        """Intialize Hud events
412           @return: None"""
413        events_to_map = {}
[270]414
415        # when we click the toggle button don't change the image
416        events_to_map["inventoryButton"] = cbwa(self.toggleInventory, False)
[326]417        events_to_map["saveButton"] = self.saveGame
418        events_to_map["loadButton"] = self.loadGame
[261]419
[313]420        hud_ready_buttons = ["hudReady1", "hudReady2", \
421                             "hudReady3", "hudReady4"]
[261]422
423        for item in hud_ready_buttons:
424            events_to_map[item] = cbwa(self.readyAction, item)
425
426        self.hud.mapEvents(events_to_map)
427
428        menu_events = {}
429        menu_events["newButton"] = self.newGame
430        menu_events["quitButton"] = self.quitGame
[326]431        menu_events["saveButton"] = self.saveGame
432        menu_events["loadButton"] = self.loadGame
[261]433        self.main_menu.mapEvents(menu_events)
434
[76]435    def setOption(self, name, value):
[143]436        """Set an option within the xml.
[159]437           @type name: string
438           @param name: The name of the option within the xml
439           @type value: any
440           @param value: The value that the option 'name' should be set to
[143]441           @return: None"""
[76]442        element = self.settings.root_element.find(name)
[143]443        if(element != None):
444            if(value != element.text):
[76]445                element.text = str(value)
446        else:
447            print 'Setting,', name, 'does not exist!'
[112]448   
[167]449    def readyAction(self, ready_button):
450        """ Called when the user selects a ready button from the HUD """
[480]451        text = "Used the item from %s" % ready_button       
[167]452        self.addAction(text)
453       
[451]454    def createBoxGUI(self, title, container):
[277]455        """Creates a window to display the contents of a box
456           @type title: string
457           @param title: The title for the window
[424]458           @param items: The box to display
[395]459           @return: A new ContainerGui"""
[451]460        events = {'takeAllButton':self.hideContainer,
461                  'closeButton':self.hideContainer}
462        #hide previous container if any, to avoid orphaned dialogs
463        self.hideContainer()
464
[568]465        self.box_container = ContainerGUI(self.controller,
[424]466                                              unicode(title), container)
[583]467        self.box_container.gui.mapEvents(events)
[451]468        self.box_container.showContainer()
[466]469        return self.box_container
[277]470
471    def hideContainer(self):
472        """Hide the container box
473           @return: None"""
474        if self.box_container:
475            self.box_container.hideContainer()
[451]476            #TODO: Move the close() call into OpenBoxAction(). This can be done
[479]477            # after createBoxGUI becomes a blocking call or it's otherwise
478            # possible to wait till the box GUI is closed.
[610]479            if self.box_container.container.trueAttr("openable"):
480                self.box_container.container.close()
[467]481            self.box_container = None
[277]482
483    def createExamineBox(self, title, desc):
484        """Create an examine box. It displays some textual description of an
485           object
486           @type title: string
487           @param title: The title of the examine box
488           @type desc: string
489           @param desc: The main body of the examine box
490           @return: None"""
[313]491        if self.examine_box is not None:
[277]492            self.examine_box.closePopUp()
493        self.examine_box = ExaminePopup(self.engine, title, desc)
494        self.examine_box.showPopUp()
[287]495
496    def showDialogue(self, npc):
497        """Show the NPC dialogue window
[360]498           @type npc: actors.NonPlayerCharacter
499           @param npc: the npc that we are having a dialogue with
[632]500           @return: The dialogue"""
[630]501        self.stopActions()
[361]502        dialogue = DialogueGUI(
[571]503                    self.controller,
[361]504                    npc,
[553]505                    self.model.game_state.quest_engine,
[579]506                    self.model.game_state.player_character)
[632]507        return dialogue
Note: See TracBrowser for help on using the repository browser.