Merge branch 'qol/file-reorg' into development

This commit is contained in:
blitzmann
2017-07-09 18:27:18 -04:00
37 changed files with 2229 additions and 2064 deletions

View File

@@ -19,19 +19,18 @@
# noinspection PyPackageRequirements
import wx
from gui.boosterView import BoosterView
from gui.droneView import DroneView
from gui.fighterView import FighterView
from gui.cargoView import CargoView
from gui.implantView import ImplantView
from gui.projectedView import ProjectedView
from gui.commandView import CommandView
from gui.notesView import NotesView
from gui.pyfatogglepanel import TogglePanel
from gui.bitmapLoader import BitmapLoader
from gui.builtinAdditionPanes.boosterView import BoosterView
from gui.builtinAdditionPanes.cargoView import CargoView
from gui.builtinAdditionPanes.commandView import CommandView
from gui.builtinAdditionPanes.droneView import DroneView
from gui.builtinAdditionPanes.fighterView import FighterView
from gui.builtinAdditionPanes.implantView import ImplantView
from gui.builtinAdditionPanes.notesView import NotesView
from gui.builtinAdditionPanes.projectedView import ProjectedView
from gui.chromeTabs import PFNotebook
from gui.pyfatogglepanel import TogglePanel
class AdditionsPane(TogglePanel):

View File

View File

@@ -21,7 +21,7 @@
import wx
import gui.display as d
import gui.globalEvents as GE
import gui.marketBrowser as marketBrowser
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
from gui.utils.staticHelpers import DragDropHelper
@@ -59,7 +59,7 @@ class BoosterView(d.Display):
self.lastFitId = None
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
self.mainFrame.Bind(marketBrowser.ITEM_SELECTED, self.addItem)
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
self.Bind(wx.EVT_LEFT_DOWN, self.click)
@@ -82,7 +82,7 @@ class BoosterView(d.Display):
"""
if data[0] == "market":
wx.PostEvent(self.mainFrame, marketBrowser.ItemSelected(itemID=int(data[1])))
wx.PostEvent(self.mainFrame, ItemSelected(itemID=int(data[1])))
def kbEvent(self, event):
keycode = event.GetKeyCode()

View File

@@ -22,7 +22,7 @@ import wx
import gui.display as d
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
import globalEvents as GE
import gui.globalEvents as GE
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
from service.market import Market

View File

@@ -19,16 +19,16 @@
# noinspection PyPackageRequirements
import wx
import gui.builtinAdditionPanes.droneView
import gui.display as d
import gui.globalEvents as GE
import gui.droneView
from eos.saveddata.drone import Drone as es_Drone
from gui.builtinContextMenus.commandFits import CommandFits
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
from gui.builtinContextMenus.commandFits import CommandFits
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
from eos.saveddata.drone import Drone as es_Drone
class DummyItem(object):
@@ -73,7 +73,7 @@ class CommandView(d.Display):
self.Bind(wx.EVT_LEFT_DCLICK, self.remove)
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
self.droneView = gui.droneView.DroneView
self.droneView = gui.builtinAdditionPanes.droneView.DroneView
if "__WXGTK__" in wx.PlatformInfo:
self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)

View File

@@ -21,7 +21,7 @@
import wx
import gui.globalEvents as GE
from gui.marketBrowser import ITEM_SELECTED, ItemSelected
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
from gui.display import Display
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu

View File

@@ -21,7 +21,7 @@
import wx
import gui.globalEvents as GE
import gui.marketBrowser as marketBrowser
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
import gui.mainFrame
import gui.display as d
from gui.builtinViewColumns.state import State
@@ -129,7 +129,7 @@ class FighterDisplay(d.Display):
self.hoveredColumn = None
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
self.mainFrame.Bind(marketBrowser.ITEM_SELECTED, self.addItem)
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
self.Bind(wx.EVT_LEFT_DOWN, self.click)
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
@@ -208,7 +208,7 @@ class FighterDisplay(d.Display):
if srcRow != -1 and dstRow != -1:
self._merge(srcRow, dstRow)
elif data[0] == "market":
wx.PostEvent(self.mainFrame, marketBrowser.ItemSelected(itemID=int(data[1])))
wx.PostEvent(self.mainFrame, ItemSelected(itemID=int(data[1])))
@staticmethod
def _merge(src, dst):

View File

@@ -24,7 +24,7 @@ import gui.marketBrowser as marketBrowser
import gui.mainFrame
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
import globalEvents as GE
import gui.globalEvents as GE
from eos.saveddata.fit import ImplantLocation
from service.fit import Fit
from service.market import Market

View File

@@ -20,17 +20,18 @@
# noinspection PyPackageRequirements
import wx
from logbook import Logger
import gui.builtinAdditionPanes.droneView
import gui.display as d
import gui.globalEvents as GE
import gui.droneView
from eos.saveddata.drone import Drone as es_Drone
from eos.saveddata.fighter import Fighter as es_Fighter
from eos.saveddata.module import Module as es_Module
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
from service.market import Market
from eos.saveddata.drone import Drone as es_Drone
from eos.saveddata.fighter import Fighter as es_Fighter
from eos.saveddata.module import Module as es_Module
pyfalog = Logger(__name__)
@@ -80,7 +81,7 @@ class ProjectedView(d.Display):
self.Bind(wx.EVT_LEFT_DCLICK, self.remove)
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
self.droneView = gui.droneView.DroneView
self.droneView = gui.builtinAdditionPanes.droneView.DroneView
if "__WXGTK__" in wx.PlatformInfo:
self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)

View File

View File

@@ -0,0 +1,7 @@
# noinspection PyPackageRequirements
import wx.lib.newevent
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
RECENTLY_USED_MODULES = -2
MAX_RECENTLY_USED_MODULES = 20

View File

@@ -0,0 +1,273 @@
import wx
import gui.builtinMarketBrowser.pfSearchBox as SBox
from gui.contextMenu import ContextMenu
from gui.display import Display
from service.attribute import Attribute
from service.fit import Fit
from gui.utils.staticHelpers import DragDropHelper
from logbook import Logger
from gui.builtinMarketBrowser.events import *
pyfalog = Logger(__name__)
class ItemView(Display):
DEFAULT_COLS = ["Base Icon",
"Base Name",
"attr:power,,,True",
"attr:cpu,,,True"]
def __init__(self, parent, marketBrowser):
Display.__init__(self, parent)
pyfalog.debug("Initialize ItemView")
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
self.unfilteredStore = set()
self.filteredStore = set()
self.recentlyUsedModules = set()
self.sMkt = marketBrowser.sMkt
self.searchMode = marketBrowser.searchMode
self.marketBrowser = marketBrowser
self.marketView = marketBrowser.marketView
# Set up timer for delaying search on every EVT_TEXT
self.searchTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.scheduleSearch, self.searchTimer)
# Make sure our search actually does interesting stuff
self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.delaySearch)
# Make sure WE do interesting stuff too
self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
# Make reverse map, used by sorter
self.metaMap = self.makeReverseMetaMap()
# Fill up recently used modules set
pyfalog.debug("Fill up recently used modules set")
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
def delaySearch(self, evt):
sFit = Fit.getInstance()
self.searchTimer.Stop()
self.searchTimer.Start(sFit.serviceFittingOptions["marketSearchDelay"], True) # 150ms
def startDrag(self, event):
row = self.GetFirstSelected()
if row != -1:
data = wx.PyTextDataObject()
dataStr = "market:" + str(self.active[row].ID)
pyfalog.debug("Dragging from market: " + dataStr)
data.SetText(dataStr)
dropSource = wx.DropSource(self)
dropSource.SetData(data)
DragDropHelper.data = dataStr
dropSource.DoDragDrop()
def itemActivated(self, event=None):
# Check if something is selected, if so, spawn the menu for it
sel = self.GetFirstSelected()
if sel == -1:
return
if self.mainFrame.getActiveFit():
self.storeRecentlyUsedMarketItem(self.active[sel].ID)
self.recentlyUsedModules = set()
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID))
def storeRecentlyUsedMarketItem(self, itemID):
if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES:
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0)
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID)
def selectionMade(self, event=None):
self.marketBrowser.searchMode = False
# Grab the threeview selection and check if it's fine
sel = self.marketView.GetSelection()
if sel.IsOk():
# Get data field of the selected item (which is a marketGroup ID if anything was selected)
seldata = self.marketView.GetPyData(sel)
if seldata is not None and seldata != RECENTLY_USED_MODULES:
# If market group treeview item doesn't have children (other market groups or dummies),
# then it should have items in it and we want to request them
if self.marketView.ItemHasChildren(sel) is False:
sMkt = self.sMkt
# Get current market group
mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup"))
# Get all its items
items = sMkt.getItemsByMarketGroup(mg)
else:
items = set()
else:
# If method was called but selection wasn't actually made or we have a hit on recently used modules
if seldata == RECENTLY_USED_MODULES:
items = self.recentlyUsedModules
else:
items = set()
# Fill store
self.updateItemStore(items)
# Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered)
if seldata is not RECENTLY_USED_MODULES:
self.setToggles()
else:
self.marketBrowser.searchMode = True
self.setToggles()
# Update filtered items
self.filterItemStore()
def updateItemStore(self, items):
self.unfilteredStore = items
def filterItemStore(self):
sMkt = self.sMkt
selectedMetas = set()
for btn in self.marketBrowser.metaButtons:
if btn.GetValue():
selectedMetas.update(sMkt.META_MAP[btn.metaName])
self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas)
self.update(list(self.filteredStore))
def setToggles(self):
metaIDs = set()
sMkt = self.sMkt
for item in self.unfilteredStore:
metaIDs.add(sMkt.getMetaGroupIdByItem(item))
for btn in self.marketBrowser.metaButtons:
btn.reset()
btnMetas = sMkt.META_MAP[btn.metaName]
if len(metaIDs.intersection(btnMetas)) > 0:
btn.setMetaAvailable(True)
else:
btn.setMetaAvailable(False)
def scheduleSearch(self, event=None):
self.searchTimer.Stop() # Cancel any pending timers
search = self.marketBrowser.search.GetLineText(0)
# Make sure we do not count wildcard as search symbol
realsearch = search.replace("*", "")
# Re-select market group if search query has zero length
if len(realsearch) == 0:
self.selectionMade()
return
# Show nothing if query is too short
elif len(realsearch) < 3:
self.clearSearch()
return
self.marketBrowser.searchMode = True
self.sMkt.searchItems(search, self.populateSearch)
def clearSearch(self, event=None):
# Wipe item store and update everything to accomodate with it
# If clearSearch was generated by SearchCtrl's Cancel button, clear the content also
if event:
self.marketBrowser.search.Clear()
self.marketBrowser.searchMode = False
self.updateItemStore(set())
self.setToggles()
self.filterItemStore()
def populateSearch(self, items):
# If we're no longer searching, dump the results
if self.marketBrowser.searchMode is False:
return
self.updateItemStore(items)
self.setToggles()
self.filterItemStore()
def itemSort(self, item):
sMkt = self.sMkt
catname = sMkt.getCategoryByItem(item).name
try:
mktgrpid = sMkt.getMarketGroupByItem(item).ID
except AttributeError:
mktgrpid = None
print("unable to find market group for", item.name)
parentname = sMkt.getParentItemByItem(item).name
# Get position of market group
metagrpid = sMkt.getMetaGroupIdByItem(item)
metatab = self.metaMap.get(metagrpid)
metalvl = self.metalvls.get(item.ID, 0)
return catname, mktgrpid, parentname, metatab, metalvl, item.name
def contextMenu(self, event):
# Check if something is selected, if so, spawn the menu for it
sel = self.GetFirstSelected()
if sel == -1:
return
item = self.active[sel]
sMkt = self.sMkt
sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc"
itemContext = sMkt.getCategoryByItem(item).name
menu = ContextMenu.getMenu((item,), (sourceContext, itemContext))
self.PopupMenu(menu)
def populate(self, items):
if len(items) > 0:
# Get dictionary with meta level attribute
sAttr = Attribute.getInstance()
attrs = sAttr.getAttributeInfo("metaLevel")
sMkt = self.sMkt
self.metalvls = sMkt.directAttrRequest(items, attrs)
# Clear selection
self.deselectItems()
# Perform sorting, using item's meta levels besides other stuff
items.sort(key=self.itemSort)
# Mark current item list as active
self.active = items
# Show them
Display.populate(self, items)
def refresh(self, items):
if len(items) > 1:
# Get dictionary with meta level attribute
sAttr = Attribute.getInstance()
attrs = sAttr.getAttributeInfo("metaLevel")
sMkt = self.sMkt
self.metalvls = sMkt.directAttrRequest(items, attrs)
# Re-sort stuff
items.sort(key=self.itemSort)
for i, item in enumerate(items[:9]):
# set shortcut info for first 9 modules
item.marketShortcut = i + 1
Display.refresh(self, items)
def makeReverseMetaMap(self):
"""
Form map which tells in which tab items of given metagroup are located
"""
revmap = {}
i = 0
for mgids in self.sMkt.META_MAP.itervalues():
for mgid in mgids:
revmap[mgid] = i
i += 1
return revmap

View File

@@ -0,0 +1,99 @@
import wx
from gui.cachingImageList import CachingImageList
from gui.builtinMarketBrowser.events import *
from logbook import Logger
pyfalog = Logger(__name__)
class MarketTree(wx.TreeCtrl):
def __init__(self, parent, marketBrowser):
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
pyfalog.debug("Initialize marketTree")
self.root = self.AddRoot("root")
self.imageList = CachingImageList(16, 16)
self.SetImageList(self.imageList)
self.sMkt = marketBrowser.sMkt
self.marketBrowser = marketBrowser
# Form market tree root
sMkt = self.sMkt
for mktGrp in sMkt.getMarketRoot():
iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp))
childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID))
# All market groups which were never expanded are dummies, here we assume
# that all root market groups are expandable
self.AppendItem(childId, "dummy")
self.SortChildren(self.root)
# Add recently used modules node
rumIconId = self.addImage("market_small", "gui")
self.AppendItem(self.root, "Recently Used Modules", rumIconId, data=wx.TreeItemData(RECENTLY_USED_MODULES))
# Bind our lookup method to when the tree gets expanded
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
def addImage(self, iconFile, location="icons"):
if iconFile is None:
return -1
return self.imageList.GetImageIndex(iconFile, location)
def expandLookup(self, event):
"""Process market tree expands"""
root = event.Item
child = self.GetFirstChild(root)[0]
# If child of given market group is a dummy
if self.GetItemText(child) == "dummy":
# Delete it
self.Delete(child)
# And add real market group contents
sMkt = self.sMkt
currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children")
for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp):
# If market should have items but it doesn't, do not show it
if sMkt.marketGroupValidityCheck(childMktGrp) is False:
continue
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
try:
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
except Exception as e:
pyfalog.debug("Error appending item.")
pyfalog.debug(e)
continue
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
self.AppendItem(childId, "dummy")
self.SortChildren(root)
def jump(self, item):
"""Open market group and meta tab of given item"""
self.marketBrowser.searchMode = False
sMkt = self.sMkt
mg = sMkt.getMarketGroupByItem(item)
jumpList = []
while mg is not None:
jumpList.append(mg.ID)
mg = mg.parent
for id in sMkt.ROOT_MARKET_GROUPS:
if id in jumpList:
jumpList = jumpList[:jumpList.index(id) + 1]
item = self.root
for i in range(len(jumpList) - 1, -1, -1):
target = jumpList[i]
child, cookie = self.GetFirstChild(item)
while self.GetItemPyData(child) != target:
child, cookie = self.GetNextChild(item, cookie)
item = child
self.Expand(item)
self.SelectItem(item)
self.marketBrowser.itemView.selectionMade()

View File

@@ -0,0 +1,24 @@
from gui.builtinMarketBrowser.events import *
from logbook import Logger
pyfalog = Logger(__name__)
class MetaButton(wx.ToggleButton):
def __init__(self, *args, **kwargs):
super(MetaButton, self).__init__(*args, **kwargs)
self.setUserSelection(True)
def setUserSelection(self, isSelected):
self.userSelected = isSelected
self.SetValue(isSelected)
def setMetaAvailable(self, isAvailable):
self.Enable(isAvailable)
# need to also SetValue(False) for windows because Enabled=False AND SetValue(True) looks enabled.
if not isAvailable:
self.SetValue(False)
def reset(self):
self.Enable(True)
self.SetValue(self.userSelected)

View File

@@ -0,0 +1,13 @@
from gui.bitmapLoader import BitmapLoader
from pfSearchBox import PFSearchBox
class SearchBox(PFSearchBox):
def __init__(self, parent, **kwargs):
PFSearchBox.__init__(self, parent, **kwargs)
cancelBitmap = BitmapLoader.getBitmap("fit_delete_small", "gui")
searchBitmap = BitmapLoader.getBitmap("fsearch_small", "gui")
self.SetSearchBitmap(searchBitmap)
self.SetCancelBitmap(cancelBitmap)
self.ShowSearchButton()
self.ShowCancelButton()

View File

View File

@@ -0,0 +1,136 @@
# coding: utf-8
import wx
from logbook import Logger
from gui.builtinShipBrowser.sfBrowserItem import SFBrowserItem
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from gui.bitmapLoader import BitmapLoader
from .events import *
pyfalog = Logger(__name__)
class CategoryItem(SFBrowserItem):
def __init__(self, parent, categoryID, fittingInfo, size=(0, 16)):
SFBrowserItem.__init__(self, parent, size=size)
if categoryID:
self.shipBmp = BitmapLoader.getBitmap("ship_small", "gui")
else:
self.shipBmp = wx.EmptyBitmap(16, 16)
self.dropShadowBitmap = drawUtils.CreateDropShadowBitmap(self.shipBmp, 0.2)
self.categoryID = categoryID
self.fittingInfo = fittingInfo
self.shipBrowser = self.Parent.Parent
self.padding = 4
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.animTimerId = wx.NewId()
self.animTimer = wx.Timer(self, self.animTimerId)
self.animStep = 0
self.animPeriod = 10
self.animDuration = 100
self.Bind(wx.EVT_TIMER, self.OnTimer)
# =====================================================================
# Disabled - it will be added as an option to Preferences
self.animCount = 0
# self.animTimer.Start(self.animPeriod)
# =====================================================================
def OnTimer(self, event):
step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration)
self.animCount = 10 - step
self.animStep += self.animPeriod
if self.animStep > self.animDuration or self.animCount < 0:
self.animCount = 0
self.animTimer.Stop()
self.Refresh()
def OnKeyUp(self, event):
if event.GetKeyCode() in (32, 13): # space and enter
self.selectCategory(event)
event.Skip()
@staticmethod
def OUT_QUAD(t, b, c, d):
t = float(t)
b = float(b)
c = float(c)
d = float(d)
t /= d
return -c * t * (t - 2) + b
def GetType(self):
return 1
def selectCategory(self, event):
categoryID = self.categoryID
wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=False))
def MouseLeftUp(self, event):
self.selectCategory(event)
def UpdateElementsPos(self, mdc):
rect = self.GetRect()
self.shipBmpx = self.padding
self.shipBmpy = (rect.height - self.shipBmp.GetWidth()) / 2
self.shipBmpx -= self.animCount
mdc.SetFont(self.fontBig)
categoryName, fittings = self.fittingInfo
wtext, htext = mdc.GetTextExtent(categoryName)
self.catx = self.shipBmpx + self.shipBmp.GetWidth() + self.padding
self.caty = (rect.height - htext) / 2
def DrawItem(self, mdc):
# rect = self.GetRect()
self.UpdateElementsPos(mdc)
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
textColor = colorUtils.GetSuitableColor(windowColor, 1)
mdc.SetTextForeground(textColor)
mdc.DrawBitmap(self.dropShadowBitmap, self.shipBmpx + 1, self.shipBmpy + 1)
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
mdc.SetFont(self.fontBig)
categoryName, fittings = self.fittingInfo
mdc.DrawText(categoryName, self.catx, self.caty)
# =============================================================================
# Waiting for total #fits impl in eos/service
#
# mdc.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, False))
#
# if fittings <1:
# fformat = "No fits"
# else:
# if fittings == 1:
# fformat = "%d fit"
# else:
# fformat = "%d fits"
#
# if fittings>0:
# xtext, ytext = mdc.GetTextExtent(fformat % fittings)
# ypos = (rect.height - ytext)/2
# else:
# xtext, ytext = mdc.GetTextExtent(fformat)
# ypos = (rect.height - ytext)/2
# =============================================================================

View File

@@ -0,0 +1,14 @@
# noinspection PyPackageRequirements
import wx.lib.newevent
FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent()
FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent()
FitRemoved, EVT_FIT_REMOVED = wx.lib.newevent.NewEvent()
BoosterListUpdated, BOOSTER_LIST_UPDATED = wx.lib.newevent.NewEvent()
Stage1Selected, EVT_SB_STAGE1_SEL = wx.lib.newevent.NewEvent()
Stage2Selected, EVT_SB_STAGE2_SEL = wx.lib.newevent.NewEvent()
Stage3Selected, EVT_SB_STAGE3_SEL = wx.lib.newevent.NewEvent()
SearchSelected, EVT_SB_SEARCH_SEL = wx.lib.newevent.NewEvent()
ImportSelected, EVT_SB_IMPORT_SEL = wx.lib.newevent.NewEvent()

View File

@@ -0,0 +1,604 @@
# coding: utf-8
import re
import time
import wx
from logbook import Logger
import gui.builtinShipBrowser.sfBrowserItem as SFItem
import gui.globalEvents as GE
import gui.mainFrame
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from events import *
from gui.bitmapLoader import BitmapLoader
from gui.builtinShipBrowser.pfBitmapFrame import PFBitmapFrame
from service.fit import Fit
pyfalog = Logger(__name__)
class FitItem(SFItem.SFBrowserItem):
def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0, None), shipID=None,
itemData=None,
id=wx.ID_ANY, pos=wx.DefaultPosition,
size=(0, 40), style=0):
# =====================================================================
# animCount should be 10 if we enable animation in Preferences
# =====================================================================
self.animCount = 0
self.selectedDelta = 0
SFItem.SFBrowserItem.__init__(self, parent, size=size)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self._itemData = itemData
self.fitID = fitID
self.shipID = shipID
self.shipBrowser = self.Parent.Parent
self.shipBmp = None
self.deleted = False
if shipID:
self.shipBmp = BitmapLoader.getBitmap(str(shipID), "renders")
if not self.shipBmp:
self.shipBmp = BitmapLoader.getBitmap("ship_no_image_big", "gui")
self.shipFittingInfo = shipFittingInfo
self.shipName, self.shipTrait, self.fitName, self.fitBooster, self.timestamp, self.notes = shipFittingInfo
self.shipTrait = re.sub("<.*?>", " ", self.shipTrait)
# see GH issue #62
# Disabling this due to change in gang boosts Nov 2016
# if self.fitBooster is None: self.fitBooster = False
self.fitBooster = False
self.boosterBmp = BitmapLoader.getBitmap("fleet_fc_small", "gui")
self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui")
self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small", "gui")
self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big", "gui")
img = wx.ImageFromBitmap(self.shipEffBk)
img = img.Mirror(False)
self.shipEffBkMirrored = wx.BitmapFromImage(img)
self.dragTLFBmp = None
self.bkBitmap = None
self.__setToolTip()
self.padding = 4
self.editWidth = 150
self.dragging = False
self.dragged = False
self.dragMotionTrail = 5
self.dragMotionTrigger = self.dragMotionTrail
self.dragWindow = None
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD)
self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.SetDraggable()
self.boosterBtn = self.toolbar.AddButton(self.boosterBmp, "Booster", show=self.fitBooster)
self.toolbar.AddButton(self.copyBmp, "Copy", self.copyBtnCB)
self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.renameBtnCB)
self.toolbar.AddButton(self.deleteBmp, "Delete", self.deleteBtnCB)
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fitName, wx.DefaultPosition, (self.editWidth, -1),
wx.TE_PROCESS_ENTER)
if self.shipBrowser.fitIDMustEditName != self.fitID:
self.tcFitName.Show(False)
else:
self.tcFitName.SetFocus()
self.tcFitName.SelectAll()
self.shipBrowser.fitIDMustEditName = -1
self.renameBtn.SetBitmap(self.acceptBmp)
self.tcFitName.Bind(wx.EVT_TEXT_ENTER, self.renameFit)
self.tcFitName.Bind(wx.EVT_KILL_FOCUS, self.editLostFocus)
self.tcFitName.Bind(wx.EVT_KEY_DOWN, self.editCheckEsc)
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnMouseCaptureLost)
self.animTimerId = wx.NewId()
self.animTimer = wx.Timer(self, self.animTimerId)
self.animStep = 0
self.animPeriod = 10
self.animDuration = 100
self.maxDelta = 48
self.Bind(wx.EVT_TIMER, self.OnTimer)
# =====================================================================
# DISABLED - it will be added as an option in PREFERENCES
# if self.shipBrowser.GetActiveStage() != 4 and self.shipBrowser.GetLastStage() !=3:
# self.animTimer.Start(self.animPeriod)
# else:
# self.animCount = 0
# =====================================================================
"""
# Remove this bit as the time stuff is non-functional (works... but not exactly sure what it's meant to do)
self.selTimerID = wx.NewId()
self.selTimer = wx.Timer(self, self.selTimerID)
self.selTimer.Start(100)
"""
self.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu)
self.Bind(wx.EVT_MIDDLE_UP, self.OpenNewTab)
def __setToolTip(self):
sFit = Fit.getInstance()
# show no tooltip if no trait available or setting is disabled
if self.shipTrait and sFit.serviceFittingOptions["showShipBrowserTooltip"]:
notes = ""
if self.notes:
notes = u'' * 20 + u"\nNotes: {}\n".format(self.notes[:197] + '...' if len(self.notes) > 200 else self.notes)
self.SetToolTip(wx.ToolTip(u'{}\n{}{}\n{}'.format(self.shipName, notes, u'' * 20, self.shipTrait)))
def OnKeyUp(self, event):
if event.GetKeyCode() in (32, 13): # space and enter
self.selectFit(event)
event.Skip()
def OpenNewTab(self, evt):
self.selectFit(newTab=True)
def OnToggleBooster(self, event):
sFit = Fit.getInstance()
sFit.toggleBoostFit(self.fitID)
self.fitBooster = not self.fitBooster
self.boosterBtn.Show(self.fitBooster)
self.Refresh()
wx.PostEvent(self.mainFrame, BoosterListUpdated())
event.Skip()
def OnProjectToFit(self, event):
activeFit = self.mainFrame.getActiveFit()
if activeFit:
sFit = Fit.getInstance()
projectedFit = sFit.getFit(self.fitID)
sFit.project(activeFit, projectedFit)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit))
self.mainFrame.additionsPane.select("Projected")
def OnAddCommandFit(self, event):
activeFit = self.mainFrame.getActiveFit()
if activeFit:
sFit = Fit.getInstance()
commandFit = sFit.getFit(self.fitID)
sFit.addCommandFit(activeFit, commandFit)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit))
self.mainFrame.additionsPane.select("Command")
def OnMouseCaptureLost(self, event):
""" Destroy drag information (GH issue #479)"""
if self.dragging and self.dragged:
self.dragging = False
self.dragged = False
if self.HasCapture():
self.ReleaseMouse()
self.dragWindow.Show(False)
self.dragWindow = None
def OnContextMenu(self, event):
""" Handles context menu for fit. Dragging is handled by MouseLeftUp() """
sFit = Fit.getInstance()
fit = sFit.getFit(self.mainFrame.getActiveFit())
if not fit:
return
pos = wx.GetMousePosition()
pos = self.ScreenToClient(pos)
# Even though we may not select a booster, automatically set this so that the fleet pane knows which fit we're applying
self.mainFrame.additionsPane.gangPage.draggedFitID = self.fitID
menu = wx.Menu()
# toggleItem = menu.Append(wx.ID_ANY, "Booster Fit", kind=wx.ITEM_CHECK)
# menu.Check(toggleItem.GetId(), self.fitBooster)
# self.Bind(wx.EVT_MENU, self.OnToggleBooster, toggleItem)
# if fit and not fit.isStructure:
# # If there is an active fit, get menu for setting individual boosters
# menu.AppendSeparator()
# boosterMenu = self.mainFrame.additionsPane.gangPage.buildBoostermenu()
# menu.AppendSubMenu(boosterMenu, 'Set Booster')
if fit:
newTabItem = menu.Append(wx.ID_ANY, "Open in new tab")
self.Bind(wx.EVT_MENU, self.OpenNewTab, newTabItem)
projectedItem = menu.Append(wx.ID_ANY, "Project onto Active Fit")
self.Bind(wx.EVT_MENU, self.OnProjectToFit, projectedItem)
commandItem = menu.Append(wx.ID_ANY, "Add Command Booster")
self.Bind(wx.EVT_MENU, self.OnAddCommandFit, commandItem)
self.PopupMenu(menu, pos)
event.Skip()
def GetType(self):
return 3
def OnTimer(self, event):
# @todo: figure out what exactly this is supposed to accomplish
if self.selTimerID == event.GetId():
ctimestamp = time.time()
interval = 5
if ctimestamp < self.timestamp + interval:
delta = (ctimestamp - self.timestamp) / interval
self.selectedDelta = self.CalculateDelta(0x0, self.maxDelta, delta)
self.Refresh()
else:
self.selectedDelta = self.maxDelta
self.selTimer.Stop()
if self.animTimerId == event.GetId():
step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration)
self.animCount = 10 - step
self.animStep += self.animPeriod
if self.animStep > self.animDuration or self.animCount < 0:
self.animCount = 0
self.animTimer.Stop()
self.Refresh()
@staticmethod
def CalculateDelta(start, end, delta):
return start + (end - start) * delta
@staticmethod
def OUT_QUAD(t, b, c, d):
t = float(t)
b = float(b)
c = float(c)
d = float(d)
t /= d
return -c * t * (t - 2) + b
def editLostFocus(self, event):
self.RestoreEditButton()
self.Refresh()
def editCheckEsc(self, event):
if event.GetKeyCode() == wx.WXK_ESCAPE:
self.RestoreEditButton()
else:
event.Skip()
def copyBtnCB(self):
if self.tcFitName.IsShown():
self.RestoreEditButton()
return
self.copyFit()
def copyFit(self, event=None):
sFit = Fit.getInstance()
fitID = sFit.copyFit(self.fitID)
self.shipBrowser.fitIDMustEditName = fitID
wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID))
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
def renameBtnCB(self):
if self.tcFitName.IsShown():
self.RestoreEditButton()
self.renameFit()
else:
self.tcFitName.SetValue(self.fitName)
self.tcFitName.Show()
self.renameBtn.SetBitmap(self.acceptBmp)
self.tcFitName.SetFocus()
self.tcFitName.SelectAll()
self.Refresh()
def renameFit(self, event=None):
sFit = Fit.getInstance()
self.tcFitName.Show(False)
self.editWasShown = 0
fitName = self.tcFitName.GetValue()
if fitName:
self.fitName = fitName
sFit.renameFit(self.fitID, self.fitName)
wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID))
else:
self.tcFitName.SetValue(self.fitName)
def deleteBtnCB(self):
if self.tcFitName.IsShown():
self.RestoreEditButton()
return
# to prevent accidental deletion, give dialog confirmation unless shift is depressed
if wx.GetMouseState().ShiftDown() or wx.GetMouseState().MiddleDown():
self.deleteFit()
else:
dlg = wx.MessageDialog(
self,
"Do you really want to delete this fit?",
"Confirm Delete",
wx.YES | wx.NO | wx.ICON_QUESTION
)
if dlg.ShowModal() == wx.ID_YES:
self.deleteFit()
def deleteFit(self, event=None):
pyfalog.debug("Deleting ship fit.")
if self.deleted:
return
else:
self.deleted = True
sFit = Fit.getInstance()
fit = sFit.getFit(self.fitID)
# need to delete from import cache before actually deleting fit
if self.shipBrowser.GetActiveStage() == 5:
if fit in self.shipBrowser.lastdata: # remove fit from import cache
self.shipBrowser.lastdata.remove(fit)
sFit.deleteFit(self.fitID)
# Notify other areas that a fit has been deleted
wx.PostEvent(self.mainFrame, FitRemoved(fitID=self.fitID))
# todo: would a simple RefreshList() work here instead of posting that a stage has been selected?
if self.shipBrowser.GetActiveStage() == 5:
wx.PostEvent(self.shipBrowser, ImportSelected(fits=self.shipBrowser.lastdata))
elif self.shipBrowser.GetActiveStage() == 4:
wx.PostEvent(self.shipBrowser, SearchSelected(text=self.shipBrowser.navpanel.lastSearch, back=True))
else:
wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID))
def MouseLeftUp(self, event):
if self.dragging and self.dragged:
self.OnMouseCaptureLost(event)
targetWnd = wx.FindWindowAtPointer()
if not targetWnd:
return
wnd = targetWnd
while wnd is not None:
handler = getattr(wnd, "handleDrag", None)
if handler:
handler("fit", self.fitID)
break
else:
wnd = wnd.Parent
event.Skip()
return
if self.dragging:
self.dragging = False
if self.tcFitName.IsShown():
self.RestoreEditButton()
else:
activeFitID = self.mainFrame.getActiveFit()
if activeFitID != self.fitID:
self.selectFit()
def MouseLeftDown(self, event):
self.dragging = True
def MouseMove(self, event):
pos = self.ClientToScreen(event.GetPosition())
if self.dragging:
if not self.dragged:
if self.dragMotionTrigger < 0:
if not self.HasCapture():
self.CaptureMouse()
self.dragWindow = PFBitmapFrame(self, pos, self.dragTLFBmp)
self.dragWindow.Show()
self.dragged = True
self.dragMotionTrigger = self.dragMotionTrail
else:
self.dragMotionTrigger -= 1
if self.dragWindow:
pos.x += 3
pos.y += 3
self.dragWindow.SetPosition(pos)
return
def selectFit(self, event=None, newTab=False):
if newTab:
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID, startup=2))
else:
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID))
def RestoreEditButton(self):
self.tcFitName.Show(False)
self.renameBtn.SetBitmap(self.renameBmp)
self.Refresh()
def UpdateElementsPos(self, mdc):
rect = self.GetRect()
self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
self.toolbarx += self.animCount
self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2
self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2
self.shipEffx -= self.animCount
self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2
self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2
self.shipBmpx -= self.animCount
self.textStartx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding
self.fitNamey = (rect.height - self.shipBmp.GetHeight()) / 2
mdc.SetFont(self.fontBig)
wtext, htext = mdc.GetTextExtent(self.fitName)
self.timestampy = self.fitNamey + htext
mdc.SetFont(self.fontSmall)
wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
self.thoverx = self.toolbarx - self.padding - wlabel
self.thovery = (rect.height - hlabel) / 2
self.thoverw = wlabel
def DrawItem(self, mdc):
rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
textColor = colorUtils.GetSuitableColor(windowColor, 1)
mdc.SetTextForeground(textColor)
self.UpdateElementsPos(mdc)
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
if self.GetState() & SFItem.SB_ITEM_HIGHLIGHTED:
shipEffBk = self.shipEffBkMirrored
else:
shipEffBk = self.shipEffBk
mdc.DrawBitmap(shipEffBk, self.shipEffx, self.shipEffy, 0)
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
mdc.SetFont(self.fontNormal)
fitDate = self.timestamp.strftime("%m/%d/%Y %H:%M")
fitLocalDate = fitDate # "%d/%02d/%02d %02d:%02d" % (fitDate[0], fitDate[1], fitDate[2], fitDate[3], fitDate[4])
pfdate = drawUtils.GetPartialText(mdc, fitLocalDate,
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
mdc.DrawText(pfdate, self.textStartx, self.timestampy)
mdc.SetFont(self.fontSmall)
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
mdc.SetFont(self.fontBig)
psname = drawUtils.GetPartialText(mdc, self.fitName,
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
mdc.DrawText(psname, self.textStartx, self.fitNamey)
if self.tcFitName.IsShown():
self.AdjustControlSizePos(self.tcFitName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
tdc = wx.MemoryDC()
self.dragTLFBmp = wx.EmptyBitmap((self.toolbarx if self.toolbarx < 200 else 200), rect.height, 24)
tdc.SelectObject(self.dragTLFBmp)
tdc.Blit(0, 0, (self.toolbarx if self.toolbarx < 200 else 200), rect.height, mdc, 0, 0, wx.COPY)
tdc.SelectObject(wx.NullBitmap)
def AdjustControlSizePos(self, editCtl, start, end):
fnEditSize = editCtl.GetSize()
wSize = self.GetSize()
fnEditPosX = end
fnEditPosY = (wSize.height - fnEditSize.height) / 2
if fnEditPosX < start:
editCtl.SetSize((self.editWidth + fnEditPosX - start, -1))
editCtl.SetPosition((start, fnEditPosY))
else:
editCtl.SetSize((self.editWidth, -1))
editCtl.SetPosition((fnEditPosX, fnEditPosY))
def GetState(self):
activeFitID = self.mainFrame.getActiveFit()
if self.highlighted and not activeFitID == self.fitID:
state = SFItem.SB_ITEM_HIGHLIGHTED
else:
if activeFitID == self.fitID:
if self.highlighted:
state = SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED
else:
state = SFItem.SB_ITEM_SELECTED
else:
state = SFItem.SB_ITEM_NORMAL
return state
def Refresh(self):
activeFit = self.mainFrame.getActiveFit()
if activeFit == self.fitID and not self.deleted:
sFit = Fit.getInstance()
fit = sFit.getFit(activeFit)
if fit is not None: # sometimes happens when deleting fits, dunno why.
self.timestamp = fit.modifiedCoalesce
self.notes = fit.notes
self.__setToolTip()
SFItem.SFBrowserItem.Refresh(self)
def RenderBackground(self):
rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
# activeFitID = self.mainFrame.getActiveFit()
state = self.GetState()
sFactor = 0.2
mFactor = None
eFactor = 0
if state == SFItem.SB_ITEM_HIGHLIGHTED:
mFactor = 0.45
eFactor = 0.30
elif state == SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED:
eFactor = 0.3
mFactor = 0.4
elif state == SFItem.SB_ITEM_SELECTED:
eFactor = (self.maxDelta - self.selectedDelta) / 100 + 0.25
else:
sFactor = 0
if self.bkBitmap:
if self.bkBitmap.eFactor == eFactor and self.bkBitmap.sFactor == sFactor and self.bkBitmap.mFactor == mFactor \
and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight():
return
else:
del self.bkBitmap
self.bkBitmap = drawUtils.RenderGradientBar(windowColor, rect.width, rect.height, sFactor, eFactor, mFactor)
self.bkBitmap.state = state
self.bkBitmap.sFactor = sFactor
self.bkBitmap.eFactor = eFactor
self.bkBitmap.mFactor = mFactor

View File

@@ -0,0 +1,274 @@
# coding: utf-8
import wx
from logbook import Logger
import gui.builtinShipBrowser.sfBrowserItem as SFItem
import gui.mainFrame
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from events import *
from gui.bitmapLoader import BitmapLoader
from service.fit import Fit
pyfalog = Logger(__name__)
class NavigationPanel(SFItem.SFBrowserItem):
def __init__(self, parent, size=(-1, 24)):
SFItem.SFBrowserItem.__init__(self, parent, size=size)
self.rewBmpH = BitmapLoader.getBitmap("frewind_small", "gui")
self.forwBmp = BitmapLoader.getBitmap("fforward_small", "gui")
self.searchBmpH = BitmapLoader.getBitmap("fsearch_small", "gui")
self.newBmpH = BitmapLoader.getBitmap("fit_add_small", "gui")
self.resetBmpH = BitmapLoader.getBitmap("freset_small", "gui")
self.switchBmpH = BitmapLoader.getBitmap("fit_switch_view_mode_small", "gui")
self.recentBmpH = BitmapLoader.getBitmap("frecent_small", "gui")
switchImg = BitmapLoader.getImage("fit_switch_view_mode_small", "gui")
switchImg = switchImg.AdjustChannels(1, 1, 1, 0.4)
self.switchBmpD = wx.BitmapFromImage(switchImg)
recentImg = BitmapLoader.getImage("frecent_small", "gui")
recentImg = recentImg.AdjustChannels(1, 1, 1, 0.4)
self.recentBmpD = wx.BitmapFromImage(recentImg)
self.resetBmp = self.AdjustChannels(self.resetBmpH)
self.rewBmp = self.AdjustChannels(self.rewBmpH)
self.searchBmp = self.AdjustChannels(self.searchBmpH)
self.switchBmp = self.AdjustChannels(self.switchBmpH)
self.recentBmp = self.AdjustChannels(self.recentBmpH)
self.newBmp = self.AdjustChannels(self.newBmpH)
self.toolbar.AddButton(self.resetBmp, "Ship groups", clickCallback=self.OnHistoryReset,
hoverBitmap=self.resetBmpH)
self.toolbar.AddButton(self.rewBmp, "Back", clickCallback=self.OnHistoryBack, hoverBitmap=self.rewBmpH)
self.btnNew = self.toolbar.AddButton(self.newBmp, "New fitting", clickCallback=self.OnNewFitting,
hoverBitmap=self.newBmpH, show=False)
self.btnSwitch = self.toolbar.AddButton(self.switchBmpD, "Hide empty ship groups",
clickCallback=self.ToggleEmptyGroupsView, hoverBitmap=self.switchBmpH,
show=False)
self.btnRecent = self.toolbar.AddButton(self.recentBmpD, "Recent Fits",
clickCallback=self.ToggleRecentShips, hoverBitmap=self.recentBmpH,
show=True)
modifier = "CTRL" if 'wxMac' not in wx.PlatformInfo else "CMD"
self.toolbar.AddButton(self.searchBmp, "Search fittings ({}+F)".format(modifier), clickCallback=self.ToggleSearchBox,
hoverBitmap=self.searchBmpH)
self.padding = 4
self.lastSearch = ""
self.recentSearches = [] # not used?
self.inSearch = False
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
w, h = size
self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition,
(-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1),
(wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
self.BrowserSearchBox.Show(False)
#self.BrowserSearchBox.Bind(wx.EVT_TEXT_ENTER, self.OnBrowserSearchBoxEnter)
#self.BrowserSearchBox.Bind(wx.EVT_KILL_FOCUS, self.OnBrowserSearchBoxLostFocus)
self.BrowserSearchBox.Bind(wx.EVT_KEY_DOWN, self.OnBrowserSearchBoxEsc)
self.BrowserSearchBox.Bind(wx.EVT_TEXT, self.OnScheduleSearch)
self.SetMinSize(size)
self.shipBrowser = self.Parent
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.Bind(wx.EVT_SIZE, self.OnResize)
def OnScheduleSearch(self, event):
search = self.BrowserSearchBox.GetValue()
# Make sure we do not count wildcard as search symbol
realsearch = search.replace("*", "")
if len(realsearch) >= 3:
self.lastSearch = search
wx.PostEvent(self.shipBrowser, SearchSelected(text=search, back=False))
def ToggleSearchBox(self):
if self.BrowserSearchBox.IsShown():
self.BrowserSearchBox.Show(False)
else:
self.BrowserSearchBox.Show(True)
self.BrowserSearchBox.ChangeValue("")
self.BrowserSearchBox.SetFocus()
def OnBrowserSearchBoxEnter(self, event):
self.OnBrowserSearchBoxLostFocus(None)
def OnBrowserSearchBoxLostFocus(self, event):
self.BrowserSearchBox.Show(False)
def OnBrowserSearchBoxEsc(self, event):
if event.GetKeyCode() == wx.WXK_ESCAPE:
self.BrowserSearchBox.Show(False)
else:
event.Skip()
def OnResize(self, event):
self.Refresh()
def ToggleRecentShips(self, bool=None, emitEvent=True):
# this is so janky. Need to revaluate pretty much entire ship browser. >.<
toggle = bool if bool is not None else not self.shipBrowser.recentFits
if not toggle:
self.shipBrowser.recentFits = False
self.btnRecent.label = "Recent Fits"
self.btnRecent.normalBmp = self.recentBmpD
if emitEvent:
wx.PostEvent(self.shipBrowser, Stage1Selected())
else:
self.shipBrowser.recentFits = True
self.btnRecent.label = "Hide Recent Fits"
self.btnRecent.normalBmp = self.recentBmp
if emitEvent:
sFit = Fit.getInstance()
fits = sFit.getRecentFits()
wx.PostEvent(self.shipBrowser, ImportSelected(fits=fits, back=True, recent=True))
def ToggleEmptyGroupsView(self):
if self.shipBrowser.filterShipsWithNoFits:
self.shipBrowser.filterShipsWithNoFits = False
self.btnSwitch.label = "Hide empty ship groups"
self.btnSwitch.normalBmp = self.switchBmpD
else:
self.shipBrowser.filterShipsWithNoFits = True
self.btnSwitch.label = "Show empty ship groups"
self.btnSwitch.normalBmp = self.switchBmp
stage = self.shipBrowser.GetActiveStage()
if stage == 1:
wx.PostEvent(self.shipBrowser, Stage1Selected())
elif stage == 2:
categoryID = self.shipBrowser.GetStageData(stage)
wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=True))
def ShowNewFitButton(self, show):
self.btnNew.Show(show)
self.Refresh()
def ShowSwitchEmptyGroupsButton(self, show):
self.btnSwitch.Show(show)
self.Refresh()
def OnNewFitting(self):
stage = self.Parent.GetActiveStage()
if stage == 3:
shipID = self.Parent.GetStageData(stage)
shipName = self.Parent.GetStage3ShipName()
sFit = Fit.getInstance()
fitID = sFit.newFit(shipID, "%s fit" % shipName)
self.shipBrowser.fitIDMustEditName = fitID
wx.PostEvent(self.Parent, Stage3Selected(shipID=shipID))
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
def OnHistoryReset(self):
self.ToggleRecentShips(False, False)
if self.shipBrowser.browseHist:
self.shipBrowser.browseHist = []
self.gotoStage(1, 0)
def OnHistoryBack(self):
self.ToggleRecentShips(False, False)
if len(self.shipBrowser.browseHist) > 0:
stage, data = self.shipBrowser.browseHist.pop()
self.gotoStage(stage, data)
@staticmethod
def AdjustChannels(bitmap):
img = wx.ImageFromBitmap(bitmap)
img = img.AdjustChannels(1.05, 1.05, 1.05, 1)
return wx.BitmapFromImage(img)
def UpdateElementsPos(self, mdc):
rect = self.GetRect()
self.toolbarx = self.padding
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
mdc.SetFont(self.fontSmall)
wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
self.thoverx = self.toolbar.GetWidth() + self.padding
self.thovery = (rect.height - hlabel) / 2
self.thoverw = wlabel
self.browserBoxX = self.thoverx
bEditBoxWidth, bEditBoxHeight = self.BrowserSearchBox.GetSize()
self.browserBoxY = (rect.height - bEditBoxHeight) / 2
self.bEditBoxWidth = rect.width - self.browserBoxX - self.padding
def DrawItem(self, mdc):
rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
textColor = colorUtils.GetSuitableColor(windowColor, 1)
sepColor = colorUtils.GetSuitableColor(windowColor, 0.2)
mdc.SetTextForeground(textColor)
self.UpdateElementsPos(mdc)
self.BrowserSearchBox.SetPosition((self.browserBoxX, self.browserBoxY))
self.BrowserSearchBox.SetSize(wx.Size(self.bEditBoxWidth, -1))
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
mdc.SetFont(self.fontSmall)
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
mdc.SetPen(wx.Pen(sepColor, 1))
mdc.DrawLine(0, rect.height - 1, rect.width, rect.height - 1)
def RenderBackground(self):
rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
sFactor = 0.1
shipGroupsFilter = getattr(self.shipBrowser, "filterShipsWithNoFits", None)
if shipGroupsFilter:
sFactor = 0.15
mFactor = 0.25
else:
mFactor = 0.2
eFactor = 0.1
if self.bkBitmap:
if self.bkBitmap.eFactor == eFactor and self.bkBitmap.sFactor == sFactor and self.bkBitmap.mFactor == mFactor \
and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight():
return
else:
del self.bkBitmap
self.bkBitmap = drawUtils.RenderGradientBar(windowColor, rect.width, rect.height, sFactor, eFactor, mFactor, 2)
self.bkBitmap.sFactor = sFactor
self.bkBitmap.eFactor = eFactor
self.bkBitmap.mFactor = mFactor
def gotoStage(self, stage, data=None):
self.shipBrowser.recentFits = False
if stage == 1:
wx.PostEvent(self.Parent, Stage1Selected())
elif stage == 2:
wx.PostEvent(self.Parent, Stage2Selected(categoryID=data, back=True))
elif stage == 3:
wx.PostEvent(self.Parent, Stage3Selected(shipID=data))
elif stage == 4:
self.shipBrowser._activeStage = 4
wx.PostEvent(self.Parent, SearchSelected(text=data, back=True))
elif stage == 5:
wx.PostEvent(self.Parent, ImportSelected(fits=data))
else:
wx.PostEvent(self.Parent, Stage1Selected())

View File

@@ -0,0 +1,14 @@
import wx
from wx.lib.buttons import GenBitmapButton
class PFGenBitmapButton(GenBitmapButton):
def __init__(self, parent, id, bitmap, pos, size, style):
GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style)
self.bgcolor = wx.Brush(wx.WHITE)
def SetBackgroundColour(self, color):
self.bgcolor = wx.Brush(color)
def GetBackgroundBrush(self, dc):
return self.bgcolor

View File

@@ -0,0 +1,59 @@
import wx
class PFBitmapFrame(wx.Frame):
def __init__(self, parent, pos, bitmap):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize,
style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP)
img = bitmap.ConvertToImage()
img = img.ConvertToGreyscale()
bitmap = wx.BitmapFromImage(img)
self.bitmap = bitmap
self.SetSize((bitmap.GetWidth(), bitmap.GetHeight()))
self.Bind(wx.EVT_PAINT, self.OnWindowPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnWindowEraseBk)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.timer = wx.Timer(self, wx.ID_ANY)
self.direction = 1
self.transp = 0
self.SetSize((bitmap.GetWidth(), bitmap.GetHeight()))
self.SetTransparent(0)
self.Refresh()
def OnTimer(self, event):
self.transp += 20 * self.direction
if self.transp > 200:
self.transp = 200
self.timer.Stop()
if self.transp < 0:
self.transp = 0
self.timer.Stop()
wx.Frame.Show(self, False)
self.Destroy()
return
self.SetTransparent(self.transp)
def Show(self, showWnd=True):
if showWnd:
wx.Frame.Show(self, showWnd)
self.Parent.SetFocus()
self.direction = 1
self.timer.Start(5)
else:
self.direction = -1
self.timer.Start(5)
def OnWindowEraseBk(self, event):
pass
def OnWindowPaint(self, event):
rect = self.GetRect()
canvas = wx.EmptyBitmap(rect.width, rect.height)
mdc = wx.BufferedPaintDC(self)
mdc.SelectObject(canvas)
mdc.DrawBitmap(self.bitmap, 0, 0)
mdc.SetPen(wx.Pen("#000000", width=1))
mdc.SetBrush(wx.TRANSPARENT_BRUSH)
mdc.DrawRectangle(0, 0, rect.width, rect.height)

View File

@@ -0,0 +1,23 @@
# coding: utf-8
import wx
from logbook import Logger
pyfalog = Logger(__name__)
class PFStaticText(wx.Panel):
def __init__(self, parent, label=wx.EmptyString):
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=parent.GetSize())
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
mainSizer = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE)
text.Wrap(-1)
mainSizer.Add(text, 1, wx.ALL, 10)
self.SetSizer(mainSizer)
self.Layout()
@staticmethod
def GetType():
return -1

View File

@@ -0,0 +1,35 @@
from gui.builtinShipBrowser.pfListPane import PFListPane
import gui.mainFrame
import gui.utils.animUtils as animUtils
class PFWidgetsContainer(PFListPane):
def __init__(self, parent):
PFListPane.__init__(self, parent)
self.anim = animUtils.LoadAnimation(self, label="", size=(100, 12))
self.anim.Stop()
self.anim.Show(False)
def ShowLoading(self, mode=True):
if mode:
aweight, aheight = self.anim.GetSize()
cweight, cheight = self.GetSize()
ax = (cweight - aweight) / 2
ay = (cheight - aheight) / 2
self.anim.SetPosition((ax, ay))
self.anim.Show()
self.anim.Play()
else:
self.anim.Stop()
self.anim.Show(False)
def IsWidgetSelectedByContext(self, widget):
mainFrame = gui.mainFrame.MainFrame.getInstance()
stage = self.Parent.GetActiveStage()
fit = mainFrame.getActiveFit()
if stage == 3 or stage == 4:
if self._wList[widget].GetType() == 3:
if fit == self._wList[widget].fitID:
return True
return False

View File

@@ -0,0 +1,271 @@
# coding: utf-8
import wx
from logbook import Logger
import gui.utils.animEffects as animEffects
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
from events import *
from gui.bitmapLoader import BitmapLoader
pyfalog = Logger(__name__)
class RaceSelector(wx.Window):
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0,
layout=wx.VERTICAL, animate=False):
wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style)
self.animTimerID = wx.NewId()
self.animTimer = wx.Timer(self, self.animTimerID)
self.animPeriod = 25
self.animDuration = 250
self.animStep = 0
self.maxWidth = 24
self.minWidth = 5 if animate else self.maxWidth
self.maxHeight = 24
self.minHeight = 10 if animate else self.maxHeight
self.direction = 0 if animate else 1
self.layout = layout
self.animate = animate
if layout == wx.VERTICAL:
self.SetSize(wx.Size(self.minWidth, -1))
self.SetMinSize(wx.Size(self.minWidth, -1))
else:
self.SetSize(wx.Size(-1, self.minHeight))
self.SetMinSize(wx.Size(-1, self.minHeight))
self.checkTimerID = wx.NewId()
self.checkTimer = wx.Timer(self, self.checkTimerID)
self.checkPeriod = 250
self.checkMaximize = True
self.shipBrowser = self.Parent
self.raceBmps = []
self.raceNames = []
self.hoveredItem = None
if layout == wx.VERTICAL:
self.buttonsBarPos = (4, 0)
else:
self.buttonsBarPos = (0, 4)
self.buttonsPadding = 4
if layout == wx.VERTICAL:
self.bmpArrow = BitmapLoader.getBitmap("down-arrow2", "gui")
else:
self.bmpArrow = BitmapLoader.getBitmap("up-arrow2", "gui")
# Make the bitmaps have the same color as window text
sysTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
img = self.bmpArrow.ConvertToImage()
if layout == wx.VERTICAL:
img = img.Rotate90(False)
img.Replace(0, 0, 0, sysTextColour[0], sysTextColour[1], sysTextColour[2])
if layout == wx.VERTICAL:
img = img.Scale(self.minWidth, 8, wx.IMAGE_QUALITY_HIGH)
self.bmpArrow = wx.BitmapFromImage(img)
self.RebuildRaces(self.shipBrowser.RACE_ORDER)
self.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnBackgroundErase)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.Bind(wx.EVT_SIZE, self.OnSizeUpdate)
self.Layout()
def OnMouseMove(self, event):
mx, my = event.GetPosition()
location = self.HitTest(mx, my)
if location != self.hoveredItem:
self.hoveredItem = location
self.Refresh()
if location is not None:
self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
else:
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
def OnSizeUpdate(self, event):
self.CalcButtonsBarPos()
self.Refresh()
event.Skip()
def CalcButtonsBarPos(self):
if self.layout == wx.HORIZONTAL:
rect = self.GetRect()
width = 0
height = 0
for bmp in self.raceBmps:
width += bmp.GetWidth() + self.buttonsPadding
height = max(bmp.GetHeight(), height)
posx = (rect.width - width) / 2
posy = (rect.height - height) / 2
self.buttonsBarPos = (posx, posy)
def OnLeftUp(self, event):
mx, my = event.GetPosition()
toggle = self.HitTest(mx, my)
if toggle is not None:
self.Refresh()
self.shipBrowser.ToggleRacesFilter(self.raceNames[toggle])
stage = self.shipBrowser.GetActiveStage()
if stage == 2:
categoryID = self.shipBrowser.GetStageData(stage)
wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=True))
event.Skip()
def HitTest(self, mx, my):
x, y = self.buttonsBarPos
padding = self.buttonsPadding
for bmp in self.raceBmps:
if (x < mx < x + bmp.GetWidth()) and (y < my < y + bmp.GetHeight()):
return self.raceBmps.index(bmp)
if self.layout == wx.VERTICAL:
y += bmp.GetHeight() + padding
else:
x += bmp.GetWidth() + padding
return None
def RebuildRaces(self, races):
self.raceBmps = []
for race in races:
if race:
self.raceBmps.append(BitmapLoader.getBitmap("race_%s_small" % race, "gui"))
self.raceNames = races
self.CalcButtonsBarPos()
self.Refresh()
def OnBackgroundErase(self, event):
pass
def OnPaint(self, event):
rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
# bkColor = colorUtils.GetSuitableColor(windowColor, 0.1)
sepColor = colorUtils.GetSuitableColor(windowColor, 0.2)
mdc = wx.BufferedPaintDC(self)
bkBitmap = drawUtils.RenderGradientBar(windowColor, rect.width, rect.height, 0.1, 0.1, 0.2, 2)
mdc.DrawBitmap(bkBitmap, 0, 0, True)
x, y = self.buttonsBarPos
if self.direction == 1:
for raceBmp in self.raceBmps:
dropShadow = drawUtils.CreateDropShadowBitmap(raceBmp, 0.2)
if self.shipBrowser.GetRaceFilterState(self.raceNames[self.raceBmps.index(raceBmp)]):
bmp = raceBmp
else:
img = wx.ImageFromBitmap(raceBmp)
if self.hoveredItem == self.raceBmps.index(raceBmp):
img = img.AdjustChannels(1, 1, 1, 0.7)
else:
img = img.AdjustChannels(1, 1, 1, 0.4)
bmp = wx.BitmapFromImage(img)
if self.layout == wx.VERTICAL:
mdc.DrawBitmap(dropShadow, rect.width - self.buttonsPadding - bmp.GetWidth() + 1, y + 1)
mdc.DrawBitmap(bmp, rect.width - self.buttonsPadding - bmp.GetWidth(), y)
y += raceBmp.GetHeight() + self.buttonsPadding
mdc.SetPen(wx.Pen(sepColor, 1))
mdc.DrawLine(rect.width - 1, 0, rect.width - 1, rect.height)
else:
mdc.DrawBitmap(dropShadow, x + 1, self.buttonsPadding + 1)
mdc.DrawBitmap(bmp, x, self.buttonsPadding)
x += raceBmp.GetWidth() + self.buttonsPadding
mdc.SetPen(wx.Pen(sepColor, 1))
mdc.DrawLine(0, 0, rect.width, 0)
if self.direction < 1:
if self.layout == wx.VERTICAL:
mdc.DrawBitmap(self.bmpArrow, -2, (rect.height - self.bmpArrow.GetHeight()) / 2)
else:
mdc.SetPen(wx.Pen(sepColor, 1))
mdc.DrawLine(0, 0, rect.width, 0)
mdc.DrawBitmap(self.bmpArrow, (rect.width - self.bmpArrow.GetWidth()) / 2, -2)
def OnTimer(self, event):
if event.GetId() == self.animTimerID:
start = 0
if self.layout == wx.VERTICAL:
end = self.maxWidth - self.minWidth
else:
end = self.maxHeight - self.minHeight
step = animEffects.OUT_CIRC(self.animStep, start, end, self.animDuration)
self.animStep += self.animPeriod * self.direction
self.AdjustSize((self.minWidth if self.layout == wx.VERTICAL else self.minHeight) + step)
if self.animStep > self.animDuration or self.animStep < 0:
self.animTimer.Stop()
self.animStep = self.animDuration if self.direction == 1 else 0
self.Parent.GetBrowserContainer().RefreshList(True)
if event.GetId() == self.checkTimerID:
if self.checkMaximize:
self.direction = 1
else:
self.direction = -1
if not self.animTimer.IsRunning():
self.animTimer.Start(self.animPeriod)
def AdjustSize(self, delta):
self.SetMinSize(wx.Size(delta, -1) if self.layout == wx.VERTICAL else wx.Size(-1, delta))
self.Parent.Layout()
self.Refresh()
def OnWindowEnter(self, event):
if not self.animate:
return
if not self.checkTimer.IsRunning():
self.checkTimer.Start(self.checkPeriod, wx.TIMER_ONE_SHOT)
self.checkMaximize = True
event.Skip()
def OnWindowLeave(self, event):
if self.hoveredItem is not None:
self.hoveredItem = None
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
self.Refresh()
if not self.animate:
return
if not self.checkTimer.IsRunning():
self.checkTimer.Start(self.checkPeriod, wx.TIMER_ONE_SHOT)
self.checkMaximize = False
event.Skip()

View File

@@ -253,6 +253,8 @@ class SFBrowserItem(wx.Window):
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
if "wxMSW" in wx.PlatformInfo:
self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown)
@@ -261,6 +263,18 @@ class SFBrowserItem(wx.Window):
self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
self.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_SET_FOCUS, self.OnFocus)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def OnFocus(self, evt):
self.SetHighlighted(True)
self.Refresh()
evt.Skip()
def OnKillFocus(self, evt):
self.SetHighlighted(False)
self.Refresh()
evt.Skip()
def Refresh(self):
self.RenderBackground()
@@ -282,6 +296,9 @@ class SFBrowserItem(wx.Window):
def OnEraseBackground(self, event):
pass
def OnKeyUp(self, event):
pass
def MouseLeftUp(self, event):
pass

View File

@@ -0,0 +1,293 @@
import re
import wx
from logbook import Logger
import gui.builtinShipBrowser.sfBrowserItem as SFItem
import gui.mainFrame
import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from events import *
from gui.bitmapLoader import BitmapLoader
from gui.contextMenu import ContextMenu
from service.fit import Fit
from service.market import Market
pyfalog = Logger(__name__)
class ShipItem(SFItem.SFBrowserItem):
def __init__(self, parent, shipID=None, shipFittingInfo=("Test", "TestTrait", 2), itemData=None,
id=wx.ID_ANY, pos=wx.DefaultPosition,
size=(0, 40), style=0):
SFItem.SFBrowserItem.__init__(self, parent, size=size)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self._itemData = itemData
self.shipRace = itemData
self.shipID = shipID
self.fontBig = wx.Font(fonts.BIG, wx.SWISS, wx.NORMAL, wx.BOLD)
self.fontNormal = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.shipBmp = None
if shipID:
self.shipBmp = BitmapLoader.getBitmap(str(shipID), "renders")
if not self.shipBmp:
self.shipBmp = BitmapLoader.getBitmap("ship_no_image_big", "gui")
self.shipFittingInfo = shipFittingInfo
self.shipName, self.shipTrait, self.shipFits = shipFittingInfo
self.shipTrait = re.sub("<.*?>", " ", self.shipTrait)
self.newBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big", "gui")
img = wx.ImageFromBitmap(self.shipEffBk)
img = img.Mirror(False)
self.shipEffBkMirrored = wx.BitmapFromImage(img)
self.raceBmp = BitmapLoader.getBitmap("race_%s_small" % self.shipRace, "gui")
if not self.raceBmp:
self.raceBmp = BitmapLoader.getBitmap("fit_delete_small", "gui")
self.raceDropShadowBmp = drawUtils.CreateDropShadowBitmap(self.raceBmp, 0.2)
sFit = Fit.getInstance()
if self.shipTrait and sFit.serviceFittingOptions["showShipBrowserTooltip"]:
self.SetToolTip(wx.ToolTip(self.shipTrait))
self.shipBrowser = self.Parent.Parent
self.editWidth = 150
self.padding = 4
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s fit" % self.shipName, wx.DefaultPosition, (120, -1),
wx.TE_PROCESS_ENTER)
self.tcFitName.Show(False)
self.newBtn = self.toolbar.AddButton(self.newBmp, "New", self.newBtnCB)
self.tcFitName.Bind(wx.EVT_TEXT_ENTER, self.createNewFit)
self.tcFitName.Bind(wx.EVT_KILL_FOCUS, self.editLostFocus)
self.tcFitName.Bind(wx.EVT_KEY_DOWN, self.editCheckEsc)
self.animTimerId = wx.NewId()
self.animTimer = wx.Timer(self, self.animTimerId)
self.animStep = 0
self.animPeriod = 10
self.animDuration = 100
self.Bind(wx.EVT_CONTEXT_MENU, self.OnShowPopup)
self.marketInstance = Market.getInstance()
self.baseItem = self.marketInstance.getItem(self.shipID)
# =====================================================================
# DISABLED - it will be added as an option in PREFERENCES
self.animCount = 0
# if self.shipBrowser.GetActiveStage() != 4 and self.shipBrowser.GetLastStage() !=2:
# self.Bind(wx.EVT_TIMER, self.OnTimer)
# self.animTimer.Start(self.animPeriod)
# else:
# self.animCount = 0
# =====================================================================
def OnShowPopup(self, event):
pos = event.GetPosition()
pos = self.ScreenToClient(pos)
contexts = [("baseShip", "Ship Basic")]
menu = ContextMenu.getMenu(self.baseItem, *contexts)
self.PopupMenu(menu, pos)
def OnTimer(self, event):
step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration)
self.animCount = 10 - step
self.animStep += self.animPeriod
if self.animStep > self.animDuration or self.animCount < 0:
self.animCount = 0
self.animTimer.Stop()
self.Refresh()
def OnKeyUp(self, event):
if event.GetKeyCode() in (32, 13): # space and enter
self.selectShip(event)
event.Skip()
@staticmethod
def OUT_QUAD(t, b, c, d):
t = float(t)
b = float(b)
c = float(c)
d = float(d)
t /= d
return -c * t * (t - 2) + b
def GetType(self):
return 2
def selectShip(self, event):
if self.tcFitName.IsShown():
self.tcFitName.Show(False)
self.newBtn.SetBitmap(self.newBmp)
self.Refresh()
else:
shipName, shipTrait, fittings = self.shipFittingInfo
if fittings > 0:
wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID, back=True))
else:
self.newBtnCB()
def MouseLeftUp(self, event):
self.selectShip(event)
def newBtnCB(self):
if self.tcFitName.IsShown():
self.tcFitName.Show(False)
self.createNewFit()
else:
self.tcFitName.SetValue("%s fit" % self.shipName)
self.tcFitName.Show()
self.tcFitName.SetFocus()
self.tcFitName.SelectAll()
self.newBtn.SetBitmap(self.acceptBmp)
self.Refresh()
def editLostFocus(self, event):
self.tcFitName.Show(False)
self.newBtn.SetBitmap(self.newBmp)
self.Refresh()
def editCheckEsc(self, event):
if event.GetKeyCode() == wx.WXK_ESCAPE:
self.tcFitName.Show(False)
else:
event.Skip()
def createNewFit(self, event=None):
self.tcFitName.Show(False)
sFit = Fit.getInstance()
fitID = sFit.newFit(self.shipID, self.tcFitName.GetValue())
wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID, back=False))
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
def UpdateElementsPos(self, mdc):
rect = self.GetRect()
self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
self.toolbarx += self.animCount
self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2
self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2
self.shipEffx -= self.animCount
self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2
self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2
self.shipBmpx -= self.animCount
self.raceBmpx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding
self.raceBmpy = (rect.height - self.raceBmp.GetHeight()) / 2
self.textStartx = self.raceBmpx + self.raceBmp.GetWidth() + self.padding
self.shipNamey = (rect.height - self.shipBmp.GetHeight()) / 2
shipName, shipTrait, fittings = self.shipFittingInfo
mdc.SetFont(self.fontBig)
wtext, htext = mdc.GetTextExtent(shipName)
self.fittingsy = self.shipNamey + htext
mdc.SetFont(self.fontSmall)
wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
self.thoverx = self.toolbarx - self.padding - wlabel
self.thovery = (rect.height - hlabel) / 2
self.thoverw = wlabel
def DrawItem(self, mdc):
# rect = self.GetRect()
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
textColor = colorUtils.GetSuitableColor(windowColor, 1)
mdc.SetTextForeground(textColor)
self.UpdateElementsPos(mdc)
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
if self.GetState() & SFItem.SB_ITEM_HIGHLIGHTED:
shipEffBk = self.shipEffBkMirrored
else:
shipEffBk = self.shipEffBk
mdc.DrawBitmap(shipEffBk, self.shipEffx, self.shipEffy, 0)
mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0)
mdc.DrawBitmap(self.raceDropShadowBmp, self.raceBmpx + 1, self.raceBmpy + 1)
mdc.DrawBitmap(self.raceBmp, self.raceBmpx, self.raceBmpy)
shipName, shipTrait, fittings = self.shipFittingInfo
if fittings < 1:
fformat = "No fits"
elif fittings == 1:
fformat = "%d fit"
else:
fformat = "%d fits"
mdc.SetFont(self.fontNormal)
mdc.DrawText(fformat % fittings if fittings > 0 else fformat, self.textStartx, self.fittingsy)
mdc.SetFont(self.fontSmall)
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
mdc.SetFont(self.fontBig)
psname = drawUtils.GetPartialText(mdc, shipName,
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
mdc.DrawText(psname, self.textStartx, self.shipNamey)
if self.tcFitName.IsShown():
self.AdjustControlSizePos(self.tcFitName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
def AdjustControlSizePos(self, editCtl, start, end):
fnEditSize = editCtl.GetSize()
wSize = self.GetSize()
fnEditPosX = end
fnEditPosY = (wSize.height - fnEditSize.height) / 2
if fnEditPosX < start:
editCtl.SetSize((self.editWidth + fnEditPosX - start, -1))
editCtl.SetPosition((start, fnEditPosY))
else:
editCtl.SetSize((self.editWidth, -1))
editCtl.SetPosition((fnEditPosX, fnEditPosY))

View File

@@ -44,7 +44,7 @@ class BaseName(ViewColumn):
self.columnText = "Name"
self.shipImage = fittingView.imageList.GetImageIndex("ship_small", "gui")
self.mask = wx.LIST_MASK_TEXT
self.projectedView = isinstance(fittingView, gui.projectedView.ProjectedView)
self.projectedView = isinstance(fittingView, gui.builtinAdditionPanes.projectedView.ProjectedView)
def getText(self, stuff):
if isinstance(stuff, Drone):

View File

@@ -22,10 +22,10 @@ import wx
# noinspection PyPackageRequirements
import wx.lib.newevent
import gui.mainFrame
import gui.marketBrowser
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
import gui.display as d
from gui.contextMenu import ContextMenu
import gui.shipBrowser
from gui.builtinShipBrowser.events import *
import gui.multiSwitch
from eos.saveddata.mode import Mode
from eos.saveddata.module import Module, Slot, Rack
@@ -50,7 +50,7 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
def __init__(self, multiSwitch):
self.multiSwitch = multiSwitch
self.mainFrame = mainFrame = gui.mainFrame.MainFrame.getInstance()
mainFrame.Bind(gui.shipBrowser.EVT_FIT_SELECTED, self.fitSelected)
mainFrame.Bind(EVT_FIT_SELECTED, self.fitSelected)
self.multiSwitch.tabsContainer.handleDrag = self.handleDrag
def fitSelected(self, event):
@@ -138,9 +138,9 @@ class FittingView(d.Display):
self.Show(False)
self.parent = parent
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
self.mainFrame.Bind(gui.shipBrowser.EVT_FIT_RENAMED, self.fitRenamed)
self.mainFrame.Bind(gui.shipBrowser.EVT_FIT_REMOVED, self.fitRemoved)
self.mainFrame.Bind(gui.marketBrowser.ITEM_SELECTED, self.appendItem)
self.mainFrame.Bind(EVT_FIT_RENAMED, self.fitRenamed)
self.mainFrame.Bind(EVT_FIT_REMOVED, self.fitRemoved)
self.mainFrame.Bind(ITEM_SELECTED, self.appendItem)
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
@@ -210,14 +210,14 @@ class FittingView(d.Display):
def handleDrag(self, type, fitID):
# Those are drags coming from pyfa sources, NOT builtin wx drags
if type == "fit":
wx.PostEvent(self.mainFrame, gui.shipBrowser.FitSelected(fitID=fitID))
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID))
def Destroy(self):
self.parent.Unbind(EVT_NOTEBOOK_PAGE_CHANGED, handler=self.pageChanged)
self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.fitChanged)
self.mainFrame.Unbind(gui.shipBrowser.EVT_FIT_RENAMED, handler=self.fitRenamed)
self.mainFrame.Unbind(gui.shipBrowser.EVT_FIT_REMOVED, handler=self.fitRemoved)
self.mainFrame.Unbind(gui.marketBrowser.ITEM_SELECTED, handler=self.appendItem)
self.mainFrame.Unbind(EVT_FIT_RENAMED, handler=self.fitRenamed)
self.mainFrame.Unbind(EVT_FIT_REMOVED, handler=self.fitRemoved)
self.mainFrame.Unbind(ITEM_SELECTED, handler=self.appendItem)
d.Display.Destroy(self)
@@ -394,7 +394,7 @@ class FittingView(d.Display):
moduleChanged = sFit.changeModule(fitID, self.mods[dstRow].modPosition, srcIdx)
if moduleChanged is None:
# the new module doesn't fit in specified slot, try to simply append it
wx.PostEvent(self.mainFrame, gui.marketBrowser.ItemSelected(itemID=srcIdx))
wx.PostEvent(self.mainFrame, ItemSelected(itemID=srcIdx))
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="modadd", typeID=srcIdx))

View File

@@ -3,11 +3,11 @@ import wx
# noinspection PyPackageRequirements
from wx.lib.buttons import GenBitmapButton
from service.market import Market
import gui.builtinMarketBrowser.pfSearchBox as SBox
import gui.display as d
import gui.PFSearchBox as SBox
from gui.bitmapLoader import BitmapLoader
from gui.marketBrowser import SearchBox
from service.market import Market
class BaseImplantEditorView(wx.Panel):

View File

@@ -45,10 +45,12 @@ import gui.globalEvents as GE
from gui.bitmapLoader import BitmapLoader
from gui.mainMenuBar import MainMenuBar
from gui.additionsPane import AdditionsPane
from gui.marketBrowser import MarketBrowser, ItemSelected
from gui.marketBrowser import MarketBrowser
from gui.builtinMarketBrowser.events import ItemSelected
from gui.multiSwitch import MultiSwitch
from gui.statsPane import StatsPane
from gui.shipBrowser import ShipBrowser, FitSelected, ImportSelected, Stage3Selected
from gui.shipBrowser import ShipBrowser
from gui.builtinShipBrowser.events import FitSelected, ImportSelected, Stage3Selected
from gui.characterEditor import CharacterEditor, SaveCharacterAs
from gui.characterSelection import CharacterSelection
from gui.patternEditor import DmgPatternEditorDlg

View File

@@ -19,44 +19,19 @@
# noinspection PyPackageRequirements
import wx
from service.market import Market
from service.fit import Fit
from service.attribute import Attribute
from gui.display import Display
import gui.PFSearchBox as SBox
from gui.cachingImageList import CachingImageList
from gui.contextMenu import ContextMenu
from gui.bitmapLoader import BitmapLoader
from gui.builtinMarketBrowser.searchBox import SearchBox
from gui.builtinMarketBrowser.itemView import ItemView
from gui.builtinMarketBrowser.metaButton import MetaButton
from gui.builtinMarketBrowser.marketTree import MarketTree
from gui.builtinMarketBrowser.events import *
from logbook import Logger
from utils.staticHelpers import DragDropHelper
pyfalog = Logger(__name__)
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
RECENTLY_USED_MODULES = -2
MAX_RECENTLY_USED_MODULES = 20
class MetaButton(wx.ToggleButton):
def __init__(self, *args, **kwargs):
super(MetaButton, self).__init__(*args, **kwargs)
self.setUserSelection(True)
def setUserSelection(self, isSelected):
self.userSelected = isSelected
self.SetValue(isSelected)
def setMetaAvailable(self, isAvailable):
self.Enable(isAvailable)
# need to also SetValue(False) for windows because Enabled=False AND SetValue(True) looks enabled.
if not isAvailable:
self.SetValue(False)
def reset(self):
self.Enable(True)
self.SetValue(self.userSelected)
class MarketBrowser(wx.Panel):
def __init__(self, parent):
@@ -125,362 +100,3 @@ class MarketBrowser(wx.Panel):
def jump(self, item):
self.marketView.jump(item)
class SearchBox(SBox.PFSearchBox):
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)
self.SetCancelBitmap(cancelBitmap)
self.ShowSearchButton()
self.ShowCancelButton()
class MarketTree(wx.TreeCtrl):
def __init__(self, parent, marketBrowser):
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
pyfalog.debug("Initialize marketTree")
self.root = self.AddRoot("root")
self.imageList = CachingImageList(16, 16)
self.SetImageList(self.imageList)
self.sMkt = marketBrowser.sMkt
self.marketBrowser = marketBrowser
# Form market tree root
sMkt = self.sMkt
for mktGrp in sMkt.getMarketRoot():
iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp))
childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID))
# All market groups which were never expanded are dummies, here we assume
# that all root market groups are expandable
self.AppendItem(childId, "dummy")
self.SortChildren(self.root)
# Add recently used modules node
rumIconId = self.addImage("market_small", "gui")
self.AppendItem(self.root, "Recently Used Modules", rumIconId, data=wx.TreeItemData(RECENTLY_USED_MODULES))
# Bind our lookup method to when the tree gets expanded
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
def addImage(self, iconFile, location="icons"):
if iconFile is None:
return -1
return self.imageList.GetImageIndex(iconFile, location)
def expandLookup(self, event):
"""Process market tree expands"""
root = event.Item
child = self.GetFirstChild(root)[0]
# If child of given market group is a dummy
if self.GetItemText(child) == "dummy":
# Delete it
self.Delete(child)
# And add real market group contents
sMkt = self.sMkt
currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children")
for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp):
# If market should have items but it doesn't, do not show it
if sMkt.marketGroupValidityCheck(childMktGrp) is False:
continue
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
try:
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
except Exception as e:
pyfalog.debug("Error appending item.")
pyfalog.debug(e)
continue
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
self.AppendItem(childId, "dummy")
self.SortChildren(root)
def jump(self, item):
"""Open market group and meta tab of given item"""
self.marketBrowser.searchMode = False
sMkt = self.sMkt
mg = sMkt.getMarketGroupByItem(item)
jumpList = []
while mg is not None:
jumpList.append(mg.ID)
mg = mg.parent
for id in sMkt.ROOT_MARKET_GROUPS:
if id in jumpList:
jumpList = jumpList[:jumpList.index(id) + 1]
item = self.root
for i in range(len(jumpList) - 1, -1, -1):
target = jumpList[i]
child, cookie = self.GetFirstChild(item)
while self.GetItemPyData(child) != target:
child, cookie = self.GetNextChild(item, cookie)
item = child
self.Expand(item)
self.SelectItem(item)
self.marketBrowser.itemView.selectionMade()
class ItemView(Display):
DEFAULT_COLS = ["Base Icon",
"Base Name",
"attr:power,,,True",
"attr:cpu,,,True"]
def __init__(self, parent, marketBrowser):
Display.__init__(self, parent)
pyfalog.debug("Initialize ItemView")
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
self.unfilteredStore = set()
self.filteredStore = set()
self.recentlyUsedModules = set()
self.sMkt = marketBrowser.sMkt
self.searchMode = marketBrowser.searchMode
self.marketBrowser = marketBrowser
self.marketView = marketBrowser.marketView
# Set up timer for delaying search on every EVT_TEXT
self.searchTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.scheduleSearch, self.searchTimer)
# Make sure our search actually does interesting stuff
self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.delaySearch)
# Make sure WE do interesting stuff too
self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
# Make reverse map, used by sorter
self.metaMap = self.makeReverseMetaMap()
# Fill up recently used modules set
pyfalog.debug("Fill up recently used modules set")
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
def delaySearch(self, evt):
sFit = Fit.getInstance()
self.searchTimer.Stop()
self.searchTimer.Start(sFit.serviceFittingOptions["marketSearchDelay"], True) # 150ms
def startDrag(self, event):
row = self.GetFirstSelected()
if row != -1:
data = wx.PyTextDataObject()
dataStr = "market:" + str(self.active[row].ID)
pyfalog.debug("Dragging from market: " + dataStr)
data.SetText(dataStr)
dropSource = wx.DropSource(self)
dropSource.SetData(data)
DragDropHelper.data = dataStr
dropSource.DoDragDrop()
def itemActivated(self, event=None):
# Check if something is selected, if so, spawn the menu for it
sel = self.GetFirstSelected()
if sel == -1:
return
if self.mainFrame.getActiveFit():
self.storeRecentlyUsedMarketItem(self.active[sel].ID)
self.recentlyUsedModules = set()
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID))
def storeRecentlyUsedMarketItem(self, itemID):
if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES:
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0)
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID)
def selectionMade(self, event=None):
self.marketBrowser.searchMode = False
# Grab the threeview selection and check if it's fine
sel = self.marketView.GetSelection()
if sel.IsOk():
# Get data field of the selected item (which is a marketGroup ID if anything was selected)
seldata = self.marketView.GetPyData(sel)
if seldata is not None and seldata != RECENTLY_USED_MODULES:
# If market group treeview item doesn't have children (other market groups or dummies),
# then it should have items in it and we want to request them
if self.marketView.ItemHasChildren(sel) is False:
sMkt = self.sMkt
# Get current market group
mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup"))
# Get all its items
items = sMkt.getItemsByMarketGroup(mg)
else:
items = set()
else:
# If method was called but selection wasn't actually made or we have a hit on recently used modules
if seldata == RECENTLY_USED_MODULES:
items = self.recentlyUsedModules
else:
items = set()
# Fill store
self.updateItemStore(items)
# Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered)
if seldata is not RECENTLY_USED_MODULES:
self.setToggles()
else:
self.marketBrowser.searchMode = True
self.setToggles()
# Update filtered items
self.filterItemStore()
def updateItemStore(self, items):
self.unfilteredStore = items
def filterItemStore(self):
sMkt = self.sMkt
selectedMetas = set()
for btn in self.marketBrowser.metaButtons:
if btn.GetValue():
selectedMetas.update(sMkt.META_MAP[btn.metaName])
self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas)
self.update(list(self.filteredStore))
def setToggles(self):
metaIDs = set()
sMkt = self.sMkt
for item in self.unfilteredStore:
metaIDs.add(sMkt.getMetaGroupIdByItem(item))
for btn in self.marketBrowser.metaButtons:
btn.reset()
btnMetas = sMkt.META_MAP[btn.metaName]
if len(metaIDs.intersection(btnMetas)) > 0:
btn.setMetaAvailable(True)
else:
btn.setMetaAvailable(False)
def scheduleSearch(self, event=None):
self.searchTimer.Stop() # Cancel any pending timers
search = self.marketBrowser.search.GetLineText(0)
# Make sure we do not count wildcard as search symbol
realsearch = search.replace("*", "")
# Re-select market group if search query has zero length
if len(realsearch) == 0:
self.selectionMade()
return
# Show nothing if query is too short
elif len(realsearch) < 3:
self.clearSearch()
return
self.marketBrowser.searchMode = True
self.sMkt.searchItems(search, self.populateSearch)
def clearSearch(self, event=None):
# Wipe item store and update everything to accomodate with it
# If clearSearch was generated by SearchCtrl's Cancel button, clear the content also
if event:
self.marketBrowser.search.Clear()
self.marketBrowser.searchMode = False
self.updateItemStore(set())
self.setToggles()
self.filterItemStore()
def populateSearch(self, items):
# If we're no longer searching, dump the results
if self.marketBrowser.searchMode is False:
return
self.updateItemStore(items)
self.setToggles()
self.filterItemStore()
def itemSort(self, item):
sMkt = self.sMkt
catname = sMkt.getCategoryByItem(item).name
try:
mktgrpid = sMkt.getMarketGroupByItem(item).ID
except AttributeError:
mktgrpid = None
print("unable to find market group for", item.name)
parentname = sMkt.getParentItemByItem(item).name
# Get position of market group
metagrpid = sMkt.getMetaGroupIdByItem(item)
metatab = self.metaMap.get(metagrpid)
metalvl = self.metalvls.get(item.ID, 0)
return catname, mktgrpid, parentname, metatab, metalvl, item.name
def contextMenu(self, event):
# Check if something is selected, if so, spawn the menu for it
sel = self.GetFirstSelected()
if sel == -1:
return
item = self.active[sel]
sMkt = self.sMkt
sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc"
itemContext = sMkt.getCategoryByItem(item).name
menu = ContextMenu.getMenu((item,), (sourceContext, itemContext))
self.PopupMenu(menu)
def populate(self, items):
if len(items) > 0:
# Get dictionary with meta level attribute
sAttr = Attribute.getInstance()
attrs = sAttr.getAttributeInfo("metaLevel")
sMkt = self.sMkt
self.metalvls = sMkt.directAttrRequest(items, attrs)
# Clear selection
self.deselectItems()
# Perform sorting, using item's meta levels besides other stuff
items.sort(key=self.itemSort)
# Mark current item list as active
self.active = items
# Show them
Display.populate(self, items)
def refresh(self, items):
if len(items) > 1:
# Get dictionary with meta level attribute
sAttr = Attribute.getInstance()
attrs = sAttr.getAttributeInfo("metaLevel")
sMkt = self.sMkt
self.metalvls = sMkt.directAttrRequest(items, attrs)
# Re-sort stuff
items.sort(key=self.itemSort)
for i, item in enumerate(items[:9]):
# set shortcut info for first 9 modules
item.marketShortcut = i + 1
Display.refresh(self, items)
def makeReverseMetaMap(self):
"""
Form map which tells in which tab items of given metagroup are located
"""
revmap = {}
i = 0
for mgids in self.sMkt.META_MAP.itervalues():
for mgid in mgids:
revmap[mgid] = i
i += 1
return revmap

View File

@@ -1,8 +1,8 @@
import csv
from logbook import Logger
# noinspection PyPackageRequirements
import wx
from logbook import Logger
try:
# noinspection PyPackageRequirements
@@ -17,7 +17,7 @@ from eos.db.gamedata.queries import getItem, getAttributeInfo
from service.market import Market
import gui.display as d
import gui.globalEvents as GE
import gui.PFSearchBox as SBox
import gui.builtinMarketBrowser.pfSearchBox as SBox
from gui.marketBrowser import SearchBox
from gui.bitmapLoader import BitmapLoader

File diff suppressed because it is too large Load Diff