viewStateSvc.py (26170B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\services\viewStateSvc.py 2 import math 3 import blue 4 import carbonui.const as uiconst 5 import eveexceptions 6 import gametime 7 import localization 8 import log 9 import uthread 10 from billboards import load_billboard_playlist_for_view, unload_billboard_playlist_for_view 11 from carbon.common.script.sys.service import Service 12 from carbonui.control.layer import LayerCore 13 from carbonui.uicore import uicore 14 from eve.client.script.ui.services.message_bus.viewMessenger import ViewMessenger 15 from eve.client.script.ui.view import overlaySettings 16 from eve.client.script.ui.view.viewStateConst import ViewOverlay, is_entering_character_selection, is_entering_game 17 from eve.common.script.sys.idCheckers import IsTriglavianSystem 18 from eveprefs import boot 19 from fsdBuiltData.client.billboards import AreVideosSupportedForView 20 from globalConfig import BillboardTakeoverEnabled 21 22 def GetViewStateSvc(): 23 return sm.GetService('viewState') 24 25 26 class ViewStateError(Exception): 27 __guid__ = 'viewstate.ViewStateError' 28 29 30 class View(object): 31 __guid__ = 'viewstate.View' 32 __notifyevents__ = [] 33 __dependencies__ = [] 34 __layerClass__ = LayerCore 35 __progressMessageLabel__ = None 36 __subLayers__ = None 37 __overlays__ = set() 38 __suppressedOverlays__ = set() 39 __exclusiveOverlay__ = set() 40 41 def __init__(self): 42 self.name = None 43 self.layer = None 44 self.scene = None 45 self._dynamicViewType = None 46 47 def GetDynamicViewType(self): 48 if self._dynamicViewType is None: 49 raise RuntimeError('View %s was activated without being set to Primary or Secondary' % self.name) 50 return self._dynamicViewType 51 52 def SetDynamicViewType(self, viewType): 53 self._dynamicViewType = viewType 54 55 def LoadView(self, **kwargs): 56 self.LogInfo('LoadView called on view', self.name, 'kwargs', kwargs) 57 58 def UnloadView(self): 59 self.LogInfo('UnloadView called on view', self.name) 60 61 def ShowView(self, **kwargs): 62 self.LogInfo('ShowView called on view', self.name, 'with', kwargs) 63 64 def HideView(self): 65 self.LogInfo('HideView called on view', self.name) 66 67 def ZoomBy(self, amount): 68 if self.layer: 69 self.layer.ZoomBy(amount) 70 71 def IsActive(self): 72 return sm.GetService('viewState').IsViewActive(self.name) 73 74 def GetProgressText(self, **kwargs): 75 if self.__progressMessageLabel__: 76 return localization.GetByLabel(self.__progressMessageLabel__) 77 78 def CanEnter(self, **kwargs): 79 return True 80 81 def CanExit(self): 82 return True 83 84 def CheckShouldReopen(self, newKwargs, cachedKwargs): 85 return newKwargs == cachedKwargs 86 87 def LoadCamera(self, cameraID = None, reopen = False): 88 pass 89 90 def __repr__(self): 91 return '%s(name=%s)' % (self.__class__.__name__, self.name) 92 93 def LogInfo(self, *args, **kwargs): 94 sm.GetService('viewState').LogInfo(self, *args, **kwargs) 95 96 def LogWarn(self, *args, **kwargs): 97 sm.GetService('viewState').LogWarn(self, *args, **kwargs) 98 99 def LogError(self, *args, **kwargs): 100 sm.GetService('viewState').LogError(self, *args, **kwargs) 101 102 103 class Transition(object): 104 __guid__ = 'viewstate.Transition' 105 106 def __init__(self, allowReopen = True, fallbackView = None): 107 self.allowReopen = allowReopen 108 self.fallbackView = fallbackView 109 self.transitionReason = None 110 self.animatedOut = set() 111 112 def StartTransition(self, fromView, toView): 113 sm.GetService('viewState').LogInfo('Transition starting for', fromView, 'to', toView, '(' + self.__class__.__name__ + ')') 114 115 def EndTransition(self, fromView, toView): 116 sm.GetService('viewState').LogInfo('Transition ending for', fromView, 'to', toView) 117 self.transitionReason = None 118 119 def IsActive(self): 120 return self.active 121 122 def SetTransitionReason(self, reason, allowOverwrite = False): 123 if reason is None or self.transitionReason is not None and not allowOverwrite: 124 return 125 self.transitionReason = reason 126 127 def AnimateUIIn(self, duration = 2): 128 uthread.new(self._AnimateUIIn, duration) 129 130 def _AnimateUIIn(self, duration = 2): 131 curveSet = None 132 for layer, doSleep in ((uicore.layer.main, False), (uicore.layer.viewstate, True)): 133 if layer in self.animatedOut: 134 layer.display = True 135 self.animatedOut.remove(layer) 136 uicore.animations.FadeIn(layer, curveSet=curveSet, duration=duration, sleep=doSleep) 137 138 self.animatedOut = set() 139 140 def AnimateUIOut(self, duration = 0.5): 141 uthread.new(self._AnimateUIOut, duration) 142 143 def _AnimateUIOut(self, duration = 0.5): 144 curveSet = None 145 myCallback = lambda : self.FadeOutEndCallback(uicore.layer.main) 146 uicore.animations.FadeOut(uicore.layer.main, duration=duration, curveSet=curveSet, callback=myCallback) 147 myCallback = lambda : self.FadeOutEndCallback(uicore.layer.viewstate) 148 uicore.animations.FadeOut(uicore.layer.viewstate, duration=duration, sleep=True, curveSet=curveSet, callback=myCallback) 149 150 def FadeOutEndCallback(self, layer, *args): 151 if layer.display: 152 self.animatedOut.add(layer) 153 layer.display = False 154 155 def GetCameraID(self): 156 return None 157 158 159 class ViewType: 160 __guid__ = 'viewstate.ViewType' 161 Primary = 0 162 Secondary = 1 163 Dynamic = 2 164 165 166 class ViewInfo(object): 167 __guid__ = 'viewstate.ViewInfo' 168 169 def __init__(self, name, view, viewType = ViewType.Primary): 170 self.name = name 171 self.view = view 172 self.viewType = viewType 173 self.entryArguments = None 174 175 def GetViewType(self): 176 if self.viewType == ViewType.Dynamic: 177 return self.view.GetDynamicViewType() 178 else: 179 return self.viewType 180 181 def IsPrimary(self): 182 return self.GetViewType() == ViewType.Primary 183 184 def IsSecondary(self): 185 return self.GetViewType() == ViewType.Secondary 186 187 def __repr__(self): 188 return 'ViewInfo(view=%s type=%d)' % (self.view, self.viewType) 189 190 191 class ViewStateSvc(Service): 192 __guid__ = 'svc.viewState' 193 __servicename__ = 'view state manager' 194 __displayname__ = 'View State Manager' 195 __notifyevents__ = ['OnShowUI'] 196 __dependencies__ = ['loading'] 197 198 def Run(self, memStream = None): 199 self.viewLayerParent = None 200 self.viewInfosByName = {} 201 self.transitionsByNames = {} 202 self.overlaysByName = {} 203 self.overlayLayerParent = None 204 self.primaryInfo = None 205 self.secondaryInfo = None 206 self.activeViewInfo = None 207 self.activeTransition = None 208 self.isOpeningView = None 209 self.lastViewOpenTime = None 210 self.initialized = False 211 212 def Initialize(self, viewLayerParent): 213 self.viewLayerParent = viewLayerParent 214 self.overlayLayerParent = self.viewLayerParent.AddLayer('l_view_overlays', LayerCore) 215 self.lastViewOpenTime = blue.os.GetWallclockTime() 216 self.initialized = True 217 218 def ActivateView(self, name, **kwargs): 219 self.LogInfo('Activating view', name, 'with key words', kwargs) 220 transitionFailed = False 221 if self.isOpeningView is not None: 222 self.LogInfo("Can't activate view", name, '. already busy opening view', self.isOpeningView) 223 return 224 self.isOpeningView = name 225 error = None 226 try: 227 newInfo = self.GetViewInfo(name) 228 oldInfo = self.secondaryInfo or self.primaryInfo 229 if newInfo.viewType == ViewType.Dynamic: 230 if self.primaryInfo is None: 231 newInfo.view.SetDynamicViewType(ViewType.Primary) 232 else: 233 newInfo.view.SetDynamicViewType(ViewType.Secondary) 234 transition = self.GetTransition(oldInfo, newInfo) 235 if transition is None and oldInfo is not None and newInfo.name == oldInfo.name: 236 self.LogInfo('No valid transition found for view', name, 'to view', name, '. Skipping since it is is already active') 237 else: 238 if oldInfo: 239 try: 240 if not oldInfo.view.CanExit(): 241 oldInfo.view.LogInfo('Unable to exit view at present') 242 return False 243 except: 244 log.LogException() 245 246 try: 247 if not newInfo.view.CanEnter(**kwargs): 248 newInfo.view.LogInfo('Unable to enter view now. Arguments:', kwargs) 249 return False 250 except: 251 log.LogException() 252 253 viewOpenTime = blue.os.GetWallclockTime() 254 self.activeTransition = transition 255 oldViewName = oldInfo.name if oldInfo else None 256 newViewName = newInfo.name 257 sm.ScatterEvent('OnBeforeViewStateChanged', oldViewName, newViewName) 258 try: 259 self.activeTransition.StartTransition(oldInfo.view if oldInfo else None, newInfo.view) 260 cameraID = self.activeTransition.GetCameraID() 261 except: 262 cameraID = None 263 log.LogException() 264 265 progressText = newInfo.view.GetProgressText(**kwargs) 266 if progressText: 267 sm.GetService('loading').ProgressWnd(progressText, '', 1, 2) 268 reopen = False 269 if newInfo.GetViewType() == ViewType.Secondary: 270 if self.secondaryInfo: 271 reopen = self.activeTransition.allowReopen and newInfo == self.secondaryInfo 272 if reopen: 273 try: 274 reopen = newInfo.view.CheckShouldReopen(kwargs, newInfo.entryArguments) 275 except: 276 log.LogException() 277 reopen = False 278 279 self._CloseView(self.secondaryInfo, unload=not reopen) 280 else: 281 self._CloseView(self.primaryInfo, unload=False) 282 else: 283 if self.secondaryInfo: 284 self._CloseView(self.secondaryInfo) 285 if self.primaryInfo: 286 if self.activeTransition.allowReopen and newInfo == self.primaryInfo: 287 try: 288 self.primaryInfo.view.CheckShouldReopen(kwargs, newInfo.entryArguments) 289 reopen = True 290 except: 291 log.LogException() 292 293 self._CloseView(self.primaryInfo, unload=False) 294 else: 295 self._CloseView(self.primaryInfo) 296 self.activeViewInfo = newInfo 297 uthread.new(sm.GetService('audio').LoadBanksForView, newInfo.name) 298 if newInfo.GetViewType() == ViewType.Primary: 299 self._PrepareBillboards(newInfo, oldInfo) 300 self._OpenPrimaryView(newInfo, reopen=reopen, cameraID=cameraID, **kwargs) 301 else: 302 self._OpenView(newInfo, reopen=reopen, cameraID=cameraID, **kwargs) 303 self.UpdateOverlays() 304 if progressText is not None: 305 sm.GetService('loading').ProgressWnd(progressText, '', 2, 2) 306 try: 307 transitionFailed = self.activeTransition.EndTransition(oldInfo, newInfo) 308 except: 309 log.LogException() 310 311 self._LogViewActivated() 312 if oldInfo: 313 integer, fractions = self.GetSplitTimeFromTimestamp(self.lastViewOpenTime) 314 self._LogViewDeactivated(oldInfo.name, int(integer), int(fractions)) 315 self.lastViewOpenTime = viewOpenTime 316 if newInfo.GetViewType() == ViewType.Primary: 317 sm.ScatterEvent('OnClientReady', newInfo.name) 318 self.LogInfo('View', name, 'was activated') 319 self._NotifyOfViewStateChange(oldViewName, newViewName) 320 except eveexceptions.UserError as e: 321 self.LogInfo('UserError raised while making a transition. UserError', e) 322 if newInfo.GetViewType() == ViewType.Secondary: 323 error = e 324 else: 325 raise RuntimeError('UserError raised while transitioning from %s to %s UserError: %s' % (oldInfo, newInfo, e)) 326 finally: 327 self.isOpeningView = None 328 if transitionFailed: 329 self.ActivateView(self.activeTransition.fallbackView, **kwargs) 330 self.activeTransition = None 331 sm.GetService('loading').HideAllLoad() 332 333 if error: 334 self.LogInfo('Trying to re-enter primary view', self.primaryInfo.name, 'using cached entry arguments', self.primaryInfo.entryArguments) 335 uthread.new(self.ActivateView, self.primaryInfo.name, **self.primaryInfo.entryArguments).context = 'viewStateSvc::AttemptToRecoverFromUserError' 336 raise error 337 return True 338 339 def _NotifyOfViewStateChange(self, old_state, new_state): 340 sm.ScatterEvent('OnViewStateChanged', old_state, new_state) 341 if is_entering_character_selection(new_state): 342 sm.ScatterEvent('OnCharacterSelectionViewEntered') 343 elif is_entering_game(old_state, new_state): 344 sm.ScatterEvent('OnGameViewEntered') 345 346 def GetSplitTimeFromTimestamp(self, timestamp): 347 if not timestamp: 348 return 349 secondsSinceTimestamp = gametime.GetSecondsSinceWallclockTime(timestamp) 350 fractions, integer = math.modf(secondsSinceTimestamp) 351 return (integer, fractions * 1000000000.0) 352 353 @eveexceptions.EatsExceptions('protoClientLogs') 354 def _LogViewActivated(self): 355 message_bus = ViewMessenger(sm.GetService('publicGatewaySvc')) 356 message_bus.view_activated(self.activeViewInfo.name) 357 358 @eveexceptions.EatsExceptions('protoClientLogs') 359 def _LogViewDeactivated(self, view_name, seconds_active, nanoseconds_active): 360 message_bus = ViewMessenger(sm.GetService('publicGatewaySvc')) 361 message_bus.view_deactivated(view_name, seconds_active, nanoseconds_active) 362 363 def _PrepareBillboards(self, newInfo, oldInfo): 364 if oldInfo: 365 unload_billboard_playlist_for_view(oldInfo.name) 366 if AreVideosSupportedForView(newInfo.name): 367 locale = str(blue.os.languageID.lower()) 368 if boot.role == 'optic': 369 locale = 'zh' 370 videoOverrides = {} 371 if IsTriglavianSystem(session.solarsystemid2): 372 videoOverrides['triglavianOvertaken'] = True 373 else: 374 videoOverrides['triglavianInvasion'] = BillboardTakeoverEnabled(sm.GetService('machoNet')) 375 load_billboard_playlist_for_view(newInfo.name, locale, **videoOverrides) 376 377 def StartDependantServices(self, viewInfo): 378 for serviceName in viewInfo.view.__dependencies__: 379 setattr(viewInfo.view, serviceName, sm.StartServiceAndWaitForRunningState(serviceName)) 380 self.LogInfo('Dependant service', serviceName, 'has started') 381 382 self.LogInfo('All dependant services started for view', viewInfo.name) 383 384 def _OpenPrimaryView(self, viewInfo, reopen = False, cameraID = None, **kwargs): 385 blue.SetCrashKeyValues('ViewState', viewInfo.name) 386 blue.statistics.SetTimelineSectionName(viewInfo.name) 387 self._OpenView(viewInfo, reopen=reopen, cameraID=cameraID, **kwargs) 388 389 def _OpenView(self, viewInfo, reopen = False, cameraID = None, **kwargs): 390 self.LogInfo('Re-open view' if reopen else 'Opening view', viewInfo, 'with kwargs', kwargs) 391 self.StartDependantServices(viewInfo) 392 showView = True 393 oldView = self.primaryInfo 394 if viewInfo.GetViewType() == ViewType.Primary: 395 if self.activeViewInfo.GetViewType() == ViewType.Secondary: 396 showView = False 397 self.primaryInfo = viewInfo 398 sm.ScatterEvent('OnPrimaryViewChanged', oldView, self.primaryInfo) 399 else: 400 self.secondaryInfo = viewInfo 401 try: 402 if showView: 403 self.LogInfo('Opening layer', viewInfo.view.layer.name) 404 viewInfo.view.layer.OpenView(**kwargs) 405 viewInfo.view.layer.pickState = uiconst.TR2_SPS_ON 406 viewInfo.view.layer.display = True 407 else: 408 self.LogInfo('Changing the primary layer while a secondary view', self.activeViewInfo.name, 'is active') 409 except: 410 log.LogException() 411 412 try: 413 if reopen: 414 self.LogInfo('View', viewInfo.name, 'is being re-opened') 415 else: 416 self.LogInfo('View', viewInfo.name, 'is being loaded.') 417 viewInfo.view.LoadView(**dict(lastView=oldView, **kwargs)) 418 if showView: 419 self.LogInfo('Showing view', viewInfo.name) 420 viewInfo.view.ShowView(**kwargs) 421 viewInfo.view.LoadCamera(cameraID, reopen) 422 except: 423 log.LogException() 424 425 sm.RegisterNotify(viewInfo.view) 426 sm.ScatterEvent('OnViewLoaded', oldView, self.primaryInfo) 427 viewInfo.entryArguments = kwargs 428 self.LogInfo('view', viewInfo, 'opened') 429 430 def _CloseView(self, viewInfo, unload = True): 431 try: 432 viewInfo.view.layer.CloseView(recreate=False) 433 except: 434 log.LogException() 435 436 viewInfo.view.layer.display = False 437 try: 438 viewInfo.view.HideView() 439 if unload: 440 sm.UnregisterNotify(viewInfo.view) 441 viewInfo.view.UnloadView() 442 self.LogInfo('Unloading view', viewInfo.name) 443 except: 444 log.LogException() 445 446 if viewInfo.GetViewType() == ViewType.Primary: 447 if unload: 448 viewInfo.entryArguments = None 449 else: 450 self.secondaryInfo = None 451 sm.ScatterEvent('OnViewClosed', viewInfo.name) 452 453 def ChangePrimaryView(self, name, **kwargs): 454 self.LogInfo('ChangePrimaryView', name) 455 while self.isOpeningView: 456 blue.pyos.synchro.Yield() 457 458 if self.secondaryInfo: 459 if (self.secondaryInfo.name, name) not in self.transitionsByNames: 460 raise ViewStateError('Changing primary view to %s from current active secondary view %s will leave the viewStateSvc in an undefined state' % (name, self.secondaryInfo.name)) 461 viewInfo = self.GetViewInfo(name) 462 self._CloseView(self.primaryInfo) 463 self._OpenView(viewInfo, **kwargs) 464 self.UpdateOverlays() 465 else: 466 return self.ActivateView(name, **kwargs) 467 468 def GetTransition(self, oldInfo, newInfo): 469 oldViewName = oldInfo.name if oldInfo else None 470 transition = self.transitionsByNames.get((oldViewName, newInfo.name)) 471 if transition is None: 472 transition = self.transitionsByNames.get((None, newInfo.name)) 473 if transition is None: 474 raise ViewStateError('There is not a valid transition from %s to %s' % (oldViewName, newInfo.name)) 475 self.LogInfo('Found transition from', oldViewName, 'to', newInfo.name) 476 return transition 477 478 def GetTransitionByName(self, fromName, toName): 479 if (fromName, toName) in self.transitionsByNames: 480 return self.transitionsByNames[fromName, toName] 481 482 def GetView(self, name): 483 return self.GetViewInfo(name).view 484 485 def HasView(self, name): 486 return name in self.viewInfosByName 487 488 def GetViewInfo(self, name): 489 try: 490 return self.viewInfosByName[name] 491 except KeyError: 492 raise ViewStateError('There is no view registered by the name %s' % name) 493 494 def GetCurrentViewInfo(self): 495 return self.activeViewInfo 496 497 def GetCurrentView(self): 498 return getattr(self.activeViewInfo, 'view', None) 499 500 def IsInitialized(self): 501 return self.initialized 502 503 def IsViewActive(self, *names): 504 return getattr(self.activeViewInfo, 'name', None) in names 505 506 def IsPrimaryViewActive(self, *names): 507 return getattr(self.primaryInfo, 'name', None) in names 508 509 def GetActiveViewName(self): 510 return getattr(self.activeViewInfo, 'name', None) 511 512 def HasActiveTransition(self): 513 if self.activeTransition is not None: 514 return True 515 else: 516 return False 517 518 def AddView(self, name, view, viewType = ViewType.Primary): 519 self.LogInfo('Adding view', name, view, viewType) 520 view.name = name 521 info = ViewInfo(name, view, viewType) 522 view.layer = self.viewLayerParent.AddLayer('l_%s' % name, view.__layerClass__, view.__subLayers__) 523 view.layer.state = uiconst.UI_HIDDEN 524 self.viewInfosByName[name] = info 525 526 def AddTransition(self, fromName, toName, transition = Transition()): 527 self.LogInfo('Adding transition', fromName or '[All]', toName, transition) 528 self.transitionsByNames[fromName, toName] = transition 529 530 def AddTransitions(self, fromNames, toNames, transition = Transition()): 531 for fromName in fromNames: 532 for toName in toNames: 533 self.AddTransition(fromName, toName, transition) 534 535 def GetPrimaryView(self): 536 try: 537 return self.primaryInfo.view 538 except AttributeError: 539 raise ViewStateError('There is no primary view set') 540 541 def CloseSecondaryView(self, name = None): 542 while self.isOpeningView: 543 blue.pyos.synchro.Yield() 544 545 if self.secondaryInfo is None: 546 self.LogInfo("Can't close secondary view since none is active") 547 else: 548 if name is None or self.activeViewInfo.name == name: 549 self.LogInfo('closing secondary view', self.secondaryInfo.name) 550 args = self.primaryInfo.entryArguments if self.primaryInfo.entryArguments is not None else dict() 551 return self.ActivateView(self.primaryInfo.name, **args) 552 self.LogInfo('The secondary view', name, 'was not closed as is not active') 553 554 def ToggleSecondaryView(self, name, **kwargs): 555 self.LogInfo('Toggling view', name) 556 while self.isOpeningView: 557 blue.pyos.synchro.Yield() 558 559 info = self.GetViewInfo(name) 560 if info.GetViewType() != ViewType.Secondary: 561 raise RuntimeError('You can only toggle secondary views (tools)') 562 if self.IsViewActive(name): 563 return self.CloseSecondaryView(name) 564 else: 565 return self.ActivateView(name, **kwargs) 566 567 def IsCurrentViewPrimary(self): 568 return self.activeViewInfo.GetViewType() == ViewType.Primary 569 570 def IsCurrentViewSecondary(self): 571 activeViewInfo = getattr(self, 'activeViewInfo', None) 572 if activeViewInfo: 573 return activeViewInfo.GetViewType() == ViewType.Secondary 574 else: 575 return False 576 577 def AddOverlay(self, name, overlayClass, subLayers = None): 578 if name not in self.overlaysByName: 579 overlay = self.overlayLayerParent.AddLayer('l_%s' % name, overlayClass, subLayers) 580 overlay.display = False 581 self.overlaysByName[name] = overlay 582 583 def UpdateOverlays(self, forcedUpdateOnOverlays = ()): 584 activeOverlays = self._GetOverlaysToEnable() 585 self.LogInfo('Overlays to enable', activeOverlays) 586 for name, overlay in self.overlaysByName.items(): 587 try: 588 if name in activeOverlays or name in self.activeViewInfo.view.__exclusiveOverlay__: 589 if overlay in forcedUpdateOnOverlays: 590 overlay.CloseView(recreate=False) 591 overlay.OpenView() 592 overlay.display = True 593 sm.ScatterEvent('OnOverlayActivated', name) 594 self.LogInfo('Overlay', name, 'activated') 595 else: 596 overlay.display = False 597 overlay.CloseView(recreate=False) 598 self.overlaysByName[name] = uicore.layer.Get(name) 599 sm.ScatterEvent('OnOverlayClosed', name) 600 self.LogInfo('Overlay', name, 'closed') 601 except: 602 log.LogException() 603 604 if sm.GetService('ui').IsUISuppressed(): 605 sm.GetService('ui').SuppressUI() 606 607 def _GetOverlaysToEnable(self): 608 activeOverlays = self.primaryInfo.view.__overlays__.copy() 609 if self.secondaryInfo: 610 activeOverlays.update(self.secondaryInfo.view.__overlays__) 611 activeOverlays.difference_update(self.primaryInfo.view.__suppressedOverlays__) 612 if self.secondaryInfo: 613 activeOverlays.difference_update(self.secondaryInfo.view.__suppressedOverlays__) 614 activeOverlays.difference_update(overlaySettings.GetOverlaysDisabledInFullscreen()) 615 return activeOverlays 616 617 def SafeLogoffInProgress(self): 618 shipUI = self.overlaysByName.get(ViewOverlay.ShipUI, None) 619 if shipUI is None or shipUI.destroyed: 620 return False 621 logoffTimer = getattr(shipUI, 'logoffTimer', None) 622 if logoffTimer is None or logoffTimer.destroyed: 623 return False 624 return logoffTimer.IsVisible() 625 626 def SetTransitionReason(self, fromName, toName, reason): 627 self.LogInfo('Adding transition reason ', fromName or '[All]', toName, reason) 628 self.transitionsByNames[fromName, toName].SetTransitionReason(reason) 629 630 def GetActiveTransitionReason(self): 631 if self.activeTransition is None: 632 return 633 return self.activeTransition.transitionReason 634 635 def GetActiveTransition(self): 636 return self.activeTransition 637 638 def OnShowUI(self): 639 if sm.GetService('ui').IsUiVisible(): 640 self.UpdateOverlays()