195 lines
6.9 KiB
Python
195 lines
6.9 KiB
Python
# noinspection PyPackageRequirements
|
|
import wx
|
|
from gui.bitmap_loader import BitmapLoader
|
|
|
|
|
|
class BaseValidator(wx.Validator):
|
|
def __init__(self):
|
|
wx.Validator.__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.parent = parent
|
|
|
|
# See https://github.com/wxWidgets/Phoenix/issues/611
|
|
self.txtctrl = self.FindWindowById(3000, self)
|
|
|
|
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, selected=None):
|
|
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.choices.sort(key=lambda p: p.name)
|
|
self.entityChoices = wx.Choice(self, choices=[p.name for p in 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.SetToolTip("{} {}".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.SetSizer(self.navSizer)
|
|
self.Layout()
|
|
|
|
self.refreshEntityList(selected=selected)
|
|
|
|
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, entity, name):
|
|
"""Override method to copy entity. Must return the copy"""
|
|
raise NotImplementedError()
|
|
|
|
def DoRename(self, entity, name):
|
|
"""Override method to rename an entity"""
|
|
raise NotImplementedError()
|
|
|
|
def DoDelete(self, entity):
|
|
"""Override method to delete entity"""
|
|
raise NotImplementedError()
|
|
|
|
def OnNew(self, event):
|
|
with TextEntryValidatedDialog(
|
|
self, self.validator, "Enter a name for your new {}:".format(self.entityName),
|
|
"New {}".format(self.entityName)
|
|
) as dlg:
|
|
dlg.CenterOnParent()
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
# using dlg.textctrl.GetValue instead of simply dlg.GetValue because the proper way does not work in wxPython 2.8
|
|
new = self.DoNew(dlg.txtctrl.GetValue().strip())
|
|
self.refreshEntityList(new)
|
|
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
|
|
else:
|
|
return False
|
|
|
|
def OnCopy(self, event):
|
|
with TextEntryValidatedDialog(
|
|
self, self.validator, "Enter a name for your {} copy:".format(self.entityName),
|
|
"Copy {}".format(self.entityName)
|
|
) as dlg:
|
|
active = self.getActiveEntity()
|
|
dlg.SetValue("{} Copy".format(active.name))
|
|
dlg.txtctrl.SetInsertionPointEnd()
|
|
dlg.CenterOnParent()
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
copy = self.DoCopy(active, dlg.txtctrl.GetValue().strip())
|
|
self.refreshEntityList(copy)
|
|
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
|
|
|
|
def OnRename(self, event):
|
|
with TextEntryValidatedDialog(
|
|
self, self.validator, "Enter a new name for your {}:".format(self.entityName),
|
|
"Rename {}".format(self.entityName)
|
|
) as dlg:
|
|
active = self.getActiveEntity()
|
|
dlg.SetValue(active.name)
|
|
dlg.txtctrl.SetInsertionPointEnd()
|
|
dlg.CenterOnParent()
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
self.DoRename(active, dlg.txtctrl.GetValue().strip())
|
|
self.refreshEntityList(active)
|
|
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
|
|
|
|
def OnDelete(self, event):
|
|
with 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
|
|
) as dlg:
|
|
dlg.CenterOnParent()
|
|
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([p.name for p in 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()]
|
|
|
|
def setActiveEntity(self, entity):
|
|
try:
|
|
idx = self.choices.index(entity)
|
|
except IndexError:
|
|
return False
|
|
self.entityChoices.SetSelection(idx)
|
|
return True
|
|
|
|
def checkEntitiesExist(self):
|
|
if len(self.choices) > 0:
|
|
return True
|
|
else:
|
|
return self.enterNewEntity()
|
|
|
|
def enterNewEntity(self):
|
|
self.Parent.Hide()
|
|
if self.OnNew(None) is False:
|
|
return False
|
|
self.Parent.Show()
|
|
|
|
return True
|
|
|
|
|