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

infoPanelRoute.py (34467B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\infoPanels\infoPanelRoute.py
      2 import random
      3 import weakref
      4 from collections import deque
      5 import eveformat
      6 import evelink.client
      7 import localization
      8 import log
      9 import threadutils
     10 import uthread
     11 import uthread2
     12 import utillib
     13 from carbon.client.script.environment.AudioUtil import PlaySound
     14 from carbon.common.script.util import timerstuff
     15 from carbonui import uiconst, TextColor
     16 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText
     17 from carbonui.control.slider import Slider
     18 from carbonui.primitives.container import Container
     19 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     20 from carbonui.primitives.fill import Fill
     21 from carbonui.primitives.sprite import Sprite
     22 from carbonui.uianimations import animations
     23 from carbonui.uicore import uicore
     24 from eve.client.script.ui import eveColor
     25 from eve.client.script.ui.control import eveLabel
     26 from carbonui.control.button import Button
     27 from eve.client.script.ui.shared.autopilotSettings import AutopilotSettings
     28 from eve.client.script.ui.shared.infoPanels.InfoPanelBase import InfoPanelBase
     29 from eve.client.script.ui.util import searchUtil, uix
     30 from eve.client.script.ui.shared.infoPanels.const import infoPanelConst, infoPanelUIConst
     31 from eve.common.lib import appConst as const
     32 from eve.common.script.search.const import ResultType
     33 from eve.common.script.sys import eveCfg, idCheckers
     34 from evePathfinder.pathfinderconst import ROUTE_TYPE_SAFE, ROUTE_TYPE_SHORTEST, ROUTE_TYPE_UNSAFE
     35 from eveformat.client.location import GetLawlessSystemSecStatusColor
     36 from eveservices.menu import GetMenuService
     37 from pirateinsurgency.client.dashboard.const import CORRUPTION_STAGES
     38 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     39 from stackless_response_router.exceptions import TimeoutException, UnpackException
     40 from stargate.client.localGates import FindLocalStargate
     41 from uihider import UiHiderMixin
     42 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
     43 ROUTE_MARKERSIZE = 8
     44 ROUTE_MARKERGAP = 2
     45 ROUTE_MARKERTYPE_NORMAL = 0
     46 ROUTE_MARKERTYPE_STATION = 1
     47 ROUTE_MARKERTYPE_WAYPOINT = 2
     48 ROUTE_MARKERTYPE_INVASION = 3
     49 ROUTE_MARKERTYPE_INSURGENCY = 4
     50 NEOCOM_PANELWIDTH = 328
     51 FRAME_WIDTH = 20
     52 FRAME_SEPERATION = 10
     53 IDLE_ROUTEMARKER_ALPHA = 1.0
     54 
     55 def _GetCurrentDestinationLabel(destination_name):
     56     if destination_name is None:
     57         return localization.GetByLabel('UI/Inflight/NoDestination')
     58     destination_label = localization.GetByLabel('UI/Neocom/Autopilot/CurrentDestination')
     59     return sm.GetService('infoPanel').GetSolarSystemTrace(destination_name, destination_label)
     60 
     61 
     62 class InfoPanelRoute(UiHiderMixin, InfoPanelBase):
     63     default_name = 'InfoPanelRoute'
     64     panelTypeID = infoPanelConst.PANEL_ROUTE
     65     label = 'UI/InfoWindow/TabNames/Route'
     66     default_iconTexturePath = 'res:/UI/Texture/Classes/InfoPanels/Route.png'
     67     hasSettings = True
     68     uniqueUiName = pConst.UNIQUE_NAME_INFO_PANEL_ROUTE
     69     __notifyevents__ = ['OnDestinationSet',
     70      'OnUIRefresh',
     71      'OnAutoPilotOn',
     72      'OnAutoPilotOff']
     73 
     74     def ApplyAttributes(self, attributes):
     75         super(InfoPanelRoute, self).ApplyAttributes(attributes)
     76         self.headerButton.uniqueUiName = pConst.UNIQUE_NAME_AUTOPILOT_SETTINGS
     77         sm.RegisterNotify(self)
     78         self.routeData = None
     79         self.sliderLabel = None
     80         self.toAnimate = []
     81         self.utilMenu = None
     82         self.header = self.headerCls(parent=self.headerCont, align=uiconst.CENTERLEFT)
     83         self.headerCompact = self.headerCls(name='headerCompact', parent=self.headerCompactCont, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL)
     84         self.headerTrigIcon = TriglavianWarningIcon(parent=self.headerCompactCont, align=uiconst.CENTERRIGHT, idx=0)
     85         self.UpdateHeaderTrigIconDisplay()
     86         self.noDestinationLabel = eveLabel.EveLabelMedium(name='noDestinationLabel', parent=self.mainCont, text=localization.GetByLabel('UI/Inflight/NoDestination'), align=uiconst.TOTOP, state=uiconst.UI_HIDDEN)
     87         self.currentParent = NextWaypointPanel(parent=self.mainCont, align=uiconst.TOTOP)
     88         self.markersParent = Container(name='markersParent', parent=self.mainCont, align=uiconst.TOTOP)
     89         self.endParent = DestinationWaypointPanel(parent=self.mainCont, align=uiconst.TOTOP)
     90 
     91     def GetSettingsMenu(self, parent):
     92         self.utilMenu = weakref.ref(parent)
     93         self.AddSearchBox(parent)
     94         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/AutopilotActive'), sm.GetService('autoPilot').GetState(), callback=self.OnCheckBoxAutopilotActive, state=uiconst.UI_DISABLED if eveCfg.IsDocked() else uiconst.UI_NORMAL)
     95         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/ShowRoutePathInSpace'), settings.user.ui.Get('routeVisualizationEnabled', True), callback=sm.GetService('gameui').routeVisualizer.ToggleRouteVisualization)
     96         pfRouteType = sm.GetService('clientPathfinderService').GetAutopilotRouteType()
     97         parent.AddRadioButton(localization.GetByLabel('UI/Map/MapPallet/cbPreferShorter'), pfRouteType == ROUTE_TYPE_SHORTEST, callback=(self.OnRadioBtnRouteType, 'shortest'), uniqueUiName=pConst.UNIQUE_NAME_ROUTE_SHORTER)
     98         parent.AddRadioButton(localization.GetByLabel('UI/Map/MapPallet/cbPreferSafer'), pfRouteType == ROUTE_TYPE_SAFE, callback=(self.OnRadioBtnRouteType, 'safe'), uniqueUiName=pConst.UNIQUE_NAME_ROUTE_SAFER)
     99         parent.AddRadioButton(localization.GetByLabel('UI/Map/MapPallet/cbPreferRisky'), pfRouteType == ROUTE_TYPE_UNSAFE, callback=(self.OnRadioBtnRouteType, 'unsafe'))
    100         sliderCont = Container(name='sliderCont', parent=parent, align=uiconst.TOTOP, height=18, padding=(17, 0, 0, 0))
    101         self.securitySlider = Slider(parent=sliderCont, align=uiconst.TOLEFT, width=100, name='pfPenalty', state=uiconst.UI_NORMAL, minValue=1, maxValue=100, labelDecimalPlaces=0, value=settings.char.ui.Get('pfPenalty', 50.0), on_dragging=self.OnSecuritySlider, callback=self.OnSecuritySliderEnd, hint=localization.GetByLabel('UI/Map/MapPallet/hintSecurityPeneltySlider'), padLeft=5)
    102         self.sliderLabel = eveLabel.EveLabelSmall(parent=sliderCont, align=uiconst.TOALL, padLeft=5, top=3)
    103         self.UpdateSliderLabel(self.securitySlider.value)
    104         parent.AddSpace()
    105         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/IncludeJumpGates'), settings.char.ui.Get('pathFinder_includeJumpGates', 0), callback=self.OnCheckBoxUseJumpGates, uniqueUiName=pConst.UNIQUE_NAME_ROUTE_INCLUDE_JUMP_GATES)
    106         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/cbAdvoidPodkill'), settings.char.ui.Get('pfAvoidPodKill', 0), callback=self.OnCheckBoxAvoidPodKill)
    107         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/cbAvoidTriglavianTales'), settings.char.ui.Get('pfAvoidTriglavianTales', 0), callback=self.OnCheckBoxAvoidTriglavianTales)
    108         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/cbAvoidEdencomSystems'), settings.char.ui.Get('pfAvoidEdencomSystems', 0), callback=self.OnCheckBoxAvoidEdencomSystems)
    109         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/cbAdvoidSystemsOnList'), settings.char.ui.Get('pfAvoidSystems', 1), callback=self.OnCheckBoxAvoidSystems)
    110         parent.AddCheckBox(localization.GetByLabel('UI/Map/MapPallet/cbDisableAtEachWaypoint'), settings.user.ui.Get('autopilot_stop_at_each_waypoint', 0) == 0, callback=self.OnCheckBoxDisableAtEachWaypoint)
    111         parent.AddDivider()
    112         starmapSvc = sm.GetService('starmap')
    113         waypoints = starmapSvc.GetWaypoints()
    114         if len(waypoints) > 0:
    115             parent.AddButton(localization.GetByLabel('UI/Neocom/ClearAllAutopilotWaypoints'), starmapSvc.ClearWaypoints, toggleMode=False)
    116         if len(waypoints) > 1:
    117             parent.AddButton(localization.GetByLabel('UI/Map/MapPallet/OptimizeRoute'), sm.GetService('autoPilot').OptimizeRoute, toggleMode=False)
    118         parent.AddButton(localization.GetByLabel('UI/Map/MapPallet/ManageRoute'), AutopilotSettings.Open, toggleMode=False)
    119 
    120     def AddSearchBox(self, parent):
    121         container = parent.AddContainer(padding=6)
    122         inpt = SingleLineEditText(name='searchbox', parent=container, align=uiconst.TOPLEFT, width=220, maxLength=64, hintText=localization.GetByLabel('UI/Map/MapPallet/lblSearchForLocation'), OnReturn=lambda *args: self.SearchForLocation(inpt, container, *args))
    123         Button(parent=container, align=uiconst.TOPLEFT, left=inpt.width + 4, label=localization.GetByLabel('UI/Map/MapPallet/btnSearchForLocation'), func=self.SearchForLocation, args=(inpt, container))
    124         parent.AddDivider()
    125 
    126     def SearchForLocation(self, inputField, container, *args):
    127         searchText = inputField.GetValue().strip()
    128         groupIDList = [ResultType.solar_system,
    129          ResultType.constellation,
    130          ResultType.region,
    131          ResultType.station,
    132          ResultType.structure_with_inlined_data]
    133         searchUtil.GetResultsInNewWindow(searchText, groupIDList, searchWndName='addressBookSearch')
    134         container.parent.Close()
    135 
    136     def OnRadioBtnRouteType(self, routeType):
    137         sm.GetService('clientPathfinderService').SetAutopilotRouteType(routeType)
    138 
    139     def OnCheckBoxAutopilotActive(self):
    140         if eveCfg.IsDocked():
    141             return
    142         autoPilotSvc = sm.GetService('autoPilot')
    143         if autoPilotSvc.GetState():
    144             autoPilotSvc.SetOff()
    145         else:
    146             autoPilotSvc.SetOn()
    147 
    148     def OnCheckBoxShowRoutePath(self):
    149         pass
    150 
    151     def OnCheckBoxAvoidPodKill(self):
    152         val = not settings.char.ui.Get('pfAvoidPodKill', 0)
    153         if val:
    154             prompt_player_fsd_dialog('MapAutoPilotAvoidPodkillZones')
    155         sm.GetService('clientPathfinderService').SetPodKillAvoidance(val)
    156 
    157     def OnCheckBoxAvoidTriglavianTales(self):
    158         val = not settings.char.ui.Get('pfAvoidTriglavianTales', 0)
    159         if val:
    160             prompt_player_fsd_dialog('MapAutoPilotAvoidTriglavianTales')
    161         sm.GetService('clientPathfinderService').SetTriglavianTaleAvoidance(val)
    162 
    163     def OnCheckBoxAvoidEdencomSystems(self):
    164         val = not settings.char.ui.Get('pfAvoidEdencomSystems', 0)
    165         if val:
    166             prompt_player_fsd_dialog('MapAutoPilotAvoidEdencomSystems')
    167         sm.GetService('clientPathfinderService').SetEdencomSystemsAvoidance(val)
    168 
    169     def OnCheckBoxAvoidSystems(self):
    170         val = not settings.char.ui.Get('pfAvoidSystems', 0)
    171         if val:
    172             prompt_player_fsd_dialog('MapAutoPilotAvoidSystems')
    173         sm.GetService('clientPathfinderService').SetSystemAvoidance(val)
    174 
    175     def OnCheckBoxDisableAtEachWaypoint(self):
    176         val = not settings.user.ui.Get('autopilot_stop_at_each_waypoint', 0)
    177         settings.user.ui.Set('autopilot_stop_at_each_waypoint', val)
    178 
    179     def OnCheckBoxUseJumpGates(self):
    180         val = not settings.char.ui.Get('pathFinder_includeJumpGates', 0)
    181         settings.char.ui.Set('pathFinder_includeJumpGates', val)
    182         sm.ScatterEvent('OnMapShowsJumpGatesChanged')
    183 
    184     def OnSecuritySlider(self, slider):
    185         self.UpdateSliderLabel(slider.value)
    186 
    187     def OnSecuritySliderEnd(self, slider):
    188         sm.GetService('clientPathfinderService').SetSecurityPenaltyFactor(slider.value)
    189         self.UpdateSliderLabel(slider.value)
    190 
    191     def UpdateSliderLabel(self, value):
    192         if self.sliderLabel:
    193             self.sliderLabel.text = '%s %i' % (localization.GetByLabel('UI/Map/MapPallet/lblSecurityPenelity'), value)
    194 
    195     def ConstructNormal(self):
    196         self.UpdateRoute()
    197 
    198     def ConstructCompact(self):
    199         self.UpdateHeaderText()
    200         self.UpdateHeaderTrigIconDisplay()
    201 
    202     def UpdateHeaderTrigIconDisplay(self):
    203         starMapSvc = sm.GetService('starmap')
    204         nextDestination = None
    205         if self.routeData is None:
    206             self.routeData = starMapSvc.GetAutopilotRoute()
    207             if not self.routeData or self.routeData == [None]:
    208                 self.routeData = starMapSvc.GetWaypoints()
    209         try:
    210             if len(self.routeData):
    211                 nextDestination = self.routeData[0]
    212         except KeyError:
    213             self.headerTrigIcon.display = False
    214             return
    215 
    216         should_display_trig_warning = ShowTriglavianWarning(nextDestination)
    217         self.headerTrigIcon.display = should_display_trig_warning
    218         header_label_width = infoPanelUIConst.PANELWIDTH - infoPanelUIConst.LEFTPAD
    219         if should_display_trig_warning:
    220             header_label_width -= self.headerTrigIcon.width
    221         self.headerCompact.SetRightAlphaFade(header_label_width, self.HEADER_FADE_WIDTH)
    222 
    223     def OnDestinationSet(self, destination):
    224         self.UpdateRoute(animate=bool(destination))
    225 
    226     def UpdateRoute(self, animate = False):
    227         starMapSvc = sm.GetService('starmap')
    228         self.routeData = starMapSvc.GetAutopilotRoute()
    229         self.UpdateHeaderText()
    230         if not session.solarsystemid2:
    231             return
    232         if self.mode != infoPanelConst.MODE_NORMAL:
    233             return
    234         if not self.routeData or self.routeData == [None]:
    235             self.routeData = starMapSvc.GetWaypoints()
    236         if not self.routeData:
    237             if self.markersParent:
    238                 self.currentParent.Hide()
    239                 self.endParent.Hide()
    240                 self.markersParent.Hide()
    241             self.noDestinationLabel.Show()
    242             return
    243         self.noDestinationLabel.Hide()
    244         planetView = sm.GetService('viewState').IsViewActive('planet')
    245         autoPilotActive = sm.GetService('autoPilot').GetState()
    246         updatingRouteData = getattr(self, 'updatingRouteData', None)
    247         if updatingRouteData == (autoPilotActive, planetView, self.routeData):
    248             return
    249         oldRouteIDs = [ child.solarSystemID for child in self.markersParent.children ]
    250         self.toAnimate = []
    251         self.markersParent.Flush()
    252         self.updatingRouteData = (autoPilotActive, planetView, self.routeData[:])
    253         self.currentParent.Show()
    254         self.currentParent.item_id = self.routeData[0]
    255         self.markersParent.Show()
    256         routeIDs = []
    257         lastStationSystemID = None
    258         for i, id in enumerate(self.routeData):
    259             isLast = i == len(self.routeData) - 1
    260             if idCheckers.IsSolarSystem(id) and not isLast and not idCheckers.IsSolarSystem(self.routeData[i + 1]):
    261                 continue
    262             if idCheckers.IsSolarSystem(id) and lastStationSystemID == id:
    263                 continue
    264             if idCheckers.IsStation(id):
    265                 lastStationSystemID = cfg.stations.Get(id).solarSystemID
    266             else:
    267                 lastStationSystemID = None
    268             routeIDs.append(id)
    269 
    270         maxWidth = infoPanelUIConst.PANELWIDTH - self.mainCont.padLeft
    271         markerX = 0
    272         markerY = 0
    273         waypoints = deque(sm.GetService('starmap').GetWaypoints())
    274         nextWaypoint = waypoints.popleft() if waypoints else None
    275         lastSystemID = session.solarsystemid2
    276         systemsIDsInRoute = []
    277         for i, destinationID in enumerate(routeIDs):
    278             if destinationID == nextWaypoint:
    279                 isWaypoint = True
    280                 nextWaypoint = waypoints.popleft() if waypoints else None
    281             else:
    282                 isWaypoint = False
    283             if idCheckers.IsSolarSystem(destinationID):
    284                 isStation = False
    285                 solarSystemID = destinationID
    286             elif idCheckers.IsStation(destinationID):
    287                 isStation = True
    288                 solarSystemID = cfg.stations.Get(destinationID).solarSystemID
    289             else:
    290                 structure = sm.GetService('structureDirectory').GetStructureInfo(destinationID)
    291                 if structure is not None:
    292                     isStation = True
    293                     solarSystemID = structure.solarSystemID
    294                 else:
    295                     log.LogError('ConstructRoute: Unknown item. I can only handle solar systems, stations and structures. You gave me', destinationID)
    296                     continue
    297             if solarSystemID != lastSystemID:
    298                 systemsIDsInRoute.append(solarSystemID)
    299                 lastSystemID = solarSystemID
    300             if len(self.markersParent.children) > i:
    301                 systemIcon = self.markersParent.children[i]
    302                 systemIcon.left = markerX
    303                 systemIcon.top = markerY
    304                 systemIcon.numJumps = len(systemsIDsInRoute)
    305             else:
    306                 systemIcon = AutopilotDestinationIcon(parent=self.markersParent, pos=(markerX,
    307                  markerY,
    308                  ROUTE_MARKERSIZE,
    309                  ROUTE_MARKERSIZE), solarSystemID=solarSystemID, destinationID=destinationID, idx=i, numJumps=len(systemsIDsInRoute))
    310                 if i >= len(oldRouteIDs) or solarSystemID != oldRouteIDs[i]:
    311                     self.toAnimate.append(systemIcon)
    312             if isStation:
    313                 systemIcon.SetMarkerType(ROUTE_MARKERTYPE_STATION)
    314             elif isWaypoint:
    315                 systemIcon.SetMarkerType(ROUTE_MARKERTYPE_WAYPOINT)
    316             elif ShowTriglavianWarning(destinationID):
    317                 systemIcon.SetMarkerType(ROUTE_MARKERTYPE_INVASION)
    318             else:
    319                 systemIcon.SetMarkerType(ROUTE_MARKERTYPE_NORMAL)
    320             systemIcon.SetSolarSystemAndDestinationID(solarSystemID, destinationID)
    321             self.endParent.pointer_offset = markerX
    322             markerParHeight = markerY + ROUTE_MARKERSIZE + ROUTE_MARKERGAP
    323             if animate:
    324                 animations.MorphScalar(self.markersParent, 'height', self.markersParent.height, markerParHeight, duration=0.3)
    325             else:
    326                 self.markersParent.height = markerParHeight
    327             markerX += ROUTE_MARKERGAP + ROUTE_MARKERSIZE
    328             if markerX + ROUTE_MARKERSIZE > maxWidth:
    329                 markerX = 0
    330                 markerY += ROUTE_MARKERGAP + ROUTE_MARKERSIZE
    331             if len(routeIDs) > 1:
    332                 self.endParent.Show()
    333                 self.endParent.item_id = routeIDs[-1]
    334             else:
    335                 self.endParent.Hide()
    336 
    337         self.updatingRouteData = None
    338         if animate:
    339             uthread.new(self.AnimateRouteIn)
    340         self.UpdateHeaderTrigIconDisplay()
    341 
    342     def UpdateHeaderText(self):
    343         starMapSvc = sm.GetService('starmap')
    344         destination = starMapSvc.GetDestination()
    345         routeData = starMapSvc.GetAutopilotRoute()
    346         if self.mode == infoPanelConst.MODE_NORMAL:
    347             numJumps = self._GetNumJumps(routeData)
    348             if not destination:
    349                 subHeader = ''
    350             elif idCheckers.IsWormholeSystem(session.solarsystemid2) or idCheckers.IsAbyssalSpaceSystem(session.solarsystemid2) or idCheckers.IsVoidSpaceSystem(session.solarsystemid2) or idCheckers.IsHiddenSpaceSystem(session.solarsystemid2):
    351                 if numJumps <= 1:
    352                     subHeader = localization.GetByLabel('UI/Market/MarketQuote/UnknownNumberOfJumps')
    353                 else:
    354                     subHeader = localization.GetByLabel('UI/Market/MarketQuote/MinimumPossibleNumberOfJumps', num=numJumps)
    355             else:
    356                 subHeader = localization.GetByLabel('UI/Market/MarketQuote/NumberOfJumps', num=numJumps)
    357             self.header.text = '%s <fontsize=12>%s' % (localization.GetByLabel('UI/InfoWindow/TabNames/Route'), subHeader)
    358         elif routeData:
    359             self.headerCompact.text = _GetCurrentDestinationLabel(routeData[0])
    360         else:
    361             destination = starMapSvc.GetDestination()
    362             self.headerCompact.text = _GetCurrentDestinationLabel(destination)
    363 
    364     def OnStartModeChanged(self, oldMode):
    365         uthread.new(self._OnStartModeChanged, oldMode)
    366 
    367     def _OnStartModeChanged(self, oldMode):
    368         if self.mode == infoPanelConst.MODE_NORMAL:
    369             if oldMode:
    370                 animations.FadeOut(self.headerCompactCont, duration=0.3, sleep=True)
    371                 animations.FadeIn(self.headerCont, duration=0.3)
    372             else:
    373                 self.headerCont.opacity = 1.0
    374                 self.headerCompactCont.opacity = 0.0
    375             self.headerCompactCont.state = uiconst.UI_DISABLED
    376         elif self.mode == infoPanelConst.MODE_COMPACT:
    377             if oldMode:
    378                 animations.FadeOut(self.headerCont, duration=0.3, sleep=True)
    379                 animations.FadeIn(self.headerCompactCont, duration=0.3)
    380             else:
    381                 self.headerCont.opacity = 0.0
    382                 self.headerCompactCont.opacity = 1.0
    383             self.headerCompactCont.state = uiconst.UI_PICKCHILDREN
    384 
    385     def AnimateRouteIn(self):
    386         if not self.toAnimate:
    387             return
    388         random.shuffle(self.toAnimate)
    389         kOffset = 0.6 / len(self.toAnimate)
    390         for i, icon in enumerate(self.toAnimate):
    391             animations.SpMaskIn(icon.icon, timeOffset=i * kOffset, loops=3, duration=0.05)
    392 
    393     def _GetNumJumps(self, routeData):
    394         if not routeData:
    395             return 0
    396         ids = []
    397         lastID = None
    398         for routeID in routeData:
    399             if idCheckers.IsStation(routeID):
    400                 routeID = cfg.stations.Get(routeID).solarSystemID
    401             if routeID != lastID and idCheckers.IsSolarSystem(routeID):
    402                 ids.append(routeID)
    403             lastID = routeID
    404 
    405         numJumps = len(ids)
    406         if ids and ids[0] == session.solarsystemid2:
    407             numJumps -= 1
    408         return numJumps
    409 
    410     def OnUIRefresh(self):
    411         self.UpdateRoute()
    412 
    413     def OnAutoPilotOn(self):
    414         if self.utilMenu and self.utilMenu():
    415             self.utilMenu().ReloadMenu()
    416 
    417     def OnAutoPilotOff(self):
    418         if self.utilMenu and self.utilMenu():
    419             self.utilMenu().ReloadMenu()
    420 
    421 
    422 class AutopilotDestinationIcon(Container):
    423     __guid__ = 'uicls.AutopilotDestinationIcon'
    424     default_align = uiconst.TOPLEFT
    425     default_state = uiconst.UI_NORMAL
    426     isDragObject = True
    427     default_pointerDirection = uiconst.POINT_BOTTOM_2
    428 
    429     def ApplyAttributes(self, attributes):
    430         Container.ApplyAttributes(self, attributes)
    431         self.icon = Sprite(parent=self, pos=(0, 0, 10, 10), state=uiconst.UI_DISABLED, shadowOffset=(0, 1), shadowColor=(0, 0, 0, 0.2), outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.0)
    432         self.markerType = None
    433         self.solarSystemID = None
    434         self.destinationID = None
    435         self.hiliteTimer = None
    436         self.fadingDisabled = False
    437         self.lawless = False
    438         self.numJumps = attributes.numJumps
    439 
    440     def SetMarkerType(self, markerType):
    441         if self.markerType == markerType:
    442             return
    443         if markerType == ROUTE_MARKERTYPE_WAYPOINT:
    444             self.icon.LoadTexture('res:/UI/Texture/classes/LocationInfo/waypointMarker.png')
    445         elif markerType == ROUTE_MARKERTYPE_STATION:
    446             self.icon.LoadTexture('res:/UI/Texture/classes/LocationInfo/stationMarker.png')
    447         elif markerType == ROUTE_MARKERTYPE_INVASION:
    448             self.icon.LoadTexture('res:/UI/Texture/classes/LocationInfo/triglavianMarker.png')
    449         elif markerType == ROUTE_MARKERTYPE_INSURGENCY:
    450             self.icon.LoadTexture('res:/UI/Texture/classes/LocationInfo/triglavianMarker.png')
    451         else:
    452             self.icon.LoadTexture('res:/UI/Texture/classes/LocationInfo/normalMarker.png')
    453         self.markerType = markerType
    454 
    455     def SetSolarSystemAndDestinationID(self, solarSystemID, destinationID):
    456         if self.solarSystemID == solarSystemID and self.destinationID == destinationID:
    457             return
    458         self.icon.SetRGBA(*eveColor.GUNMETAL_GREY)
    459         animations.MorphScalar(self.icon, 'opacity', 1.0, 0.0, duration=1, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE, timeOffset=random.random())
    460         self.solarSystemID = solarSystemID
    461         self.destinationID = destinationID
    462         uthread2.StartTasklet(self.UpdateLawlessStatus, solarSystemID)
    463 
    464     def UpdateLawlessStatus(self, solarSystemID):
    465         c = sm.GetService('map').GetModifiedSystemColor(solarSystemID)
    466         try:
    467             corruptionStage = sm.GetService('corruptionSuppressionSvc').GetSystemCorruptionStage(solarSystemID)
    468         except (TimeoutException, UnpackException):
    469             corruptionStage = 0
    470 
    471         if corruptionStage == CORRUPTION_STAGES:
    472             self.lawless = True
    473         if self.lawless:
    474             secStatus = sm.GetService('map').GetSecurityStatus(solarSystemID)
    475             c = GetLawlessSystemSecStatusColor(secStatus)
    476             if self.markerType == ROUTE_MARKERTYPE_NORMAL:
    477                 self.SetMarkerType(ROUTE_MARKERTYPE_INSURGENCY)
    478         animations.StopAnimation(self.icon, 'opacity')
    479         self.icon.SetRGBA(c[0], c[1], c[2], IDLE_ROUTEMARKER_ALPHA)
    480 
    481     def OnMouseEnter(self, *args):
    482         PlaySound(uiconst.SOUND_BUTTON_HOVER)
    483         if self.fadingDisabled:
    484             return
    485         animations.MorphScalar(self.icon, 'glowBrightness', self.icon.glowBrightness, 0.5, duration=uiconst.TIME_ENTRY)
    486         if self.hiliteTimer is None:
    487             self.hiliteTimer = timerstuff.AutoTimer(111, self.CheckIfMouseOver)
    488 
    489     def CheckIfMouseOver(self, *args):
    490         if uicore.uilib.mouseOver == self or self.fadingDisabled:
    491             return
    492         animations.MorphScalar(self.icon, 'glowBrightness', self.icon.glowBrightness, 0.0, duration=uiconst.TIME_ENTRY)
    493         self.hiliteTimer = None
    494 
    495     def OnMouseExit(self, *args):
    496         self.CheckIfMouseOver()
    497 
    498     def LoadTooltipPanel(self, tooltipPanel, *args):
    499         tooltipPanel.LoadGeneric1ColumnTemplate()
    500         if self.lawless:
    501             traceText = sm.GetService('infoPanel').GetLawlessSolarSystemTrace(self.destinationID, traceFontSize=None)
    502         else:
    503             traceText = sm.GetService('infoPanel').GetSolarSystemTrace(self.destinationID, traceFontSize=None)
    504         tooltipPanel.AddTextBodyLabel(text=traceText)
    505         if not idCheckers.IsSolarSystem(self.destinationID):
    506             if idCheckers.IsStation(self.destinationID) or sm.GetService('structureDirectory').GetStructureInfo(self.destinationID):
    507                 text = cfg.evelocations.Get(self.destinationID).name
    508                 tooltipPanel.AddTextBodyLabel(text=text)
    509         if ShowTriglavianWarning(self.solarSystemID):
    510             text = localization.GetByLabel('UI/Invasion/HUD/InvasionWarning')
    511             tooltipPanel.AddTextBodyLabel(text=text)
    512         if self.numJumps:
    513             text = localization.GetByLabel('UI/Common/numberOfJumps', numJumps=self.numJumps)
    514             tooltipPanel.AddTextDetailsLabel(text=text, color=TextColor.SECONDARY)
    515 
    516     def GetMenu(self, *args):
    517         if idCheckers.IsSolarSystem(self.destinationID):
    518             return GetMenuService().GetMenuFromItemIDTypeID(self.destinationID, const.typeSolarSystem)
    519         typeID = self.GetStationOrStructureTypeID(self.destinationID)
    520         if typeID:
    521             return GetMenuService().GetMenuFromItemIDTypeID(self.destinationID, typeID)
    522 
    523     def OnClick(self, *args):
    524         PlaySound(uiconst.SOUND_BUTTON_CLICK)
    525         if idCheckers.IsSolarSystem(self.destinationID):
    526             sm.GetService('info').ShowInfo(const.typeSolarSystem, self.destinationID)
    527         typeID = self.GetStationOrStructureTypeID(self.destinationID)
    528         if typeID:
    529             sm.GetService('info').ShowInfo(typeID, self.destinationID)
    530 
    531     def GetDragData(self, *args):
    532         entry = utillib.KeyVal()
    533         entry.__guid__ = 'xtriui.ListSurroundingsBtn'
    534         entry.itemID = self.destinationID
    535         entry.label = cfg.evelocations.Get(self.destinationID).name
    536         if idCheckers.IsSolarSystem(self.destinationID):
    537             entry.typeID = const.typeSolarSystem
    538         else:
    539             typeID = self.GetStationOrStructureTypeID(self.destinationID)
    540             if typeID:
    541                 entry.typeID = typeID
    542         return [entry]
    543 
    544     def GetStationOrStructureTypeID(self, destinationID):
    545         if idCheckers.IsStation(self.destinationID):
    546             station = sm.StartService('ui').GetStationStaticInfo(self.destinationID)
    547             return station.stationTypeID
    548         structureInfo = sm.GetService('structureDirectory').GetStructureInfo(self.destinationID)
    549         if structureInfo:
    550             return structureInfo.typeID
    551 
    552     def OnMouseDown(self, *args):
    553         uthread.new(self.OnMouseDown_thread)
    554 
    555     def OnMouseDown_thread(self):
    556         destinationID = self.destinationID
    557         if idCheckers.IsSolarSystem(destinationID):
    558             typeID = const.typeSolarSystem
    559         elif idCheckers.IsStation(destinationID):
    560             station = sm.StartService('ui').GetStationStaticInfo(destinationID)
    561             typeID = station.stationTypeID
    562         else:
    563             structure = sm.GetService('structureDirectory').GetStructureInfo(destinationID)
    564             if structure is None:
    565                 return
    566             typeID = structure.typeID
    567         GetMenuService().TryExpandActionMenu(itemID=destinationID, clickedObject=self, typeID=typeID)
    568 
    569     def GetRadialMenuIndicator(self, create = True, *args):
    570         radialMenuSprite = getattr(self, 'radialMenuSprite', None)
    571         if radialMenuSprite and not radialMenuSprite.destroyed:
    572             return radialMenuSprite
    573         if not create:
    574             return
    575         radialMenuSprite = Fill(name='radialMenuSprite', bgParent=self, padding=(-1, -1, -2, -2), color=(0.5, 0.5, 0.5, 0.8))
    576         self.radialMenuSprite = radialMenuSprite
    577         return radialMenuSprite
    578 
    579     def ShowRadialMenuIndicator(self, slimItem, *args):
    580         mySprite = self.GetRadialMenuIndicator(create=True)
    581         mySprite.display = True
    582         self.icon.SetAlpha(1.0)
    583         self.fadingDisabled = True
    584 
    585     def HideRadialMenuIndicator(self, slimItem, *args):
    586         mySprite = self.GetRadialMenuIndicator(create=False)
    587         if mySprite:
    588             mySprite.display = False
    589         self.fadingDisabled = False
    590         self.CheckIfMouseOver()
    591 
    592     def GetTooltipPositionFallbacks(self):
    593         return [uiconst.POINT_BOTTOM_1]
    594 
    595 
    596 def ShowTriglavianWarning(solarSystemID):
    597     return False
    598 
    599 
    600 class WaypointPanel(ContainerAutoSize):
    601     COLOR_BACKGROUND = (0.0, 0.0, 0.0, 0.3)
    602 
    603     def __init__(self, item_id = None, link_hint = None, **kwargs):
    604         self._item_id = item_id
    605         self._waypoint_trace_label = None
    606         self._link_hint = link_hint
    607         super(WaypointPanel, self).__init__(alignMode=uiconst.TOTOP, **kwargs)
    608         self.layout()
    609         self._update()
    610 
    611     def layout(self):
    612         main_cont = ContainerAutoSize(parent=self, align=uiconst.TOTOP, alignMode=uiconst.TOTOP)
    613         Fill(bgParent=main_cont, color=self.COLOR_BACKGROUND)
    614         self._waypoint_trace_label = eveLabel.EveLabelMedium(parent=main_cont, align=uiconst.TOTOP, padding=8, state=uiconst.UI_NORMAL)
    615         self._waypoint_trace_label.OnMouseDownWithUrl = self._on_mouse_down_with_url
    616         self._trig_warning = TriglavianWarningIcon(parent=main_cont, align=uiconst.CENTERRIGHT, left=8)
    617 
    618     @property
    619     def item_id(self):
    620         return self._item_id
    621 
    622     @item_id.setter
    623     def item_id(self, item_id):
    624         if self._item_id == item_id:
    625             return
    626         self._item_id = item_id
    627         self._update()
    628 
    629     @property
    630     def should_show_triglavian_warning(self):
    631         return self.item_id is not None and ShowTriglavianWarning(self.item_id)
    632 
    633     def _update(self):
    634         if self._item_id is None:
    635             text = localization.GetByLabel('UI/Inflight/NoDestination')
    636         else:
    637             text = eveformat.center(sm.GetService('infoPanel').GetSolarSystemTrace(self.item_id, self._link_hint))
    638         self._waypoint_trace_label.text = text
    639         if self.should_show_triglavian_warning:
    640             self._waypoint_trace_label.padRight = 34
    641             self._trig_warning.Show()
    642         else:
    643             self._waypoint_trace_label.padRight = 8
    644             self._trig_warning.Hide()
    645 
    646     @threadutils.threaded
    647     def _on_mouse_down_with_url(self, url, *args):
    648         try:
    649             parsed = evelink.parse_show_info_url(url)
    650         except Exception:
    651             log.LogWarning('Failed to parse URL')
    652             return
    653 
    654         if parsed.item_id is None or not idCheckers.IsSolarSystem(parsed.item_id):
    655             return
    656         local_stargate = FindLocalStargate(parsed.item_id)
    657         if local_stargate:
    658             destination_id = local_stargate.itemID
    659             type_id = local_stargate.typeID
    660         else:
    661             destination_id = parsed.item_id
    662             type_id = const.typeSolarSystem
    663         GetMenuService().TryExpandActionMenu(itemID=destination_id, clickedObject=self, typeID=type_id)
    664 
    665 
    666 class NextWaypointPanel(WaypointPanel):
    667 
    668     def __init__(self, item_id = None, **kwargs):
    669         self._trig_icon_cont = None
    670         super(NextWaypointPanel, self).__init__(item_id=item_id, link_hint=localization.GetByLabel('UI/Neocom/Autopilot/NextSystemInRoute'), **kwargs)
    671 
    672     def layout(self):
    673         super(NextWaypointPanel, self).layout()
    674         Sprite(parent=Container(parent=self, align=uiconst.TOTOP, height=12), align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/LocationInfo/pointerDown.png', width=10, height=10, color=self.COLOR_BACKGROUND)
    675 
    676 
    677 class DestinationWaypointPanel(WaypointPanel):
    678 
    679     def __init__(self, item_id = None, pointer_offset = 0, **kwargs):
    680         self._pointer = None
    681         self._pointer_offset = pointer_offset
    682         super(DestinationWaypointPanel, self).__init__(item_id=item_id, link_hint=localization.GetByLabel('UI/Neocom/Autopilot/CurrentDestination'), **kwargs)
    683 
    684     def layout(self):
    685         self._pointer = Sprite(parent=Container(parent=self, align=uiconst.TOTOP, height=12), align=uiconst.BOTTOMLEFT, state=uiconst.UI_DISABLED, left=self.pointer_offset, texturePath='res:/UI/Texture/classes/LocationInfo/pointerUp.png', width=10, height=10, color=self.COLOR_BACKGROUND)
    686         super(DestinationWaypointPanel, self).layout()
    687 
    688     @property
    689     def pointer_offset(self):
    690         return self._pointer_offset
    691 
    692     @pointer_offset.setter
    693     def pointer_offset(self, pointer_offset):
    694         self._pointer_offset = pointer_offset
    695         self._pointer.left = pointer_offset
    696 
    697 
    698 class TriglavianWarningIcon(Sprite):
    699 
    700     def __init__(self, **kwargs):
    701         super(TriglavianWarningIcon, self).__init__(texturePath='res:/UI/Texture/classes/Invasions/triglavianRace_18x18.png', width=18, height=18, hint=localization.GetByLabel('UI/Invasion/HUD/InvasionSolarSystemHint'), color=(1.0, 0.2, 0.1), **kwargs)