comparison engine/python/fife/extensions/fife_settings.py @ 538:00aa20dc8b7f

Made the Setting class much more customizable by adding the SettingEntry class. Adopted demos to the changes Note: Setting ScreenWidth and ScreenHeight are now combined into ScreenResolution of format <width>x<height> FullScreen and PlaySounds are now of type bool
author nihathrael@33b003aa-7bff-0310-803a-e67f0ece8222
date Tue, 01 Jun 2010 18:14:26 +0000
parents 082e919cc348
children 4c7b5eee211c
comparison
equal deleted inserted replaced
537:764510a6d2f9 538:00aa20dc8b7f
86 </Module> 86 </Module>
87 87
88 </Settings> 88 </Settings>
89 """ 89 """
90 90
91 DEFAULT_MODULE = "FIFE"
92
91 class Setting(object): 93 class Setting(object):
92 """ 94 """
93 This class manages loading and saving of game settings. 95 This class manages loading and saving of game settings.
94 96
95 Usage:: 97 Usage::
145 tree = ET.parse(StringIO(EMPTY_SETTINGS)) 147 tree = ET.parse(StringIO(EMPTY_SETTINGS))
146 tree.write(os.path.join(self._appdata, self._settings_file), 'UTF-8') 148 tree.write(os.path.join(self._appdata, self._settings_file), 'UTF-8')
147 149
148 #default settings 150 #default settings
149 self._resolutions = ['640x480', '800x600', '1024x768', '1280x800', '1440x900'] 151 self._resolutions = ['640x480', '800x600', '1024x768', '1280x800', '1440x900']
152 self._renderbackends = ['OpenGL', 'SDL']
150 153
151 #Used to stylize the options gui 154 #Used to stylize the options gui
152 self._gui_style = "default" 155 self._gui_style = "default"
153 156
154 self.loadSettings() 157 self.loadSettings()
158
159 # Holds SettingEntries
160 self._entries = []
161
162 self._initDefaultSettingEntries()
163
164 def _initDefaultSettingEntries(self):
165 """Initializes the default fife setting entries. Not to be called from
166 outside this class."""
167 self.createAndAddEntry(DEFAULT_MODULE, "PlaySounds", "enable_sound",
168 requiresrestart=True)
169 self.createAndAddEntry(DEFAULT_MODULE, "FullScreen", "enable_fullscreen",
170 requiresrestart=True)
171 self.createAndAddEntry(DEFAULT_MODULE, "ScreenResolution", "screen_resolution", initialdata = self._resolutions,
172 requiresrestart=True)
173 self.createAndAddEntry(DEFAULT_MODULE, "RenderBackend", "render_backend", initialdata = self._renderbackends,
174 requiresrestart=True)
175
176 def createAndAddEntry(self, module, name, widgetname, applyfunction=None, initialdata=None, requiresrestart=False):
177 """"
178 @param module: The Setting module this Entry belongs to
179 @type module: C{String}
180 @param name: The Setting's name
181 @type name: C{String}
182 @param widgetname: The name of the widget that is used to change this
183 setting
184 @type widgetname: C{String}
185 @param applyfunction: function that makes the changes when the Setting is
186 saved
187 @type applyfunction: C{function}
188 @param initialdata: If the widget supports the setInitialData() function
189 this can be used to set the initial data
190 @type initialdata: C{String} or C{Boolean}
191 @param requiresrestart: Whether or not the changing of this setting
192 requires a restart
193 @type requiresrestart: C{Boolean}
194 """
195 entry = SettingEntry(module, name, widgetname, applyfunction, initialdata, requiresrestart)
196 self._entries.append(entry)
197
198 def addEntry(self, entry):
199 """Adds a new C{SettingEntry} to the Settting
200 @param entry: A new SettingEntry that is to be added
201 @type entry: C{SettingEntry}
202 """
203 self._entries.append(entry)
155 204
156 def loadSettings(self): 205 def loadSettings(self):
157 self._tree = ET.parse(os.path.join(self._appdata, self._settings_file)) 206 self._tree = ET.parse(os.path.join(self._appdata, self._settings_file))
158 self._root_element = self._tree.getroot() 207 self._root_element = self._tree.getroot()
159 self.validateTree() 208 self.validateTree()
374 if os.path.isfile(self._settings_gui_xml): 423 if os.path.isfile(self._settings_gui_xml):
375 self.OptionsDlg = pychan.loadXML(self._settings_gui_xml) 424 self.OptionsDlg = pychan.loadXML(self._settings_gui_xml)
376 else: 425 else:
377 self.OptionsDlg = pychan.loadXML(StringIO(self._settings_gui_xml)) 426 self.OptionsDlg = pychan.loadXML(StringIO(self._settings_gui_xml))
378 self.OptionsDlg.stylize(self._gui_style) 427 self.OptionsDlg.stylize(self._gui_style)
379 self.OptionsDlg.distributeInitialData({ 428 self.fillWidgets()
380 'screen_resolution' : self._resolutions,
381 'render_backend' : ['OpenGL', 'SDL']
382 })
383 self.OptionsDlg.distributeData({
384 'screen_resolution' : self._resolutions.index(str(self.get("FIFE", "ScreenWidth")) + 'x' + str(self.get("FIFE", "ScreenHeight"))),
385 'render_backend' : 0 if self.get("FIFE", "RenderBackend") == "OpenGL" else 1,
386 'enable_fullscreen' : self.get("FIFE", "FullScreen"),
387 'enable_sound' : self.get("FIFE", "PlaySounds")
388 })
389 self.OptionsDlg.mapEvents({ 429 self.OptionsDlg.mapEvents({
390 'okButton' : self.applySettings, 430 'okButton' : self.applySettings,
391 'cancelButton' : self.OptionsDlg.hide, 431 'cancelButton' : self.OptionsDlg.hide,
392 'defaultButton' : self.setDefaults 432 'defaultButton' : self.setDefaults
393 }) 433 })
394 self.OptionsDlg.show() 434 self.OptionsDlg.show()
395 435
436 def fillWidgets(self):
437 for entry in self._entries:
438 widget = self.OptionsDlg.findChildByName(entry.settingwidgetname)
439 value = self.get(entry.module, entry.name)
440 if type(entry.initialdata) is list:
441 try:
442 value = entry.initialdata.index(value)
443 except ValueError:
444 raise ValueError(value + " is not a valid value for " + entry.name)
445 entry.initializeWidget(widget, value)
446
396 def applySettings(self): 447 def applySettings(self):
397 """ 448 """
398 Writes the settings file. If a change requires a restart of the engine 449 Writes the settings file. If a change requires a restart of the engine
399 it notifies you with a small dialog box. 450 it notifies you with a small dialog box.
400 """ 451 """
401 screen_resolution, render_backend, enable_fullscreen, enable_sound = self.OptionsDlg.collectData('screen_resolution', 'render_backend', 'enable_fullscreen', 'enable_sound') 452 for entry in self._entries:
402 render_backend = 'OpenGL' if render_backend is 0 else 'SDL' 453 widget = self.OptionsDlg.findChildByName(entry.settingwidgetname)
403 if render_backend != self.get("FIFE", "RenderBackend"): 454 data = widget.getData()
404 self.set("FIFE", 'RenderBackend', render_backend) 455
405 self.changesRequireRestart = True 456 # If the data is a list we need to get the correct selected data
406 if int(enable_fullscreen) != int(self.get("FIFE", "FullScreen")): 457 # from the list. This is needed for e.g. dropdowns or listboxs
407 self.set("FIFE", 'FullScreen', int(enable_fullscreen)) 458 if type(entry.initialdata) is list:
408 self.changesRequireRestart = True 459 value = entry.initialdata[data]
409 if int(enable_sound) != int(self.get("FIFE", "PlaySounds")): 460 self.set(entry.module, entry.name, value)
410 self.set("FIFE", 'PlaySounds', int(enable_sound)) 461 else:
411 self.changesRequireRestart = True 462 self.set(entry.module, entry.name, data)
412 if screen_resolution != self._resolutions.index(str(self.get("FIFE", "ScreenWidth")) + 'x' + str(self.get("FIFE", "ScreenHeight"))): 463
413 self.set("FIFE", 'ScreenWidth', int(self._resolutions[screen_resolution].partition('x')[0])) 464 if entry.requiresrestart:
414 self.set("FIFE", 'ScreenHeight', int(self._resolutions[screen_resolution].partition('x')[2])) 465 self.changesRequireRestart = True
415 self.changesRequireRestart = True 466 entry.onApply(widget)
416 467
417 self.saveSettings() 468 self.saveSettings()
418 469
419 self.OptionsDlg.hide() 470 self.OptionsDlg.hide()
420 if self.changesRequireRestart: 471 if self.changesRequireRestart:
421 RestartDlg = pychan.loadXML(StringIO(self._changes_gui_xml)) 472 self._showChangeRequireRestartDialog()
422 RestartDlg.mapEvents({ 'closeButton' : RestartDlg.hide }) 473
423 RestartDlg.show() 474
475 def _showChangeRequireRestartDialog(self):
476 """Shows a dialog that informes the user that a restart is required
477 to perform the changes."""
478 RestartDlg = pychan.loadXML(StringIO(self._changes_gui_xml))
479 RestartDlg.mapEvents({ 'closeButton' : RestartDlg.hide })
480 RestartDlg.show()
481
424 482
425 def setAvailableScreenResolutions(self, reslist): 483 def setAvailableScreenResolutions(self, reslist):
426 """ 484 """
427 A list of valid default screen resolutions. This should be called once 485 A list of valid default screen resolutions. This should be called once
428 right after you instantiate Settings. 486 right after you instantiate Settings.
439 Overwrites the setting file with the default settings-dist.xml file. 497 Overwrites the setting file with the default settings-dist.xml file.
440 """ 498 """
441 shutil.copyfile('settings-dist.xml', os.path.join(self._appdata, self._settings_file)) 499 shutil.copyfile('settings-dist.xml', os.path.join(self._appdata, self._settings_file))
442 self.changesRequireRestart = True 500 self.changesRequireRestart = True
443 self.loadSettings() 501 self.loadSettings()
444 self.applySettings() 502 self._showChangeRequireRestartDialog()
445 503
446 if self.OptionsDlg: 504 if self.OptionsDlg:
447 self.OptionsDlg.hide() 505 self.OptionsDlg.hide()
506
507
508
509 class SettingEntry(object):
510
511 def __init__(self, module, name, widgetname, applyfunction=None, initialdata=None, requiresrestart=False):
512 """
513 @param module: The Setting module this Entry belongs to
514 @type module: C{String}
515 @param name: The Setting's name
516 @type name: C{String}
517 @param widgetname: The name of the widget that is used to change this
518 setting
519 @type widgetname: C{String}
520 @param applyfunction: function that makes the changes when the Setting is
521 saved
522 @type applyfunction: C{function}
523 @param initialdata: If the widget supports the setInitialData() function
524 this can be used to set the initial data
525 @type initialdata: C{String} or C{Boolean}
526 @param requiresrestart: Whether or not the changing of this setting
527 requires a restart
528 @type requiresrestart: C{Boolean}
529 """
530 self._module = module
531 self._name = name
532 self._settingwidgetname = widgetname
533 self._requiresrestart = requiresrestart
534 self._initialdata = initialdata
535 self._applyfunction = applyfunction
536
537 def initializeWidget(self, widget, currentValue):
538 """Initialize the widget with needed data"""
539 if self._initialdata is not None:
540 widget.setInitialData(self._initialdata)
541 widget.setData(currentValue)
542
543 def onApply(self, widget):
544 """Implement actions that need to be taken when the setting is changed
545 here.
546 """
547 if self._applyfunction is not None:
548 self._applyfunction(widget.getData())
549
550 def _getModule(self):
551 return self._module
552
553 def _setModule(self, module):
554 self._module = module
555
556 def _getName(self):
557 return self._name
558
559 def _setName(self, name):
560 self._name = name
561
562 def _getSettingWidgetName(self):
563 return self._settingwidgetname
564
565 def _setSettingWidgetName(self, settingwidgetname):
566 self._settingwidgetname = settingwidgetname
567
568 def _getRequiresRestart(self):
569 return self._requiresrestart
570
571 def _setRequiresRestart(self, requiresrestart):
572 self._requiresrestart = requiresrestart
573
574 def _getInitialData(self):
575 return self._initialdata
576
577 def _setInitialData(self, initialdata):
578 self._initialdata = initialdata
579
580 def _getApplyFunction(self):
581 return self._applyfunction
582
583 def _setApplyFunction(self, applyfunction):
584 self._applyfunction = applyfunction
585
586 module = property(_getModule, _setModule)
587 name = property(_getName, _setName)
588 settingwidgetname = property(_getSettingWidgetName, _setSettingWidgetName)
589 requiresrestart = property(_getRequiresRestart, _setRequiresRestart)
590 initialdata = property(_getInitialData, _setInitialData)
591 applyfunction = property(_getApplyFunction, _setApplyFunction)
592
593 def __str__(self):
594 return "SettingEntry: " + self.name + " Module: " + self.module + " Widget: " + \
595 self.settingwidgetname + " requiresrestart: " + str(self.requiresrestart) + \
596 " initialdata: " + str(self.initialdata)
597
598