overviewWindow.py (59317B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\overview\overviewWindow.py 2 import _weakref 3 import appConst 4 import bisect 5 import logging 6 import sys 7 from collections import defaultdict 8 import blue 9 import stackless 10 import telemetry 11 import eveicon 12 import evetypes 13 import gametime 14 import homestation.client 15 import localization 16 import locks 17 import overviewPresets.overviewSettingsConst as osConst 18 import trinity 19 import uthread 20 import uthread2 21 from carbon.client.script.environment.AudioUtil import PlaySound 22 from carbon.common.script.sys.serviceConst import ROLE_GML 23 from carbon.common.script.util.format import FmtDist 24 from carbonui.control.basicDynamicScroll import BasicDynamicScroll 25 from carbonui.control.buttonIcon import ButtonIcon 26 from carbonui.control.contextMenu.menuEntryData import MenuEntryData, MenuEntryDataCheckbox, MenuEntryDataCaption 27 from carbonui.decorative.divider_line import DividerLine 28 from carbonui.uicore import uicore 29 from carbonui.util.color import Color 30 from carbonui.util.various_unsorted import IsUnder 31 from carbonui.util import colorblind 32 from carbonui.window.header.small import SmallWindowHeader 33 from carbonui.window.widget import WidgetWindow 34 from eve.client.script.parklife import states as state 35 from eve.client.script.parklife.overview import overviewSignals 36 from eve.client.script.ui.control.entries.util import GetFromClass 37 from carbonui.window.control.action import WindowMenuAction 38 from eve.client.script.ui.inflight import actionPanelDefaults 39 from eve.client.script.ui.inflight.actions import ActionPanel 40 from eve.client.script.ui.inflight.bracketsAndTargets.bracketVarious import GetIconColor 41 from eve.client.script.ui.inflight.overViewLabel import OverviewLabel, SortHeaders 42 from eve.client.script.ui.inflight.overview import overviewConst, overviewColumns, overviewSettings, overviewPulse 43 from eve.client.script.ui.inflight.overview.addTabPopup import AddTabPopup 44 from eve.client.script.ui.inflight.overview.overviewConst import * 45 from eve.client.script.ui.inflight.overview.overviewMenuUtil import GetBracketVisibilitySubMenu, GetColumnVisibilitySubMenu 46 from eve.client.script.ui.inflight.overview.overviewNodeUtil import PrimeDisplayName, UpdateIconAndBackgroundFlagsOnNode, PrimeCorpAndAllianceName, UpdateVelocityData 47 from eve.client.script.ui.inflight.overview.overviewScrollEntry import OverviewScrollEntry 48 from eve.client.script.ui.inflight.overview.overviewTabGroup import OverviewTabGroup 49 from eve.client.script.ui.inflight.overview.overviewUtil import GetSortValueWhenBroadcastGoToTop, GetAllianceTickerName, GetCorpTickerName, PrepareLocalizationTooltip, GetSlimItemForCharID, GetEntryFontSize, GetEntryHeight, GetColumnValuesToCalculate, GetColumnSettingsAndSortKeys 50 from eve.client.script.ui.inflight.overview.slimItemDisplayChecker import SlimItemDisplayChecker 51 from eve.client.script.ui.shared.pointerTool import pointerToolConst as pConst 52 from eve.client.script.ui.shared.stateFlag import GetIconFlagAndBackgroundFlag, FindDockingRightsToDisplay, GetGateLockValue, GetLockedToGateID, GetGateLockValueForSlimItem 53 from eve.common.lib import appConst as const 54 from eve.common.script.sys.idCheckers import IsSolarSystem 55 from eveexceptions import ExceptionEater 56 from globalConfig.getFunctions import GetOverviewMousemovementTimeout 57 from inventorycommon.util import IsNPC 58 from menu import MenuLabel 59 from npcs.npccorporations import get_corporation_faction_id 60 from overviewPresets.overviewSettingsConst import SETTING_TAB_NAME, SETTING_TAB_COLOR, MAX_TAB_NUM 61 from spacecomponents.common.helper import GetMineableComponentTypeAttributes, HasMineableComponent 62 from stargate.client.gate_signals import on_lock_removed 63 from structures import STATE_UNANCHORED, DOCKING_ACCESS_UNKNOWN 64 from structures.types import IsFlexStructure 65 from uihider import UiHiderMixin 66 ScrollListLock = locks.RLock() 67 log = logging.getLogger(__name__) 68 69 class OverviewWindow(UiHiderMixin, WidgetWindow): 70 __notifyevents__ = ['OnDestinationSet', 71 'OnOverviewPresetsChanged', 72 'OnReloadingOverviewProfile', 73 'OnEwarStart', 74 'OnEwarEnd', 75 'OnStateSetupChange', 76 'OnSessionChanged', 77 'OnFleetJoin_Local', 78 'OnFleetLeave_Local', 79 'OnPostCfgDataChanged', 80 'OnOverviewPresetLoaded', 81 'OnFleetStateChange', 82 'OnStateChange', 83 'DoBallsAdded', 84 'DoBallRemove', 85 'OnSlimItemChange', 86 'OnContactChange', 87 'OnItemHighlighted', 88 'ProcessBountyInfoUpdated', 89 'DoBallsRemove', 90 'OnStructuresVisibilityUpdated', 91 'OnEnterSpace', 92 'OnRefreshWhenDockingRequestDenied', 93 'OnStructureAccessUpdated', 94 'OnOverviewOverrideChangedOnDoBallAddEgoChange', 95 'OnShipLabelsUpdated', 96 'OnFullOverviewReload', 97 'OnFreezeOverviewWindows', 98 'OnUnfreezeOverviewWindows', 99 'OnFlagsInvalidated', 100 'OnOverviewTabsChanged', 101 'OnBracketIconUpdated', 102 'OnEmanationLockUpdated'] 103 default_windowID = overviewConst.WINDOW_ID 104 default_open = True 105 default_cursor = uiconst.UICURSOR_HASMENU 106 default_isKillable = False 107 default_scope = uiconst.SCOPE_INFLIGHT 108 default_minSize = (128, 128) 109 default_iconNum = 'res:/ui/Texture/WindowIcons/overview.png' 110 sortingFrozen = False 111 uniqueUiName = pConst.UNIQUE_NAME_OVERVIEW_WND 112 _tab_line = None 113 114 @staticmethod 115 def default_left(*args): 116 return actionPanelDefaults.GetOverviewLeft() 117 118 @staticmethod 119 def default_top(*args): 120 return actionPanelDefaults.GetOverviewTop() 121 122 @staticmethod 123 def default_width(): 124 return actionPanelDefaults.GetOverviewWidth() 125 126 @staticmethod 127 def default_height(): 128 return actionPanelDefaults.GetOverviewHeight() 129 130 @telemetry.ZONE_METHOD 131 def ApplyAttributes(self, attributes): 132 self.stateSvc = sm.GetService('stateSvc') 133 self.fleetSvc = sm.GetService('fleet') 134 self.machoNet = sm.GetService('machoNet') 135 self.presetSvc = sm.GetService('overviewPresetSvc') 136 self.michelle = sm.GetService('michelle') 137 super(OverviewWindow, self).ApplyAttributes(attributes) 138 self.updateEntryOrderThread = None 139 self._freezeOverview = False 140 self._ballparkDirty = True 141 self._scrollEntriesDirty = True 142 self._scrollNodesByItemID = {} 143 self.displayChecker = SlimItemDisplayChecker() 144 self.tabGroup = None 145 self._update_extend_content_into_header() 146 self.jammers = {} 147 self.ewarTypes = self.stateSvc.GetEwarTypes() 148 self.ewarHintsByGraphicID = {} 149 for jamType, (flag, graphicID) in self.ewarTypes: 150 self.ewarHintsByGraphicID[graphicID] = self.stateSvc.GetEwarHint(jamType) 151 152 self.prevMouseCoords = trinity.mainWindow.GetCursorPos() 153 self.lastMovementTime = blue.os.GetWallclockTime() 154 self.mouseMovementTimeout = GetOverviewMousemovementTimeout(self.machoNet) 155 homeStationService = homestation.Service.instance() 156 if not homeStationService.is_home_station_data_loaded: 157 uthread.new(homeStationService.get_home_station) 158 self._ConnectSignals() 159 self.tabGroup = OverviewTabGroup(align=uiconst.TOTOP, parent=self.content, padding=self._get_tab_group_padding(), groupID='overviewTabs', UIIDPrefix='OverviewTab_', callback=self.OnTabSelected, show_line=False) 160 self._tab_line = DividerLine(parent=self.content, align=uiconst.TOTOP_NOPUSH, top=self._get_tab_line_top(), padding=self._get_tab_line_padding()) 161 self.ConstructScroll() 162 self.ReconstructTabs() 163 164 def ConstructScroll(self): 165 self.scroll = BasicDynamicScroll(name='overviewscroll2', align=uiconst.TOALL, parent=self.content, multiSelect=False, autoPurgeHiddenEntries=False) 166 self.scroll.OnSelectionChange = self.OnScrollSelectionChange 167 self.scroll.OnChar = self.OnChar 168 self.scroll.OnKeyUp = self.OnKeyUp 169 self.sortHeaders = SortHeaders(parent=self.scroll.sr.maincontainer, settingsID='overviewScroll2', idx=0, get_menu_func=self.GetMenuForsortHeaders) 170 self.sortHeaders.SetDefaultColumn(COLUMN_DISTANCE, True) 171 self.sortHeaders.OnColumnSizeChange = self.OnColumnSizeChanged 172 self.sortHeaders.OnSortingChange = self.OnSortingChange 173 self.sortHeaders.OnColumnSizeReset = self.OnColumnSizeReset 174 175 def GetMenuForsortHeaders(self): 176 return GetColumnVisibilitySubMenu(self.GetSelectedTabID()) 177 178 def GetScrollContent(self): 179 return self.scroll.sr.content 180 181 def _ConnectSignals(self): 182 homeStationService = homestation.Service.instance() 183 homeStationService.on_home_station_changed.connect(self._OnHomeStationChanged) 184 homeStationService.on_home_station_data_loaded.connect(self._UpdateHomeStation) 185 self.on_compact_mode_changed.connect(self._on_compact_mode_changed) 186 self.on_header_inset_changed.connect(self._on_header_inset_changed) 187 self.on_content_padding_changed.connect(self._on_content_padding_changed) 188 overviewSignals.on_preset_saved.connect(self.OnOverviewPresetsChanged) 189 overviewSignals.on_preset_saved_as.connect(self.OnPresetSavedAs) 190 overviewSignals.on_preset_restored.connect(self.OnOverviewPresetsChanged) 191 overviewSignals.on_tab_columns_changed.connect(self.OnTabColumnsChanged) 192 overviewPulse.connect_to_visible_entry_update_pulse(self.OnVisibleEntryUpdatePulse) 193 colorblind.on_colorblind_mode_changed.connect(self.OnColorblindModeChanged) 194 on_lock_removed.connect(self.OnEmanationGateLockRemoved) 195 196 def OnVisibleEntryUpdatePulse(self): 197 if self.destroyed: 198 return 199 self.LoadVisibleEntries() 200 201 def OnTabColumnsChanged(self, tabID): 202 if tabID == self.GetSelectedTabID(): 203 self.ReconstructTabs() 204 self.FullReload() 205 206 def OnPresetSavedAs(self, oldPresetName, presetName): 207 tabID = self.GetSelectedTabID() 208 currTabPresetName = self.presetSvc.GetTabPreset(tabID) 209 (oldPresetName, 210 presetName, 211 currTabPresetName, 212 tabID, 213 self.destroyed) 214 if oldPresetName != presetName and currTabPresetName == oldPresetName: 215 self.presetSvc.SetTabPreset(tabID, presetName) 216 self.OnOverviewPresetsChanged() 217 218 def _on_compact_mode_changed(self, window): 219 self.header.show_caption = not self.compact 220 self._update_extend_content_into_header() 221 self._update_tab_line_top() 222 self.ReconstructTabs() 223 self.FullReload() 224 225 def _on_content_padding_changed(self, window): 226 self._update_tab_line_padding() 227 self._update_tabs_padding() 228 229 def _on_header_inset_changed(self, window): 230 self._update_tabs_padding() 231 232 def _update_extend_content_into_header(self): 233 self.extend_content_into_header = self.compact 234 235 def _get_tab_line_padding(self): 236 pad_left, _, pad_right, _ = self.content_padding 237 return (-pad_left, 238 0, 239 -pad_right, 240 0) 241 242 def _update_tab_line_padding(self): 243 if self._tab_line: 244 self._tab_line.padding = self._get_tab_line_padding() 245 246 def _get_tab_line_top(self): 247 _, _, _, tabs_pad_bottom = self._get_tab_group_padding() 248 return -1 - tabs_pad_bottom 249 250 def _update_tab_line_top(self): 251 if self._tab_line: 252 self._tab_line.top = self._get_tab_line_top() 253 254 def _get_tab_group_padding(self): 255 _, inset_right = self.header_inset 256 _, pad_top, pad_right, _ = self.content_padding 257 return (0, 258 -8, 259 inset_right - pad_right if self.compact else -4, 260 4 if self.compact else 8) 261 262 def _update_tabs_padding(self): 263 self.tabGroup.padding = self._get_tab_group_padding() 264 265 def Prepare_Header_(self): 266 self._SetHeader(SmallWindowHeader(show_caption=not self.compact)) 267 268 def get_wnd_menu_unique_name(self): 269 return pConst.UNIQUE_NAME_OVERVIEW_SETTINGS 270 271 def Close(self, setClosed = False, *args, **kwds): 272 ActionPanel.Close(self) 273 with ExceptionEater('closing OverviewWindow'): 274 homeStationService = homestation.Service.instance() 275 homeStationService.on_home_station_changed.disconnect(self._OnHomeStationChanged) 276 homeStationService.on_home_station_data_loaded.disconnect(self._UpdateHomeStation) 277 on_lock_removed.disconnect(self.OnEmanationGateLockRemoved) 278 279 @telemetry.ZONE_METHOD 280 def DoBallsRemove(self, pythonBalls, isRelease): 281 for ball, slimItem, terminal in pythonBalls: 282 self.DoBallRemove(ball, slimItem, terminal) 283 284 def DoBallRemove(self, ball, slimItem, terminal): 285 if ball is None: 286 return 287 itemID = slimItem.itemID 288 node = self._scrollNodesByItemID.get(itemID, None) 289 if node: 290 node.leavingOverview = True 291 if node.panel: 292 node.panel.opacity = 0.25 293 node.panel.state = uiconst.UI_DISABLED 294 if node.itemID in self._scrollNodesByItemID: 295 del self._scrollNodesByItemID[node.itemID] 296 297 def DoBallsAdded(self, lst, *args, **kw): 298 uthread.new(self._DoBallsAdded, lst, *args, **kw) 299 300 @telemetry.ZONE_METHOD 301 def _DoBallsAdded(self, lst, *args, **kw): 302 columns = overviewColumns.GetColumns(self.GetSelectedTabID()) 303 if self.sortHeaders.GetCurrentColumns() != columns: 304 self.sortHeaders.CreateColumns(columns, fixedColumns=FIXEDCOLUMNS) 305 with ScrollListLock: 306 newEntries = [] 307 for ball, slimItem in lst: 308 if slimItem.itemID in self._scrollNodesByItemID: 309 continue 310 if not self.displayChecker.ShouldDisplayItem(slimItem): 311 continue 312 updateItem = self.stateSvc.CheckIfUpdateItem(slimItem) 313 newNode = GetFromClass(OverviewScrollEntry, {'itemID': slimItem.itemID, 314 'updateItem': updateItem}) 315 newNode.ball = _weakref.ref(ball) 316 newNode.slimItem = _weakref.ref(slimItem) 317 if updateItem: 318 newNode.ewarGraphicIDs = self.GetEwarDataForNode(newNode) 319 newNode.ewarHints = self.ewarHintsByGraphicID 320 newEntries.append(newNode) 321 322 if newEntries: 323 self._UpdateStaticDataForNodes(newEntries) 324 self._UpdateDynamicDataForNodes(newEntries) 325 currentActive, currentDirection = self.sortHeaders.GetCurrentActive() 326 broadcastsToTop = self.presetSvc.GetSettingValueBroadcastToTop() 327 fleetBroadcasts = self.fleetSvc.GetCurrentFleetBroadcasts() 328 329 def GetSortValue(_node): 330 if broadcastsToTop: 331 return GetSortValueWhenBroadcastGoToTop(_node, fleetBroadcasts, currentDirection) 332 return _node.sortValue 333 334 self.scroll.ShowHint() 335 if self.sortingFrozen: 336 newEntries.sort(key=lambda x: GetSortValue(x), reverse=not currentDirection) 337 self.scroll.AddNodes(-1, newEntries) 338 else: 339 sortValues = [ GetSortValue(x) for x in self.scroll.sr.nodes ] 340 entriesAtIdx = defaultdict(list) 341 for entry in newEntries: 342 insertionIndex = bisect.bisect(sortValues, GetSortValue(entry)) 343 entriesAtIdx[insertionIndex].append(entry) 344 345 insertionPoints = sorted(entriesAtIdx.keys(), reverse=True) 346 for insertionIdx in insertionPoints: 347 sortedGroup = sorted(entriesAtIdx[insertionIdx], key=GetSortValue, reverse=not currentDirection) 348 self.scroll.AddNodes(insertionIdx, sortedGroup) 349 350 def UpdateUIScaling(self, value, oldValue): 351 super(OverviewWindow, self).UpdateUIScaling(value, oldValue) 352 self.FullReload() 353 354 def OnStateChange(self, itemID, flag, newState, *args): 355 node = self._scrollNodesByItemID.get(itemID, None) 356 if node and node.panel: 357 node.panel.OnStateChange(itemID, flag, newState, *args) 358 if flag in (state.flagWreckEmpty, state.flagWreckAlreadyOpened): 359 self.FlagBallparkDirty() 360 361 def OnFleetStateChange(self, fleetState): 362 if not fleetState: 363 return 364 for itemID, tag in fleetState.targetTags.iteritems(): 365 node = self._scrollNodesByItemID.get(itemID, None) 366 if node is None: 367 continue 368 node.display_TAG = tag 369 if node.sortTagIndex is not None: 370 if tag: 371 node.sortValue[node.sortTagIndex] = tag.lower() 372 else: 373 node.sortValue[node.sortTagIndex] = 0 374 375 def OnSlimItemChange(self, oldSlim, newSlim): 376 node = self._scrollNodesByItemID.get(oldSlim.itemID, None) 377 if node: 378 node.slimItem = _weakref.ref(newSlim) 379 node.iconColor = None 380 PrimeDisplayName(node) 381 currentActive, _ = self.sortHeaders.GetCurrentActive() 382 columnSettings, _ = GetColumnSettingsAndSortKeys(currentActive, self.GetSelectedTabID()) 383 PrimeCorpAndAllianceName(node, columnSettings) 384 UpdateIconAndBackgroundFlagsOnNode(node) 385 if node.panel: 386 node.panel.UpdateIcon() 387 388 def ProcessBountyInfoUpdated(self, itemIDs): 389 for itemID in itemIDs: 390 node = self._scrollNodesByItemID.get(itemID, None) 391 if node is not None: 392 UpdateIconAndBackgroundFlagsOnNode(node) 393 394 def FlushEwarStates(self): 395 if self.jammers: 396 currentSourceIDs = self.jammers.keys() 397 self.jammers = {} 398 for sourceBallID in currentSourceIDs: 399 self.UpdateEwarStateOnItemID(sourceBallID) 400 401 def OnEwarStart(self, sourceBallID, moduleID, targetBallID, jammingType): 402 if targetBallID != session.shipid: 403 return 404 if not jammingType: 405 return 406 if not hasattr(self, 'jammers'): 407 self.jammers = {} 408 jammingID = sm.StartService('stateSvc').GetEwarGraphicID(jammingType) 409 if sourceBallID not in self.jammers: 410 self.jammers[sourceBallID] = {} 411 if jammingID not in self.jammers[sourceBallID]: 412 self.jammers[sourceBallID][jammingID] = {} 413 self.jammers[sourceBallID][jammingID][moduleID] = True 414 self.UpdateEwarStateOnItemID(sourceBallID) 415 416 def OnEwarEnd(self, sourceBallID, moduleID, targetBallID, jammingType): 417 if targetBallID != session.shipid: 418 return 419 if not jammingType: 420 return 421 if not hasattr(self, 'jammers'): 422 return 423 jammingID = sm.StartService('stateSvc').GetEwarGraphicID(jammingType) 424 if sourceBallID not in self.jammers or jammingID not in self.jammers[sourceBallID] or moduleID not in self.jammers[sourceBallID][jammingID]: 425 return 426 del self.jammers[sourceBallID][jammingID][moduleID] 427 if self.jammers[sourceBallID][jammingID] == {}: 428 del self.jammers[sourceBallID][jammingID] 429 self.UpdateEwarStateOnItemID(sourceBallID) 430 431 def UpdateEwarStateOnItemID(self, itemID): 432 node = self._scrollNodesByItemID.get(itemID, None) 433 if node is None: 434 return 435 node.ewarGraphicIDs = self.GetEwarDataForNode(node) 436 if node.panel: 437 node.panel.UpdateEwar() 438 439 def GetEwarDataForNode(self, node): 440 if node.itemID not in self.jammers: 441 return 442 jammersOnItem = self.jammers.get(node.itemID, None) 443 if not jammersOnItem: 444 return 445 ret = [] 446 for jamType, (flag, graphicID) in self.ewarTypes: 447 if graphicID in jammersOnItem: 448 ret.append(graphicID) 449 450 return ret 451 452 def OnOverviewPresetLoaded(self, presetName, preset): 453 self.FlagScrollEntriesAndBallparkDirty_InstantUpdate('OnOverviewPresetLoaded') 454 455 def UpdateWindowCaption(self, presetName): 456 presetDisplayName = self.presetSvc.GetPresetDisplayName(presetName) 457 text = localization.GetByLabel('UI/Tactical/OverviewCaption', preset=presetDisplayName) 458 if overviewSettings.show_debug_info.is_enabled(): 459 text += ' windowInstanceID=%s' % self.windowInstanceID 460 self.SetCaption(text) 461 462 def OnPostCfgDataChanged(self, what, data): 463 if what == 'evelocations': 464 itemID = data[0] 465 if itemID in self._scrollNodesByItemID: 466 node = self._scrollNodesByItemID[itemID] 467 PrimeDisplayName(node) 468 469 def OnDestinationSet(self, *etc): 470 for node in self.scroll.sr.nodes: 471 slimItem = node.slimItem() 472 if not slimItem: 473 continue 474 if slimItem.groupID not in (const.groupStargate, const.groupStation) and slimItem.categoryID != const.categoryStructure: 475 continue 476 node.iconColor = None 477 478 def OnContactChange(self, contactIDs, contactType = None): 479 self.FlagBallparkDirty() 480 481 def OnFleetJoin_Local(self, member, *args): 482 self.UpdateFleetMemberOrFlagDirty(member) 483 self.FlagBallparkDirty() 484 485 def OnFleetLeave_Local(self, member, *args): 486 self.UpdateFleetMemberOrFlagDirty(member) 487 self.FlagBallparkDirty() 488 489 def OnDoBallAddEgoChange(self): 490 self.TriggerInstantUpdate('OnDoBallAddEgoChange') 491 492 def OnShipLabelsUpdated(self): 493 self.FullReload() 494 495 def OnFullOverviewReload(self): 496 self.FullReload() 497 498 def UpdateFleetMemberOrFlagDirty(self, member): 499 if member.charID == session.charid: 500 self.FlagScrollEntriesDirty('UpdateFleetMemberOrFlagDirty') 501 else: 502 slimItem = GetSlimItemForCharID(member.charID) 503 if slimItem and slimItem.itemID in self._scrollNodesByItemID: 504 node = self._scrollNodesByItemID[slimItem.itemID] 505 UpdateIconAndBackgroundFlagsOnNode(node) 506 507 def _OnHomeStationChanged(self): 508 homeStationService = homestation.Service.instance() 509 if not homeStationService.is_home_station_data_loaded: 510 uthread.new(homeStationService.get_home_station) 511 512 def _UpdateHomeStation(self): 513 homeStation = homestation.Service.instance().get_home_station() 514 for node in self.scroll.sr.nodes: 515 isHomeStation = node.itemID == homeStation.id 516 if isHomeStation != node.isHomeStation: 517 node.isHomeStation = isHomeStation 518 if node.panel and node.panel.state != uiconst.UI_HIDDEN: 519 node.panel.Load(node) 520 UpdateIconAndBackgroundFlagsOnNode(node) 521 522 def OnRefreshWhenDockingRequestDenied(self, structureID): 523 self._RefreshStructureDockingAccess(structureID) 524 525 def OnStructureAccessUpdated(self): 526 structuresInOverview = {node.itemID for node in self.scroll.sr.nodes if node.slimItem and node.slimItem().categoryID == const.categoryStructure} 527 for eachStructureID in structuresInOverview: 528 self._RefreshStructureDockingAccess(eachStructureID) 529 530 def _RefreshStructureDockingAccess(self, structureID): 531 ballpark = self.michelle.GetBallpark() 532 if not ballpark: 533 return 534 slimItem = ballpark.GetInvItem(structureID) 535 if not slimItem: 536 return 537 if IsFlexStructure(slimItem.typeID): 538 return 539 node = self._scrollNodesByItemID.get(slimItem.itemID, None) 540 if node: 541 hasDockingRights = FindDockingRightsToDisplay(sm.GetService('structureProximityTracker'), slimItem) 542 node.hasDockingRights = hasDockingRights 543 if node.panel and node.panel.state != uiconst.UI_HIDDEN: 544 node.panel.Load(node) 545 node.panel.UpdateIcon() 546 547 def OnFlagsInvalidated(self, itemIDs = None): 548 if itemIDs: 549 self.UpdateAllIconAndBackgroundFlagsForItemIDs(itemIDs) 550 else: 551 self.UpdateAllIconAndBackgroundFlagsForAllNodes() 552 553 @telemetry.ZONE_METHOD 554 def UpdateAllIconAndBackgroundFlagsForAllNodes(self): 555 for node in self.scroll.sr.nodes: 556 self.UpdateAllIconAndBackgroundFlagsForNode(node) 557 558 @telemetry.ZONE_METHOD 559 def UpdateAllIconAndBackgroundFlagsForItemIDs(self, itemIDs): 560 for eachItemID in itemIDs: 561 node = self._scrollNodesByItemID.get(eachItemID, None) 562 if node: 563 self.UpdateAllIconAndBackgroundFlagsForNode(node) 564 565 def UpdateAllIconAndBackgroundFlagsForNode(self, node): 566 if node.updateItem: 567 UpdateIconAndBackgroundFlagsOnNode(node) 568 else: 569 slimItem = node.slimItem() 570 if slimItem is not None and slimItem.groupID in const.containerGroupIDs: 571 node.iconColor = None 572 if node.panel is not None: 573 node.panel.UpdateIconColor() 574 575 def OnReloadingOverviewProfile(self): 576 self.FullReload() 577 578 def OnOverviewPresetsChanged(self, *args): 579 self.ReconstructTabs() 580 581 def OnOverviewTabsChanged(self): 582 self.ReconstructTabs() 583 584 def OnColorblindModeChanged(self): 585 self.ReconstructTabs() 586 587 def OnBracketIconUpdated(self, itemID): 588 node = self._scrollNodesByItemID.get(itemID, None) 589 if node and node.panel: 590 node.panel.UpdateIcon() 591 592 def ReconstructTabs(self): 593 if self.destroyed: 594 return 595 selectedID = self.tabGroup.GetSelectedID() 596 tabIDs = self.presetSvc.GetTabIDs(self.windowInstanceID) 597 if tabIDs is None: 598 self.Close() 599 return 600 self.tabGroup.Flush() 601 self._ConstructTabs(tabIDs) 602 self._update_tabs_padding() 603 self._update_window_controls() 604 numTabs = len(self.presetSvc.GetSettingsByTabID()) 605 if not self.presetSvc.IsReadOnly(): 606 if numTabs < MAX_TAB_NUM and not self.compact: 607 self.tabGroup.AddButton(icon=eveicon.add, func=self.AddTab, hint=localization.GetByLabel('UI/Overview/AddTab')) 608 if selectedID is not None and selectedID in tabIDs: 609 self.tabGroup.SelectByID(selectedID) 610 else: 611 self.tabGroup.AutoSelect() 612 sm.ScatterEvent('OnOverviewTabsReconstructed') 613 614 def _ShouldShowBracketDictatingIconButton(self): 615 return self.presetSvc.IsBracketFilterDictatingWindow(self.windowInstanceID) and len(self.presetSvc.GetWindowInstanceIDs()) > 1 616 617 def _ConstructTabs(self, tabIDs): 618 for tabID in tabIDs: 619 tabSettings = self.presetSvc.GetTabSettings(tabID) 620 if not tabSettings: 621 log.warning('No settings found for tabID=%s' % tabID) 622 continue 623 tabName = tabSettings.get(SETTING_TAB_NAME, None).strip() 624 tabColor = tabSettings.get(SETTING_TAB_COLOR, None) 625 if tabColor: 626 hexColor = Color.RGBtoHex(*tabColor) 627 tabName = '<color=%s>%s</color>' % (hexColor, tabName) 628 self.tabGroup.AddTab(tabName, tabID=tabID) 629 630 def GetCustomHeaderButtons(self): 631 actions = super(OverviewWindow, self).GetCustomHeaderButtons() 632 if not self.presetSvc.IsReadOnly() and self._ShouldShowBracketDictatingIconButton(): 633 actions.append(WindowMenuAction(window=self, label=localization.GetByLabel('UI/Overview/DictateBracketFilterHint'), icon=eveicon.brackets, callback=self.BracketButtonMenuCallback)) 634 return actions 635 636 def BracketButtonMenuCallback(self, window): 637 return [MenuEntryDataCaption(MenuLabel('UI/Overview/BracketVisibility'))] + GetBracketVisibilitySubMenu() 638 639 def OnStateSetupChange(self, reason = None): 640 self.FlagScrollEntriesDirty('OnStateSetupChange') 641 642 def AddTab(self): 643 PlaySound(uiconst.SOUND_BUTTON_CLICK) 644 addTabPopup = AddTabPopup.Open() 645 if addTabPopup.ShowModal() != 1: 646 return 647 name, overviewPreset, bracketPreset, inNewWindow = addTabPopup.result 648 wndInstanceID = None if inNewWindow else self.windowInstanceID 649 self.presetSvc.AddTab(name, overviewPreset, bracketPreset, wndInstanceID) 650 651 def _SetOpacity(self, value): 652 if self.sr.underlay: 653 display = True if value else False 654 self.sr.underlay.display = display 655 super(OverviewWindow, self)._SetOpacity(value) 656 657 def OnSetActive_(self, *args): 658 if self.scroll is not None: 659 selected = self.scroll.GetSelected() 660 if selected is None: 661 self.scroll.SetSelected(0) 662 663 def OnKeyUp(self, *args): 664 selected = self.scroll.GetSelected() 665 if not selected: 666 return 667 uicore.cmd.ExecuteCombatCommand(selected[0].itemID, uiconst.UI_KEYUP) 668 669 def OnChar(self, *args): 670 return False 671 672 def OnTabSelected(self, tabID, oldTabID): 673 self.presetSvc.LoadTab(tabID) 674 self.displayChecker.UpdateState(tabID) 675 self.sortHeaders.SetSubSettingID(tabID) 676 presetName = self.presetSvc.GetTabPreset(tabID) 677 self.UpdateWindowCaption(presetName) 678 679 def OnColumnSizeReset(self, columnID): 680 fontSize = GetEntryFontSize() 681 labelClass = OverviewLabel 682 widths = [COLUMNMINSIZE - COLUMNMARGIN * 2] 683 for node in self.scroll.sr.nodes: 684 displayValue = OverviewScrollEntry.GetColumnDisplayValue(node, columnID) 685 if displayValue: 686 textWidth, textHeight = labelClass.MeasureTextSize(displayValue, fontSize=fontSize) 687 widths.append(textWidth) 688 689 self.sortHeaders.SetColumnSize(columnID, max(widths) + COLUMNMARGIN * 2) 690 self.TriggerInstantUpdate('OnColumnSizeReset') 691 692 def OnColumnSizeChanged(self, columnID, headerWidth, currentSizes, *args): 693 self.TriggerInstantUpdate('OnColumnSizeChanged') 694 695 def OnSortingChange(self, oldColumnID, columnID, oldSortDirection, sortDirection): 696 if oldColumnID == columnID and oldSortDirection != sortDirection: 697 self.TriggerInstantUpdate('OnSortingChange') 698 else: 699 self.FlagScrollEntriesDirty_InstantUpdate('OnSortingChange') 700 701 def OnScrollSelectionChange(self, nodes, *args): 702 if not nodes: 703 return 704 node = nodes[0] 705 if node and node.itemID: 706 self.stateSvc.SetState(node.itemID, state.selected, 1) 707 if sm.GetService('target').IsTarget(node.itemID): 708 self.stateSvc.SetState(node.itemID, state.activeTarget, 1) 709 710 def GetMenuMoreOptions(self): 711 m = [] 712 if session.role & ROLE_GML: 713 m.append(MenuEntryData('GM / WM Extras', subMenuData=self.GetDevMenu)) 714 if self.presetSvc.IsReadOnly(): 715 return m 716 m.append(MenuEntryData(MenuLabel('UI/Overview/AddTab'), self.AddTab, texturePath=eveicon.add.resolve(16))) 717 m.append(MenuEntryData(MenuLabel('UI/Commands/OpenOverviewSettings'), sm.GetService('tactical').OpenSettings, texturePath=eveicon.settings)) 718 if len(self.presetSvc.GetWindowInstanceIDs()) == 1: 719 m.append(MenuEntryData(MenuLabel('UI/Overview/BracketVisibility'), subMenuData=GetBracketVisibilitySubMenu())) 720 return super(OverviewWindow, self).GetMenuMoreOptions() + m 721 722 def GetDevMenu(self): 723 m = self.presetSvc.GetPresetsMenuElevated() 724 m += [None, MenuEntryDataCheckbox('Show debug info', setting=overviewSettings.show_debug_info)] 725 return m 726 727 def _GetDeletePresetsSubMenu(self): 728 allPresets = self.presetSvc.GetAllPresets().copy() 729 for name in self.presetSvc.GetDefaultOverviewPresetNames(): 730 if name in allPresets: 731 del allPresets[name] 732 733 m = [] 734 for label in allPresets: 735 m.append(MenuEntryData(label, lambda l = label: self.presetSvc.DeletePreset(l))) 736 737 m.sort(key=lambda menuEntry: menuEntry.GetText()) 738 return m 739 740 def Cleanup(self): 741 pass 742 743 @telemetry.ZONE_METHOD 744 def UpdateAll(self, *args, **kwds): 745 pass 746 747 @telemetry.ZONE_METHOD 748 def FullReload(self): 749 self.StopOverviewUpdate() 750 self.scroll.Clear() 751 self._scrollNodesByItemID = {} 752 self.FlagScrollEntriesAndBallparkDirty_InstantUpdate() 753 754 def StopOverviewUpdate(self): 755 if self.updateEntryOrderThread: 756 self.updateEntryOrderThread.kill() 757 self.updateEntryOrderThread = None 758 759 def TriggerInstantUpdate(self, fromFunction = None): 760 self.StopOverviewUpdate() 761 if self.IsCollapsed() or self.IsMinimized(): 762 return 763 self.UpdateEntryOrder() 764 765 def FlagBallparkDirty(self, fromFunction = None): 766 self._ballparkDirty = True 767 if self.IsCollapsed() or self.IsMinimized(): 768 self.StopOverviewUpdate() 769 return 770 if not self.updateEntryOrderThread: 771 self.updateEntryOrderThread = uthread.new(self.UpdateEntryOrder) 772 773 def FlagScrollEntriesAndBallparkDirty_InstantUpdate(self, fromFunction = None): 774 self._ballparkDirty = True 775 self._scrollEntriesDirty = True 776 self.TriggerInstantUpdate('FlagScrollEntriesDirtyDirty_InstantUpdate') 777 778 def FlagScrollEntriesDirty_InstantUpdate(self, fromFunction = None): 779 self._scrollEntriesDirty = True 780 self.TriggerInstantUpdate('FlagScrollEntriesDirtyDirty_InstantUpdate') 781 782 def FlagScrollEntriesDirty(self, fromFunction = None): 783 self._scrollEntriesDirty = True 784 if self.IsCollapsed() or self.IsMinimized(): 785 self.StopOverviewUpdate() 786 return 787 if not self.updateEntryOrderThread: 788 self.updateEntryOrderThread = uthread.new(self.UpdateEntryOrder) 789 790 @telemetry.ZONE_METHOD 791 def _UpdateStaticDataForNodes(self, nodeList): 792 structureProximityTrackerSvc = sm.GetService('structureProximityTracker') 793 isDockingAccessUnknown = structureProximityTrackerSvc.HasDockingAccessChanged() 794 emanationLockedGateID = GetLockedToGateID() 795 usingLocalizationTooltips = localization.UseImportantTooltip() 796 useSmallColorTags = self.presetSvc.GetSettingValueOrDefaultFromName(osConst.SETTING_NAME_SMALL_TAGS, False) 797 useSmallText = self.presetSvc.GetSettingValueOrDefaultFromName(osConst.SETTING_NAME_SMALL_TEXT, False) 798 columnWidths = self.sortHeaders.GetCurrentSizes() 799 currentActive, _ = self.sortHeaders.GetCurrentActive() 800 columnSettings, sortKeys = GetColumnSettingsAndSortKeys(currentActive, self.GetSelectedTabID()) 801 showIcon, sortIconIndex = columnSettings[COLUMN_ICON] 802 showName, sortNameIndex = columnSettings[COLUMN_NAME] 803 showDistance, sortDistanceIndex = columnSettings[COLUMN_DISTANCE] 804 showSize, sortSizeIndex = columnSettings[COLUMN_SIZE] 805 showAlliance, sortAllianceIndex = columnSettings[COLUMN_ALLIANCE] 806 showType, sortTypeIndex = columnSettings[COLUMN_TYPE] 807 showTag, sortTagIndex = columnSettings[COLUMN_TAG] 808 showCorporation, sortCorporationIndex = columnSettings[COLUMN_CORPORATION] 809 showFaction, sortFactionIndex = columnSettings[COLUMN_FACTION] 810 showMilitia, sortMilitiaIndex = columnSettings[COLUMN_MILITIA] 811 showVelocity, sortVelocityIndex = columnSettings[COLUMN_VELOCITY] 812 showRadialVelocity, sortRadialVelocityIndex = columnSettings[COLUMN_RADIALVELOCITY] 813 showAngularVelocity, sortAngularVelocityIndex = columnSettings[COLUMN_ANGULARVELOCITY] 814 showTransversalVelocity, sortTransversalVelocityIndex = columnSettings[COLUMN_TRANSVERSALVELOCITY] 815 defaultSortValue = [ 0 for _ in sortKeys ] 816 inFleet = bool(session.fleetid) 817 for node in nodeList: 818 slimItem = node.slimItem() 819 ball = node.ball() 820 if not (ball and slimItem): 821 node.leavingOverview = True 822 if node.itemID in self._scrollNodesByItemID: 823 del self._scrollNodesByItemID[node.itemID] 824 continue 825 self._scrollNodesByItemID[node.itemID] = node 826 node.usingLocalizationTooltips = usingLocalizationTooltips 827 node.useSmallText = useSmallText 828 node.useSmallColorTags = useSmallColorTags 829 node.decoClass.ENTRYHEIGHT = GetEntryHeight(self.compact) 830 node.fontSize = GetEntryFontSize() 831 node.columns = overviewColumns.GetColumns(self.GetSelectedTabID()) 832 node.columnWidths = columnWidths 833 node.sortNameIndex = sortNameIndex 834 node.sortDistanceIndex = sortDistanceIndex 835 node.sortIconIndex = sortIconIndex 836 node.sortTagIndex = sortTagIndex 837 node.sortVelocityIndex = sortVelocityIndex 838 node.sortRadialVelocityIndex = sortRadialVelocityIndex 839 node.sortAngularVelocityIndex = sortAngularVelocityIndex 840 node.sortTransversalVelocityIndex = sortTransversalVelocityIndex 841 sortValue = defaultSortValue[:] 842 node.sortValue = sortValue 843 if node.display_NAME is None: 844 PrimeDisplayName(node) 845 elif sortNameIndex is not None: 846 sortValue[sortNameIndex] = node.display_NAME.lower() 847 if showType and slimItem.typeID: 848 if node.display_TYPE is None: 849 typeName = self.get_type_column_text(slimItem) 850 if usingLocalizationTooltips: 851 typeName, hint = PrepareLocalizationTooltip(typeName) 852 node.hint_TYPE = hint 853 node.display_TYPE = typeName 854 if sortTypeIndex is not None: 855 sortValue[sortTypeIndex] = node.display_TYPE.lower() 856 if showSize: 857 size = ball.radius * 2 858 if node.display_SIZE is None: 859 node.display_SIZE = FmtDist(size) 860 if sortSizeIndex is not None: 861 sortValue[sortSizeIndex] = size 862 if showTag: 863 if inFleet: 864 if node.display_TAG is None: 865 node.display_TAG = self.fleetSvc.GetTargetTag(node.itemID) 866 else: 867 node.display_TAG = '' 868 if sortTagIndex is not None: 869 tag = node.display_TAG 870 if tag is None: 871 sortValue[sortTagIndex] = 'zzz' 872 elif tag: 873 sortValue[sortTagIndex] = tag.lower() 874 else: 875 sortValue[sortTagIndex] = 0 876 if showCorporation and slimItem.corpID: 877 node.display_CORPORATION = corpTag = GetCorpTickerName(slimItem) 878 if sortCorporationIndex is not None: 879 sortValue[sortCorporationIndex] = corpTag.lower() 880 if showMilitia and slimItem.warFactionID: 881 militia = cfg.eveowners.Get(slimItem.warFactionID).name 882 if usingLocalizationTooltips: 883 militia, hint = PrepareLocalizationTooltip(militia) 884 node.hint_MILITIA = hint 885 node.display_MILITIA = militia 886 if sortMilitiaIndex is not None: 887 sortValue[sortMilitiaIndex] = militia.lower() 888 if showAlliance and slimItem.allianceID: 889 node.display_ALLIANCE = alliance = GetAllianceTickerName(slimItem) 890 if sortAllianceIndex is not None: 891 sortValue[sortAllianceIndex] = alliance.lower() 892 if showFaction: 893 if slimItem.ownerID and IsNPC(slimItem.ownerID) or slimItem.charID and IsNPC(slimItem.charID): 894 factionID = get_corporation_faction_id(slimItem.ownerID or slimItem.charID) 895 if factionID: 896 faction = cfg.eveowners.Get(factionID).name 897 if usingLocalizationTooltips: 898 faction, hint = PrepareLocalizationTooltip(faction) 899 node.hint_FACTION = hint 900 node.display_FACTION = faction 901 if sortFactionIndex is not None: 902 sortValue[sortFactionIndex] = faction.lower() 903 if emanationLockedGateID and slimItem.groupID == const.groupStargate: 904 node.gateLockValue = GetGateLockValue(emanationLockedGateID, slimItem.itemID) 905 if node.iconAndBackgroundFlags is None: 906 iconFlag, backgroundFlag = (0, 0) 907 if node.updateItem: 908 iconFlag, backgroundFlag = GetIconFlagAndBackgroundFlag(slimItem, self.stateSvc) 909 node.iconAndBackgroundFlags = (iconFlag, backgroundFlag) 910 if slimItem.categoryID == const.categoryStructure and not IsFlexStructure(slimItem.typeID) and node.hasDockingRights in (DOCKING_ACCESS_UNKNOWN, None): 911 if isDockingAccessUnknown: 912 node.hasDockingRights = DOCKING_ACCESS_UNKNOWN 913 elif slimItem.state != STATE_UNANCHORED: 914 hasDockingRights = FindDockingRightsToDisplay(structureProximityTrackerSvc, slimItem) 915 node.hasDockingRights = hasDockingRights 916 if sortIconIndex is not None: 917 iconFlag, backgroundFlag = node.iconAndBackgroundFlags 918 node.iconColor, colorSortValue = GetIconColor(slimItem, getSortValue=True) 919 if slimItem.categoryID == const.categoryStructure and colorSortValue: 920 iconFlag = colorSortValue 921 sortValue[sortIconIndex] = [iconFlag, 922 colorSortValue, 923 backgroundFlag, 924 slimItem.categoryID, 925 slimItem.groupID, 926 slimItem.typeID] 927 928 def get_type_column_text(self, slim_item): 929 if slim_item.groupID in (appConst.groupIce, appConst.groupHarvestableCloud, appConst.groupPhasedAsteroids): 930 return evetypes.GetGroupNameByGroup(slim_item.groupID) 931 if slim_item.categoryID == appConst.categoryAsteroid: 932 return evetypes.GetCategoryNameByCategory(slim_item.categoryID) 933 return evetypes.GetName(slim_item.typeID) 934 935 @telemetry.ZONE_METHOD 936 def _UpdateDynamicDataForNodes(self, nodeList, doYield = False): 937 bp = self.michelle.GetBallpark(doWait=True) 938 if not bp: 939 self.FlagBallparkDirty('DoBallsAdded') 940 return 941 myBall = bp.GetBall(session.shipid) 942 GetInvItem = bp.GetInvItem 943 columns = overviewColumns.GetColumns(self.GetSelectedTabID()) 944 isDockingAccessUnknown = sm.GetService('structureProximityTracker').HasDockingAccessChanged() 945 showDistance = COLUMN_DISTANCE in columns 946 showIcon = COLUMN_ICON in columns 947 homeStationID = None 948 homeStationService = homestation.Service.instance() 949 if homeStationService.is_home_station_data_loaded: 950 homeStationID = homeStationService.get_home_station().id 951 calculateAngularVelocity, calculateCombinedVelocity, calculateRadialNormal, calculateRadialVelocity, calculateTransveralVelocity, calculateVelocity, showVelocityCombined = GetColumnValuesToCalculate(columns) 952 now = blue.os.GetSimTime() 953 counter = 0 954 for node in nodeList: 955 ball = node.ball() 956 slimItem = node.slimItem() 957 if not slimItem: 958 slimItem = GetInvItem(node.itemID) 959 if slimItem: 960 node.slimItem = _weakref.ref(slimItem) 961 node.iconColor = None 962 PrimeDisplayName(node) 963 if node.panel: 964 if showIcon: 965 node.panel.UpdateIcon() 966 node.panel.UpdateIconColor() 967 UpdateIconAndBackgroundFlagsOnNode(node) 968 if ball: 969 if showDistance: 970 ball.GetVectorAt(now) 971 node.rawDistance = rawDistance = max(ball.surfaceDist, 0) 972 if node.sortDistanceIndex is not None: 973 node.sortValue[node.sortDistanceIndex] = rawDistance 974 if showVelocityCombined and ball.isFree and myBall: 975 ball.GetVectorAt(now) 976 UpdateVelocityData(node, ball, myBall, calculateVelocity, calculateRadialVelocity, calculateCombinedVelocity, calculateRadialNormal, calculateTransveralVelocity, calculateAngularVelocity) 977 self._UpdateStructureNode(node, slimItem, isDockingAccessUnknown) 978 if homeStationID is not None: 979 node.isHomeStation = homeStationID == node.itemID 980 if doYield: 981 counter += 1 982 if counter == 20: 983 blue.pyos.BeNice() 984 if self.destroyed: 985 self.StopOverviewUpdate() 986 return 987 counter = 0 988 989 @telemetry.ZONE_METHOD 990 def _UpdateStructureNode(self, node, slimItem, isDockingAccessUnknown): 991 if not slimItem: 992 return 993 if slimItem.categoryID != const.categoryStructure: 994 return 995 itemID = slimItem.itemID 996 if not sm.GetService('structureProximityTracker').IsStructureVisible(itemID): 997 node.leavingOverview = True 998 if itemID in self._scrollNodesByItemID: 999 del self._scrollNodesByItemID[itemID] 1000 if IsFlexStructure(slimItem.typeID): 1001 pass 1002 elif isDockingAccessUnknown and node.hasDockingRights != DOCKING_ACCESS_UNKNOWN: 1003 node.hasDockingRights = DOCKING_ACCESS_UNKNOWN 1004 UpdateIconAndBackgroundFlagsOnNode(node) 1005 if node.panel: 1006 node.panel.UpdateIcon() 1007 1008 @telemetry.ZONE_METHOD 1009 def CheckForNewEntriesAndRefreshScrollSetup(self): 1010 ballpark = self.michelle.GetBallpark(doWait=True) 1011 if ballpark is None: 1012 return 1013 if self.destroyed: 1014 return 1015 columns = overviewColumns.GetColumns(self.GetSelectedTabID()) 1016 self.sortHeaders.CreateColumns(columns, fixedColumns=FIXEDCOLUMNS) 1017 newEntries = [] 1018 currentNotWanted = set() 1019 with ScrollListLock: 1020 if self._ballparkDirty: 1021 GetInvItem = ballpark.GetInvItem 1022 currentItemIDs = self._scrollNodesByItemID 1023 log.info('Overview - Checking ballpark for new entries') 1024 for itemID in ballpark.balls.keys(): 1025 slimItem = GetInvItem(itemID) 1026 display = self.displayChecker.ShouldDisplayItem(slimItem) 1027 if not display: 1028 if itemID in currentItemIDs: 1029 currentNotWanted.add(itemID) 1030 if itemID in self._scrollNodesByItemID: 1031 node = self._scrollNodesByItemID[itemID] 1032 node.leavingOverview = True 1033 del self._scrollNodesByItemID[itemID] 1034 continue 1035 if itemID not in currentItemIDs: 1036 newNode = self._ConstructScrollEntry(itemID, slimItem, ballpark) 1037 newEntries.append(newNode) 1038 1039 nodeList = newEntries[:] 1040 if self._scrollEntriesDirty: 1041 log.info('Overview - Update static data on current overview entries') 1042 nodeList.extend([ node for node in self.scroll.sr.nodes if node.itemID not in currentNotWanted ]) 1043 self._UpdateStaticDataForNodes(nodeList) 1044 self.scroll.PurgeInvisibleEntries() 1045 self.overviewSorted = False 1046 if newEntries: 1047 self.scroll.ShowHint() 1048 self.scroll.AddNodes(-1, newEntries) 1049 return newEntries 1050 1051 def _ConstructScrollEntry(self, itemID, slimItem, ballpark): 1052 updateItem = self.stateSvc.CheckIfUpdateItem(slimItem) 1053 newNode = GetFromClass(OverviewScrollEntry, {'itemID': itemID, 1054 'updateItem': updateItem}) 1055 ball = ballpark.GetBall(itemID) 1056 newNode.ball = _weakref.ref(ball) 1057 newNode.slimItem = _weakref.ref(slimItem) 1058 if updateItem: 1059 newNode.ewarGraphicIDs = self.GetEwarDataForNode(newNode) 1060 newNode.ewarHints = self.ewarHintsByGraphicID 1061 return newNode 1062 1063 @telemetry.ZONE_METHOD 1064 def UpdateEntryOrder(self, doYield = False): 1065 if self.destroyed: 1066 return 1067 newEntries = False 1068 if self._ballparkDirty or self._scrollEntriesDirty: 1069 newEntries = self.CheckForNewEntriesAndRefreshScrollSetup() 1070 if newEntries: 1071 doYield = False 1072 self._ballparkDirty = False 1073 self._scrollEntriesDirty = False 1074 updateStartTime = blue.os.GetWallclockTimeNow() 1075 try: 1076 if not session.solarsystemid: 1077 self.StopOverviewUpdate() 1078 return 1079 if self.IsCollapsed() or self.IsMinimized(): 1080 self.StopOverviewUpdate() 1081 return 1082 if self.destroyed: 1083 return 1084 bp = self.michelle.GetBallpark(doWait=True) 1085 if not bp: 1086 self.StopOverviewUpdate() 1087 return 1088 columnWidths = self.sortHeaders.GetCurrentSizes() 1089 broadcastsToTop = self.presetSvc.GetSettingValueBroadcastToTop() 1090 fleetBroadcasts = self.fleetSvc.GetCurrentFleetBroadcasts() 1091 mouseCoords = trinity.mainWindow.GetCursorPos() 1092 if mouseCoords != self.prevMouseCoords: 1093 self.lastMovementTime = blue.os.GetWallclockTime() 1094 self.prevMouseCoords = mouseCoords 1095 insider = IsUnder(uicore.uilib.mouseOver, self.scroll.GetContentContainer()) or uicore.uilib.mouseOver is self.scroll.GetContentContainer() 1096 mouseMoving = blue.os.TimeDiffInMs(self.lastMovementTime, blue.os.GetWallclockTime()) > self.mouseMovementTimeout 1097 mouseInsideApp = mouseCoords[0] > 0 and mouseCoords[0] < trinity.app.width and mouseCoords[1] > 0 and mouseCoords[1] < trinity.app.height 1098 sortingFrozen = self.sortingFrozen = insider and mouseInsideApp and not mouseMoving or self._freezeOverview 1099 if sortingFrozen: 1100 updateList = self.scroll.GetVisibleNodes() 1101 self.sortHeaders.SetSortIcon('res:/UI/Texture/classes/Overview/columnLock.png') 1102 else: 1103 updateList = self.scroll.sr.nodes 1104 self.sortHeaders.SetSortIcon(None) 1105 currentActive, currentDirection = self.sortHeaders.GetCurrentActive() 1106 1107 def GetSortValue(_node): 1108 if broadcastsToTop: 1109 return GetSortValueWhenBroadcastGoToTop(_node, fleetBroadcasts, currentDirection) 1110 return _node.sortValue 1111 1112 ballpark = self.michelle.GetBallpark(doWait=True) 1113 if ballpark is None: 1114 return 1115 self._UpdateDynamicDataForNodes(updateList, doYield=doYield) 1116 counter = 0 1117 nodesToRemove = [] 1118 for node in updateList: 1119 node.columnWidths = columnWidths 1120 if node.leavingOverview: 1121 if node.panel: 1122 node.panel.opacity = 0.25 1123 node.panel.state = uiconst.UI_DISABLED 1124 nodesToRemove.append(node) 1125 continue 1126 ball = node.ball() 1127 slimItem = node.slimItem() 1128 if not (slimItem and ball): 1129 node.leavingOverview = True 1130 if node.itemID in self._scrollNodesByItemID: 1131 del self._scrollNodesByItemID[node.itemID] 1132 if node.panel: 1133 node.panel.opacity = 0.25 1134 node.panel.state = uiconst.UI_DISABLED 1135 nodesToRemove.append(node) 1136 continue 1137 if doYield: 1138 counter += 1 1139 if counter == 20: 1140 blue.pyos.BeNice() 1141 if self.destroyed: 1142 self.StopOverviewUpdate() 1143 return 1144 counter = 0 1145 1146 if doYield: 1147 blue.synchro.Yield() 1148 if self.destroyed: 1149 self.StopOverviewUpdate() 1150 return 1151 if not sortingFrozen: 1152 if nodesToRemove: 1153 self.scroll.RemoveNodes(nodesToRemove) 1154 currentActive, currentDirection = self.sortHeaders.GetCurrentActive() 1155 with ScrollListLock: 1156 sortlist = sorted(self.scroll.sr.nodes, key=GetSortValue, reverse=not currentDirection) 1157 self.scroll.SetOrderedNodes(sortlist, loadNodes=False) 1158 self.overviewSorted = True 1159 else: 1160 self.overviewSorted = False 1161 self.LoadVisibleEntriesIfNeverLoaded() 1162 self.CheckShowNoContentHint() 1163 except Exception: 1164 log.exception('Error updating inflight overview') 1165 sys.exc_clear() 1166 1167 if doYield: 1168 diff = (gametime.GetWallclockTimeNow() - updateStartTime) / const.SEC 1169 duration = max(overviewConst.ENTRY_ORDER_UPDATE_SLEEP - diff, overviewConst.ENTRY_ORDER_UPDATE_SLEEP_MIN) 1170 uthread2.sleep(duration) 1171 if not self.destroyed and (not self.updateEntryOrderThread or self.updateEntryOrderThread == stackless.getcurrent()): 1172 self.updateEntryOrderThread = uthread.new(self.UpdateEntryOrder, doYield=True) 1173 1174 def LoadVisibleEntriesIfNeverLoaded(self): 1175 visibleNodes = self.scroll.GetVisibleNodes() 1176 self._UpdateDynamicDataForNodes(visibleNodes) 1177 for node in visibleNodes: 1178 entry = node.panel 1179 if entry and entry.display and not entry.hasLoaded: 1180 entry.Load(node) 1181 1182 def LoadVisibleEntries(self): 1183 visibleNodes = self.scroll.GetVisibleNodes() 1184 self._UpdateDynamicDataForNodes(visibleNodes) 1185 for node in visibleNodes: 1186 entry = node.panel 1187 if entry and entry.state != uiconst.UI_HIDDEN: 1188 entry.Load(node) 1189 1190 def CheckShowNoContentHint(self): 1191 if not self.scroll.sr.nodes: 1192 self.scroll.ShowHint(localization.GetByLabel('UI/Common/NothingFound')) 1193 else: 1194 self.scroll.ShowHint() 1195 1196 def OnFreezeOverviewWindows(self): 1197 self._SetFreezeOverview(True) 1198 1199 def OnUnfreezeOverviewWindows(self): 1200 self._SetFreezeOverview(False) 1201 1202 def _SetFreezeOverview(self, freeze = True): 1203 triggerUpdate = False 1204 if not freeze and freeze != self._freezeOverview: 1205 triggerUpdate = True 1206 self._freezeOverview = freeze 1207 if triggerUpdate and getattr(self, 'overviewSorted', False) is False: 1208 self.TriggerInstantUpdate('SetFreezeOverview') 1209 1210 def UpdateForOneCharacter(self, charID, *args): 1211 pass 1212 1213 def OnExpanded(self, *args): 1214 super(OverviewWindow, self).OnExpanded(*args) 1215 self.TriggerInstantUpdate('OnExpanded') 1216 1217 def OnCollapsed(self, *args): 1218 super(OverviewWindow, self).OnCollapsed(*args) 1219 self.StopOverviewUpdate() 1220 self.cachedScrollPos = self.scroll.GetScrollProportion() 1221 1222 def OnEndMaximize_(self, *args): 1223 self.TriggerInstantUpdate('OnEndMaximize_') 1224 1225 def OnEndMinimize_(self, *args): 1226 self.StopOverviewUpdate() 1227 self.cachedScrollPos = self.scroll.GetScrollProportion() 1228 1229 def GetSelectedTabID(self): 1230 if self.tabGroup: 1231 return self.tabGroup.GetSelectedID() 1232 1233 def OnSessionChanged(self, isRemote, session, change): 1234 if self.destroyed: 1235 return 1236 if 'solarsystemid' in change: 1237 self.scroll.Clear() 1238 self._scrollNodesByItemID = {} 1239 if 'shipid' in change: 1240 self.FlushEwarStates() 1241 self.FlagBallparkDirty('OnSessionChanged') 1242 1243 def OnEnterSpace(self): 1244 self.FlagBallparkDirty('OnEnterSpace') 1245 1246 def OnOverviewOverrideChanged(self): 1247 self.FlagBallparkDirty('OnOverviewOverrideChanged') 1248 1249 def OnItemHighlighted(self, itemID, isActive): 1250 node = self._scrollNodesByItemID.get(itemID, None) 1251 if node is None: 1252 return 1253 if node.panel: 1254 node.panel.UpdateTutorialHighlight(isActive) 1255 1256 def OnStructuresVisibilityUpdated(self): 1257 self.FlagBallparkDirty('OnStructuresVisibilityUpdated') 1258 1259 def GetNextInRouteNodeAndDirection(self): 1260 destinationPath = sm.GetService('starmap').GetDestinationPath() 1261 if not destinationPath: 1262 return (None, None) 1263 nextInRouteItemID = destinationPath[0] 1264 isSolarSystem = IsSolarSystem(nextInRouteItemID) 1265 nextInRouteNode = None 1266 for eachNode in self.scroll.GetNodes(): 1267 if eachNode.itemID == nextInRouteItemID: 1268 nextInRouteNode = eachNode 1269 break 1270 if isSolarSystem and eachNode.slimItem: 1271 slimItem = eachNode.slimItem() 1272 if slimItem.groupID in (const.groupStargate, const.groupUpwellJumpGate): 1273 if slimItem.jumps and slimItem.jumps[0].locationID == nextInRouteItemID: 1274 nextInRouteNode = eachNode 1275 break 1276 1277 if not nextInRouteNode: 1278 return (None, None) 1279 if nextInRouteNode.panel and nextInRouteNode.panel.IsVisible(): 1280 return (nextInRouteNode.panel, None) 1281 myNodeIdx = nextInRouteNode.idx 1282 visibleNodes = self.scroll.GetVisibleNodes() 1283 if visibleNodes: 1284 firstNode = visibleNodes[0] 1285 lastNode = visibleNodes[-1] 1286 if firstNode.idx > myNodeIdx: 1287 pointToInstead = self.sortHeaders or firstNode.panel 1288 return (pointToInstead, 'up') 1289 if lastNode.idx < myNodeIdx: 1290 pointToInstead = lastNode.panel 1291 return (pointToInstead, 'down') 1292 return (None, None) 1293 1294 def OnEmanationLockUpdated(self, lockDetails): 1295 if not lockDetails or lockDetails.solar_system_id != session.solarsystemid2: 1296 return 1297 self._UpdateEmanationLock() 1298 1299 def OnEmanationGateLockRemoved(self, *args): 1300 self._UpdateEmanationLock() 1301 1302 def _UpdateEmanationLock(self): 1303 systemInfo = cfg.mapSolarSystemContentCache.get(session.solarsystemid2, None) 1304 if not systemInfo: 1305 return 1306 for gateID in systemInfo.stargates.iterkeys(): 1307 node = self._scrollNodesByItemID.get(gateID, None) 1308 if not node: 1309 continue 1310 slimItem = node.slimItem() 1311 node.gateLockValue = GetGateLockValueForSlimItem(slimItem) 1312 if node.panel: 1313 UpdateIconAndBackgroundFlagsOnNode(node) 1314 1315 1316 class BracketButtonIcon(ButtonIcon): 1317 expandOnLeft = True 1318 1319 def GetMenu(self, *args): 1320 return GetBracketVisibilitySubMenu()