dockPanel.py (32275B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\mapView\dockPanel.py 2 import logging 3 import blue 4 import eveicon 5 from carbonui.button.menu import MenuButtonIcon 6 from carbonui.control.buttonIcon import ButtonIcon 7 from mathext import clamp 8 import localization 9 import uthread 10 from carbon.client.script.environment.AudioUtil import PlaySound 11 from carbonui import uiconst, Align 12 from carbonui.control.window import Window 13 from carbonui.primitives.base import Base 14 from carbonui.primitives.container import Container 15 from carbonui.primitives.fill import Fill 16 from carbonui.primitives.layoutGrid import LayoutGrid, LayoutGridRow 17 from carbonui.uicore import uicore 18 from carbonui.window.resizer import Side 19 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveLabelMediumBold 20 from carbonui.loggers.message_bus.windowMessenger import WindowMessenger, DOCKING_MODES_CONVERSION 21 from eve.client.script.ui.control.themeColored import FillThemeColored, StretchSpriteHorizontalThemeColored 22 from eve.client.script.ui.shared.infoPanels.const import infoPanelUIConst 23 from eve.client.script.ui.shared.infoPanels.infoPanelContainer import InfoPanelContainer 24 from eve.client.script.ui.shared.mapView.dockPanelUtil import GetDockPanelManager, GetPanelSettings, RegisterPanelSettings 25 from eveexceptions import EatsExceptions 26 logger = logging.getLogger(__name__) 27 TOOLBARWIDTH_FULLSCREEN = 400 28 TOOLBARHEIGHT = 26 29 BUTTON_FULLSCREEN = 1 30 BUTTON_DOCKLEFT = 2 31 BUTTON_DOCKRIGHT = 3 32 BUTTON_FLOAT = 4 33 BUTTON_DATA_BY_ID = {BUTTON_FULLSCREEN: ('res:/UI/Texture/classes/DockPanel/fullscreenButton.png', 'UI/Control/DockPanel/Fullscreen'), 34 BUTTON_DOCKLEFT: ('res:/UI/Texture/classes/DockPanel/dockLeftButton.png', 'UI/Control/DockPanel/DockLeft'), 35 BUTTON_DOCKRIGHT: ('res:/UI/Texture/classes/DockPanel/dockRightButton.png', 'UI/Control/DockPanel/DockRight'), 36 BUTTON_FLOAT: ('res:/UI/Texture/classes/DockPanel/floatButton.png', 'UI/Control/DockPanel/Floating')} 37 SNAP_RELEASE_THRESHOLD = 5 38 SNAP_INDICATOR_SIZE = 2 39 40 class DockablePanelHeaderButton(ButtonIcon): 41 default_width = 16 42 default_height = 16 43 default_minSize = (300, 300) 44 45 def GetTooltipPointer(self): 46 return uiconst.POINT_TOP_1 47 48 def GetTooltipDelay(self): 49 return 5 50 51 def GetTooltipPositionFallbacks(self, *args, **kwds): 52 return [uiconst.POINT_TOP_2, 53 uiconst.POINT_TOP_1, 54 uiconst.POINT_TOP_3, 55 uiconst.POINT_BOTTOM_2, 56 uiconst.POINT_BOTTOM_1, 57 uiconst.POINT_BOTTOM_3] 58 59 60 class DockablePanelHeaderButtonMenu(DockablePanelHeaderButton): 61 callback = None 62 tooltipPanelMenu = None 63 64 def __init__(self, dock_options, **kw): 65 super(DockablePanelHeaderButtonMenu, self).__init__(**kw) 66 self.dock_options = dock_options 67 68 def ApplyAttributes(self, attributes): 69 DockablePanelHeaderButton.ApplyAttributes(self, attributes) 70 self.panelID = attributes.panelID 71 self.callback = attributes.dockViewModeCallback 72 self.UpdateButtonState() 73 74 def Close(self, *args, **kwds): 75 DockablePanelHeaderButton.Close(self) 76 self.callback = None 77 self.tooltipPanelMenu = None 78 79 def UpdateButtonState(self): 80 currentSetting = GetPanelSettings(self.panelID) 81 align = currentSetting['align'] 82 if align == uiconst.TOALL: 83 buttonID = BUTTON_FULLSCREEN 84 elif align == uiconst.TOLEFT: 85 buttonID = BUTTON_DOCKLEFT 86 elif align == uiconst.TORIGHT: 87 buttonID = BUTTON_DOCKRIGHT 88 else: 89 buttonID = BUTTON_FLOAT 90 texturePath, labelPath = BUTTON_DATA_BY_ID[buttonID] 91 self.SetTexturePath(texturePath) 92 93 def GetTooltipPointer(self): 94 return uiconst.POINT_TOP_1 95 96 def GetTooltipDelay(self): 97 return 5 98 99 def GetTooltipPositionFallbacks(self, *args, **kwds): 100 return [uiconst.POINT_TOP_2, 101 uiconst.POINT_TOP_1, 102 uiconst.POINT_TOP_3, 103 uiconst.POINT_BOTTOM_2, 104 uiconst.POINT_BOTTOM_1, 105 uiconst.POINT_BOTTOM_3] 106 107 def LoadTooltipPanel(self, tooltipPanel, *args): 108 tooltipPanel.columns = 2 109 tooltipPanel.margin = 4 110 for buttonID in self.dock_options: 111 texturePath, labelPath = BUTTON_DATA_BY_ID[buttonID] 112 tooltipPanel.AddRow(rowClass=ButtonTooltipRow, buttonID=buttonID, texturePath=texturePath, label=localization.GetByLabel(labelPath), callback=self._LocalCallback) 113 114 tooltipPanel.state = uiconst.UI_NORMAL 115 self.tooltipPanelMenu = tooltipPanel 116 117 def _LocalCallback(self, buttonID): 118 if self.tooltipPanelMenu and not self.tooltipPanelMenu.destroyed: 119 self.tooltipPanelMenu.state = uiconst.UI_HIDDEN 120 if self.callback: 121 self.callback(buttonID) 122 self.UpdateButtonState() 123 124 125 class ButtonTooltipRow(LayoutGridRow): 126 default_state = uiconst.UI_NORMAL 127 callback = None 128 buttonID = None 129 130 def ApplyAttributes(self, attributes): 131 LayoutGridRow.ApplyAttributes(self, attributes) 132 self.callback = attributes.callback 133 self.buttonID = attributes.buttonID 134 self.icon = ButtonIcon(pos=(0, 0, 16, 16), texturePath=attributes.texturePath, state=uiconst.UI_DISABLED) 135 self.AddCell(cellObject=self.icon, cellPadding=(3, 2, 3, 2)) 136 label = EveLabelMedium(text=attributes.label, align=uiconst.CENTERLEFT) 137 self.AddCell(cellObject=label, cellPadding=(0, 1, 6, 1)) 138 self.highLight = Fill(bgParent=self, color=(1, 1, 1, 0.1), state=uiconst.UI_HIDDEN) 139 140 def Close(self, *args): 141 LayoutGridRow.Close(self, *args) 142 self.callback = None 143 144 def OnMouseEnter(self, *args): 145 self.icon.OnMouseEnter() 146 self.highLight.display = True 147 148 def OnMouseExit(self, *args): 149 self.icon.OnMouseExit() 150 self.highLight.display = False 151 152 def OnClick(self, *args): 153 if self.callback: 154 self.callback(self.buttonID) 155 156 157 class DockablePanel(Window): 158 default_captionLabelPath = None 159 default_isStackable = False 160 default_performFitsCheck = True 161 default_isLightBackgroundConfigurable = False 162 dock_options = (BUTTON_FULLSCREEN, 163 BUTTON_DOCKLEFT, 164 BUTTON_DOCKRIGHT, 165 BUTTON_FLOAT) 166 panelSize = (500, 500) 167 panelID = None 168 toolbarContainer = None 169 snapToDockMode = None 170 snapIndicator = None 171 viewState = None 172 hasImmersiveAudioOverlay = False 173 __notifyevents__ = ['OnViewStateChanged'] 174 175 def ApplyAttributes(self, attributes): 176 self._immersiveAudioOverlay = None 177 self._caption_label = None 178 attributes.windowID = attributes.panelID or self.panelID 179 attributes.parent = attributes.parent or uicore.layer.main 180 self.performFitsCheck = attributes.get('performFitsCheck', self.default_performFitsCheck) 181 super(DockablePanel, self).ApplyAttributes(attributes) 182 GetDockPanelManager() 183 self.content.state = uiconst.UI_NORMAL 184 self.CreateToolbar() 185 self.panelID = attributes.panelID or self.panelID 186 uicore.dockablePanelManager.RegisterPanel(self) 187 self.ConstructSidePanel() 188 if self.hasImmersiveAudioOverlay: 189 self._CreateImmersiveAudioOverlay() 190 191 @property 192 def content_padding(self): 193 return (2, 2, 2, 2) 194 195 def GetWindowBorderPadding(self): 196 if self.align == Align.TOALL: 197 return (0, 0, 0, 0) 198 else: 199 return super(DockablePanel, self).GetWindowBorderPadding() 200 201 def ConstructSidePanel(self): 202 self.sidePanel = Container(parent=self.GetMainArea(), name='sidePanel', align=uiconst.TOLEFT_NOPUSH, width=infoPanelUIConst.PANELWIDTH, padding=(0, 30, 0, 0), idx=0) 203 self.infoPanelContainer = InfoPanelContainer(parent=self.sidePanel, align=uiconst.TOTOP, settingsID='%s_dockablePanel' % self.windowID, performFitsCheck=self.performFitsCheck) 204 205 def OnViewStateChanged(self, from_view, to_view): 206 if not self.IsFullscreen(): 207 return 208 fullScreenView = self.GetFullscreenViewStateName() 209 viewStateSvc = sm.GetService('viewState') 210 if fullScreenView and from_view == fullScreenView and viewStateSvc.GetViewInfo(to_view).IsSecondary(): 211 self.Minimize() 212 213 def GetFullscreenViewStateName(self): 214 return self.viewState 215 216 def SetOrder(self, idx): 217 if not self.IsFloating(): 218 return 219 return Window.SetOrder(self, idx) 220 221 def InitializeStatesAndPosition(self, *args, **kw): 222 self.InitDockPanelPosition() 223 self._SetOpen(True) 224 if self.IsMinimized(): 225 self._SetMaximized() 226 227 def GetRegisteredPushedByIndex(self): 228 currentSettings = self.GetPanelSettings() 229 pushedBy = currentSettings['pushedBy'] 230 if pushedBy: 231 for objectName in reversed(pushedBy): 232 for obj in uicore.layer.sidePanels.children: 233 if obj.name == objectName: 234 index = uicore.layer.sidePanels.children.index(obj) + 1 235 return index 236 237 return 0 238 239 def GetFullScreenViewsOrdered(self): 240 return [ panel for panel in uicore.layer.sidePanels.children if isinstance(panel, DockablePanel) and panel.IsFullscreen() ] 241 242 def InitDockPanelPosition(self): 243 currentSettings = self.GetPanelSettings() 244 if currentSettings['align'] == uiconst.TOPLEFT: 245 self.UnDock() 246 elif currentSettings['align'] == uiconst.TOLEFT: 247 self.DockOnLeft() 248 elif currentSettings['align'] == uiconst.TORIGHT: 249 self.DockOnRight() 250 elif currentSettings['align'] == uiconst.TOALL: 251 self.DockFullscreen() 252 self.state = uiconst.UI_NORMAL 253 254 def GetAbsolutePosition(self): 255 stack = self.GetStack() 256 if stack: 257 return stack.contentCont.GetAbsolutePosition() 258 return Base.GetAbsolutePosition(self) 259 260 def InitializeSize(self, *args, **kwds): 261 pass 262 263 def RegisterPositionAndSize(self, *args, **kwds): 264 pass 265 266 def ToggleCollapse(self, *args, **kwds): 267 pass 268 269 def ToggleMinimize(self): 270 if not self.IsFullscreen(): 271 return Window.ToggleMinimize(self) 272 if self.IsMinimizable(): 273 if self.IsMinimized(): 274 self.Maximize() 275 else: 276 self.Minimize() 277 278 def Minimize(self, animate = True): 279 if self.GetFullscreenViewStateName() and self.IsFullscreen(): 280 uthread.new(sm.GetService('viewState').CloseSecondaryView, self.GetFullscreenViewStateName()) 281 if self._immersiveAudioOverlay: 282 self._immersiveAudioOverlay.set_minimized() 283 super(DockablePanel, self).Minimize(animate) 284 285 def Collapse(self, *args, **kwds): 286 pass 287 288 def Prepare_Header_(self): 289 if self.sr.headerParent: 290 self.sr.headerParent.Close() 291 self.sr.headerParent = Container(parent=self.sr.maincontainer, name='__headerParent', state=uiconst.UI_PICKCHILDREN, align=uiconst.TOTOP_NOPUSH, clipChildren=True, pos=(0, 292 0, 293 0, 294 TOOLBARHEIGHT + 2), padding=2, idx=0) 295 self.headerParent = self.sr.headerParent 296 297 def _is_side_resizable(self, side): 298 if self.IsFullscreen(): 299 return False 300 elif self.IsDockedLeft() and side != Side.RIGHT: 301 return False 302 elif self.IsDockedRight() and side != Side.LEFT: 303 return False 304 else: 305 return super(DockablePanel, self)._is_side_resizable(side) 306 307 @classmethod 308 def GetIfOpen(cls, *args, **kwds): 309 dockablePanelManager = GetDockPanelManager() 310 return dockablePanelManager.GetIfOpen(cls.panelID) 311 312 @classmethod 313 def CloseIfOpen(cls, *args, **kwds): 314 dockablePanelManager = GetDockPanelManager() 315 panel = dockablePanelManager.GetIfOpen(cls.panelID) 316 if panel: 317 panel.CloseByUser() 318 return True 319 return False 320 321 @classmethod 322 def Open(cls, *args, **kwds): 323 dockablePanelManager = GetDockPanelManager() 324 panel = dockablePanelManager.GetIfOpen(cls.panelID) 325 if panel: 326 return panel 327 return cls(*args, **kwds) 328 329 def CreateToolbar(self): 330 self.toolbarContainer = Container(parent=self.headerParent, name='toolbarContainer', align=uiconst.CENTERTOP, width=TOOLBARWIDTH_FULLSCREEN, height=TOOLBARHEIGHT, state=uiconst.UI_NORMAL) 331 self.toolbarContainer.DelegateEvents(self) 332 self._caption_label = EveLabelMediumBold(parent=self.toolbarContainer, align=uiconst.CENTER, text=self.caption) 333 FillThemeColored(bgParent=self.toolbarContainer, opacity=0.9, padding=(1, 1, 1, 0)) 334 grid = LayoutGrid(parent=self.toolbarContainer, columns=5, cellPadding=2, align=uiconst.CENTERRIGHT, left=6) 335 self.menuButton = MenuButtonIcon(name='DockPanel_MenuButton', parent=grid, texturePath=eveicon.more_vertical, get_menu_func=self.GetMenuMoreOptions, height=16, width=16) 336 self.menuButton.display = False 337 if len(self.dock_options) > 1: 338 self.dockViewModeButton = DockablePanelHeaderButtonMenu(name='DockPanel_HeaderButton_ChangeViewMode', parent=grid, dockViewModeCallback=self.ChangeViewMode, panelID=self.panelID, dock_options=self.dock_options) 339 else: 340 self.dockViewModeButton = None 341 if self.minimizable: 342 DockablePanelHeaderButton(name='DockPanel_HeaderButton_Minimize', parent=grid, hint=localization.GetByLabel('/Carbon/UI/Controls/Window/Minimize'), texturePath='res:/UI/Texture/classes/DockPanel/minimizeButton.png', func=self.Minimize) 343 DockablePanelHeaderButton(name='DockPanel_HeaderButton_Close', parent=grid, hint=localization.GetByLabel('UI/Generic/Close'), texturePath='res:/UI/Texture/classes/DockPanel/closeButton.png', func=self.CloseByUser) 344 StretchSpriteHorizontalThemeColored(texturePath='res:/UI/Texture/classes/MapView/toolbarLine.png', colorType=uiconst.COLORTYPE_UIHILIGHT, opacity=uiconst.OPACITY_FRAME, leftEdgeSize=64, rightEdgeSize=64, parent=self.toolbarContainer, align=uiconst.TOBOTTOM_NOPUSH, padding=(-48, 0, -48, -15), height=64) 345 StretchSpriteHorizontalThemeColored(texturePath='res:/UI/Texture/classes/MapView/toolbarFill.png', colorType=uiconst.COLORTYPE_UIBASE, leftEdgeSize=64, rightEdgeSize=64, parent=self.toolbarContainer, align=uiconst.TOBOTTOM_NOPUSH, padding=(-48, 0, -48, -15), height=64) 346 347 def Close(self, setClosed = False, *args, **kwds): 348 if self.destroyed: 349 return 350 Window.Close(self, setClosed=setClosed, *args) 351 if self.snapIndicator and not self.snapIndicator.destroyed: 352 self.snapIndicator.Close() 353 self.snapIndicator = None 354 uicore.dockablePanelManager.UnregisterPanel(self) 355 if self.GetFullscreenViewStateName() and self.IsFullscreen(): 356 sm.GetService('viewState').CloseSecondaryView(self.GetFullscreenViewStateName()) 357 if self._immersiveAudioOverlay: 358 self._immersiveAudioOverlay.close() 359 self._immersiveAudioOverlay = None 360 361 def ChangeViewMode(self, buttonID, *args, **kwds): 362 if buttonID == BUTTON_FULLSCREEN: 363 if not self.IsFullscreen(): 364 self.DockFullscreen() 365 elif buttonID == BUTTON_DOCKLEFT: 366 self.DockOnLeft() 367 elif buttonID == BUTTON_DOCKRIGHT: 368 self.DockOnRight() 369 elif self.is_undockable(): 370 self.UnDock() 371 self.sr.underlay.padding = self.GetWindowBorderPadding() 372 373 def is_undockable(self): 374 return BUTTON_FLOAT in self.dock_options 375 376 def _OnCaptionChanged(self): 377 if self._caption_label: 378 self._caption_label.text = self.caption 379 380 def IsFullscreen(self): 381 return self.align == uiconst.TOALL 382 383 def IsDockedLeft(self): 384 return self.align == uiconst.TOLEFT 385 386 def IsDockedRight(self): 387 return self.align == uiconst.TORIGHT 388 389 def IsFloating(self): 390 return self.align == uiconst.TOPLEFT 391 392 @apply 393 def displayRect(): 394 fget = Container.displayRect.fget 395 396 def fset(self, value): 397 Container.displayRect.fset(self, value) 398 uicore.dockablePanelManager.UpdateCameraCenter() 399 400 return property(**locals()) 401 402 def GetPanelSettings(self): 403 return GetPanelSettings(self.panelID) 404 405 def RegisterPanelSettings(self): 406 if not self.panelID: 407 return 408 current = self.GetPanelSettings() 409 current['align'] = self.align 410 if not self.IsFullscreen(): 411 current['dblToggleFullScreenAlign'] = self.align 412 if self.IsFloating(): 413 current['positionX'] = (self.left + self.width / 2) / float(uicore.desktop.width) 414 current['positionY'] = (self.top + self.height / 2) / float(uicore.desktop.height) 415 current['heightProportion'] = self.height / float(uicore.desktop.height) 416 current['widthProportion'] = self.width / float(uicore.desktop.width) 417 elif self.align in (uiconst.TOLEFT, uiconst.TORIGHT): 418 current['widthProportion_docked'] = min(0.5, self.width / float(uicore.desktop.width)) 419 current['heightProportion_docked'] = 1.0 420 RegisterPanelSettings(self.panelID, current) 421 if self.align in (uiconst.TOLEFT, uiconst.TORIGHT): 422 uicore.dockablePanelManager.UpdatePanelsPushedBySettings() 423 if self.dockViewModeButton: 424 self.dockViewModeButton.UpdateButtonState() 425 426 def CloseByUser(self, *args): 427 if not self.destroyed and self.IsClosable(): 428 self._LogWindowClosed() 429 PlaySound(uiconst.SOUND_CLOSE) 430 uthread.new(self.Close, True) 431 432 def _StartScale(self, sides): 433 if self.align == uiconst.TOALL: 434 return 435 self.scaleData = (self.left, 436 self.top, 437 self.width, 438 self.height) 439 if 'left' in sides and self.align != uiconst.TOLEFT: 440 modX = -1 441 elif 'right' in sides and self.align != uiconst.TORIGHT: 442 modX = 1 443 else: 444 modX = 0 445 if 'top' in sides: 446 modY = -1 447 elif 'bottom' in sides: 448 modY = 1 449 else: 450 modY = 0 451 if not (modX or modY): 452 return 453 self.scaleModifiers = (modX, modY) 454 self._scaling = True 455 uthread.new(self.OnScale, uicore.uilib.x, uicore.uilib.y) 456 457 def OnDblClick(self, *args, **kwds): 458 if self.IsFullscreen(): 459 currentSettings = self.GetPanelSettings() 460 currentSettings['align'] = currentSettings['dblToggleFullScreenAlign'] 461 RegisterPanelSettings(self.panelID, currentSettings) 462 self.InitDockPanelPosition() 463 else: 464 self.DockFullscreen() 465 466 def OnScale(self, initMouseX, initMouseY): 467 while self._scaling and uicore.uilib.leftbtn and not self.destroyed: 468 mouseX, mouseY = uicore.uilib.x, uicore.uilib.y 469 dX = mouseX - initMouseX 470 dY = mouseY - initMouseY 471 l, t, w, h = self.scaleData 472 widthMod, heightMod = self.scaleModifiers 473 if widthMod: 474 newWidth = max(self.GetMinWidth(), w - dX * -widthMod) 475 if self.align in (uiconst.TOLEFT, uiconst.TORIGHT): 476 newWidth = min(uicore.desktop.width / 2, newWidth) 477 self.width = newWidth 478 if widthMod < 0 and self.IsFloating(): 479 self.left = l + w - newWidth 480 if heightMod and self.IsFloating(): 481 newHeight = max(self.GetMinHeight(), h - dY * -heightMod) 482 self.height = newHeight 483 if heightMod < 0: 484 self.top = t + h - newHeight 485 self.RegisterPanelSettings() 486 blue.pyos.synchro.SleepWallclock(1) 487 488 self.ValidateWindows() 489 self.RegisterPanelSettings() 490 491 def OnScaleMove(self, dX, dY, scaleModifiers): 492 if self.align == uiconst.TOALL: 493 return 494 l, t, w, h = self.scaleData 495 widthMod, heightMod = self.scaleModifiers 496 if widthMod: 497 newWidth = max(self.GetMinWidth(), w - dX * -widthMod) 498 self.width = newWidth 499 if widthMod < 0 and self.IsFloating(): 500 self.left = l + w - newWidth 501 if heightMod and self.IsFloating(): 502 newHeight = max(self.GetMinHeight(), h - dY * -heightMod) 503 self.height = newHeight 504 if heightMod < 0: 505 self.top = t + h - newHeight 506 self.RegisterPanelSettings() 507 508 def DockFullscreen(self, *args): 509 if self.destroyed: 510 return 511 fullScreenViews = self.GetFullScreenViewsOrdered() 512 self.SetParent(uicore.layer.sidePanels) 513 self.toolbarContainer.align = uiconst.CENTERTOP 514 self.align = uiconst.TOALL 515 self.width = 0 516 self.height = 0 517 self.left = 0 518 self.top = 0 519 self.FinalizeModeChange() 520 for each in fullScreenViews: 521 each.SetParent(uicore.layer.sidePanels, -1) 522 523 self._CheckActivateFullScreenViewState() 524 525 def _CheckActivateFullScreenViewState(self): 526 currViewName = sm.GetService('viewState').GetActiveViewName() 527 fullScreenViewName = self.GetFullscreenViewStateName() 528 if fullScreenViewName and currViewName != fullScreenViewName: 529 self.ActivateViewStateView() 530 531 def DockOnRight(self, index = None, *args): 532 if index is None: 533 index = self.GetRegisteredPushedByIndex() 534 self._DockOnSide(align=uiconst.TORIGHT, index=index) 535 536 def DockOnLeft(self, index = None, *args): 537 if index is None: 538 index = self.GetRegisteredPushedByIndex() 539 self._DockOnSide(align=uiconst.TOLEFT, index=index) 540 541 def _DockOnSide(self, align, index = 0): 542 current = self.GetPanelSettings() 543 self.SetParent(uicore.layer.sidePanels, idx=index) 544 self.toolbarContainer.align = uiconst.TOTOP_NOPUSH 545 self.align = align 546 minWidth = min(self.GetMinWidth(), uicore.desktop.width / 2.0) 547 width = int(current['widthProportion_docked'] * uicore.desktop.width) 548 self.width = max(minWidth, min(width, uicore.desktop.width / 2.0)) 549 self.height = 0 550 self.left = 0 551 self.top = 0 552 self.FinalizeModeChange() 553 if self.GetFullscreenViewStateName(): 554 self.CloseViewStateView() 555 556 def UnDock(self, setPosition = True, registerSettings = True, *args): 557 if not self.is_undockable(): 558 return 559 if self.destroyed: 560 return 561 current = self.GetPanelSettings() 562 if self.parent != uicore.layer.main: 563 self.SetParent(uicore.layer.main, idx=0) 564 self.toolbarContainer.align = uiconst.TOTOP_NOPUSH 565 self.toolbarContainer.SetParent(self.headerParent, idx=0) 566 self.align = uiconst.TOPLEFT 567 self.width = max(self.GetMinWidth(), int(current['widthProportion'] * uicore.desktop.width)) 568 self.height = max(self.GetMinHeight(), int(current['heightProportion'] * uicore.desktop.height)) 569 if setPosition: 570 left = int(uicore.desktop.width * current['positionX']) - self.width / 2 571 self.left = clamp(left, 0, uicore.desktop.width - self.WINDOW_NEVER_OFFSCREEN_BUFFER) 572 top = int(uicore.desktop.height * current['positionY']) - self.height / 2 573 self.top = clamp(top, 0, uicore.desktop.height - self.WINDOW_NEVER_OFFSCREEN_BUFFER) 574 self.FinalizeModeChange(registerSettings) 575 if self.GetFullscreenViewStateName(): 576 self.CloseViewStateView() 577 578 def ActivateViewStateView(self): 579 self.infoPanelContainer.Hide() 580 uthread.new(sm.GetService('viewState').ActivateView, self.GetFullscreenViewStateName()) 581 582 def CloseViewStateView(self): 583 self.infoPanelContainer.Show() 584 sm.GetService('viewState').CloseSecondaryView(self.GetFullscreenViewStateName()) 585 586 def FinalizeModeChange(self, registerSettings = True): 587 if registerSettings: 588 self.RegisterPanelSettings() 589 uthread.new(uicore.dockablePanelManager.CheckViewState) 590 if self._immersiveAudioOverlay: 591 if self.IsFullscreen(): 592 self._immersiveAudioOverlay.set_full_screen() 593 elif self.IsMinimized(): 594 self._immersiveAudioOverlay.set_windowed() 595 else: 596 self._immersiveAudioOverlay.set_windowed() 597 self.Prepare_ScaleAreas_() 598 self.OnDockModeChanged(self) 599 600 def OnDockModeChanged(self, *args, **kwds): 601 pass 602 603 def DeactivateUnderlay(self): 604 if self.IsFullscreen(): 605 return 606 super(DockablePanel, self).DeactivateUnderlay() 607 608 def OnDragTick(self, *args, **kwds): 609 610 def FindSnapPosition(mousePosition, snapPositions): 611 for snapPosition, index in snapPositions: 612 if snapPosition - 2 < mousePosition < snapPosition + 2: 613 return (snapPosition, index) 614 615 snapToDockMode = self.snapToDockMode 616 xLeftPositions, xRightPositions = self.snapPositions 617 snapLeft = FindSnapPosition(uicore.uilib.x, xLeftPositions) 618 snapRight = FindSnapPosition(uicore.uilib.x, xRightPositions) 619 if snapLeft and BUTTON_DOCKLEFT in self.dock_options: 620 self.snapToDockMode = (BUTTON_DOCKLEFT, snapLeft) 621 elif snapRight and BUTTON_DOCKRIGHT in self.dock_options: 622 self.snapToDockMode = (BUTTON_DOCKRIGHT, snapRight) 623 elif uicore.uilib.y == 0: 624 self.snapToDockMode = (BUTTON_FULLSCREEN, (0, -1)) 625 elif self.snapToDockMode: 626 dockMode, (snapPosition, index) = self.snapToDockMode 627 if dockMode == BUTTON_FULLSCREEN and uicore.uilib.y > SNAP_RELEASE_THRESHOLD: 628 self.snapToDockMode = None 629 elif dockMode in (BUTTON_DOCKLEFT, BUTTON_DOCKRIGHT): 630 if not snapPosition - SNAP_RELEASE_THRESHOLD < uicore.uilib.x < snapPosition + SNAP_RELEASE_THRESHOLD: 631 self.snapToDockMode = None 632 if snapToDockMode != self.snapToDockMode: 633 self.UpdateSnapIndicator(xLeftPositions, xRightPositions) 634 635 def UpdateSnapIndicator(self, xLeftPositions, xRightPositions): 636 if self.snapToDockMode: 637 dockMode, (position, index) = self.snapToDockMode 638 if not self.snapIndicator: 639 self.snapIndicator = DockPanelSnapIndicator(parent=uicore.desktop, idx=0) 640 if dockMode == BUTTON_FULLSCREEN: 641 self.snapIndicator.align = uiconst.TOPLEFT 642 self.snapIndicator.left = max([ snapPosition for snapPosition, index in xLeftPositions ]) 643 self.snapIndicator.top = 0 644 self.snapIndicator.width = min([ snapPosition for snapPosition, index in xRightPositions ]) - self.snapIndicator.left 645 self.snapIndicator.height = SNAP_INDICATOR_SIZE 646 self.snapIndicator.Pulse() 647 return 648 if dockMode == BUTTON_DOCKLEFT: 649 onBoundary = xLeftPositions.index((position, index)) == 0 650 self.snapIndicator.align = uiconst.TOLEFT_NOPUSH 651 if onBoundary: 652 self.snapIndicator.left = position 653 else: 654 self.snapIndicator.left = position - SNAP_INDICATOR_SIZE 655 self.snapIndicator.top = 0 656 self.snapIndicator.width = SNAP_INDICATOR_SIZE 657 self.snapIndicator.height = 0 658 self.snapIndicator.Pulse() 659 return 660 if dockMode == BUTTON_DOCKRIGHT: 661 onBoundary = xRightPositions.index((position, index)) == 0 662 self.snapIndicator.align = uiconst.TOLEFT_NOPUSH 663 if onBoundary: 664 self.snapIndicator.left = position - SNAP_INDICATOR_SIZE 665 else: 666 self.snapIndicator.left = position - SNAP_INDICATOR_SIZE 667 self.snapIndicator.top = 0 668 self.snapIndicator.width = SNAP_INDICATOR_SIZE 669 self.snapIndicator.height = 0 670 self.snapIndicator.Pulse() 671 return 672 if self.snapIndicator: 673 self.snapIndicator.Rest(close=True) 674 self.snapIndicator = None 675 676 def _BeginDrag(self, *args, **kwds): 677 if not self.is_undockable(): 678 return 679 if not self.IsFloating(): 680 initMouseX, initMouseY = self.dragMousePosition 681 left, top, width, height = self.toolbarContainer.GetAbsolute() 682 if self.align == uiconst.TOALL: 683 propLeft = initMouseX / float(uicore.desktop.width) 684 else: 685 propLeft = (initMouseX - left) / float(width) 686 self.UnDock(setPosition=False, registerSettings=False) 687 self.left = uicore.uilib.x - int(self.width * propLeft) 688 self.top = 0 689 self.snapPositions = self.GetSnapPositions() 690 Window._BeginDrag(self) 691 self.state = uiconst.UI_NORMAL 692 693 def AdjustWindowPositionToFitScreen(self): 694 if not self.IsFloating(): 695 return 696 super(DockablePanel, self).AdjustWindowPositionToFitScreen() 697 698 def OnMouseUp(self, *args): 699 Window.OnMouseUp(self, *args) 700 if self.snapToDockMode: 701 dockMode, (position, index) = self.snapToDockMode 702 if dockMode == BUTTON_FULLSCREEN: 703 self.DockFullscreen() 704 elif dockMode == BUTTON_DOCKLEFT: 705 self.DockOnLeft(index=index) 706 elif dockMode == BUTTON_DOCKRIGHT: 707 self.DockOnRight(index=index) 708 self.snapToDockMode = None 709 if self.snapIndicator: 710 self.snapIndicator.Close() 711 self.snapIndicator = None 712 self.RegisterPanelSettings() 713 714 def GetSnapPositions(self): 715 xPositionLeft = [] 716 xPositionRight = [] 717 l, t, w, h = uicore.layer.sidePanels.GetAbsolute() 718 xPositionLeft.append((l, 0)) 719 xPositionRight.append((l + w - 1, 0)) 720 for index, each in enumerate(uicore.layer.sidePanels.children): 721 if each.align == uiconst.TOLEFT: 722 l, t, w, h = each.GetAbsolute() 723 xPositionLeft.append((l, index)) 724 xPositionLeft.append((l + w, index + 1)) 725 elif each.align == uiconst.TORIGHT: 726 l, t, w, h = each.GetAbsolute() 727 xPositionRight.append((l, index + 1)) 728 xPositionRight.append((l + w, index)) 729 730 return (xPositionLeft, xPositionRight) 731 732 def IsClosable(self): 733 return True 734 735 def _CreateImmersiveAudioOverlay(self): 736 if not self.hasImmersiveAudioOverlay: 737 return 738 self._immersiveAudioOverlay = sm.GetService('audio').CreateImmersiveOverlay(self.windowID) 739 740 @EatsExceptions('protoClientLogs') 741 def _LogWindowEventOpened(self): 742 if self.analyticID: 743 message_bus = WindowMessenger(sm.GetService('publicGatewaySvc')) 744 currentSettings = self.GetPanelSettings() 745 message_bus.window_opened(self.analyticID, DOCKING_MODES_CONVERSION[currentSettings.get('align', uiconst.TOPLEFT)]) 746 747 def UpdateUIScaling(self, *args): 748 super(DockablePanel, self).UpdateUIScaling(*args) 749 if not self.minimized and not self.IsFullscreen(): 750 self.InitDockPanelPosition() 751 752 753 class DockPanelSnapIndicator(Container): 754 755 def ApplyAttributes(self, attributes): 756 Container.ApplyAttributes(self, attributes) 757 self.fill = FillThemeColored(parent=self, colorType=uiconst.COLORTYPE_UIHILIGHTGLOW) 758 759 def Pulse(self): 760 uicore.animations.MorphScalar(self.fill, 'opacity', startVal=0.0, endVal=1.0, curveType=uiconst.ANIM_OVERSHOT, duration=0.1, callback=self.Rest) 761 762 def Rest(self, close = False): 763 if close: 764 uicore.animations.MorphScalar(self.fill, 'opacity', startVal=self.fill.opacity, endVal=0.0, duration=0.3, callback=self.Close) 765 else: 766 uicore.animations.MorphScalar(self.fill, 'opacity', startVal=self.fill.opacity, endVal=0.3, duration=0.5)