From 0d0ec42daf74fdf26a0726e284705d82a2673107 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 1 Nov 2015 19:49:22 -0500 Subject: [PATCH] Initial GUI commit. Still need to actually handle the attribute change --- eos/db/saveddata/queries.py | 3 + gui/PFSearchBox.py | 2 +- gui/mainFrame.py | 7 ++ gui/mainMenuBar.py | 5 ++ gui/marketBrowser.py | 4 +- gui/propertyEditor.py | 136 ++++++++++++++++++++++++++++++++++++ service/market.py | 24 +++++-- 7 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 gui/propertyEditor.py diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 3fbe55322..7b2853b6f 100644 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -422,6 +422,9 @@ def getOverrides(itemID, eager=None): else: raise TypeError("Need integer as argument") +def getAllOverrides(eager=None): + return saveddata_session.query(Override).all() + def removeInvalid(fits): invalids = [f for f in fits if f.isInvalid] diff --git a/gui/PFSearchBox.py b/gui/PFSearchBox.py index 88c67617b..7fff91e9b 100644 --- a/gui/PFSearchBox.py +++ b/gui/PFSearchBox.py @@ -11,7 +11,7 @@ TextTyped, EVT_TEXT = wx.lib.newevent.NewEvent() class PFSearchBox(wx.Window): def __init__(self, parent, id = wx.ID_ANY, value = "", pos = wx.DefaultPosition, size = wx.Size(-1,24), style = 0): - wx.Window.__init__(self, parent, id, pos, size, style = 0) + wx.Window.__init__(self, parent, id, pos, size, style = style) self.isSearchButtonVisible = False self.isCancelButtonVisible = False diff --git a/gui/mainFrame.py b/gui/mainFrame.py index cb90ce0cc..4bb6bfb5d 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -53,6 +53,7 @@ from gui.copySelectDialog import CopySelectDialog from gui.utils.clipboard import toClipboard, fromClipboard from gui.fleetBrowser import FleetBrowser from gui.updateDialog import UpdateDialog +from gui.propertyEditor import AttributeEditor from gui.builtinViews import * from time import gmtime, strftime @@ -329,6 +330,10 @@ class MainFrame(wx.Frame): dlg=CharacterEditor(self) dlg.Show() + def showAttrEditor(self, event): + dlg=AttributeEditor(self) + dlg.Show() + def showTargetResistsEditor(self, event): dlg=ResistsEditorDlg(self) dlg.ShowModal() @@ -416,6 +421,8 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.saveCharAs, id = menuBar.saveCharAsId) # Save current character self.Bind(wx.EVT_MENU, self.revertChar, id = menuBar.revertCharId) + # Open attribute editor + self.Bind(wx.EVT_MENU, self.showAttrEditor, id = menuBar.attrEditor) #Clipboard exports self.Bind(wx.EVT_MENU, self.exportToClipboard, id=wx.ID_COPY) diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index 7c971ae4d..555e86ca2 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -40,6 +40,7 @@ class MainMenuBar(wx.MenuBar): self.saveCharId = wx.NewId() self.saveCharAsId = wx.NewId() self.revertCharId = wx.NewId() + self.attrEditor = wx.NewId() self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -102,6 +103,10 @@ class MainMenuBar(wx.MenuBar): preferencesItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui")) windowMenu.AppendItem(preferencesItem) + attrItem = wx.MenuItem(windowMenu, self.attrEditor, "Attribute Editor\tCTRL+A") + attrItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui")) + windowMenu.AppendItem(attrItem) + # Help menu helpMenu = wx.Menu() self.Append(helpMenu, "&Help") diff --git a/gui/marketBrowser.py b/gui/marketBrowser.py index 53f704c37..14dea666c 100644 --- a/gui/marketBrowser.py +++ b/gui/marketBrowser.py @@ -103,8 +103,8 @@ class MarketBrowser(wx.Panel): self.marketView.jump(item) class SearchBox(SBox.PFSearchBox): - def __init__(self, parent): - SBox.PFSearchBox.__init__(self, parent) + def __init__(self, parent, **kwargs): + SBox.PFSearchBox.__init__(self, parent, **kwargs) cancelBitmap = BitmapLoader.getBitmap("fit_delete_small","gui") searchBitmap = BitmapLoader.getBitmap("fsearch_small","gui") self.SetSearchBitmap(searchBitmap) diff --git a/gui/propertyEditor.py b/gui/propertyEditor.py new file mode 100644 index 000000000..88e499119 --- /dev/null +++ b/gui/propertyEditor.py @@ -0,0 +1,136 @@ +import wx +import wx.propgrid as wxpg +import eos.db + +import gui.PFSearchBox as SBox +from gui.marketBrowser import SearchBox +import gui.display as d +import service + +import logging + +logger = logging.getLogger(__name__) + +class AttributeEditor( wx.Frame ): + + def __init__( self, parent ): + wx.Frame.__init__(self, parent, wx.ID_ANY, title="Attribute Editor", size=wx.Size(700,500)) + + self.panel = panel = wx.Panel(self, wx.ID_ANY) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + leftsizer = wx.BoxSizer(wx.VERTICAL) + + self.searchBox = SearchBox(panel, style=wx.DOUBLE_BORDER if 'wxMSW' in wx.PlatformInfo else wx.SIMPLE_BORDER) + self.itemView = ItemView(panel) + self.pg = AttributeGrid(panel) + + topsizer.Add(leftsizer, 1, wx.ALL|wx.EXPAND, 5) + topsizer.Add(self.pg, 1, wx.ALL|wx.EXPAND, 5) + + leftsizer.Add(self.searchBox, 0, wx.EXPAND) + leftsizer.Add(self.itemView, 1, wx.EXPAND) + + panel.SetSizer(topsizer) + topsizer.SetSizeHints(panel) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetAutoLayout(True) + + +# This is literally a stripped down version of the market. +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 + sMkt = service.Market.getInstance() + self.things = sMkt.getItemsWithOverrides() + self.items = self.things + + # Bind search actions + parent.Parent.searchBox.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) + parent.Parent.searchBox.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) + parent.Parent.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) + parent.Parent.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch) + + self.update(self.items) + + def clearSearch(self, event=None): + if event: + self.parent.Parent.searchBox.Clear() + self.items = self.things + self.update(self.items) + + def scheduleSearch(self, event=None): + sMkt = service.Market.getInstance() + + search = self.parent.Parent.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 + + self.parent.searchMode = True + sMkt.searchItems(search, self.populateSearch, False) + + def populateSearch(self, items): + self.items = list(items) + self.update(items) + + +class AttributeGrid(wxpg.PropertyGrid): + + def __init__(self, parent): + wxpg.PropertyGrid.__init__(self, parent, style=wxpg.PG_HIDE_MARGIN|wxpg.PG_HIDE_CATEGORIES|wxpg.PG_BOLD_MODIFIED|wxpg.PG_TOOLTIPS) + self.parent = parent + + self.Bind( wxpg.EVT_PG_CHANGED, self.OnPropGridChange ) + self.Bind( wxpg.EVT_PG_SELECTED, self.OnPropGridSelect ) + self.Bind( wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick ) + + parent.Parent.itemView.Bind(wx.EVT_LIST_ITEM_SELECTED, self.itemActivated) + parent.Parent.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) + + def itemActivated(self, event): + self.Clear() + sel = event.EventObject.GetFirstSelected() + item = self.parent.Parent.itemView.items[sel] + + for key in sorted(item.attributes.keys()): + override = item.overrides.get(key, None) + default = item.attributes[key].value + if override and override != item.attributes[key].value: + prop = wxpg.FloatProperty(key, value=override) + prop.defaultValue = default + prop.SetModifiedStatus(True) + else: + prop = wxpg.FloatProperty(key, value=default) + + self.Append(prop) + + def OnPropGridChange(self, event): + p = event.GetProperty() + if p: + logger.debug('%s changed to "%s"' % (p.GetName(), p.GetValueAsString())) + + def OnPropGridSelect(self, event): + p = event.GetProperty() + if p: + logger.debug('%s selected' % (event.GetProperty().GetName())) + else: + logger.debug('Nothing selected') + + def OnPropGridRightClick(self, event): + p = event.GetProperty() + if p: + logger.debug('%s right clicked' % (event.GetProperty().GetName())) + else: + logger.debug('Nothing right clicked') diff --git a/service/market.py b/service/market.py index e0a77b8b3..9abed103c 100644 --- a/service/market.py +++ b/service/market.py @@ -116,12 +116,15 @@ class SearchWorkerThread(threading.Thread): while self.searchRequest is None: cv.wait() - request, callback = self.searchRequest + request, callback, filterOn = self.searchRequest self.searchRequest = None cv.release() sMkt = Market.getInstance() - # Rely on category data provided by eos as we don't hardcode them much in service - filter = eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES) + if filterOn: + # Rely on category data provided by eos as we don't hardcode them much in service + filter = eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES) + else: + filter=None results = eos.db.searchItems(request, where=filter, join=(eos.types.Item.group, eos.types.Group.category), eager=("icon", "group.category", "metaGroup", "metaGroup.parent")) @@ -133,9 +136,9 @@ class SearchWorkerThread(threading.Thread): items.add(item) wx.CallAfter(callback, items) - def scheduleSearch(self, text, callback): + def scheduleSearch(self, text, callback, filterOn=True): self.cv.acquire() - self.searchRequest = (text, callback) + self.searchRequest = (text, callback, filterOn) self.cv.notify() self.cv.release() @@ -665,9 +668,16 @@ class Market(): ships.add(item) return ships - def searchItems(self, name, callback): + def searchItems(self, name, callback, filterOn=True): """Find items according to given text pattern""" - self.searchWorkerThread.scheduleSearch(name, callback) + self.searchWorkerThread.scheduleSearch(name, callback, filterOn) + + def getItemsWithOverrides(self): + overrides = eos.db.getAllOverrides() + items = set() + for x in overrides: + items.add(x.item) + return list(items) def directAttrRequest(self, items, attribs): try: