From c3dcdb06869d14a8f06fab7a4b3a5e88d8be44aa Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 27 Mar 2016 21:48:19 -0400 Subject: [PATCH] Entity = characters, damage profiles... anything with the generic drop down list of entities along with new/rename/etc buttons. This commit starts refactoring how we handle this, hopefully simplifying the process to a series of dialogs rather than trying to manage multiple control in the window. --- gui/builtinViews/entityEditor.py | 151 ++++++++++++++++++ gui/patternEditor.py | 252 +++++++++---------------------- service/damagePattern.py | 5 +- 3 files changed, 225 insertions(+), 183 deletions(-) create mode 100644 gui/builtinViews/entityEditor.py diff --git a/gui/builtinViews/entityEditor.py b/gui/builtinViews/entityEditor.py new file mode 100644 index 000000000..7eb439fb1 --- /dev/null +++ b/gui/builtinViews/entityEditor.py @@ -0,0 +1,151 @@ +import wx +from gui.bitmapLoader import BitmapLoader +import service + +class BaseValidator(wx.PyValidator): + def __init__(self): + wx.PyValidator.__init__(self) + + def Validate(self, win): + raise NotImplementedError() + + def TransferToWindow(self): + return True + + def TransferFromWindow(self): + return True + +class TextEntryValidatedDialog(wx.TextEntryDialog): + def __init__(self, parent, validator=None, *args, **kargs): + wx.TextEntryDialog.__init__(self, parent, *args, **kargs) + self.txtctrl = self.FindWindowById(3000) + if validator: + self.txtctrl.SetValidator(validator()) + +class EntityEditor (wx.Panel): + """ + Entity Editor is a panel that takes some sort of list as a source and populates a drop down with options to add/ + rename/clone/delete an entity. Comes with dialogs that take user input. Classes that derive this class must override + functions that get the list from the source, what to do when user does an action, and how to validate the input. + """ + + def __init__(self, parent, entityName): + wx.Panel.__init__(self, parent, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL) + self.entityName = entityName + self.validator = None + self.navSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.choices = self.getEntitiesFromContext() + self.choices.sort(key=lambda p: p.name) + self.entityChoices = wx.Choice(self, choices=map(lambda p: p.name, self.choices)) + self.navSizer.Add(self.entityChoices, 1, wx.ALL, 5) + + buttons = (("new", wx.ART_NEW, self.OnNew), + ("rename", BitmapLoader.getBitmap("rename", "gui"), self.OnRename), + ("copy", wx.ART_COPY, self.OnCopy), + ("delete", wx.ART_DELETE, self.OnDelete)) + + size = None + for name, art, func in buttons: + bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) if name != "rename" else art + btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) + if size is None: + size = btn.GetSize() + + btn.SetMinSize(size) + btn.SetMaxSize(size) + + btn.SetToolTipString("{} {}".format(name.capitalize(), self.entityName)) + btn.Bind(wx.EVT_BUTTON, func) + setattr(self, "btn%s" % name.capitalize(), btn) + self.navSizer.Add(btn, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 2) + + self.entityChoices.SetSelection(0) + self.SetSizer(self.navSizer) + self.Layout() + + def SetEditorValidator(self, validator=None): + """ Sets validator class (not an instance of the class) """ + self.validator = validator + + def getEntitiesFromContext(self): + """ Gets list of entities from current context """ + raise NotImplementedError() + + def DoNew(self, name): + """Override method to do new entity logic. Must return the new entity""" + raise NotImplementedError() + + def DoCopy(self, name): + """Override method to copy entity. Must return the copy""" + raise NotImplementedError() + + def DoRename(self, name): + """Override method to rename an entity""" + raise NotImplementedError() + + def DoDelete(self, name): + """Override method to delete entity""" + raise NotImplementedError() + + def OnNew(self, event): + dlg = TextEntryValidatedDialog(self, self.validator, + "Enter a name for your new {}:".format(self.entityName), + "New {}".format(self.entityName)) + + if dlg.ShowModal() == wx.ID_OK: + new = self.DoNew(dlg.GetValue().strip()) + self.refreshEntityList(new) + wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED)) + + def OnCopy(self, event): + dlg = TextEntryValidatedDialog(self, self.validator, + "Enter a name for your {} copy:".format(self.entityName), + "Copy {}".format(self.entityName)) + active = self.getActiveEntity() + dlg.SetValue("{} Copy".format(active.name)) + dlg.txtctrl.SetInsertionPointEnd() + + if dlg.ShowModal() == wx.ID_OK: + copy = self.DoCopy(active, dlg.GetValue().strip()) + self.refreshEntityList(copy) + wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED)) + + def OnRename(self, event): + dlg = TextEntryValidatedDialog(self, self.validator, + "Enter a new name for your {}:".format(self.entityName), + "Rename {}".format(self.entityName)) + active = self.getActiveEntity() + dlg.SetValue(active.name) + dlg.txtctrl.SetInsertionPointEnd() + + if dlg.ShowModal() == wx.ID_OK: + self.DoRename(active, dlg.GetValue().strip()) + self.refreshEntityList(active) + wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED)) + + def OnDelete(self, event): + dlg = wx.MessageDialog(self, + "Do you really want to delete the {} {}?".format(self.getActiveEntity().name, self.entityName), + "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) + + if dlg.ShowModal() == wx.ID_YES: + self.DoDelete(self.getActiveEntity()) + self.refreshEntityList() + wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED)) + + def refreshEntityList(self, selected=None): + self.choices = self.getEntitiesFromContext() + self.entityChoices.Clear() + self.entityChoices.AppendItems(map(lambda p: p.name, self.choices)) + if selected: + idx = self.choices.index(selected) + self.entityChoices.SetSelection(idx) + else: + self.entityChoices.SetSelection(0) + + def getActiveEntity(self): + if len(self.choices) == 0: + return None + + return self.choices[self.entityChoices.GetSelection()] \ No newline at end of file diff --git a/gui/patternEditor.py b/gui/patternEditor.py index 40b8e45aa..88f24c17c 100644 --- a/gui/patternEditor.py +++ b/gui/patternEditor.py @@ -23,11 +23,65 @@ import service from wx.lib.intctrl import IntCtrl from gui.utils.clipboard import toClipboard, fromClipboard from service.damagePattern import ImportError - +from gui.builtinViews.entityEditor import EntityEditor, BaseValidator ########################################################################### ## Class DmgPatternEditorDlg ########################################################################### +class DmgPatternTextValidor(BaseValidator): + def __init__(self): + BaseValidator.__init__(self) + + def Clone(self): + return DmgPatternTextValidor() + + def Validate(self, win): + profileEditor = win.Parent + textCtrl = self.GetWindow() + text = textCtrl.GetValue().strip() + + try: + if len(text) == 0: + raise ValueError("You must supply a name for your Damage Profile!") + elif text in [x.name for x in profileEditor.choices]: + raise ValueError("Damage Profile name already in use, please choose another.") + + return True + except ValueError, e: + wx.MessageBox(u"{}".format(e), "Error") + textCtrl.SetFocus() + return False + + +class DmgPatternEntityEditor(EntityEditor): + def __init__(self, parent): + EntityEditor.__init__(self, parent, "Damage Profile") + self.SetEditorValidator(DmgPatternTextValidor) + + def getEntitiesFromContext(self): + """ Gets list of entities from current context """ + sDP = service.DamagePattern.getInstance() + choices = sorted(sDP.getDamagePatternList(), key=lambda p: p.name) + return [c for c in choices if c.name != "Selected Ammo"] + + def DoNew(self, name): + sDP = service.DamagePattern.getInstance() + return sDP.newPattern(name) + + def DoRename(self, entity, name): + sDP = service.DamagePattern.getInstance() + sDP.renamePattern(entity, name) + + def DoCopy(self, entity, name): + sDP = service.DamagePattern.getInstance() + copy = sDP.copyPattern(entity) + sDP.renamePattern(copy, name) + return copy + + def DoDelete(self, entity): + sDP = service.DamagePattern.getInstance() + sDP.deletePattern(entity) + class DmgPatternEditorDlg(wx.Dialog): DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") @@ -39,52 +93,12 @@ class DmgPatternEditorDlg(wx.Dialog): mainSizer = wx.BoxSizer(wx.VERTICAL) - self.headerSizer = headerSizer = wx.BoxSizer(wx.HORIZONTAL) - sDP = service.DamagePattern.getInstance() self.choices = sDP.getDamagePatternList() - # Remove "Selected Ammo" Damage Pattern - for dp in self.choices: - if dp.name == "Selected Ammo": - self.choices.remove(dp) - # Sort the remaining list and continue on - self.choices.sort(key=lambda p: p.name) - self.ccDmgPattern = wx.Choice(self, choices=map(lambda p: p.name, self.choices)) - self.ccDmgPattern.Bind(wx.EVT_CHOICE, self.patternChanged) - self.ccDmgPattern.SetSelection(0) - self.namePicker = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER) - self.namePicker.Bind(wx.EVT_TEXT_ENTER, self.processRename) - self.namePicker.Hide() - - size = None - headerSizer.Add(self.ccDmgPattern, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT|wx.LEFT, 3) - buttons = (("new", wx.ART_NEW), - ("rename", BitmapLoader.getBitmap("rename", "gui")), - ("copy", wx.ART_COPY), - ("delete", wx.ART_DELETE)) - for name, art in buttons: - bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) if name != "rename" else art - btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) - if size is None: - size = btn.GetSize() - - btn.SetMinSize(size) - btn.SetMaxSize(size) - - btn.Layout() - setattr(self, name, btn) - btn.Enable(True) - btn.SetToolTipString("%s pattern" % name.capitalize()) - headerSizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL) - - self.btnSave = wx.Button(self, wx.ID_SAVE) - self.btnSave.Hide() - self.btnSave.Bind(wx.EVT_BUTTON, self.processRename) - self.headerSizer.Add(self.btnSave, 0, wx.ALIGN_CENTER) - - mainSizer.Add(headerSizer, 0, wx.EXPAND | wx.ALL, 2) + self.entityEditor = DmgPatternEntityEditor(self) + mainSizer.Add(self.entityEditor, 0, wx.ALL | wx.EXPAND, 2) self.sl = wx.StaticLine(self) mainSizer.Add(self.sl, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) @@ -108,7 +122,7 @@ class DmgPatternEditorDlg(wx.Dialog): bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big"%type, "gui")) if i%2: style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT - border = 10 + border = 20 else: style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT border = 5 @@ -155,6 +169,7 @@ class DmgPatternEditorDlg(wx.Dialog): importExport = (("Import", wx.ART_FILE_OPEN, "from"), ("Export", wx.ART_FILE_SAVE_AS, "to")) + for name, art, direction in importExport: bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) @@ -170,14 +185,9 @@ class DmgPatternEditorDlg(wx.Dialog): self.Layout() bsize = self.GetBestSize() - self.SetSize((-1,bsize.height)) + self.SetSize((-1, bsize.height)) - self.new.Bind(wx.EVT_BUTTON, self.newPattern) - self.rename.Bind(wx.EVT_BUTTON, self.renamePattern) - self.copy.Bind(wx.EVT_BUTTON, self.copyPattern) - self.delete.Bind(wx.EVT_BUTTON, self.deletePattern) - self.Import.Bind(wx.EVT_BUTTON, self.importPatterns) - self.Export.Bind(wx.EVT_BUTTON, self.exportPatterns) + self.Bind(wx.EVT_CHOICE, self.patternChanged) self.patternChanged() @@ -188,7 +198,7 @@ class DmgPatternEditorDlg(wx.Dialog): if self.block: return - p = self.getActivePattern() + p = self.entityEditor.getActiveEntity() total = sum(map(lambda attr: getattr(self, "%sEdit"%attr).GetValue(), self.DAMAGE_TYPES)) for type in self.DAMAGE_TYPES: editObj = getattr(self, "%sEdit"%type) @@ -207,24 +217,18 @@ class DmgPatternEditorDlg(wx.Dialog): for type in self.DAMAGE_TYPES: editObj = getattr(self, "%sEdit"%type) editObj.Enable(False) - self.rename.Enable(False) - self.delete.Enable(False) + self.entityEditor.btnRename.Enable(False) + self.entityEditor.btnDelete.Enable(False) def unrestrict(self): for type in self.DAMAGE_TYPES: editObj = getattr(self, "%sEdit"%type) editObj.Enable() - self.rename.Enable() - self.delete.Enable() - - def getActivePattern(self): - if len(self.choices) == 0: - return None - - return self.choices[self.ccDmgPattern.GetSelection()] + self.entityEditor.btnRename.Enable() + self.entityEditor.btnDelete.Enable() def patternChanged(self, event=None): - p = self.getActivePattern() + p = self.entityEditor.getActiveEntity() if p is None: return @@ -244,126 +248,9 @@ class DmgPatternEditorDlg(wx.Dialog): self.block = False self.ValuesUpdated() - def newPattern(self, event): - self.restrict() - - self.block = True - # reset values - for type in self.DAMAGE_TYPES: - editObj = getattr(self, "%sEdit"%type) - editObj.SetValue(0) - - self.block = False - - self.btnSave.SetLabel("Create") - self.Refresh() - self.renamePattern() - - def renamePattern(self, event=None): - if event is not None: - self.btnSave.SetLabel("Rename") - - self.ccDmgPattern.Hide() - self.namePicker.Show() - self.headerSizer.Replace(self.ccDmgPattern, self.namePicker) - self.namePicker.SetFocus() - - if event is not None: # Rename mode - self.btnSave.SetLabel("Rename") - self.namePicker.SetValue(self.getActivePattern().name) - else: # Create mode - self.namePicker.SetValue("") - - for btn in (self.new, self.rename, self.delete, self.copy): - btn.Hide() - - self.btnSave.Show() - self.headerSizer.Layout() - if event is not None: - event.Skip() - - def processRename(self, event): - newName = self.namePicker.GetLineText(0) - self.stNotice.SetLabel("") - - if newName == "": - self.stNotice.SetLabel("Invalid name.") - return - - sDP = service.DamagePattern.getInstance() - if self.btnSave.Label == "Create": - p = sDP.newPattern() - else: - # we are renaming, so get the current selection - p = self.getActivePattern() - - for pattern in self.choices: - if pattern.name == newName and p != pattern: - self.stNotice.SetLabel("Name already used, please choose another") - return - - sDP.renamePattern(p, newName) - - self.updateChoices(newName) - self.headerSizer.Replace(self.namePicker, self.ccDmgPattern) - self.ccDmgPattern.Show() - self.namePicker.Hide() - self.btnSave.Hide() - for btn in (self.new, self.rename, self.delete, self.copy): - btn.Show() - - sel = self.ccDmgPattern.GetSelection() - self.ccDmgPattern.Delete(sel) - self.ccDmgPattern.Insert(newName, sel) - self.ccDmgPattern.SetSelection(sel) - self.ValuesUpdated() - self.unrestrict() - - def copyPattern(self,event): - sDP = service.DamagePattern.getInstance() - p = sDP.copyPattern(self.getActivePattern()) - self.choices.append(p) - id = self.ccDmgPattern.Append(p.name) - self.ccDmgPattern.SetSelection(id) - self.btnSave.SetLabel("Copy") - self.renamePattern() - self.patternChanged() - - def deletePattern(self,event): - sDP = service.DamagePattern.getInstance() - sel = self.ccDmgPattern.GetSelection() - sDP.deletePattern(self.getActivePattern()) - self.ccDmgPattern.Delete(sel) - self.ccDmgPattern.SetSelection(max(0, sel - 1)) - del self.choices[sel] - self.patternChanged() - - def __del__( self ): + def __del__(self): pass - def updateChoices(self, select=None): - "Gathers list of patterns and updates choice selections" - sDP = service.DamagePattern.getInstance() - self.choices = sDP.getDamagePatternList() - - for dp in self.choices: - if dp.name == "Selected Ammo": # don't include this special butterfly - self.choices.remove(dp) - - # Sort the remaining list and continue on - self.choices.sort(key=lambda p: p.name) - self.ccDmgPattern.Clear() - - for i, choice in enumerate(map(lambda p: p.name, self.choices)): - self.ccDmgPattern.Append(choice) - - if select is not None and choice == select: - self.ccDmgPattern.SetSelection(i) - - if select is None: - self.ccDmgPattern.SetSelection(0) - self.patternChanged() - def importPatterns(self, event): text = fromClipboard() if text: @@ -384,3 +271,6 @@ class DmgPatternEditorDlg(wx.Dialog): sDP = service.DamagePattern.getInstance() toClipboard( sDP.exportPatterns() ) self.stNotice.SetLabel("Patterns exported to clipboard") + + def contextChanged(self, event): + print "lol" \ No newline at end of file diff --git a/service/damagePattern.py b/service/damagePattern.py index 374940e0c..b67b10956 100644 --- a/service/damagePattern.py +++ b/service/damagePattern.py @@ -46,9 +46,10 @@ class DamagePattern(): def getDamagePattern(self, name): return eos.db.getDamagePattern(name) - def newPattern(self): + def newPattern(self, name): p = eos.types.DamagePattern(0, 0, 0, 0) - p.name = "" + p.name = name + eos.db.save(p) return p def renamePattern(self, p, newName):