From c1653c5f2e2ca2fdecbcbf7d13ff58ae261d649f Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 20 Mar 2016 02:59:09 -0400 Subject: [PATCH] Abstract the implant editor to work with different sources --- gui/builtinViews/__init__.py | 2 +- gui/builtinViews/implantEditor.py | 254 ++++++++++++++++++++++++++++++ gui/characterEditor.py | 254 ++---------------------------- gui/setEditor.py | 15 +- 4 files changed, 281 insertions(+), 244 deletions(-) create mode 100644 gui/builtinViews/implantEditor.py diff --git a/gui/builtinViews/__init__.py b/gui/builtinViews/__init__.py index 4d1ed63c6..46a500f7b 100644 --- a/gui/builtinViews/__init__.py +++ b/gui/builtinViews/__init__.py @@ -1 +1 @@ -__all__ = ["fittingView", "fleetView"] +__all__ = ["fittingView", "fleetView", "implantEditor"] diff --git a/gui/builtinViews/implantEditor.py b/gui/builtinViews/implantEditor.py new file mode 100644 index 000000000..615fc3da4 --- /dev/null +++ b/gui/builtinViews/implantEditor.py @@ -0,0 +1,254 @@ +import wx +import service +import gui.display as d +from gui.bitmapLoader import BitmapLoader +import gui.PFSearchBox as SBox +from gui.marketBrowser import SearchBox +from wx.lib.buttons import GenBitmapButton + +class BaseImplantEditorView (wx.Panel): + def addMarketViewImage(self, iconFile): + if iconFile is None: + return -1 + bitmap = BitmapLoader.getBitmap(iconFile, "icons") + if bitmap is None: + return -1 + else: + return self.availableImplantsImageList.Add(bitmap) + + def __init__(self, parent): + wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL) + self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) + + pmainSizer = wx.BoxSizer(wx.HORIZONTAL) + + availableSizer = wx.BoxSizer(wx.VERTICAL) + + self.searchBox = SearchBox(self) + self.itemView = ItemView(self) + + self.itemView.Hide() + + availableSizer.Add(self.searchBox, 0, wx.EXPAND) + availableSizer.Add(self.itemView, 1, wx.EXPAND) + + ''' + self.availableImplantsSearch = wx.SearchCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER) + self.availableImplantsSearch.ShowCancelButton(True) + + availableSizer.Add(self.availableImplantsSearch, 0, wx.BOTTOM | wx.EXPAND, 2) + ''' + + self.availableImplantsTree = wx.TreeCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) + root = self.availableRoot = self.availableImplantsTree.AddRoot("Available") + self.availableImplantsImageList = wx.ImageList(16, 16) + self.availableImplantsTree.SetImageList(self.availableImplantsImageList) + + availableSizer.Add(self.availableImplantsTree, 1, wx.EXPAND) + + + pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5) + + + buttonSizer = wx.BoxSizer(wx.VERTICAL) + buttonSizer.AddSpacer(( 0, 0), 1) + + self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), style = wx.BORDER_NONE) + buttonSizer.Add(self.btnAdd, 0) + + self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), style = wx.BORDER_NONE) + buttonSizer.Add(self.btnRemove, 0) + + buttonSizer.AddSpacer(( 0, 0), 1) + pmainSizer.Add(buttonSizer, 0, wx.EXPAND, 0) + + characterImplantSizer = wx.BoxSizer(wx.VERTICAL) + self.pluggedImplantsTree = AvailableImplantsView(self) + characterImplantSizer.Add(self.pluggedImplantsTree, 1, wx.ALL|wx.EXPAND, 5) + pmainSizer.Add(characterImplantSizer, 1, wx.EXPAND, 5) + + self.SetSizer(pmainSizer) + + # Populate the market tree + + sMkt = service.Market.getInstance() + for mktGrp in sMkt.getImplantTree(): + iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(mktGrp)) + childId = self.availableImplantsTree.AppendItem(root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID)) + if sMkt.marketGroupHasTypesCheck(mktGrp) is False: + self.availableImplantsTree.AppendItem(childId, "dummy") + + self.availableImplantsTree.SortChildren(self.availableRoot) + + #Bind the event to replace dummies by real data + self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup) + self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.itemSelected) + + self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemSelected) + + #Bind add & remove buttons + self.btnAdd.Bind(wx.EVT_BUTTON, self.itemSelected) + self.btnRemove.Bind(wx.EVT_BUTTON, self.removeItem) + + # We update with an empty list first to set the initial size for Layout(), then update later with actual + # implants for character. This helps with sizing issues. + self.pluggedImplantsTree.update([]) + self.bindContext() + self.Layout() + + self.update() + + def bindContext(self): + # Binds self.contextChanged to whatever changes the context + raise NotImplementedError() + + def getImplantsFromContext(self): + """ Gets list of implants from current context """ + raise NotImplementedError() + + def addImplantToContext(self, item): + """ Adds implant to the current context""" + raise NotImplementedError() + + def removeImplantFromContext(self, pos): + """ Removes implant from the current context""" + raise NotImplementedError() + + def update(self): + """Updates implant list based off the current context""" + self.implants = self.getImplantsFromContext() + self.implants.sort(key=lambda i: int(i.getModifiedItemAttr("implantness"))) + self.pluggedImplantsTree.update(self.implants) + + def contextChanged(self, event): + self.update() + event.Skip() + + def expandLookup(self, event): + tree = self.availableImplantsTree + sMkt = service.Market.getInstance() + parent = event.Item + child, _ = tree.GetFirstChild(parent) + text = tree.GetItemText(child) + + if text == "dummy" or text == "itemdummy": + tree.Delete(child) + + # if the dummy item is a market group, replace with actual market groups + if text == "dummy": + #Add 'real stoof!' instead + currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent), eager="children") + for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): + iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(childMktGrp)) + childId = tree.AppendItem(parent, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID)) + if sMkt.marketGroupHasTypesCheck(childMktGrp) is False: + tree.AppendItem(childId, "dummy") + else: + tree.AppendItem(childId, "itemdummy") + + # replace dummy with actual items + if text == "itemdummy": + currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent)) + items = sMkt.getItemsByMarketGroup(currentMktGrp) + for item in items: + iconId = self.addMarketViewImage(item.icon.iconFile) + tree.AppendItem(parent, item.name, iconId, data=wx.TreeItemData(item)) + + tree.SortChildren(parent) + + def itemSelected(self, event): + if event.EventObject is self.btnAdd: + # janky fix that sets EventObject so that we don't have similar code elsewhere. + if self.itemView.IsShown(): + event.EventObject = self.itemView + else: + event.EventObject = self.availableImplantsTree + + if event.EventObject is self.itemView: + sel = event.EventObject.GetFirstSelected() + item = self.itemView.items[sel] + else: + root = self.availableImplantsTree.GetSelection() + + if not root.IsOk(): + return + + nchilds = self.availableImplantsTree.GetChildrenCount(root) + if nchilds == 0: + item = self.availableImplantsTree.GetPyData(root) + else: + event.Skip() + return + + if item: + self.addImplantToContext(item) + self.update() + + def removeItem(self, event): + pos = self.pluggedImplantsTree.GetFirstSelected() + if pos != -1: + self.removeImplantFromContext(pos) + self.update() + +class AvailableImplantsView(d.Display): + DEFAULT_COLS = ["attr:implantness", + "Base Icon", + "Base Name"] + + def __init__(self, parent): + d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) + self.Bind(wx.EVT_LEFT_DCLICK, parent.removeItem) + +class ItemView(d.Display): + DEFAULT_COLS = ["Base Icon", + "Base Name", + "attr:power,,,True", + "attr:cpu,,,True"] + + def __init__(self, parent): + d.Display.__init__(self, parent) + self.parent = parent + self.searchBox = parent.searchBox + + self.items = [] + + # Bind search actions + self.searchBox.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) + self.searchBox.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) + self.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) + self.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch) + + def clearSearch(self, event=None): + if self.IsShown(): + self.parent.availableImplantsTree.Show() + self.Hide() + self.parent.Layout() + + if event: + self.searchBox.Clear() + + self.items = [] + self.update(self.items) + + def scheduleSearch(self, event=None): + sMkt = service.Market.getInstance() + + search = self.searchBox.GetLineText(0) + # Make sure we do not count wildcard as search symbol + realsearch = search.replace("*", "") + # Show nothing if query is too short + if len(realsearch) < 3: + self.clearSearch() + return + + sMkt.searchItems(search, self.populateSearch, ["Implant"]) + + def populateSearch(self, items): + if not self.IsShown(): + self.parent.availableImplantsTree.Hide() + self.Show() + self.parent.Layout() + + self.items = sorted(list(items), key=lambda i: i.name) + + self.update(self.items) \ No newline at end of file diff --git a/gui/characterEditor.py b/gui/characterEditor.py index 5f437dbe3..697862146 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -19,18 +19,13 @@ import wx -import gui.mainFrame import wx.lib.newevent import wx.gizmos from gui.bitmapLoader import BitmapLoader import service -import gui.display as d from gui.contextMenu import ContextMenu -from wx.lib.buttons import GenBitmapButton import gui.globalEvents as GE - -import gui.PFSearchBox as SBox -from gui.marketBrowser import SearchBox +from gui.builtinViews.implantEditor import BaseImplantEditorView class CharacterEditor(wx.Frame): def __init__(self, parent): @@ -97,7 +92,7 @@ class CharacterEditor(wx.Frame): self.viewsNBContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0) self.sview = SkillTreeView(self.viewsNBContainer) - self.iview = ImplantsTreeView(self.viewsNBContainer) + self.iview = ImplantEditorView(self.viewsNBContainer) self.aview = APIView(self.viewsNBContainer) self.viewsNBContainer.AddPage(self.sview, "Skills") @@ -460,256 +455,31 @@ class SkillTreeView (wx.Panel): wx.PostEvent(self.Parent.Parent, GE.CharListUpdated()) event.Skip() -class ImplantsTreeView (wx.Panel): - def addMarketViewImage(self, iconFile): - if iconFile is None: - return -1 - bitmap = BitmapLoader.getBitmap(iconFile, "icons") - if bitmap is None: - return -1 - else: - return self.availableImplantsImageList.Add(bitmap) +class ImplantEditorView(BaseImplantEditorView): def __init__(self, parent): - wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL) - self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) + BaseImplantEditorView.__init__ (self, parent) - pmainSizer = wx.BoxSizer(wx.HORIZONTAL) - - availableSizer = wx.BoxSizer(wx.VERTICAL) - - self.searchBox = SearchBox(self) - self.itemView = ItemView(self) - - self.itemView.Hide() - - availableSizer.Add(self.searchBox, 0, wx.EXPAND) - availableSizer.Add(self.itemView, 1, wx.EXPAND) - - ''' - self.availableImplantsSearch = wx.SearchCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER) - self.availableImplantsSearch.ShowCancelButton(True) - - availableSizer.Add(self.availableImplantsSearch, 0, wx.BOTTOM | wx.EXPAND, 2) - ''' - - self.availableImplantsTree = wx.TreeCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) - root = self.availableRoot = self.availableImplantsTree.AddRoot("Available") - self.availableImplantsImageList = wx.ImageList(16, 16) - self.availableImplantsTree.SetImageList(self.availableImplantsImageList) - - availableSizer.Add(self.availableImplantsTree, 1, wx.EXPAND) - - - pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5) - - - buttonSizer = wx.BoxSizer(wx.VERTICAL) - buttonSizer.AddSpacer(( 0, 0), 1) - #pmainSizer.Add(buttonSizer, 0, wx.TOP, 5) - - self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), style = wx.BORDER_NONE) - buttonSizer.Add(self.btnAdd, 0) - - self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), style = wx.BORDER_NONE) - buttonSizer.Add(self.btnRemove, 0) - - buttonSizer.AddSpacer(( 0, 0), 1) - pmainSizer.Add(buttonSizer, 0, wx.EXPAND, 0) - - characterImplantSizer = wx.BoxSizer(wx.VERTICAL) - self.pluggedImplantsTree = AvailableImplantsView(self) - characterImplantSizer.Add(self.pluggedImplantsTree, 1, wx.ALL|wx.EXPAND, 5) - pmainSizer.Add(characterImplantSizer, 1, wx.EXPAND, 5) - - self.SetSizer(pmainSizer) - - # Populate the market tree - - sMkt = service.Market.getInstance() - for mktGrp in sMkt.getImplantTree(): - iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(mktGrp)) - childId = self.availableImplantsTree.AppendItem(root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID)) - if sMkt.marketGroupHasTypesCheck(mktGrp) is False: - self.availableImplantsTree.AppendItem(childId, "dummy") - - self.availableImplantsTree.SortChildren(self.availableRoot) - - #Bind the event to replace dummies by real data - self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup) - self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.addImplant) - - self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) - - #Bind add & remove buttons - self.btnAdd.Bind(wx.EVT_BUTTON, self.addImplant) - self.btnRemove.Bind(wx.EVT_BUTTON, self.removeImplant) - - #Bind the change of a character* - self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged) - - # We update with an empty list first to set the initial size for Layout(), then update later with actual - # implants for character. This helps with sizing issues. - self.update([]) - - self.Layout() + def bindContext(self): + self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.contextChanged) + def getImplantsFromContext(self): sChar = service.Character.getInstance() charID = self.Parent.Parent.getActiveCharacter() - self.update(sChar.getImplants(charID)) - def itemActivated(self, event): - sel = event.EventObject.GetFirstSelected() - item = self.itemView.items[sel] + return sChar.getImplants(charID) - if item: - sChar = service.Character.getInstance() - charID = self.Parent.Parent.getActiveCharacter() - - sChar.addImplant(charID, item.ID) - self.update(sChar.getImplants(charID)) - - def update(self, implants): - self.implants = implants[:] - self.implants.sort(key=lambda i: int(i.getModifiedItemAttr("implantness"))) - self.pluggedImplantsTree.update(self.implants) - - def charChanged(self, event): + def addImplantToContext(self, item): sChar = service.Character.getInstance() charID = self.Parent.Parent.getActiveCharacter() - name = sChar.getCharName(charID) - if name == "All 0" or name == "All 5": - self.Enable(False) - else: - self.Enable(True) - self.update(sChar.getImplants(charID)) - event.Skip() + sChar.addImplant(charID, item.ID) - def expandLookup(self, event): - tree = self.availableImplantsTree - sMkt = service.Market.getInstance() - parent = event.Item - child, _ = tree.GetFirstChild(parent) - text = tree.GetItemText(child) - - if text == "dummy" or text == "itemdummy": - tree.Delete(child) - - # if the dummy item is a market group, replace with actual market groups - if text == "dummy": - #Add 'real stoof!' instead - currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent), eager="children") - for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): - iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(childMktGrp)) - childId = tree.AppendItem(parent, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID)) - if sMkt.marketGroupHasTypesCheck(childMktGrp) is False: - tree.AppendItem(childId, "dummy") - else: - tree.AppendItem(childId, "itemdummy") - - # replace dummy with actual items - if text == "itemdummy": - currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent)) - items = sMkt.getItemsByMarketGroup(currentMktGrp) - for item in items: - iconId = self.addMarketViewImage(item.icon.iconFile) - tree.AppendItem(parent, item.name, iconId, data=wx.TreeItemData(item.ID)) - - tree.SortChildren(parent) - - def addImplant(self, event): - root = self.availableImplantsTree.GetSelection() - - if not root.IsOk(): - return - - nchilds = self.availableImplantsTree.GetChildrenCount(root) + def removeImplantFromContext(self, pos): sChar = service.Character.getInstance() charID = self.Parent.Parent.getActiveCharacter() - if nchilds == 0: - itemID = self.availableImplantsTree.GetPyData(root) - sChar.addImplant(charID, itemID) - self.update(sChar.getImplants(charID)) - else: - event.Skip() - def removeImplant(self, event): - pos = self.pluggedImplantsTree.GetFirstSelected() - if pos != -1: - sChar = service.Character.getInstance() - charID = self.Parent.Parent.getActiveCharacter() - sChar.removeImplant(charID, self.implants[pos]) - self.update(sChar.getImplants(charID)) - -class AvailableImplantsView(d.Display): - DEFAULT_COLS = ["attr:implantness", - "Base Icon", - "Base Name"] - - def __init__(self, parent): - d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) - - self.Bind(wx.EVT_LEFT_DCLICK, parent.removeImplant) - - #if "__WXGTK__" in wx.PlatformInfo: - # self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) - #else: - # self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) - -class ItemView(d.Display): - DEFAULT_COLS = ["Base Icon", - "Base Name", - "attr:power,,,True", - "attr:cpu,,,True"] - - def __init__(self, parent): - d.Display.__init__(self, parent) - self.parent = parent - self.searchBox = parent.searchBox - - self.items = [] - - # Bind search actions - self.searchBox.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) - self.searchBox.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) - self.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) - self.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch) - - def clearSearch(self, event=None): - if self.IsShown(): - self.parent.availableImplantsTree.Show() - self.Hide() - self.parent.Layout() - - if event: - self.searchBox.Clear() - - self.items = [] - self.update(self.items) - - def scheduleSearch(self, event=None): - sMkt = service.Market.getInstance() - - search = self.searchBox.GetLineText(0) - # Make sure we do not count wildcard as search symbol - realsearch = search.replace("*", "") - # Show nothing if query is too short - if len(realsearch) < 3: - self.clearSearch() - return - - sMkt.searchItems(search, self.populateSearch, ["Implant"]) - - def populateSearch(self, items): - if not self.IsShown(): - self.parent.availableImplantsTree.Hide() - self.Show() - self.parent.Layout() - - self.items = sorted(list(items), key=lambda i: i.name) - - self.update(self.items) + sChar.removeImplant(charID, self.implants[pos]) class APIView (wx.Panel): diff --git a/gui/setEditor.py b/gui/setEditor.py index 5af848f42..14037b24b 100644 --- a/gui/setEditor.py +++ b/gui/setEditor.py @@ -19,14 +19,24 @@ import wx from gui.bitmapLoader import BitmapLoader +from gui.builtinViews.implantEditor import BaseImplantEditorView import service from gui.utils.clipboard import toClipboard, fromClipboard from service.targetResists import ImportError +class EditorView(BaseImplantEditorView): + def __init__(self, parent): + BaseImplantEditorView.__init__(self, parent) + self.parent = parent + + def getImplants(self): + return [] + + class ImplantSetEditorDlg(wx.Dialog): def __init__(self, parent): - wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Implant Set Editor", size = wx.Size( 350,240 )) + wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Implant Set Editor", size = wx.Size(640, 600)) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -82,6 +92,9 @@ class ImplantSetEditorDlg(wx.Dialog): self.sl = wx.StaticLine(self) mainSizer.Add(self.sl, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) + self.iview = EditorView(self) + mainSizer.Add(self.iview, 0, wx.EXPAND) + contentSizer = wx.BoxSizer(wx.VERTICAL) self.slfooter = wx.StaticLine(self)