NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

assetsWindow.py (45351B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\assetsWindow.py
      2 import sys
      3 from collections import defaultdict
      4 import blue
      5 import eveicon
      6 import evetypes
      7 import localization
      8 import log
      9 import uthread
     10 import uthread2
     11 import utillib
     12 from carbonui.control.contextMenu.menuData import MenuData
     13 from carbonui.util.sortUtil import SortListOfTuples
     14 from player_messaging.client.ui_message import message_player
     15 from evePathfinder.core import IsUnreachableJumpCount
     16 from carbonui import TextColor, uiconst
     17 from carbonui.control.button import Button
     18 from carbonui.control.combo import Combo
     19 from carbonui.control.window import Window
     20 from carbonui.primitives.container import Container
     21 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     22 from carbonui.primitives.sprite import Sprite
     23 from carbonui.uianimations import animations
     24 from carbonui.uicore import uicore
     25 from carbonui.util.dpi import reverse_scale_dpi
     26 from carbonui.window.header.tab_navigation import TabNavigationWindowHeader
     27 from carbonui.window.settings import WindowMarginMode
     28 from eve.client.script.ui.control import eveScroll
     29 from eve.client.script.ui.control.entries.util import GetFromClass
     30 from eve.client.script.ui.control.infoIcon import MoreInfoIcon
     31 from eve.client.script.ui.control.listgroup import ListGroup
     32 from carbonui.control.tabGroup import TabGroup
     33 from eve.client.script.ui.control.entries.universe import LocationGroup
     34 from eve.client.script.ui.shared.assets.assetSafety import AssetSafetyCont
     35 from eve.client.script.ui.shared.assets.assetSafetyControllers import SafetyControllerCharacter
     36 from eve.client.script.ui.shared.assetsSearch import SearchBox
     37 from eve.client.script.ui.shared.inventory.invWindow import Inventory as InventoryWindow
     38 from eve.client.script.ui.shared.item import InvAssetItem
     39 from eve.client.script.ui.util import uix
     40 from eve.client.script.ui.util.uix import IsValidNamedItem
     41 from eve.common.lib import appConst as const
     42 from eve.common.script.sys import idCheckers, eveCfg
     43 from eve.common.script.sys.idCheckers import IsWormholeSystem, IsTriglavianSystem
     44 from eveAssets.assetSearchUtil import SearchNamesHelper, AssetKeywordSearch, IsPartOfText, ParseString
     45 from eveAssets.assetSearching import GetSearchResults, GetFakeRowset
     46 from eveformat.client import solar_system_security_status
     47 from eveservices.menu import GetMenuService, StartMenuService
     48 from eveui import skip_if_destroyed
     49 from localization import GetByLabel
     50 from menu import MenuLabel
     51 from menucheckers.itemCheckers import ItemChecker
     52 SORT_BY_NAME = 0
     53 SORT_BY_JUMPS = 1
     54 SORT_BY_ITEMS = 2
     55 SORT_BY_OPTIONS = [(GetByLabel('UI/Common/Name'), SORT_BY_NAME), (GetByLabel('UI/Common/NumberOfJumps'), SORT_BY_JUMPS), (GetByLabel('UI/Common/NumberOfItems'), SORT_BY_ITEMS)]
     56 TYPE_ALLITEMS = 'allitems'
     57 TYPE_REGION = 'regitems'
     58 TYPE_CONSTELLATION = 'conitems'
     59 TYPE_SYSTEM = 'sysitems'
     60 FILTER_TYPE_OPTIONS = ((GetByLabel('UI/Inventory/AssetsWindow/AllItems'), TYPE_ALLITEMS),
     61  (GetByLabel('UI/Common/LocationTypes/Region'), TYPE_REGION),
     62  (GetByLabel('UI/Common/LocationTypes/Constellation'), TYPE_CONSTELLATION),
     63  (GetByLabel('UI/Common/LocationTypes/SolarSystem'), TYPE_SYSTEM))
     64 WINDOW_CAPTION_LABEL = 'UI/Inventory/AssetsWindow/PersonalAssets'
     65 WINDOW_SUBCAPTION_LABEL = 'UI/Inventory/AssetsWindow/DelayedFiveMinutes'
     66 NO_CONTENT_HIT_BY_KEY = {'allitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsAtStation'),
     67  'regitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInRegion'),
     68  'conitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInConstellation'),
     69  'sysitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInSolarSystem')}
     70 IMPORTANCE_NONE = 0
     71 IMPORTANCE_PINNED = 1
     72 IMPORTANCE_HIDDEN = -1
     73 
     74 class AssetsWindow(Window):
     75     __guid__ = 'form.AssetsWindow'
     76     __notifyevents__ = ['OnDestinationSet']
     77     default_width = 550
     78     default_height = 450
     79     default_minSize = (395, 256)
     80     default_windowID = 'assets'
     81     default_captionLabelPath = 'Tooltips/Neocom/PersonalAssets'
     82     default_descriptionLabelPath = 'Tooltips/Neocom/PersonalAssets_description'
     83     default_iconNum = 'res:/ui/Texture/WindowIcons/assets.png'
     84     _update_delay_hint = None
     85 
     86     def __init__(self, **kwargs):
     87         self._loading_thread = None
     88         super(AssetsWindow, self).__init__(**kwargs)
     89 
     90     def ApplyAttributes(self, attributes):
     91         super(AssetsWindow, self).ApplyAttributes(attributes)
     92         self.pathfinder = sm.GetService('clientPathfinderService')
     93         self.key = None
     94         self.invalidateOpenState_regitems = 1
     95         self.invalidateOpenState_allitems = 1
     96         self.invalidateOpenState_conitems = 1
     97         self.invalidateOpenState_sysitems = 1
     98         self.safetyCont = None
     99         self.searchCont = None
    100         self.filterCont = None
    101         self.searchlist = None
    102         self.stationTabs = None
    103         self.searchEditBox = None
    104         self.filterValueCombo = None
    105         self.pending = None
    106         self.loading = 0
    107         self.station_inited = False
    108         self.search_inited = False
    109         self.filt_inited = False
    110         self.nameHelper = SearchNamesHelper(sm.GetService('ui'))
    111         self.assetKeywordSearch = AssetKeywordSearch(self.nameHelper, sm.GetService('ui'), sm.GetService('map'), sm.GetService('godma'), sm.GetService('structureDirectory'), localization, cfg)
    112         self.searchKeywords = self.assetKeywordSearch.GetSearchKeywords()
    113         if attributes.exactTypeID:
    114             autoSelectTab = False
    115             self.searchText = self.GetSearchTextForTypeID(attributes.exactTypeID)
    116         else:
    117             self.searchText = None
    118             autoSelectTab = True
    119         self.scrollPosition = defaultdict(float)
    120         self.ReconstructLayout(autoSelectTab)
    121         self._update_delay_hint = UpdateDelayHint(parent=self.header.extra_content, align=uiconst.TORIGHT, padding=self._get_update_delay_hint_padding())
    122         self.on_margin_mode_changed.connect(self._on_margin_mode_changed)
    123         self.on_stacked_changed.connect(self._on_stacked_changed)
    124 
    125     def _get_update_delay_hint_padding(self):
    126         if self.stacked:
    127             return (0, 0, 0, 0)
    128         else:
    129             return (8, 0, 8, 0)
    130 
    131     def _update_update_delay_hint_padding(self):
    132         if self._update_delay_hint:
    133             self._update_delay_hint.padding = self._get_update_delay_hint_padding()
    134 
    135     def _on_stacked_changed(self, window):
    136         self._update_update_delay_hint_padding()
    137 
    138     def OnDestinationSet(self, destinationID = None):
    139         self.ReconstructLayout()
    140 
    141     def ReloadTabs(self, *args):
    142         self.tabGroup.ReloadVisible()
    143 
    144     @skip_if_destroyed
    145     def ReconstructLayout(self, autoSelectTab = True, *args):
    146         self.station_inited = False
    147         self.search_inited = False
    148         self.filt_inited = False
    149         try:
    150             self.scrollPosition[self.key] = self.scroll.GetScrollProportion()
    151         except Exception:
    152             self.scrollPosition[self.key] = 0.0
    153 
    154         self._RecoverSearchText()
    155         self.sr.main.Flush()
    156         self.scroll = eveScroll.Scroll(parent=self.sr.main, padding=(0, 8, 0, 0))
    157         self.scroll.sr.id = 'assets'
    158         self.scroll.sr.minColumnWidth = {GetByLabel('UI/Common/Name'): 44}
    159         self.scroll.allowFilterColumns = 1
    160         self.scroll.OnNewHeaders = self.ReloadTabs
    161         self.scroll.sortGroups = True
    162         self.scroll.SetColumnsHiddenByDefault(uix.GetInvItemDefaultHiddenHeaders())
    163         self._ReconstructTabs()
    164         if autoSelectTab:
    165             self.tabGroup.AutoSelect(silently=True)
    166 
    167     @skip_if_destroyed
    168     def _ReconstructTabs(self):
    169         self.tabGroup = self.header.tab_group
    170         tabs = [(GetByLabel(self.default_captionLabelPath),
    171           self.scroll,
    172           self,
    173           'allitems')]
    174         tabs += [(GetByLabel('UI/Common/Buttons/Search'),
    175           self.scroll,
    176           self,
    177           'search'), (GetByLabel('UI/Inventory/AssetSafety/AssetSafety'),
    178           self.scroll,
    179           self,
    180           'safety',
    181           None,
    182           GetByLabel('UI/Inventory/AssetSafety/AssetSafetyHint'))]
    183         self.tabGroup.Flush()
    184         for tab in tabs:
    185             self.tabGroup.AddTab(*tab)
    186 
    187     def Prepare_Header_(self):
    188         self.header = TabNavigationWindowHeader()
    189 
    190     def _RecoverSearchText(self):
    191         assetSearchBox = self.searchEditBox
    192         if assetSearchBox:
    193             self.searchText = assetSearchBox.GetValue()
    194 
    195     def Load(self, key, reloadStationID = None):
    196         if self.loading:
    197             self.pending = (key, reloadStationID)
    198             return
    199         uthread.new(self._Load, key, reloadStationID)
    200 
    201     def _Load(self, key, reloadStationID = None):
    202         self.loading = 1
    203         self.pending = None
    204         if key != self.key:
    205             self.scrollPosition[self.key] = self.scroll.GetScrollProportion()
    206         self.key = key
    207         if self.safetyCont:
    208             self.safetyCont.display = False
    209         if key == 'safety':
    210             self.LoadAssetSafety()
    211         elif key[:7] == 'station':
    212             self.LoadCurrStation(key)
    213         elif key in ('allitems', 'regitems', 'conitems', 'sysitems'):
    214             self.LoadAssets(key)
    215         elif key == 'search':
    216             self.LoadSearch()
    217         self.loading = 0
    218         if self.pending:
    219             self.Load(*self.pending)
    220 
    221     def LoadAssetSafety(self):
    222 
    223         def Hide(cont):
    224             if cont:
    225                 cont.display = False
    226 
    227         Hide(self.scroll)
    228         Hide(self.searchCont)
    229         Hide(self.filterCont)
    230         Hide(self.stationTabs)
    231         if self.safetyCont is None or self.safetyCont.destroyed:
    232             self.safetyCont = AssetSafetyCont(parent=self.sr.main, controller=SafetyControllerCharacter())
    233         self.safetyCont.display = True
    234         self.safetyCont.Load()
    235 
    236     def LoadCurrStation(self, key):
    237         if not self.station_inited:
    238             self.stationTabs = TabGroup(name='tabparent2', parent=self.sr.main, idx=2)
    239             tabs = [[GetByLabel('UI/Common/ItemTypes/Ships'),
    240               self.scroll,
    241               self,
    242               '%sships' % key],
    243              [GetByLabel('UI/Common/ItemTypes/Modules'),
    244               self.scroll,
    245               self,
    246               '%smodules' % key],
    247              [GetByLabel('UI/Common/ItemTypes/Charges'),
    248               self.scroll,
    249               self,
    250               '%scharges' % key],
    251              [GetByLabel('UI/Common/ItemTypes/Minerals'),
    252               self.scroll,
    253               self,
    254               '%sminerals' % key],
    255              [GetByLabel('UI/Common/Other'),
    256               self.scroll,
    257               self,
    258               '%sother' % key]]
    259             self.station_inited = 1
    260             self.stationTabs.Startup(tabs, 'assetsatstation', silently=True)
    261         if self.filterCont:
    262             self.filterCont.state = uiconst.UI_HIDDEN
    263         self.stationTabs.state = uiconst.UI_NORMAL
    264         if self.searchCont:
    265             self.searchCont.state = uiconst.UI_HIDDEN
    266         if key != 'station':
    267             self.ShowStationItems(key[7:])
    268         else:
    269             self.stationTabs.AutoSelect(1)
    270 
    271     def LoadAssets(self, key):
    272         if not self.filt_inited:
    273             self.ConstructFilterCont()
    274             self.filt_inited = True
    275         else:
    276             self.filterCont.Show()
    277         if self.stationTabs:
    278             self.stationTabs.Hide()
    279         if self.searchCont:
    280             self.searchCont.Hide()
    281         key = self.filterTypeCombo.GetValue()
    282         self.PopulateScroll(key, None, None)
    283 
    284     def ConstructFilterCont(self):
    285         self.filterCont = Container(name='filterContainer', align=uiconst.TOTOP, state=uiconst.UI_PICKCHILDREN, height=Combo.default_height, parent=self.sr.main, padding=self._get_top_cont_padding(), idx=self.scroll.GetOrder())
    286         self.sortByCombo = Combo(label=GetByLabel('UI/Common/SortBy'), parent=self.filterCont, options=SORT_BY_OPTIONS, name='sortcombo', align=uiconst.TORIGHT, select=None, callback=self.Filter, width=115, padRight=4)
    287         self.filterTypeCombo = Combo(name='filterTypeCombo', parent=self.filterCont, align=uiconst.TOLEFT, width=115, padRight=4, options=FILTER_TYPE_OPTIONS, select=settings.char.ui.Get('assets_window_filter_type', None), prefskey=('char', 'ui', 'assets_window_filter_type'), callback=self.OnFilterTypeCombo)
    288         self.filterValueCombo = Combo(parent=self.filterCont, options=[], name='filtcombo', select=None, callback=self.Filter, width=115, align=uiconst.TOLEFT, padRight=4)
    289         self.UpdateFilterValueComboVisibility()
    290 
    291     def OnFilterTypeCombo(self, *args):
    292         self.filterTypeCombo.UpdateSettings()
    293         self.UpdateFilterValueComboVisibility()
    294         self.Filter()
    295 
    296     def UpdateFilterValueComboVisibility(self):
    297         self.filterValueCombo.display = self.filterTypeCombo.GetValue() != TYPE_ALLITEMS
    298 
    299     def _get_top_cont_padding(self):
    300         if self.margin_mode == WindowMarginMode.COMPACT:
    301             return (0, 12, 0, 0)
    302         else:
    303             return (0, 4, 0, 0)
    304 
    305     def _on_margin_mode_changed(self, window):
    306         if self.searchCont is not None:
    307             self.searchCont.padding = self._get_top_cont_padding()
    308         if self.filterCont is not None:
    309             self.filterCont.padding = self._get_top_cont_padding()
    310 
    311     def LoadSearch(self):
    312         if self.stationTabs:
    313             self.stationTabs.state = uiconst.UI_HIDDEN
    314         if not self.search_inited:
    315             self.searchCont = Container(name='searchCont', align=uiconst.TOTOP, height=32, parent=self.sr.main, idx=self.scroll.GetOrder(), padding=self._get_top_cont_padding())
    316             Container(name='comboCont', align=uiconst.TOLEFT, parent=self.searchCont, width=108)
    317             self.sortByCombosearch = Combo(label=GetByLabel('UI/Common/SortBy'), parent=self.searchCont, options=SORT_BY_OPTIONS, name='sortcombosearch', select=settings.char.ui.Get('assetsSearchSortKey', None), callback=self.Search, width=100, pos=(0, 0, 0, 0))
    318             buttonCont = ContainerAutoSize(name='bottonCont', parent=self.searchCont, align=uiconst.TORIGHT)
    319             infoIcon = MoreInfoIcon(name='infoIcon', parent=buttonCont, align=uiconst.CENTERRIGHT)
    320             infoIcon.LoadTooltipPanel = self.LoadInfoTooltip
    321             button = Button(name='searchButton', parent=buttonCont, align=uiconst.CENTERRIGHT, left=infoIcon.left + infoIcon.width + 8, label=GetByLabel('UI/Common/Buttons/Search'), func=self.Search)
    322             self.searchEditBox = SearchBox(name='assetssearchtype', parent=self.searchCont, align=uiconst.TOALL, width=0, padding=(0, 0, 8, 0), label=GetByLabel('UI/Common/SearchText'), maxLength=100, OnReturn=self.Search, OnClearFilter=self.Search, keywords=self.searchKeywords, isTypeField=True)
    323             self.searchEditBox.ShowClearButton()
    324             self.searchEditBox.SetValueAfterDragging = self.SetSearchTypeValueAfterDragging
    325             self._RestoreSearchText()
    326             self.search_inited = 1
    327         if self.filterCont:
    328             self.filterCont.state = uiconst.UI_HIDDEN
    329         self.searchCont.state = uiconst.UI_PICKCHILDREN
    330         sortKeySearch = settings.char.ui.Get('assetsSearchSortKey', None)
    331         searchlist = getattr(self, 'searchlist', [])
    332         if searchlist:
    333             self._start_loading_thread(self._LoadSearch, sortKeySearch)
    334         else:
    335             self.Search()
    336 
    337     def SetSearchTypeValueAfterDragging(self, name, draggedValue):
    338         name = self.GetSearchTextForTypeID(draggedValue)
    339         SearchBox.SetValueAfterDragging(self.searchEditBox, name, draggedValue)
    340 
    341     def _RestoreSearchText(self):
    342         if self.searchText:
    343             searchBox = self.searchEditBox
    344             if searchBox:
    345                 searchBox.SetValue(self.searchText)
    346 
    347     def Filter(self, *args):
    348         key = self.filterTypeCombo.GetValue()
    349         keyID = self.filterValueCombo.GetValue()
    350         sortKey = self.sortByCombo.GetValue()
    351         self.PopulateScroll(key, keyID, sortKey)
    352 
    353     def GetConditions(self, advancedMatches):
    354         conditions = []
    355         for word, value in advancedMatches:
    356             try:
    357                 for kw in self.searchKeywords:
    358                     if IsPartOfText(kw.keyword, word):
    359                         kw.matchFunction(conditions, value)
    360                         break
    361 
    362             except:
    363                 import log
    364                 log.LogException()
    365                 sm.GetService('assets').LogInfo('Failed parsing keyword', word, 'value', value, 'and happily ignoring it')
    366 
    367         return conditions
    368 
    369     def Search(self, *args):
    370         self._start_loading_thread(self.Search_thread)
    371 
    372     def Search_thread(self, *args):
    373         self.ShowLoad()
    374         try:
    375             if self.tabGroup.GetSelectedArgs() == 'search':
    376                 self.scroll.Load(contentList=[], noContentHint=GetByLabel('UI/Common/GettingData'))
    377             blue.pyos.synchro.Yield()
    378             log.LogNotice('Asset Search - fetch items')
    379             invContainer = sm.GetService('invCache').GetInventory(const.containerGlobal)
    380             allitems = invContainer.ListIncludingContainers()
    381             log.LogNotice('Asset Search - items fetched =', len(allitems))
    382             itemRowset = GetFakeRowset(allitems)
    383             log.LogNotice('Asset Search - fake rows created')
    384             blue.pyos.synchro.Yield()
    385             if self.tabGroup.GetSelectedArgs() == 'search':
    386                 self.scroll.Load(contentList=[], noContentHint=GetByLabel('UI/Common/Searching'))
    387             blue.pyos.synchro.Yield()
    388             searchtype = unicode(self.searchEditBox.GetValue() or '').lower()
    389             searchtype, advancedMatches = ParseString(searchtype)
    390             conditions = self.GetConditions(advancedMatches)
    391             self.assetKeywordSearch.ResetPerRunDicts()
    392             allContainersByItemIDs, itemsByContainerID, stations = GetSearchResults(conditions, itemRowset, searchtype)
    393             containersInfoByStations = defaultdict(lambda : defaultdict(tuple))
    394             for containerID, itemsInContainer in itemsByContainerID.iteritems():
    395                 containerItem = allContainersByItemIDs.get(containerID)
    396                 if containerItem and containerItem.typeID == const.typePlasticWrap:
    397                     continue
    398                 if containerItem:
    399                     containersInfoByStations[containerItem.locationID][containerID] = (containerItem, itemsInContainer)
    400 
    401             for stationID in containersInfoByStations.iterkeys():
    402                 stations[stationID].extend([])
    403 
    404             sortlocations = []
    405             ownerStations = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStations().Index('stationID')
    406             for stationID, stationItems in stations.iteritems():
    407                 stationData = ownerStations.get(stationID, None)
    408                 if stationData is None:
    409                     continue
    410                 stationsContainersInfo = containersInfoByStations.get(stationID, {})
    411                 sortlocations.append((stationData.solarSystemID,
    412                  stationID,
    413                  stationItems,
    414                  stationsContainersInfo))
    415 
    416             sortlocations.sort()
    417             sortlocations = sortlocations
    418             self.searchlist = sortlocations
    419             sortKey = self.sortByCombosearch.GetValue()
    420             self._LoadSearch(sortKey)
    421         finally:
    422             self.HideLoad()
    423 
    424     def PopulateScroll(self, key, keyID, sortKey, *args):
    425         if keyID is None:
    426             keyID = settings.char.ui.Get('assetsKeyID_%s' % key, None)
    427         oldSortKey = settings.char.ui.Get('assetsSortKey', None)
    428         if sortKey is not None:
    429             if oldSortKey != sortKey:
    430                 for k in self.scrollPosition.keys():
    431                     self.scrollPosition[k] = 0.0
    432 
    433         else:
    434             sortKey = oldSortKey
    435         settings.char.ui.Set('assetsKeyID_%s' % key, keyID)
    436         settings.char.ui.Set('assetsSortKey', sortKey)
    437         self.ShowLoad()
    438         self.SetHint()
    439         closed = [0, 1][getattr(self, 'invalidateOpenState_%s' % key, 0)]
    440         sortlocations = sm.GetService('assets').GetAll(key, keyID=keyID, sortKey=sortKey)
    441         try:
    442             options = self.GetFilterValueComboOptions(key)
    443             self.filterValueCombo.LoadOptions(options, None)
    444             if keyID:
    445                 self.filterValueCombo.SelectItemByLabel(cfg.evelocations.Get(keyID).name)
    446             if sortKey:
    447                 self.sortByCombo.SelectItemByIndex(sortKey)
    448         except (Exception,):
    449             sys.exc_clear()
    450 
    451         allImportanceSettings = settings.char.ui.Get('assets_window_importance', {})
    452         destPathList = sm.GetService('starmap').GetDestinationPath()
    453         scrolllist = []
    454         hiddenEntries = []
    455         for solarsystemID, station in sortlocations:
    456             importanceValue = allImportanceSettings.get(station.stationID, IMPORTANCE_NONE)
    457             data = self.GetLocationData(solarsystemID, station, key, forceClosed=closed, scrollID=self.scroll.sr.id, sortKey=sortKey, path=destPathList, importanceValue=importanceValue)
    458             blue.pyos.BeNice()
    459             entry = GetFromClass(LocationGroup, data)
    460             if importanceValue == IMPORTANCE_HIDDEN:
    461                 hiddenEntries.append(entry)
    462             else:
    463                 scrolllist.append(entry)
    464 
    465         if hiddenEntries:
    466             scrolllist.append(self.GetHiddenEntry(hiddenEntries))
    467         if self.destroyed:
    468             return
    469         setattr(self, 'invalidateOpenState_%s' % key, 0)
    470         scrollPosition = self.scrollPosition[key]
    471         self.scroll.Load(contentList=scrolllist, headers=uix.GetInvItemDefaultHeaders(), noContentHint=NO_CONTENT_HIT_BY_KEY[key], scrollTo=scrollPosition, showCollapseIcon=True)
    472         self.HideLoad()
    473 
    474     def GetHiddenSubContent(self, nodedata, *args):
    475         return nodedata.groupItems
    476 
    477     def GetHiddenEntry(self, hiddenEntries):
    478         data = {'GetSubContent': self.GetHiddenSubContent,
    479          'label': 'Hidden',
    480          'groupItems': hiddenEntries,
    481          'id': 'assetslocations_hiddenEntries',
    482          'state': 'locked',
    483          'showicon': eveicon.hidden,
    484          'showlen': 1,
    485          'BlockOpenWindow': 1}
    486         return GetFromClass(ListGroup, data)
    487 
    488     def GetFilterValueComboOptions(self, key):
    489         key = self.filterTypeCombo.GetValue()
    490         options = [(GetByLabel('UI/Common/Current'), 0)]
    491         opts = {}
    492         for r in sm.GetService('assets').locationCache.iterkeys():
    493             if key == 'regitems' and idCheckers.IsRegion(r) or key == 'conitems' and idCheckers.IsConstellation(r) or key == 'sysitems' and idCheckers.IsSolarSystem(r):
    494                 opts[cfg.evelocations.Get(r).name] = r
    495 
    496         keys = opts.keys()
    497         keys.sort()
    498         for k in keys:
    499             options.append((k, opts[k]))
    500 
    501         return options
    502 
    503     def ShowStationItems(self, key):
    504         self.ShowLoad()
    505         hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar)
    506         items = hangarInv.List(const.flagHangar)
    507         if not len(items):
    508             self.SetHint(GetByLabel('UI/Inventory/AssetsWindow/NoAssets'))
    509             return
    510         assetsList = []
    511         self.scroll.Load(fixedEntryHeight=42, contentList=[], headers=uix.GetInvItemDefaultHeaders())
    512         itemname = ' ' + key
    513         itemSet = set()
    514         for each in items:
    515             if each.flagID not in (const.flagHangar, const.flagWallet):
    516                 continue
    517             if key == 'ships':
    518                 if each.categoryID != const.categoryShip:
    519                     continue
    520             elif key == 'modules':
    521                 if not evetypes.IsCategoryHardwareByCategory(evetypes.GetCategoryID(each.typeID)):
    522                     continue
    523             elif key == 'minerals':
    524                 if each.groupID != const.groupMineral:
    525                     continue
    526             elif key == 'charges':
    527                 if each.categoryID != const.categoryCharge:
    528                     continue
    529             else:
    530                 itemname = None
    531                 if each.categoryID == const.categoryShip or evetypes.IsCategoryHardwareByCategory(evetypes.GetCategoryID(each.typeID)) or each.groupID == const.groupMineral or each.categoryID == const.categoryCharge:
    532                     continue
    533             itemSet.add(each)
    534 
    535         self.PrimeLocationNames(itemSet)
    536         for eachItem in itemSet:
    537             assetsList.append(GetFromClass(InvAssetItem, uix.GetItemData(eachItem, 'details', scrollID=self.scroll.sr.id)))
    538 
    539         locText = {'ships': GetByLabel('UI/Inventory/AssetsWindow/NoShipsAtStation'),
    540          'modules': GetByLabel('UI/Inventory/AssetsWindow/NoModulesAtStation'),
    541          'minerals': GetByLabel('UI/Inventory/AssetsWindow/NoMineralsAtStation'),
    542          'charges': GetByLabel('UI/Inventory/AssetsWindow/NoChargesAtStation')}
    543         if not assetsList:
    544             if not itemname:
    545                 self.SetHint(GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInCategoryAtStation'))
    546             else:
    547                 self.SetHint(locText[key])
    548         else:
    549             self.SetHint()
    550         self.scroll.Load(contentList=assetsList, sortby='label', headers=uix.GetInvItemDefaultHeaders(), noContentHint=GetByLabel('UI/Common/NothingFound'))
    551         self.HideLoad()
    552 
    553     def GetLocationData(self, solarsystemID, station, key, forceClosed = 0, scrollID = None, sortKey = None, fakeItems = None, path = (), importanceValue = IMPORTANCE_NONE):
    554         isHidden = importanceValue == IMPORTANCE_HIDDEN
    555         isPinned = importanceValue == IMPORTANCE_PINNED
    556         location = cfg.evelocations.Get(station.stationID)
    557         if forceClosed:
    558             uicore.registry.SetListGroupOpenState(('assetslocations_%s' % key, location.locationID), 0)
    559         autopilotNumJumps = self.pathfinder.GetAutopilotJumpCount(session.solarsystemid2, solarsystemID)
    560         itemCount = fakeItems or station.itemCount
    561         secStatus = solar_system_security_status(solarsystemID)
    562         if IsUnreachableJumpCount(autopilotNumJumps):
    563             label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabelNoRoute', location=location.locationID, itemCount=itemCount, secStatus=secStatus)
    564         elif key is not 'sysitems':
    565             label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabel', location=location.locationID, itemCount=itemCount, jumps=autopilotNumJumps, secStatus=secStatus)
    566         else:
    567             label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabelNoJump', location=location.locationID, itemCount=itemCount, secStatus=secStatus)
    568         if sortKey == SORT_BY_JUMPS:
    569             sortVal = (-isPinned,
    570              autopilotNumJumps,
    571              location.name,
    572              itemCount)
    573         elif sortKey == SORT_BY_ITEMS:
    574             sortVal = (-isPinned,
    575              -itemCount,
    576              location.name,
    577              autopilotNumJumps)
    578         else:
    579             sortVal = (-isPinned,
    580              location.name,
    581              itemCount,
    582              autopilotNumJumps)
    583         inMyPath = self._IsInMyPath(path, solarsystemID, location.locationID)
    584         sublevel = 1 if isHidden else 0
    585         data = {'GetSubContent': self.GetSubContent,
    586          'DragEnterCallback': self.OnGroupDragEnter,
    587          'DeleteCallback': self.OnGroupDeleted,
    588          'MenuFunction': self.GetMenuLocationMenu,
    589          'GetDragDataFunc': self.GetLocationDragData,
    590          'label': label,
    591          'jumps': autopilotNumJumps,
    592          'itemCount': station.itemCount,
    593          'groupItems': [],
    594          'id': ('assetslocations_%s' % key, location.locationID),
    595          'tabs': [],
    596          'state': 'locked',
    597          'location': location,
    598          'showicon': 'hide',
    599          'showlen': 0,
    600          'key': key,
    601          'scrollID': scrollID,
    602          'inMyPath': inMyPath,
    603          'itemID': station.stationID,
    604          'upkeepState': getattr(station, 'upkeepState', None),
    605          'charIndex': location.name,
    606          'sublevel': sublevel}
    607         if isPinned:
    608             data['rightIconInfo'] = (eveicon.pinned, GetByLabel('UI/Inventory/AssetsWindow/PinnedLocation'))
    609         headers = uix.GetInvItemDefaultHeaders()
    610         for each in headers:
    611             data['sort_%s' % each] = sortVal
    612 
    613         return data
    614 
    615     def _IsInMyPath(self, path, solarsystemID, locationID):
    616         if solarsystemID in path:
    617             return True
    618         if locationID in path:
    619             return True
    620         if not eveCfg.IsDocked() and solarsystemID == session.solarsystemid2:
    621             return True
    622         return False
    623 
    624     def GetLocationDragData(self, node):
    625         solarSystemID, stationTypeID = self.GetStationSolarSystemIDAndTypeID(node)
    626         stationInfo = sm.GetService('ui').GetStationStaticInfo(node.itemID)
    627         if stationInfo:
    628             node['typeID'] = stationInfo.stationTypeID
    629             node['genericDisplayLabel'] = cfg.evelocations.Get(node.itemID).name
    630         elif stationTypeID:
    631             node['typeID'] = stationTypeID
    632             node['genericDisplayLabel'] = cfg.evelocations.Get(node.itemID).name
    633         return [node]
    634 
    635     def GetContainerSubContent(self, nodedata, *args):
    636         scrollList = []
    637         self.PrimeLocationNames(nodedata.groupItems)
    638         for each in nodedata.groupItems:
    639             data = uix.GetItemData(each, 'details', scrollID=nodedata.scrollID)
    640             data.sublevel = nodedata.sublevel
    641             scrollList.append(GetFromClass(InvAssetItem, data))
    642 
    643         return scrollList
    644 
    645     def GetContainerMenu(self, node):
    646         return GetMenuService().InvItemMenu(node.item)
    647 
    648     def OnDblClickContainer(self, groupEntry):
    649         nodedata = groupEntry.sr.node
    650         if ItemChecker(nodedata.item).IsInPilotLocation():
    651             invID = ('StationContainer', nodedata.itemID)
    652             InventoryWindow.OpenOrShow(invID=invID, openFromWnd=self)
    653 
    654     def GetContainerGroupEntries(self, containersInfo, scrollID):
    655         scrollList = []
    656         cfg.evelocations.Prime(containersInfo.keys())
    657         for containerID, infoOnContainer in containersInfo.iteritems():
    658             containerItem, itemsInContainer = infoOnContainer
    659             scrollList.append(GetFromClass(ListGroup, {'GetSubContent': self.GetContainerSubContent,
    660              'label': uix.GetItemName(containerItem),
    661              'MenuFunction': self.GetContainerMenu,
    662              'groupItems': itemsInContainer,
    663              'id': ('assetslocations_%s' % containerID, containerID),
    664              'state': 'locked',
    665              'showicon': 'hide',
    666              'showlen': 1,
    667              'itemID': containerID,
    668              'item': containerItem,
    669              'sublevel': 1,
    670              'scrollID': scrollID,
    671              'OnDblClick': self.OnDblClickContainer}))
    672 
    673         return scrollList
    674 
    675     def GetSubContent(self, data, *args):
    676         if data.key == 'search':
    677             scrolllist = []
    678             items = []
    679             containersInfo = {}
    680             for solarsystemID, stationID, stationItems, stationsContainersInfo in self.searchlist:
    681                 if stationID == data.location.locationID:
    682                     items = stationItems
    683                     containersInfo = stationsContainersInfo
    684                     break
    685 
    686             self.PrimeLocationNames(items)
    687             groupEntries = self.GetContainerGroupEntries(containersInfo, data.scrollID)
    688             scrolllist.extend(groupEntries)
    689             for each in items:
    690                 if each.flagID not in (const.flagHangar, const.flagWallet, const.flagAssetSafety):
    691                     continue
    692                 scrolllist.append(GetFromClass(InvAssetItem, uix.GetItemData(each, 'details', scrollID=data.scrollID)))
    693                 blue.pyos.BeNice()
    694 
    695             return scrolllist
    696         sublevel = data.get('sublevel', 0)
    697         if session.stationid and data.location.locationID in (session.stationid, session.structureid):
    698             hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar)
    699             items = hangarInv.List()
    700             scrolllist = []
    701             self.PrimeLocationNames(items)
    702             for each in items:
    703                 if each.flagID not in (const.flagHangar, const.flagWallet, const.flagAssetSafety):
    704                     continue
    705                 scrolllist.append(GetFromClass(InvAssetItem, uix.GetItemData(each, 'details', scrollID=data.scrollID, sublevel=sublevel)))
    706 
    707             return scrolllist
    708         items = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStationItems(data.location.locationID)
    709         badLocations = [const.locationTemp, const.locationSystem, session.charid]
    710         scrolllist = []
    711         self.PrimeLocationNames(items)
    712         for each in items:
    713             if idCheckers.IsJunkLocation(each.locationID) or each.locationID in badLocations:
    714                 continue
    715             if each.stacksize == 0:
    716                 continue
    717             data = uix.GetItemData(each, 'details', scrollID=data.scrollID, sublevel=sublevel)
    718             if idCheckers.IsStation(each.locationID):
    719                 station = sm.GetService('ui').GetStationStaticInfo(each.locationID)
    720                 if station:
    721                     data.factionID = sm.GetService('faction').GetFactionOfSolarSystem(station.solarSystemID)
    722             scrolllist.append(GetFromClass(InvAssetItem, data))
    723 
    724         return scrolllist
    725 
    726     def PrimeLocationNames(self, items):
    727         itemLocationToPrime = set()
    728         for each in items:
    729             if IsValidNamedItem(each):
    730                 itemLocationToPrime.add(each.itemID)
    731 
    732         cfg.evelocations.Prime(itemLocationToPrime)
    733 
    734     def UpdateLite(self, stationID, key, fromID):
    735         if not self or self.destroyed:
    736             return
    737         self.ShowLoad()
    738         try:
    739             destPathList = sm.GetService('starmap').GetDestinationPath()
    740             assetStations = sm.GetService('assets').GetStations().Index('stationID')
    741             searchKey = 'assetslocations_%s' % key
    742             affectedNodes = [ node for node in self.scroll.GetNodes() if node.Get('id', None) in ((searchKey, stationID), (searchKey, fromID)) ]
    743             for node in affectedNodes:
    744                 locationID = node.Get('id')[1]
    745                 station = assetStations.get(locationID, None)
    746                 if station is None:
    747                     station = utillib.KeyVal(solarSystemID=node.location.solarSystemID, stationID=locationID, itemCount=node.itemCount)
    748                 node.data = self.GetLocationData(station.solarSystemID, station, key, scrollID=self.scroll.sr.id, path=destPathList)
    749                 if node.panel:
    750                     node.panel.Load(node)
    751                 self.scroll.PrepareSubContent(node)
    752                 self.scroll.ScrollToProportion(self.scroll.GetScrollProportion())
    753 
    754         finally:
    755             self.ReconstructLayout()
    756             self.HideLoad()
    757 
    758     def ShowSearch(self, sortKey = None, *args):
    759         uthread2.start_tasklet(self._LoadSearch, sortKey)
    760 
    761     def _LoadSearch(self, sortKey):
    762         if sortKey is None:
    763             sortKey = settings.char.ui.Get('assetsSearchSortKey', None)
    764         settings.char.ui.Set('assetsSearchSortKey', sortKey)
    765         if sortKey:
    766             self.sortByCombosearch.SelectItemByIndex(sortKey)
    767         self.SetHint()
    768         self.scroll.ShowLoading()
    769         try:
    770             scrolllist = []
    771             searchlist = getattr(self, 'searchlist', []) or []
    772             sortedList = []
    773             for solarsystemID, stationID, items, stationsContainersInfo in searchlist:
    774                 numContainerItems = sum([ len(y) for x, y in stationsContainersInfo.values() ])
    775                 station = utillib.KeyVal()
    776                 station.stationID = stationID
    777                 station.solarsystemID = solarsystemID
    778                 station.stationName = cfg.evelocations.Get(stationID).name
    779                 station.itemCount = len(items) + numContainerItems
    780                 sortedList.append(station)
    781 
    782             allImportanceSettings = settings.char.ui.Get('assets_window_importance', {})
    783             destPathList = sm.GetService('starmap').GetDestinationPath()
    784             hiddenEntries = []
    785             for station in sortedList:
    786                 importanceValue = allImportanceSettings.get(station.stationID, IMPORTANCE_NONE)
    787                 data = self.GetLocationData(station.solarsystemID, station, 'search', scrollID=self.scroll.sr.id, sortKey=sortKey, path=destPathList, importanceValue=importanceValue)
    788                 entry = GetFromClass(LocationGroup, data)
    789                 if importanceValue == IMPORTANCE_HIDDEN:
    790                     hiddenEntries.append(entry)
    791                 else:
    792                     scrolllist.append(entry)
    793                 blue.pyos.BeNice()
    794 
    795             if hiddenEntries:
    796                 scrolllist.append(self.GetHiddenEntry(hiddenEntries))
    797             scrollPosition = 0
    798             if self.tabGroup.GetSelectedArgs() == 'search':
    799                 scrollPosition = self.scrollPosition.get('search', 0)
    800             self.scroll.Load(contentList=scrolllist, headers=uix.GetInvItemDefaultHeaders(), noContentHint=GetByLabel('UI/Common/NothingFound'), scrollTo=scrollPosition, showCollapseIcon=True)
    801         finally:
    802             self.scroll.HideLoading()
    803             self.HideLoad()
    804 
    805     def GetMenuLocationMenu(self, node):
    806         locationID = node.location.locationID
    807         solarSystemID, stationTypeID = self.GetStationSolarSystemIDAndTypeID(node)
    808         menu = StartMenuService().CelestialMenu(node.location.locationID, typeID=stationTypeID, parentID=solarSystemID)
    809         menu += self._GetImportanceMenu(locationID, solarSystemID)
    810         if not idCheckers.IsStation(locationID):
    811             if session.structureid != locationID:
    812                 if IsWormholeSystem(solarSystemID) or IsTriglavianSystem(solarSystemID):
    813                     label = MenuLabel('UI/Inventory/AssetSafety/MoveItemsToSpace')
    814                 else:
    815                     label = MenuLabel('UI/Inventory/AssetSafety/MoveItemsToSafety')
    816                 menu.append((label, self.MoveItemsInStructureToAssetSafety, (solarSystemID, locationID)))
    817         return menu
    818 
    819     def _GetImportanceMenu(self, locationID, solarSystemID):
    820         m = MenuData()
    821         importanceSetting = settings.char.ui.Get('assets_window_importance', {}).get(locationID, None)
    822         if importanceSetting == IMPORTANCE_PINNED:
    823             label = MenuLabel('UI/Inventory/AssetsWindow/UnpinPersonalAssets')
    824             m.AddEntry(label, lambda : self.Unpin(locationID), texturePath=eveicon.unpin)
    825         elif importanceSetting == IMPORTANCE_HIDDEN:
    826             label = MenuLabel('UI/Inventory/AssetsWindow/UnhidePersonalAssets')
    827             m.AddEntry(label, lambda : self.Unhide(locationID), texturePath=eveicon.hidden)
    828         else:
    829             label = MenuLabel('UI/Inventory/AssetsWindow/PinPersonalAssets')
    830             m.AddEntry(label, lambda : self.Pin(locationID), texturePath=eveicon.pinned)
    831             label = MenuLabel('UI/Inventory/AssetsWindow/HidePersonalAssets')
    832             m.AddEntry(label, lambda : self.Hide(locationID), texturePath=eveicon.visibility)
    833         return m
    834 
    835     def Pin(self, locationID, *args):
    836         if self._SetLocationImportance(locationID, IMPORTANCE_PINNED):
    837             message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationPinned'))
    838 
    839     def Unpin(self, locationID, *args):
    840         if self._SetLocationImportance(locationID, IMPORTANCE_NONE):
    841             message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationUnpinned'))
    842 
    843     def Hide(self, locationID, *args):
    844         if self._SetLocationImportance(locationID, IMPORTANCE_HIDDEN):
    845             message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationHidden'))
    846 
    847     def Unhide(self, locationID, *args):
    848         if self._SetLocationImportance(locationID, IMPORTANCE_NONE):
    849             message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationUnhidden'))
    850 
    851     def _SetLocationImportance(self, locationID, newImportanceValue):
    852         allImportanceSettings = settings.char.ui.Get('assets_window_importance', {})
    853         importanceSetting = allImportanceSettings.get(locationID, IMPORTANCE_NONE)
    854         if importanceSetting == newImportanceValue:
    855             return False
    856         if newImportanceValue == IMPORTANCE_NONE:
    857             allImportanceSettings.pop(locationID, None)
    858         else:
    859             allImportanceSettings[locationID] = newImportanceValue
    860         settings.char.ui.Set('assets_window_importance', allImportanceSettings)
    861         self.ReloadTabs()
    862         return True
    863 
    864     def GetStationSolarSystemIDAndTypeID(self, node):
    865         locationID = node.location.locationID
    866         solarSystemID = stationTypeID = None
    867         if idCheckers.IsStation(locationID):
    868             stationInfo = sm.GetService('ui').GetStationStaticInfo(locationID)
    869             stationTypeID = stationInfo.stationTypeID
    870             solarSystemID = stationInfo.solarSystemID
    871         else:
    872             stations = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStations()
    873             for station in stations:
    874                 if station.stationID == locationID:
    875                     stationTypeID = station.typeID
    876                     solarSystemID = station.solarSystemID
    877                     break
    878 
    879         return (solarSystemID, stationTypeID)
    880 
    881     def MoveItemsInStructureToAssetSafety(self, solarSystemID, structureID):
    882         sm.GetService('assetSafety').MoveItemsInStructureToAssetSafetyForCharacter(solarSystemID, structureID)
    883 
    884     def SetHint(self, hintstr = None):
    885         if self.scroll:
    886             self.scroll.ShowHint(hintstr)
    887 
    888     def OnGroupDeleted(self, ids):
    889         pass
    890 
    891     def OnGroupDragEnter(self, group, drag):
    892         pass
    893 
    894     def LoadInfoTooltip(self, tooltipPanel, *args):
    895         tooltipPanel.LoadGeneric2ColumnTemplate()
    896         tooltipPanel.cellSpacing = 1
    897         tooltipPanel.AddLabelLarge(text=GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearch'), colSpan=2)
    898         tooltipPanel.AddLabelMedium(text='<b>%s' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchKeywords'))
    899         tooltipPanel.AddLabelMedium(wrapWidth=200, text='<b>%s' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchHints'), padLeft=20)
    900         for keywordOption in self.searchKeywords:
    901             tooltipPanel.AddLabelSmall(text='<b>%s:</b>' % keywordOption.keyword, opacity=0.85)
    902             tooltipPanel.AddLabelSmall(wrapWidth=200, text=keywordOption.optionDescription, padLeft=20, opacity=0.75)
    903 
    904         tooltipPanel.AddSpacer(width=0, height=10, colSpan=3)
    905         tooltipPanel.AddLabelMedium(text='<b>%s:' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchExamples'), colSpan=3)
    906         text = '%s:%s' % (GetByLabel('UI/Inventory/AssetSearch/KeywordType'), evetypes.GetName(1230)[:5])
    907         tooltipPanel.AddLabelSmall(text=text, opacity=0.75, colSpan=3, padLeft=10)
    908         text = '%s:%s %s:2 %s:9 %s:0.9' % (GetByLabel('UI/Inventory/AssetSearch/KeywordCategory'),
    909          evetypes.GetCategoryNameByCategory(const.categoryShip),
    910          GetByLabel('UI/Inventory/AssetSearch/KeywordTechLevel'),
    911          GetByLabel('UI/Inventory/AssetSearch/KeywordMetalevel'),
    912          GetByLabel('UI/Inventory/AssetSearch/KeywordMinSecurityLevel'))
    913         tooltipPanel.AddLabelSmall(text=text, opacity=0.75, colSpan=2, padLeft=10)
    914 
    915     def SearchTypeID(self, typeID):
    916         self.tabGroup.SelectByID('search')
    917         searchText = self.GetSearchTextForTypeID(typeID)
    918         if self.search_inited:
    919             self.searchEditBox.SetValue(searchText)
    920         self.searchText = searchText
    921         self.Search()
    922 
    923     def GetSearchTextForTypeID(self, typeID):
    924         return '%s:%s' % (GetByLabel('UI/Inventory/AssetSearch/KeywordTypeExact'), evetypes.GetName(typeID))
    925 
    926     def UnloadTabPanel(self, args, panel, tabgroup):
    927         self._kill_loading_thread_maybe()
    928 
    929     def _start_loading_thread(self, func, *args, **kwargs):
    930         self._kill_loading_thread_maybe()
    931 
    932         def loading_thread():
    933             try:
    934                 func(*args, **kwargs)
    935             finally:
    936                 self._loading_thread = None
    937 
    938         self._loading_thread = uthread2.start_tasklet(loading_thread)
    939 
    940     def _kill_loading_thread_maybe(self):
    941         if self._loading_thread is not None:
    942             self._loading_thread.kill()
    943 
    944     def ShowLoad(self, doBlock = True):
    945         pass
    946 
    947     def HideLoad(self):
    948         pass
    949 
    950 
    951 class UpdateDelayHint(ContainerAutoSize):
    952     ICON_SIZE = 16
    953     _visible = True
    954 
    955     def __init__(self, **kwargs):
    956         super(UpdateDelayHint, self).__init__(**kwargs)
    957         self._layout()
    958 
    959     def _layout(self):
    960         Sprite(parent=self, align=uiconst.CENTER, width=self.ICON_SIZE, height=self.ICON_SIZE, texturePath=eveicon.clock, hint=localization.GetByLabel('UI/Inventory/AssetsWindow/CachedFor5Min'), color=TextColor.DISABLED)
    961 
    962     def UpdateAlignment(self, budgetLeft = 0, budgetTop = 0, budgetWidth = 0, budgetHeight = 0, updateChildrenOnly = False):
    963         required_budget = self.left + self.padLeft + self.ICON_SIZE + self.padRight
    964         if reverse_scale_dpi(budgetWidth) < required_budget:
    965             if self._visible:
    966                 self._visible = False
    967                 animations.FadeOut(self, duration=0.3)
    968         elif not self._visible:
    969             self._visible = True
    970             animations.FadeIn(self, duration=0.3)
    971         return super(UpdateDelayHint, self).UpdateAlignment(budgetLeft, budgetTop, budgetWidth, budgetHeight, updateChildrenOnly)