# noinspection PyPackageRequirements import wx from .helpers import AutoListCtrl from service.price import Price as ServicePrice from service.market import Market from service.attribute import Attribute from gui.utils.numberFormatter import formatAmount _t = wx.GetTranslation def defaultSort(item): return (item.metaLevel or 0, item.name) class ItemCompare(wx.Panel): def __init__(self, parent, stuff, item, items, context=None): # Start dealing with Price stuff to get that thread going sPrice = ServicePrice.getInstance() sPrice.getPrices(items, self.UpdateList, fetchTimeout=90) wx.Panel.__init__(self, parent) self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) mainSizer = wx.BoxSizer(wx.VERTICAL) self.paramList = AutoListCtrl(self, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0) self.SetSizer(mainSizer) self.toggleView = 1 self.stuff = stuff self.currentSort = None self.sortReverse = False self.item = item self.items = sorted(items, key=defaultSort) self.attrs = {} # get a dict of attrName: attrInfo of all unique attributes across all items for item in self.items: for attr in list(item.attributes.keys()): if item.attributes[attr].info.displayName: self.attrs[attr] = item.attributes[attr].info # Process attributes for items and find ones that differ for attr in list(self.attrs.keys()): value = None for item in self.items: # we can automatically break here if this item doesn't have the attribute, # as that means at least one item did if attr not in item.attributes: break # this is the first attribute for the item set, set the initial value if value is None: value = item.attributes[attr].value continue if attr not in item.attributes or item.attributes[attr].value != value: break else: # attribute values were all the same, delete del self.attrs[attr] self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) mainSizer.Add(self.m_staticline, 0, wx.EXPAND) bSizer = wx.BoxSizer(wx.HORIZONTAL) self.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, " ", wx.DefaultPosition, wx.DefaultSize, 0) bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT) self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, _t("Toggle view mode"), wx.DefaultPosition, wx.DefaultSize, 0) bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL) self.refreshBtn = wx.Button(self, wx.ID_ANY, _t("Refresh"), wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT) bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL) self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshValues) mainSizer.Add(bSizer, 0, wx.ALIGN_RIGHT) self.PopulateList() self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode) self.Bind(wx.EVT_LIST_COL_CLICK, self.SortCompareCols) def SortCompareCols(self, event): self.Freeze() self.paramList.ClearAll() self.PopulateList(event.Column) self.Thaw() def UpdateList(self, items=None): # We do nothing with `items`, but it gets returned by the price service thread self.Freeze() self.paramList.ClearAll() self.PopulateList() self.Thaw() self.paramList.resizeLastColumn(100) def RefreshValues(self, event): self.UpdateList() event.Skip() def ToggleViewMode(self, event): self.toggleView *= -1 self.UpdateList() event.Skip() def processPrices(self, prices): for i, price in enumerate(prices): self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(price.value, 3, 3, 9, currency=True)) def PopulateList(self, sort=None): if sort is not None and self.currentSort == sort: self.sortReverse = not self.sortReverse else: self.currentSort = sort self.sortReverse = False if sort is not None: if sort == 0: # Name sort func = lambda _val: _val.name else: try: # Remember to reduce by 1, because the attrs array # starts at 0 while the list has the item name as column 0. attr = str(list(self.attrs.keys())[sort - 1]) func = lambda _val: _val.attributes[attr].value if attr in _val.attributes else 0.0 # Clicked on a column that's not part of our array (price most likely) except IndexError: # Price if sort == len(self.attrs) + 1: func = lambda i: i.price.price if i.price.price != 0 else float("Inf") # Something else else: self.sortReverse = False func = defaultSort self.items = sorted(self.items, key=func, reverse=self.sortReverse) self.paramList.InsertColumn(0, _t("Item")) self.paramList.SetColumnWidth(0, 200) for i, attr in enumerate(self.attrs.keys()): name = self.attrs[attr].displayName if self.attrs[attr].displayName else attr self.paramList.InsertColumn(i + 1, name) self.paramList.SetColumnWidth(i + 1, 120) self.paramList.InsertColumn(len(self.attrs) + 1, _t("Price")) self.paramList.SetColumnWidth(len(self.attrs) + 1, 60) for item in self.items: i = self.paramList.InsertItem(self.paramList.GetItemCount(), item.name) for x, attr in enumerate(self.attrs.keys()): if attr in item.attributes: info = self.attrs[attr] value = item.attributes[attr].value if self.toggleView != 1: valueUnit = str(value) elif info and info.unit and self.toggleView == 1: valueUnit = self.TranslateValueUnit(value, info.unit.displayName, info.unit.name) else: valueUnit = formatAmount(value, 3, 0, 0) self.paramList.SetItem(i, x + 1, valueUnit) # Add prices self.paramList.SetItem(i, len(self.attrs) + 1, formatAmount(item.price.price, 3, 3, 9, currency=True) if item.price.price else "") self.paramList.RefreshRows() self.Layout() @staticmethod def TranslateValueUnit(value, unitName, unitDisplayName): def itemIDCallback(): item = Market.getInstance().getItem(value) return "%s (%d)" % (item.name, value) if item is not None else str(value) def groupIDCallback(): group = Market.getInstance().getGroup(value) return "%s (%d)" % (group.name, value) if group is not None else str(value) def attributeIDCallback(): attribute = Attribute.getInstance().getAttributeInfo(value) return "%s (%d)" % (attribute.name.capitalize(), value) trans = { "Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName), "Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName), "Modifier Percent": (lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName), "Volume": (lambda: value, "m\u00B3"), "Sizeclass": (lambda: value, ""), "Absolute Percent": (lambda: (value * 100), unitName), "Milliseconds": (lambda: value / 1000.0, unitName), "typeID": (itemIDCallback, ""), "groupID": (groupIDCallback, ""), "attributeID": (attributeIDCallback, "") } override = trans.get(unitDisplayName) if override is not None: v = override[0]() if isinstance(v, str): fvalue = v elif isinstance(v, (int, float)): fvalue = formatAmount(v, 3, 0, 0) else: fvalue = v return "%s %s" % (fvalue, override[1]) else: return "%s %s" % (formatAmount(value, 3, 0), unitName)