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

Revision 796, 19.5 KB checked in by aspidites, 8 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
Line 
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
16from fife.extensions import pychan
17from fife.extensions.pychan.tools import callbackWithArguments as cbwa
18
19from parpg.gui.filebrowser import FileBrowser
20from parpg.gui.menus import ContextMenu, SettingsMenu
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
26from actionsbox import ActionsBox
27
28class Hud(object):
29    """Main Hud class"""
30    def __init__(self, controller, settings, callbacks):
31        """Initialise the instance.
32           @type controller: Class derived from ControllerBase
33           @param controller: The current controller
34           @type settings: settings.Setting
35           @param settings: The settings
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
42           @return: None"""
43
44        # TODO: perhaps this should not be hard-coded here
45        pychan.registerWidget(ActionsBox)
46        self.hud = pychan.loadXML("gui/hud.xml")
47        self.controller = controller
48        self.engine = controller.engine
49        self.model = controller.model
50        self.settings = settings
51        self.inventory = None
52        self.character_screen = None
53
54        self.save_game_callback = callbacks['saveGame']
55        self.load_game_callback = callbacks['loadGame']
56        self.quit_callback      = callbacks['quitGame']
57
58        self.box_container = None
59        self.examine_box = None
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
66        self.bottom_panel = self.hud.findChild(name="mainHudWindow")
67       
68        self.actions_box = self.hud.findChild(name="actionsBox")
69        self.menu_displayed = False
70        self.inventory_storage = None
71        self.initializeHud()
72        self.initializeMainMenu()
73        self.initializeContextMenu()
74        self.initializeHelpMenu()
75        self.initializeEvents()
76        self.initializeQuitDialog()
77        self.initializeSettingsMenu()
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       
93    def initializeHud(self):
94        """Initialize and show the main HUD
95           @return: None"""
96        self.events_to_map = {"menuButton":self.displayMenu, }
97        self.hud.mapEvents(self.events_to_map) 
98        # set HUD size according to screen size
99        screen_width = self.engine.getSettings().getScreenWidth()
100        self.hud.findChild(name="mainHudWindow").size = (screen_width, 65)
101        self.hud.findChild(name="inventoryButton").position = \
102                                                    (screen_width-59, 7)
103        # add ready slots
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')
108
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)
117        self.actions_box.position = (280+gap, 5)
118        actions_width = screen_width - 470 - 2*gap
119
120        self.actions_box.ContentBox.min_width = actions_width
121        self.actions_box.ContentBox.max_width = actions_width
122       
123        # and finally add an actions box
124        self.actions_box.min_size = (actions_width, 55)
125        self.actions_box.max_size = (actions_width, 55)
126        # now it should be OK to display it all
127        self.showHUD()
128       
129    def addAction(self, action):
130        """Add an action to the actions box.
131           @type action: (unicode) string
132           @param action: The text that you want to display in the actions box
133           @return: None"""   
134        self.actions_box.addAction(action)
135
136    def showHUD(self):
137        """Show the HUD.
138           @return: None"""
139        self.hud.show()
140        self.enabled = True
141
142    def hideHUD(self):
143        """Hide the HUD.
144           @return: None"""
145        self.hud.hide()
146        self.enabled = False
147
148    def initializeInventory(self):
149        """Initialize the inventory"""
150        if not self.inventory:
151            self.inventory = inventorygui.InventoryGUI(self.controller,
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()
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   
175    def initializeContextMenu(self):
176        """Initialize the Context Menu
177           @return: None"""
178        self.context_menu = ContextMenu (self.engine, [], (0, 0))
179
180    def showContextMenu(self, data, pos):
181        """Display the Context Menu with model at pos
182           @type model: list
183           @param model: model to pass to context menu
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)
188        self.context_menu.show()
189
190    def hideContextMenu(self):
191        """Hides the context menu
192           @return: None"""
193        self.context_menu.hide()
194
195    def initializeMainMenu(self):
196        """Initalize the main menu.
197           @return: None"""
198        self.main_menu = pychan.loadXML("gui/hud_pause_menu.xml")
199        #TODO: find more suitalbe place for onOptilonsPress implementation
200        self.menu_events = {"resumeButton": self.hideMenu, 
201                            "settingsButton": self.displaySettings,
202                            "helpButton": self.displayHelp}
203        self.main_menu.mapEvents(self.menu_events)
204
205    def displayMenu(self):
206        """Displays the main in-game menu.
207           @return: None"""
208        self.stopActions()
209        if (self.menu_displayed == False):
210            self.main_menu.show()
211            self.menu_displayed = True
212            self.model.pause(True)
213            self.controller.pause(True)
214            self.enabled = False
215        elif (self.menu_displayed == True):
216            self.hideMenu()
217
218    def hideMenu(self):
219        """Hides the main in-game menu.
220           @return: None"""
221        self.main_menu.hide()
222        self.menu_displayed = False
223        self.model.pause(False)
224        self.controller.pause(False)
225        self.enabled = True
226
227    def initializeSettingsMenu(self):
228        self.settings_menu = SettingsMenu(self.settings)
229
230    def displaySettings(self):
231        self.settings_menu.show()
232
233    def initializeHelpMenu(self):
234        """Initialize the help menu
235           @return: None"""
236        self.help_dialog = pychan.loadXML("gui/help.xml")
237        help_events = {"closeButton":self.help_dialog.hide}
238        self.help_dialog.mapEvents(help_events)
239        main_help_text = u"Welcome to Post-Apocalyptic RPG or PARPG![br][br]"\
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]"
249       
250        k_text = u" Keybindings" 
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/)"
255        k_text += "[br] F10 : Toggle console"
256        k_text += "[br] PAUSE : (Un)Pause the game"
257        k_text += "[br] Q : Quit the game"
258        self.help_dialog.distributeInitialData({
259                "MainHelpText":main_help_text,
260                "KeybindText":k_text
261                })
262
263    def displayHelp(self):
264        """Display the help screen.
265           @return: None"""
266        self.help_dialog.show()
267
268    def saveGame(self):
269        """ Called when the user wants to save the game.
270            @return: None"""
271        self.stopActions()
272        save_browser = FileBrowser(self.engine,
273                                   self.save_game_callback,
274                                   self.loadsave_close,
275                                   save_file=True,
276                                   gui_xml_path="gui/savebrowser.xml",
277                                   extensions = ('.dat'))
278        save_browser.showBrowser()
279        self.controller.pause(True)
280        self.model.pause(True)
281        self.enabled = False
282
283    def stopActions(self):
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."""
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
292            data_drag.dragged_item = None
293        if self.inventory:
294            self.inventory.closeInventory()
295       
296    def newGame(self):
297        """Called when user request to start a new game.
298           @return: None"""
299        self.stopActions()
300        print 'new game'
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           
309    def loadGame(self):
310        """ Called when the user wants to load a game.
311            @return: None"""
312        self.stopActions()
313        load_browser = FileBrowser(self.engine,
314                                   self.load_game_callback,
315                                   close_callback = self.loadsave_close,
316                                   save_file=False,
317                                   gui_xml_path='gui/loadbrowser.xml',
318                                   extensions=('.dat'))
319        load_browser.showBrowser()
320        self.model.pause(True)
321        self.controller.pause(True)
322        self.enabled = False
323   
324    def initializeQuitDialog(self):
325        """Creates the quit confirmation dialog
326           @return: None"""
327        self.quit_window = pychan.widgets.Window(title=unicode("Quit?"), \
328                                                 min_size=(200,0))
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", 
334                                           text=unicode("Yes"),
335                                           min_size=(90,20),
336                                           max_size=(90,20))
337        no_button = pychan.widgets.Button(name="no_button",
338                                          text=unicode("No"),
339                                          min_size=(90,20),
340                                          max_size=(90,20))
341
342        self.quit_window.addChild(label)
343        hbox.addChild(yes_button)
344        hbox.addChild(no_button)
345        self.quit_window.addChild(hbox)
346
347        events_to_map = { "yes_button": self.quit_callback,
348                          "no_button":  self.quit_window.hide }
349       
350        self.quit_window.mapEvents(events_to_map)
351
352
353    def quitGame(self):
354        """Called when user requests to quit game.
355           @return: None"""
356        self.stopActions()
357        self.quit_window.show()
358
359    def toggleInventoryButton(self):
360        """Manually toggles the inventory button.
361           @return: None"""
362        button = self.hud.findChild(name="inventoryButton")
363        if button.toggled == 0:
364            button.toggled = 1
365        else:
366            button.toggled = 0
367
368    def toggleInventory(self, toggle_image=True):
369        """Displays the inventory screen
370           @return: None"""
371        if self.inventory == None:
372            self.initializeInventory()
373        self.inventory.toggleInventory(toggle_image)
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   
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"""
387        for ready in range(1, 5):
388            button = self.hud.findChild(name=("hudReady%d" % ready))
389            if self.inventory_storage == None :
390                origin = None
391            else:
392                origin = self.inventory_storage.getItemsInSlot('ready', ready-1)
393            if origin == None:
394                self.setImages(button, 
395                               self.inventory.slot_empty_images['ready'])
396            else:
397                self.setImages(button, origin.getInventoryThumbnail())
398
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 = {}
414
415        # when we click the toggle button don't change the image
416        events_to_map["inventoryButton"] = cbwa(self.toggleInventory, False)
417        events_to_map["saveButton"] = self.saveGame
418        events_to_map["loadButton"] = self.loadGame
419
420        hud_ready_buttons = ["hudReady1", "hudReady2", \
421                             "hudReady3", "hudReady4"]
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
431        menu_events["saveButton"] = self.saveGame
432        menu_events["loadButton"] = self.loadGame
433        self.main_menu.mapEvents(menu_events)
434
435    def setOption(self, name, value):
436        """Set an option within the xml.
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
441           @return: None"""
442        element = self.settings.root_element.find(name)
443        if(element != None):
444            if(value != element.text):
445                element.text = str(value)
446        else:
447            print 'Setting,', name, 'does not exist!'
448   
449    def readyAction(self, ready_button):
450        """ Called when the user selects a ready button from the HUD """
451        text = "Used the item from %s" % ready_button       
452        self.addAction(text)
453       
454    def createBoxGUI(self, title, container):
455        """Creates a window to display the contents of a box
456           @type title: string
457           @param title: The title for the window
458           @param items: The box to display
459           @return: A new ContainerGui"""
460        events = {'takeAllButton':self.hideContainer,
461                  'closeButton':self.hideContainer}
462        #hide previous container if any, to avoid orphaned dialogs
463        self.hideContainer()
464
465        self.box_container = ContainerGUI(self.controller,
466                                              unicode(title), container)
467        self.box_container.gui.mapEvents(events)
468        self.box_container.showContainer()
469        return self.box_container
470
471    def hideContainer(self):
472        """Hide the container box
473           @return: None"""
474        if self.box_container:
475            self.box_container.hideContainer()
476            #TODO: Move the close() call into OpenBoxAction(). This can be done
477            # after createBoxGUI becomes a blocking call or it's otherwise
478            # possible to wait till the box GUI is closed.
479            if self.box_container.container.trueAttr("openable"):
480                self.box_container.container.close()
481            self.box_container = None
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"""
491        if self.examine_box is not None:
492            self.examine_box.closePopUp()
493        self.examine_box = ExaminePopup(self.engine, title, desc)
494        self.examine_box.showPopUp()
495
496    def showDialogue(self, npc):
497        """Show the NPC dialogue window
498           @type npc: actors.NonPlayerCharacter
499           @param npc: the npc that we are having a dialogue with
500           @return: The dialogue"""
501        self.stopActions()
502        dialogue = DialogueGUI(
503                    self.controller,
504                    npc,
505                    self.model.game_state.quest_engine,
506                    self.model.game_state.player_character)
507        return dialogue
Note: See TracBrowser for help on using the repository browser.