window.py (130049B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\window.py 2 import math 3 import sys 4 import weakref 5 import blue 6 import eveicon 7 import gametime 8 import localization 9 import log 10 import signals 11 import telemetry 12 import types 13 import uthread 14 from carbon.common.script.sys.serviceConst import ROLE_PROGRAMMER 15 from carbon.client.script.environment.AudioUtil import PlaySound 16 from carbonui.text.settings import set_font_size_setting 17 from carbonui.text.settings import FontSizeOption 18 from carbonui import uiconst 19 from carbonui.control.animatedsprite import AnimSprite 20 from carbonui.control.button import Button 21 from carbonui.button.const import ButtonVariant 22 from carbonui.control.contextMenu.menuData import MenuData, MenuEntryData 23 from carbonui.window.resizer import Resizer, Side 24 from carbonui.window.snap import find_sibling_windows, SNAP_DISTANCE, WINDOW_SNAP_DISTANCE 25 from carbonui.window.underlay import WindowUnderlay 26 from carbonui.primitives.container import Container 27 from carbonui.primitives.containerAutoSize import ContainerAutoSize 28 from carbonui.primitives.fill import Fill 29 from carbonui.primitives.sprite import Sprite 30 from carbonui.primitives.transform import Transform 31 from carbonui.uianimations import animations 32 from carbonui.uicore import uicore 33 from carbonui.util.bunch import Bunch 34 from carbonui.util.various_unsorted import GetWindowAbove, Transplant 35 from carbonui.window.header.base import WindowHeaderBase 36 from carbonui.window.settings import GetRegisteredState, RegisterState, WindowCompactModeSetting, WindowMarginMode, window_compact_mode_default_setting, window_margin_mode 37 from carbonui.window.util import is_blocked 38 from eve.client.script.ui import eveThemeColor 39 from carbonui.button.group import ButtonGroup, ButtonSizeMode 40 from carbonui.loggers.message_bus.windowMessenger import WindowMessenger 41 from carbonui.window.control.default import DefaultWindowControls 42 from carbonui.window.control.action import CloseWindowAction, CollapseWindowAction, CompactModeWindowAction, LightBackgroundWindowAction, LockWindowAction, MinimizeWindowAction, OverlayWindowAction 43 from carbonui.window.header.default import DefaultWindowHeader 44 from eveexceptions import EatsExceptions, UserError 45 from menu import MenuLabel 46 POSOVERLAPSHIFT = 11 47 LEGACY_SIDE_NAME_BY_SIDE = {Side.LEFT: 'left', 48 Side.TOP: 'top', 49 Side.RIGHT: 'right', 50 Side.BOTTOM: 'bottom'} 51 52 class Window(Container): 53 __guid__ = 'uicontrols.Window' 54 isDragObject = True 55 isTopLevelWindow = True 56 default_width = 256 57 default_height = 128 58 default_minSize = (default_width, default_height) 59 default_maxSize = (None, None) 60 default_fixedHeight = None 61 default_fixedWidth = None 62 default_left = '__center__' 63 default_top = '__center__' 64 default_name = 'window' 65 default_idx = 0 66 default_state = uiconst.UI_HIDDEN 67 default_isLightBackground = False 68 default_isLightBackgroundConfigurable = True 69 default_isOverlayed = False 70 default_isOverlayable = True 71 default_iconNum = 'res:/UI/Texture/WindowIcons/other.png' 72 default_scope = uiconst.SCOPE_INGAME 73 default_soundOpen = None 74 default_extend_content_into_header = False 75 default_apply_content_padding = True 76 default_windowInstanceID = None 77 default_stackID = None 78 default_caption = None 79 default_captionLabelPath = None 80 default_descriptionLabelPath = None 81 default_align = uiconst.RELATIVE 82 default_openMinimized = False 83 default_isKillable = True 84 default_isMinimizable = True 85 default_isStackable = True 86 default_isCompactable = False 87 default_isLockable = True 88 default_useDefaultPos = False 89 default_analyticID = None 90 default_isCollapseable = True 91 default_isCompact = None 92 default_windowID = None 93 WINDOW_NEVER_OFFSCREEN_BUFFER = 20 94 COLLAPSE_AREA_HEIGHT = 25 95 __active = False 96 __active_snap_grid = None 97 __caption = None 98 __closing = False 99 __collapsed = False 100 __drag_started = False 101 __focused_at_timestamp = None 102 __header = None 103 __header_has_sufficient_bottom_padding = False 104 __header_inset = (0, 0) 105 __hide_loading_indicator_requested = False 106 __hovered = False 107 __modal_result = None 108 __on_active_changed = None 109 __on_caption_changed = None 110 __on_collapsed_changed = None 111 __on_collapsible_changed = None 112 __on_compact_mode_changed = None 113 __on_content_padding_changed = None 114 __on_end_scale = None 115 __on_fixed_height_changed = None 116 __on_fixed_width_changed = None 117 __on_header_height_changed = None 118 __on_header_inset_changed = None 119 __on_icon_changed = None 120 __on_killable_changed = None 121 __on_light_background_changed = None 122 __on_lockable_changed = None 123 __on_locked_changed = None 124 __on_margin_mode_changed = None 125 __on_minimizable_changed = None 126 __on_stacked_changed = None 127 __on_start_scale = None 128 __on_window_state_changed = None 129 __opened_at_timestamp = None 130 __previous_content_padding = None 131 __previous_header_height = None 132 __ready = False 133 __resizer = None 134 __scale_sides = None 135 __stack = None 136 __window_controls = None 137 __window_controls_cont = None 138 139 @staticmethod 140 def __get_default_compact(window_ref): 141 window = window_ref() 142 if not window or window.closing: 143 return False 144 elif window.compactable and window.default_isCompact is None: 145 return window_compact_mode_default_setting.get() 146 else: 147 return window.default_isCompact 148 149 @classmethod 150 def Reload(cls, instance): 151 attributes = instance.attributesBunch 152 state = instance.state 153 if instance.isDialog: 154 instance.Close() 155 return 156 attributes.openMinimized = instance.IsMinimized() 157 instance.Close() 158 wnd = cls.Open(**attributes) 159 wnd.SetState(state) 160 161 def __init__(self, show_window_controls = True, **kwargs): 162 self.default_parent = uicore.layer.main 163 self.__apply_content_padding = kwargs.get('apply_content_padding', self.default_apply_content_padding) 164 self.__collapsible = self.default_isCollapseable 165 self.__compact_mode_setting = WindowCompactModeSetting(window_id=kwargs.get('windowID', self.default_windowID), default_value=lambda _window_ref = weakref.ref(self): Window.__get_default_compact(_window_ref)) 166 self.__compactable = self.default_isCompactable 167 self.__extend_content_into_header = kwargs.get('extend_content_into_header', self.default_extend_content_into_header) 168 self.__icon = kwargs.get('iconNum', self.GetDefaultWndIcon()) 169 self.__killable = self.default_isKillable 170 self.__lockable = self.default_isLockable 171 self.__minimizable = kwargs.get('isMinimizable', self.default_isMinimizable) 172 self.__scene_containers = set() 173 self.__show_window_controls = show_window_controls 174 self.__stackable = self.default_isStackable 175 self._changing = False 176 self._fixedHeight = self.default_fixedHeight 177 self._fixedWidth = self.default_fixedWidth 178 self._resizeable = True 179 self._scaling = False 180 self.preDragAbs = None 181 self.preDragCursorPos = None 182 self.stackID = kwargs.get('stackID', self.default_stackID) 183 self.sortedScaleWindows = None 184 self.minmaxScale = None 185 self.dragMousePosition = None 186 self.isBlinking = False 187 self.isDialog = False 188 self.isModal = False 189 self.maxsize = kwargs.get('maxSize', self.default_maxSize) 190 self.minsize = kwargs.get('minSize', self.default_minSize) 191 self.scope = kwargs.get('scope', self.default_scope) 192 self.windowID = kwargs.get('windowID', self.default_windowID) 193 self.windowInstanceID = kwargs.get('windowInstanceID', self.default_windowInstanceID) 194 super(Window, self).__init__(**kwargs) 195 attributesBunch = Bunch(**kwargs) 196 self.PostApplyAttributes(attributesBunch) 197 window_margin_mode.on_changed.connect(self.__on_global_window_margin_mode_changed) 198 notifyevents = getattr(self, '__notifyevents__', None) 199 if not notifyevents: 200 notifyevents = ['OnUIRefresh'] 201 elif 'OnUIRefresh' not in notifyevents: 202 notifyevents.append('OnUIRefresh') 203 self.__notifyevents__ = notifyevents 204 sm.RegisterNotify(self) 205 206 def ApplyAttributes(self, attributes): 207 self.attributesBunch = attributes 208 self.sr.tab = None 209 self.sr.modalParent = None 210 self.sr.loadingParent = None 211 self.sr.underlay = None 212 self.sr.headerParent = None 213 self.sr.loadingIndicator = None 214 self._CheckCallableDefaults() 215 uicore.registry.RegisterWindow(self) 216 left, top, _, _ = self.GetDefaultSizeAndPosition() 217 attributes['left'] = left 218 attributes['top'] = top 219 if self.windowID: 220 try: 221 attributes.name = str(self.windowID) 222 except Exception: 223 attributes.name = repr(self.windowID) 224 225 super(Window, self).ApplyAttributes(attributes) 226 self.sr.maincontainer = Container(name='content', parent=self, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN) 227 self.cacheContents = True 228 self.InitializeSize(useDefaultPos=attributes.get('useDefaultPos', self.default_useDefaultPos)) 229 self.Prepare_() 230 self._UpdateHeaderInset(silent=True) 231 self._UpdateBorderPadding() 232 self.__compact_mode_setting.on_change.connect(self.__on_compact_mode_setting_changed) 233 self._analyticID = attributes.Get('analyticID', self.default_analyticID) 234 self.__opened_at_timestamp = gametime.GetWallclockTime() 235 sm.ScatterEvent('OnWindowOpened', self) 236 self._LogWindowEventOpened() 237 soundOpen = attributes.get('soundOpen', self.default_soundOpen) 238 if soundOpen: 239 PlaySound(soundOpen) 240 241 @property 242 def active(self): 243 return self.__active 244 245 @property 246 def on_active_changed(self): 247 if self.__on_active_changed is None: 248 self.__on_active_changed = signals.Signal('{}.on_active_changed'.format(self.__class__.__name__)) 249 return self.__on_active_changed 250 251 def _emit_on_active_changed(self): 252 if not self.closing and self.__on_active_changed is not None: 253 self.__on_active_changed(self) 254 255 @property 256 def analyticID(self): 257 return self._analyticID 258 259 @property 260 def caption(self): 261 return self.__caption 262 263 @caption.setter 264 def caption(self, value): 265 if self.__caption != value: 266 self.__caption = value 267 self._emit_on_caption_changed() 268 269 @property 270 def on_caption_changed(self): 271 if self.__on_caption_changed is None: 272 self.__on_caption_changed = signals.Signal('Window.on_caption_changed') 273 return self.__on_caption_changed 274 275 def _emit_on_caption_changed(self): 276 if not self.closing: 277 self._OnCaptionChanged() 278 if self.__on_caption_changed is not None: 279 self.__on_caption_changed(self) 280 281 @property 282 def content(self): 283 return self.sr.main 284 285 @property 286 def content_padding(self): 287 if self.compact or self.margin_mode == WindowMarginMode.COMPACT: 288 padding = 8 289 else: 290 padding = 16 291 should_apply_top_padding = self.__extend_content_into_header or not self.__header_has_sufficient_bottom_padding 292 top_padding = padding if should_apply_top_padding else 0 293 return (padding, 294 top_padding, 295 padding, 296 padding) 297 298 @property 299 def on_content_padding_changed(self): 300 if self.__on_content_padding_changed is None: 301 self.__on_content_padding_changed = signals.Signal('Window.on_content_padding_changed') 302 return self.__on_content_padding_changed 303 304 def _emit_on_content_padding_changed(self): 305 if not self.closing and self.__on_content_padding_changed is not None: 306 self.__on_content_padding_changed(self) 307 308 @property 309 def apply_content_padding(self): 310 return self.__apply_content_padding 311 312 @apply_content_padding.setter 313 def apply_content_padding(self, value): 314 value = bool(value) 315 if value != self.__apply_content_padding: 316 self.__apply_content_padding = value 317 self._UpdateContentPadding() 318 319 @property 320 def closing(self): 321 return self.__closing or self.stacked and self.stack.closing 322 323 @property 324 def collapsed(self): 325 if self.stacked: 326 return self.stack.collapsed 327 return self.__collapsed 328 329 @property 330 def on_collapsed_changed(self): 331 if self.__on_collapsed_changed is None: 332 self.__on_collapsed_changed = signals.Signal('Window.on_collapsed_changed') 333 return self.__on_collapsed_changed 334 335 def _emit_on_collapsed_changed(self): 336 if not self.closing and self.__on_collapsed_changed is not None: 337 self.__on_collapsed_changed(self) 338 339 @collapsed.setter 340 def collapsed(self, value): 341 if value: 342 self.Collapse() 343 else: 344 self.Expand() 345 346 @property 347 def collapsible(self): 348 return self.__collapsible 349 350 @collapsible.setter 351 def collapsible(self, value): 352 if self.__collapsible != value: 353 if value: 354 self.__collapsible = True 355 else: 356 self.__collapsible = False 357 self._emit_on_collapsible_changed() 358 359 @property 360 def on_collapsible_changed(self): 361 if self.__on_collapsible_changed is None: 362 self.__on_collapsible_changed = signals.Signal('{}.on_collapsible_changed'.format(self.__class__.__name__)) 363 return self.__on_collapsible_changed 364 365 def _emit_on_collapsible_changed(self): 366 if self.__on_collapsible_changed is not None: 367 self.__on_collapsible_changed(self) 368 369 @property 370 def compact(self): 371 if self.compactable: 372 return self.__compact_mode_setting.get() 373 else: 374 return self.__compact_mode_setting.get_default() 375 376 @compact.setter 377 def compact(self, value): 378 action = 'compact' if value else 'uncompact' 379 if self.compactable and not is_blocked(action, self.windowID): 380 self.__compact_mode_setting.set(value) 381 382 @property 383 def on_compact_mode_changed(self): 384 if self.__on_compact_mode_changed is None: 385 self.__on_compact_mode_changed = signals.Signal('Window.on_compact_mode_changed') 386 return self.__on_compact_mode_changed 387 388 def _emit_on_compact_mode_changed(self): 389 if not self.closing: 390 if self.compact: 391 self.OnCompactModeEnabled() 392 else: 393 self.OnCompactModeDisabled() 394 self._UpdateContentPadding() 395 self._update_window_controls() 396 if self.__on_compact_mode_changed is not None: 397 self.__on_compact_mode_changed(self) 398 399 def __on_compact_mode_setting_changed(self, value): 400 if not self.closing: 401 self._emit_on_compact_mode_changed() 402 403 @property 404 def compactable(self): 405 return self.__compactable 406 407 @property 408 def displayRect(self): 409 return (self._displayX, 410 self._displayY, 411 self._displayWidth, 412 self._displayHeight) 413 414 @displayRect.setter 415 def displayRect(self, value): 416 displayX, displayY, displayWidth, displayHeight = value 417 self._displayX = int(round(displayX)) 418 self._displayY = int(round(displayY)) 419 self._displayWidth = int(round(displayWidth)) 420 self._displayHeight = int(round(displayHeight)) 421 ro = self.renderObject 422 if ro: 423 ro.displayX = self._displayX 424 ro.displayY = self._displayY 425 ro.displayWidth = self._displayWidth 426 ro.displayHeight = self._displayHeight 427 428 @property 429 def extend_content_into_header(self): 430 return self.__extend_content_into_header 431 432 @extend_content_into_header.setter 433 def extend_content_into_header(self, value): 434 if self.__extend_content_into_header != value: 435 self.__extend_content_into_header = value 436 self._UpdateHeaderAlignment() 437 self._UpdateContentPadding() 438 439 @property 440 def fixed_height(self): 441 return self._fixedHeight 442 443 @fixed_height.setter 444 def fixed_height(self, value): 445 self.SetFixedHeight(value) 446 447 @property 448 def on_fixed_height_changed(self): 449 if self.__on_fixed_height_changed is None: 450 self.__on_fixed_height_changed = signals.Signal('{}.on_fixed_height_changed'.format(self.__class__.__name__)) 451 return self.__on_fixed_height_changed 452 453 def _emit_fixed_height_changed(self): 454 if not self.closing and self.__on_fixed_height_changed is not None: 455 self.__on_fixed_height_changed(self) 456 457 @property 458 def fixed_width(self): 459 return self._fixedWidth 460 461 @fixed_width.setter 462 def fixed_width(self, value): 463 self.SetFixedWidth(value) 464 465 @property 466 def on_fixed_width_changed(self): 467 if self.__on_fixed_width_changed is None: 468 self.__on_fixed_width_changed = signals.Signal('{}.on_fixed_width_changed'.format(self.__class__.__name__)) 469 return self.__on_fixed_width_changed 470 471 def _emit_fixed_width_changed(self): 472 if not self.closing and self.__on_fixed_width_changed is not None: 473 self.__on_fixed_width_changed(self) 474 475 @property 476 def header(self): 477 if self.closing: 478 raise RuntimeError('Attempting to manipulate a window header while the window is closing or already closed.') 479 elif self.__header is not None and self.__header.destroyed: 480 raise RuntimeError("The window's header has been destroyed, even though the window has not been closed yet") 481 return self.__header 482 483 @header.setter 484 def header(self, value): 485 if not self.closing: 486 if value is None: 487 value = DefaultWindowHeader() 488 self._SetHeader(value) 489 490 @property 491 def header_height(self): 492 if self.__header is not None: 493 _, height = self.__header.GetAbsoluteSize() 494 return height + self.__header.padTop + self.__header.padBottom 495 return 0 496 497 @property 498 def on_header_height_changed(self): 499 if self.__on_header_height_changed is None: 500 self.__on_header_height_changed = signals.Signal('{}.on_header_height_changed'.format(self.__class__.__name__)) 501 return self.__on_header_height_changed 502 503 def _emit_on_header_height_changed(self): 504 if not self.closing and self.__on_header_height_changed is not None: 505 self.__on_header_height_changed(self) 506 507 @property 508 def header_inset(self): 509 return self.__header_inset 510 511 @property 512 def on_header_inset_changed(self): 513 if self.__on_header_inset_changed is None: 514 self.__on_header_inset_changed = signals.Signal('Window.on_header_inset_changed') 515 return self.__on_header_inset_changed 516 517 def _emit_on_header_inset_changed(self): 518 if not self.closing and self.__on_header_inset_changed is not None: 519 self.__on_header_inset_changed(self) 520 521 @property 522 def icon(self): 523 return self.__icon 524 525 @icon.setter 526 def icon(self, value): 527 if self.__icon != value: 528 self.__icon = value 529 self._emit_on_icon_changed() 530 531 @property 532 def on_icon_changed(self): 533 if self.__on_icon_changed is None: 534 self.__on_icon_changed = signals.Signal('Window.on_icon_changed') 535 return self.__on_icon_changed 536 537 def _emit_on_icon_changed(self): 538 if not self.closing and self.__on_icon_changed is not None: 539 self.__on_icon_changed(self) 540 541 @property 542 def is_stack(self): 543 return False 544 545 @property 546 def killable(self): 547 return self.__killable 548 549 @killable.setter 550 def killable(self, value): 551 if self.__killable != value: 552 self.__killable = value 553 self._emit_on_killable_changed() 554 555 @property 556 def on_killable_changed(self): 557 if self.__on_killable_changed is None: 558 self.__on_killable_changed = signals.Signal('Window.on_killable_changed') 559 return self.__on_killable_changed 560 561 def _emit_on_killable_changed(self): 562 if not self.closing and self.__on_killable_changed is not None: 563 self.__on_killable_changed(self) 564 565 @property 566 def light_background_enabled(self): 567 return self.IsLightBackgroundEnabled() 568 569 @light_background_enabled.setter 570 def light_background_enabled(self, value): 571 if value == self.light_background_enabled: 572 return 573 if value: 574 self.EnableLightBackground() 575 else: 576 self.DisableLightBackground() 577 578 @property 579 def on_light_background_changed(self): 580 if self.__on_light_background_changed is None: 581 self.__on_light_background_changed = signals.Signal('Window.on_light_background_changed') 582 return self.__on_light_background_changed 583 584 def _emit_on_light_background_changed(self): 585 if not self.closing: 586 self.UpdateIntersectionBackground() 587 if self.__on_light_background_changed is not None: 588 self.__on_light_background_changed(self) 589 590 @property 591 def locked(self): 592 return self.GetRegisteredState('locked', False) 593 594 @locked.setter 595 def locked(self, value): 596 action = 'lock' if value else 'unlock' 597 if is_blocked(action, self.windowID): 598 return 599 if self.locked != value: 600 self.RegisterState('locked', bool(value)) 601 self._emit_on_locked_changed() 602 603 @property 604 def on_locked_changed(self): 605 if self.__on_locked_changed is None: 606 self.__on_locked_changed = signals.Signal('Window.on_locked_changed') 607 return self.__on_locked_changed 608 609 def _emit_on_locked_changed(self): 610 if not self.closing: 611 self.Prepare_ScaleAreas_() 612 if self.__on_locked_changed is not None: 613 self.__on_locked_changed(self) 614 615 @property 616 def lockable(self): 617 return self.default_isLockable 618 619 @lockable.setter 620 def lockable(self, value): 621 if self.__lockable != value: 622 self.__lockable = value 623 self._emit_on_lockable_changed() 624 625 @property 626 def on_lockable_changed(self): 627 if self.__on_lockable_changed is None: 628 self.__on_lockable_changed = signals.Signal('{}.on_lockable_changed'.format(self.__class__.__name__)) 629 return self.__on_lockable_changed 630 631 def _emit_on_lockable_changed(self): 632 if self.__on_lockable_changed is not None: 633 self.__on_lockable_changed(self) 634 635 @property 636 def margin_mode(self): 637 return window_margin_mode.value 638 639 @property 640 def on_margin_mode_changed(self): 641 if self.__on_margin_mode_changed is None: 642 self.__on_margin_mode_changed = signals.Signal('{}.on_margin_mode_changed'.format(self.__class__.__name__)) 643 return self.__on_margin_mode_changed 644 645 @property 646 def minimizable(self): 647 return self.__minimizable 648 649 @minimizable.setter 650 def minimizable(self, value): 651 if self.__minimizable != value: 652 self.__minimizable = value 653 self._emit_on_minimizable_changed() 654 655 @property 656 def on_minimizable_changed(self): 657 if self.__on_minimizable_changed is None: 658 self.__on_minimizable_changed = signals.Signal('{}.on_minimizable_changed'.format(self.__class__.__name__)) 659 return self.__on_minimizable_changed 660 661 def _emit_on_minimizable_changed(self): 662 if not self.closing and self.__on_minimizable_changed is not None: 663 self.__on_minimizable_changed(self) 664 665 @property 666 def minimized(self): 667 return self.IsMinimized() 668 669 @minimized.setter 670 def minimized(self, value): 671 if value: 672 self.Minimize() 673 else: 674 self.Maximize() 675 676 @property 677 def overlayable(self): 678 return self.default_isOverlayable 679 680 @property 681 def show_window_controls(self): 682 return self.__show_window_controls 683 684 @show_window_controls.setter 685 def show_window_controls(self, value): 686 if self.__show_window_controls != value: 687 self.__show_window_controls = value 688 self._update_window_controls_visibility() 689 690 @property 691 def stack(self): 692 return self.__stack 693 694 @property 695 def stacked(self): 696 return self.__stack is not None 697 698 @property 699 def on_stacked_changed(self): 700 if self.__on_stacked_changed is None: 701 self.__on_stacked_changed = signals.Signal('Window.on_stacked_changed') 702 return self.__on_stacked_changed 703 704 def _emit_on_stacked_changed(self): 705 if not self.closing and self.__on_stacked_changed is not None: 706 self.__on_stacked_changed(self) 707 708 @property 709 def on_start_scale(self): 710 if self.__on_start_scale is None: 711 self.__on_start_scale = signals.Signal('Window.on_start_scale') 712 return self.__on_start_scale 713 714 def _emit_on_start_scale(self): 715 if not self.closing and self.__on_start_scale is not None: 716 self.__on_start_scale(self) 717 718 @property 719 def on_end_scale(self): 720 if self.__on_end_scale is None: 721 self.__on_end_scale = signals.Signal('Window.on_end_scale') 722 return self.__on_end_scale 723 724 def _emit_on_end_scale(self): 725 if not self.closing and self.__on_end_scale is not None: 726 self.__on_end_scale(self) 727 728 def OnUIRefresh(self): 729 self.Reload(self) 730 731 @telemetry.ZONE_METHOD 732 def PostApplyAttributes(self, attributes): 733 self.RegisterSize() 734 if attributes.get('ignoreStack', False): 735 self.RegisterStackID(None) 736 self.InitializeCaption(attributes) 737 if attributes.get('openDragging', False) and uicore.uilib.leftbtn: 738 self.RegisterStackID(None) 739 self._SetOpen(True) 740 uthread.new(self._OpenDraggingThread) 741 else: 742 self.InitializeStatesAndPosition(showIfInStack=attributes.get('showIfInStack', True), useDefaultPos=attributes.get('useDefaultPos', self.default_useDefaultPos)) 743 if attributes.get('openMinimized', self.default_openMinimized): 744 self.Minimize(animate=False) 745 uicore.registry.SetFocus(self) 746 self.__ready = True 747 748 def InitializeCaption(self, attributes): 749 if self.__caption is not None: 750 return 751 caption = attributes.get('caption', self.default_caption) 752 if caption is not None: 753 self.SetCaption(caption) 754 else: 755 captionLabelPath = attributes.get('captionLabelPath', self.default_captionLabelPath) 756 if captionLabelPath: 757 self.SetCaption(localization.GetByLabel(captionLabelPath)) 758 759 def Show(self, *args): 760 self.Maximize(*args) 761 762 def _OpenDraggingThread(self): 763 self.state = uiconst.UI_NORMAL 764 if self.IsLocked(): 765 return 766 self.dragMousePosition = (uicore.uilib.x, uicore.uilib.y) 767 self.left = uicore.uilib.x - 5 768 self.top = uicore.uilib.y - 5 769 uicore.uilib.SetMouseCapture(self) 770 compact = self.GetRegisteredState('compact', False) 771 if compact: 772 self.Compact() 773 self._BeginDrag() 774 775 def GetAbsolutePosition(self): 776 stack = self.stack 777 if stack: 778 return stack.contentCont.GetAbsolutePosition() 779 return (self.left, self.top) 780 781 def _CheckCallableDefaults(self): 782 if callable(self.default_left): 783 self.default_left = self.default_left() 784 if callable(self.default_top): 785 self.default_top = self.default_top() 786 if callable(self.default_width): 787 self.default_width = self.default_width() 788 if callable(self.default_height): 789 self.default_height = self.default_height() 790 791 def Prepare_(self): 792 self.Prepare_Layout() 793 self._create_window_controls() 794 self.Prepare_Header_() 795 self.Prepare_LoadingIndicator_() 796 self.Prepare_Background_() 797 self.Prepare_ScaleAreas_() 798 799 def Prepare_Layout(self): 800 self.ConstructHeaderParent() 801 self.sr.main = self.construct_content_cont() 802 803 def construct_content_cont(self): 804 return Container(parent=self.sr.maincontainer, name='main', align=uiconst.TOALL, padding=self.content_padding) 805 806 def ConstructHeaderParent(self): 807 self.sr.headerParent = ContainerAutoSize(parent=self.sr.maincontainer, name='headerParent', align=self._GetHeaderAlignment(), alignMode=uiconst.TOTOP, callback=self.__on_header_parent_size_changed, only_use_callback_when_size_changes=True) 808 index = 0 809 if self.__resizer is not None: 810 index = self.__resizer.GetOrder() 811 self.__window_controls_cont = Container(name='window_controls_cont', parent=self, align=uiconst.TOTOP_NOPUSH, padding=self._get_window_controls_cont_padding(), idx=index) 812 813 def _get_window_controls_cont_padding(self): 814 pad_left, pad_top, pad_right, pad_bottom = self.GetWindowBorderPadding() 815 size_left, size_top, size_right, size_bottom = self.GetWindowBorderSize() 816 return (pad_left + size_left, 817 pad_top + size_top, 818 pad_right + size_right, 819 pad_bottom + size_bottom) 820 821 def Prepare_Header_(self): 822 self._SetHeader(DefaultWindowHeader()) 823 824 def _create_window_controls(self): 825 actions = self._get_window_actions() 826 self.__window_controls = DefaultWindowControls(window=self, parent=self.__window_controls_cont, actions=actions, get_menu=self.GetMenuMoreOptions, get_link_data=self.GetWindowLinkData, menu_unique_name=self.get_wnd_menu_unique_name(), on_reserved_width_changed=self._UpdateHeaderInset, display=self._get_window_controls_visible()) 827 828 def update_window_controls(self): 829 if self.stacked: 830 self.stack.__window_controls.update() 831 else: 832 self.__window_controls.update() 833 834 def _get_window_actions(self): 835 actions = [CloseWindowAction(self), 836 MinimizeWindowAction(self), 837 LockWindowAction(self), 838 OverlayWindowAction(self), 839 CompactModeWindowAction(self), 840 LightBackgroundWindowAction(self), 841 CollapseWindowAction(self)] 842 actions.extend(self.GetCustomHeaderButtons()) 843 return actions 844 845 def get_wnd_menu_unique_name(self): 846 return None 847 848 def _update_window_controls(self): 849 self._destroy_window_controls() 850 self._create_window_controls() 851 852 def _destroy_window_controls(self): 853 if self.__window_controls is not None: 854 self.__window_controls.Close() 855 self.__window_controls = None 856 857 def _get_window_controls_visible(self): 858 return self.__show_window_controls and not self.stacked 859 860 def _update_window_controls_visibility(self): 861 if self.__window_controls is not None: 862 self.__window_controls.display = self._get_window_controls_visible() 863 864 def GetCustomHeaderButtons(self): 865 return [] 866 867 def SwapLanguage(self, lang): 868 sm.GetService('gameui').SetLanguage(lang, doReload=True) 869 870 def SetFontSize(self, size): 871 set_font_size_setting(size) 872 873 def GetToggleOption(self, label, callback, enabled, md): 874 if enabled: 875 icon = 'res:/UI/Texture/classes/UtilMenu/checkBoxActive.png' 876 else: 877 icon = 'res:/UI/Texture/classes/UtilMenu/checkBoxInactive.png' 878 md.AddEntry(text=label, func=callback, texturePath=icon) 879 880 def ToggleLabelDefaults(self): 881 localization.SetFallBackMode(not localization.GetFallBackMode()) 882 883 def GetLabelMissingOption(self, md): 884 enabled = localization.GetFallBackMode() 885 label = 'Localization Label Defaults' 886 return self.GetToggleOption(label, self.ToggleLabelDefaults, enabled, md) 887 888 def AddDeveloperMenu(self, md): 889 languages = ['English', 890 'Korean', 891 'German', 892 'Russian', 893 'Japanese', 894 'Chinese', 895 'Spanish'] 896 font_sizes = [('ExtraLarge', FontSizeOption.EXTRA_LARGE), 897 ('Large', FontSizeOption.LARGE), 898 ('Medium', FontSizeOption.MEDIUM), 899 ('Small', FontSizeOption.SMALL), 900 ('Tiny', FontSizeOption.EXTRA_SMALL)] 901 md.AddLabel('Developer/Programmer') 902 md.AddEntry(text='Reload Window', func=self.DebugReload) 903 self.GetLabelMissingOption(md) 904 language_submenus = [] 905 for lang in languages: 906 language_submenus.append(MenuEntryData(text=lang, func=lambda l = lang: self.SwapLanguage(l), texturePath='res:/UI/Texture/classes/insider/localization_18.png')) 907 908 md.AddEntry(text='Swap UI Language', subMenuData=language_submenus) 909 font_size_submenus = [] 910 for font_size in font_sizes: 911 font_size_submenus.append(MenuEntryData(text=font_size[0], func=lambda fs = font_size[1]: self.SetFontSize(fs), texturePath='res:/UI/Texture/classes/insider/text_styles_18.png')) 912 913 md.AddEntry(text='Set Font Size', subMenuData=font_size_submenus) 914 md.AddSeparator() 915 916 def GetMenuMoreOptions(self): 917 md = MenuData() 918 if session.role & ROLE_PROGRAMMER: 919 self.AddDeveloperMenu(md) 920 return md 921 922 def DebugReload(self, *args): 923 self.Reload(self) 924 925 def GetWindowLinkData(self): 926 return None 927 928 def Prepare_Background_(self): 929 self.sr.underlay = WindowUnderlay(parent=self, padding=self.GetWindowBorderPadding()) 930 931 def GetDefaultWndIcon(self): 932 return self.default_iconNum 933 934 def GetNeocomGroupIcon(self): 935 return self.icon 936 937 def GetNeocomGroupLabel(self): 938 return self.GetCaption() 939 940 def EnableLightBackground(self): 941 self.sr.underlay.EnableLightBackground() 942 self._SetLightBackground(True) 943 944 def DisableLightBackground(self): 945 self.sr.underlay.DisableLightBackground() 946 self._SetLightBackground(False) 947 948 def IsLightBackgroundConfigurable(self, *args): 949 return self.default_isLightBackgroundConfigurable 950 951 def IsLightBackgroundEnabled(self): 952 default = self.default_isLightBackground 953 if callable(self.default_isLightBackground): 954 default = default() 955 return self.GetRegisteredState('isLightBackground', default) 956 957 def _SetLightBackground(self, isLightBackground): 958 self.RegisterState('isLightBackground', isLightBackground) 959 self._emit_on_light_background_changed() 960 961 def IsOverlayed(self): 962 return self.GetRegisteredState('isOverlayed', self.default_isOverlayed) 963 964 def SetOverlayed(self): 965 self.RegisterState('isOverlayed', True) 966 967 def SetNotOverlayed(self): 968 self.RegisterState('isOverlayed', False) 969 970 def IsBlinking(self): 971 return self.isBlinking 972 973 def SetBlinking(self): 974 if uicore.registry.GetActive() == self: 975 return 976 self.isBlinking = True 977 sm.ScatterEvent('OnWindowStartBlinking', self) 978 979 def SetNotBlinking(self): 980 self.isBlinking = False 981 sm.ScatterEvent('OnWindowStopBlinking', self) 982 983 def _handle_start_scale(self, sides): 984 sides = [ LEGACY_SIDE_NAME_BY_SIDE[side] for side in sides ] 985 self._StartScale(sides=sides) 986 987 def _handle_end_scale(self, sides): 988 self.EndScale(None) 989 990 def _is_side_resizable(self, side): 991 if not self.IsResizeable() or self.stacked: 992 return False 993 elif side in {Side.LEFT, Side.RIGHT}: 994 return self.fixed_width is None 995 elif side in {Side.TOP, Side.BOTTOM}: 996 return self.fixed_height is None 997 else: 998 return True 999 1000 def _get_resizer_padding(self): 1001 return (0, 0, 0, 0) 1002 1003 def _get_resizer_inner_padding(self): 1004 margin_left, margin_top, margin_right, margin_bottom = self.GetWindowBorderPadding() 1005 _, border_top, _, _ = self.GetWindowBorderSize() 1006 pad_top = margin_top 1007 if self.active: 1008 pad_top += border_top 1009 return (margin_left, 1010 pad_top, 1011 margin_right, 1012 margin_bottom) 1013 1014 def _update_resizer_padding(self): 1015 self.__resizer.padding = self._get_resizer_padding() 1016 self.__resizer.inner_padding = self._get_resizer_inner_padding() 1017 1018 def Prepare_ScaleAreas_(self): 1019 if self.__resizer is None: 1020 index = 0 1021 if self.__window_controls_cont is not None: 1022 index = self.__window_controls_cont.GetOrder() + 1 1023 self.__resizer = Resizer(parent=self, idx=index, locked_sides=filter(lambda s: not self._is_side_resizable(s), Side.iter()), on_start_scale=self._handle_start_scale, on_end_scale=self._handle_end_scale, padding=self._get_resizer_padding(), inner_padding=self._get_resizer_inner_padding()) 1024 else: 1025 self._update_resizer_padding() 1026 self.__resizer.locked_sides = [ side for side in Side.iter() if not self._is_side_resizable(side) ] 1027 1028 def Prepare_LoadingIndicator_(self): 1029 if self.sr.loadingParent: 1030 self.sr.loadingParent.Close() 1031 self.sr.loadingParent = Container(name='__loadingParent', parent=self.sr.maincontainer, state=uiconst.UI_HIDDEN, idx=0) 1032 self.sr.loadingIndicator = AnimSprite(parent=self.sr.loadingParent, state=uiconst.UI_HIDDEN, align=uiconst.TOPRIGHT, left=5) 1033 self.sr.loadingIndicator.icons = [ 'ui_38_16_%s' % (210 + i) for i in xrange(8) ] 1034 1035 def GetStackID(self): 1036 window_id = self.windowID 1037 if isinstance(window_id, tuple): 1038 window_id, _ = window_id 1039 if not window_id: 1040 return None 1041 stack_id_by_window_id = settings.char.windows.Get('stacksWindows', {}) 1042 return stack_id_by_window_id.get(window_id, self.stackID) 1043 1044 def RegisterStackID(self, stack = None): 1045 window_id = self.windowID 1046 if isinstance(window_id, tuple): 1047 window_id, _ = window_id 1048 if not window_id: 1049 return 1050 stack_id = None 1051 if stack is not None: 1052 stack_id = stack.windowID 1053 stack_id_by_window_id = settings.char.windows.Get('stacksWindows', {}) 1054 stack_id_by_window_id[window_id] = stack_id 1055 settings.char.windows.Set('stacksWindows', stack_id_by_window_id) 1056 1057 def OnStackInsert(self, stack): 1058 self.__stack = stack 1059 self.align = uiconst.TOALL 1060 self.__ready = False 1061 self.left = self.top = self.width = self.height = 0 1062 self.__ready = True 1063 self._stack_cacheContents = self.cacheContents 1064 self.cacheContents = False 1065 self.state = uiconst.UI_HIDDEN 1066 self.sr.loadingIndicator.Stop() 1067 self._update_window_controls_visibility() 1068 self._UpdateContentPadding() 1069 self._UpdateBorderPadding() 1070 self.Prepare_ScaleAreas_() 1071 self._emit_on_stacked_changed() 1072 1073 def OnStackRemove(self, correctpos, dragging, grab): 1074 self.__stack = None 1075 self.sr.tab = None 1076 self.align = uiconst.RELATIVE 1077 self.state = uiconst.UI_NORMAL 1078 self.grab = grab 1079 self.dragMousePosition = (uicore.uilib.x, uicore.uilib.y) 1080 if dragging: 1081 uicore.uilib.SetMouseCapture(self) 1082 uthread.new(self._BeginDrag) 1083 if self.height < self.GetMinHeight(): 1084 self.height = self.GetMinHeight() 1085 if self.width < self.GetMinWidth(): 1086 self.width = self.GetMinWidth() 1087 self.ShowBackground() 1088 self.Prepare_ScaleAreas_() 1089 if correctpos: 1090 self.left = uicore.uilib.x - grab[0] 1091 self.top = uicore.uilib.y - grab[1] 1092 self._update_window_controls_visibility() 1093 self._UpdateContentPadding() 1094 self._UpdateBorderPadding() 1095 self._emit_on_stacked_changed() 1096 1097 def _UpdateBorderPadding(self): 1098 if self.stacked: 1099 self.sr.maincontainer.padding = 0 1100 else: 1101 margin_left, margin_top, margin_right, margin_bottom = self.GetWindowBorderPadding() 1102 border_left, border_top, border_right, border_bottom = self.GetWindowBorderSize() 1103 self.sr.maincontainer.padding = (margin_left + border_left, 1104 margin_top + border_top, 1105 margin_right + border_right, 1106 margin_bottom + border_bottom) 1107 self._update_resizer_padding() 1108 1109 def _UpdateHeaderAlignment(self): 1110 if self.sr.headerParent is not None: 1111 self.sr.headerParent.align = self._GetHeaderAlignment() 1112 1113 def _GetHeaderAlignment(self): 1114 if self.extend_content_into_header: 1115 return uiconst.TOTOP_NOPUSH 1116 return uiconst.TOTOP 1117 1118 def InitializeSize(self, useDefaultPos = False): 1119 d = uicore.desktop 1120 if useDefaultPos: 1121 left, top, width, height = self.GetDefaultSizeAndPosition() 1122 else: 1123 left, top, width, height, dw, dh = self.GetRegisteredPositionAndSize() 1124 maxWidth, maxHeight = self.GetMaxWidth(), self.GetMaxHeight() 1125 minWidth, minHeight = self.GetMinWidth(), self.GetMinHeight() 1126 if self._fixedWidth: 1127 self.width = self._fixedWidth 1128 else: 1129 self.width = min(maxWidth, max(minWidth, min(d.width, width))) 1130 if self._fixedHeight: 1131 self.height = self._fixedHeight 1132 else: 1133 self.height = min(maxHeight, max(minHeight, min(d.height, height))) 1134 1135 def OnResetWindowSettings(self): 1136 if self.__stack is not None: 1137 sm.ChainEvent('ProcessWindowUnstacked', self, self.__stack) 1138 self.OnStackRemove(0, 0, (0, 0)) 1139 if self.IsMinimized(): 1140 self.Maximize() 1141 self.state = uiconst.UI_HIDDEN 1142 self.align = uiconst.TOPLEFT 1143 self.ShowBackground() 1144 self.InitializeSize() 1145 self.InitializeStatesAndPosition() 1146 1147 def InitializeStatesAndPosition(self, showIfInStack = True, useDefaultPos = False, **kwds): 1148 self.__ready = False 1149 log.LogInfo('Window.InitializeStatesAndPosition', self.windowID) 1150 if self.IsLightBackgroundConfigurable(): 1151 if self.IsLightBackgroundEnabled(): 1152 self.EnableLightBackground() 1153 else: 1154 self.DisableLightBackground() 1155 if self.IsLocked(): 1156 self.Lock() 1157 else: 1158 self.Unlock() 1159 if self.IsMinimized(): 1160 self._SetMaximized() 1161 stack = None 1162 stackID = self.GetStackID() 1163 from carbonui.window.stack import WindowStack 1164 if not isinstance(self, WindowStack): 1165 if self.IsStackable() and stackID: 1166 stack = uicore.registry.GetWindow(stackID) 1167 if stack and not stack.closing: 1168 log.LogInfo('Window.InitializeStatesAndPosition, windowStack already created', self.windowID) 1169 stack.InsertWnd(self, False, showIfInStack, 1) 1170 if not stack or stack.closing: 1171 collapsed = self.GetRegisteredState('collapsed', False) 1172 if collapsed: 1173 self.Collapse() 1174 elif self.IsCollapsed(): 1175 self.Expand() 1176 self.UpdatePosition(useDefaultPos) 1177 if stackID is not None and not isinstance(self, self.GetStackClass()) and self.__stackable: 1178 self.state = uiconst.UI_HIDDEN 1179 log.LogInfo('Window.InitializeStatesAndPosition creating new stack while initializing', self.windowID) 1180 stack = uicore.registry.GetStack(stackID, self.GetStackClass()) 1181 if stack and not stack.closing: 1182 stack.InsertWnd(self, True, showIfInStack, 1) 1183 if not self.InStack() and not self.IsMinimized(): 1184 self.state = uiconst.UI_NORMAL 1185 self._SetMaximized() 1186 self._SetOpen(True) 1187 self.__ready = True 1188 1189 def InitializeFocus(self): 1190 focus = uicore.registry.GetFocus() 1191 from carbonui.control.editPlainText import EditPlainTextCore 1192 from carbonui.control.singlelineedits.baseSingleLineEdit import BaseSingleLineEdit 1193 editFieldHasFocus = focus and isinstance(focus, (EditPlainTextCore, BaseSingleLineEdit)) 1194 if not editFieldHasFocus: 1195 uthread.new(uicore.registry.SetFocus, self) 1196 1197 def UpdatePosition(self, useDefaultPos = False): 1198 if useDefaultPos: 1199 left, top, width, height = self.GetDefaultSizeAndPosition() 1200 else: 1201 left, top, width, height, dw, dh = self.GetRegisteredPositionAndSize() 1202 left = max(0, min(uicore.desktop.width - self.width, left)) 1203 top = max(0, min(uicore.desktop.height - self.height, top)) 1204 leftpush, rightpush = self.GetSideOffset() 1205 if left in (0, SNAP_DISTANCE): 1206 left += leftpush 1207 elif left + self.width in (uicore.desktop.width, uicore.desktop.width - SNAP_DISTANCE): 1208 left -= rightpush 1209 self.left = left 1210 self.top = top 1211 self.CheckWndPos() 1212 1213 @classmethod 1214 def GetSideOffset(cls): 1215 if uicore.layer.sidePanels: 1216 return uicore.layer.sidePanels.GetSideOffset() 1217 return (0, 0) 1218 1219 def RegisterState(self, statename, value): 1220 RegisterState(self.windowID, statename, value) 1221 1222 def GetRegisteredState(self, statename, default = None): 1223 return GetRegisteredState(self.windowID, statename, default) 1224 1225 def IsRegisteringPositionAndSizeAllowed(self): 1226 if self.windowID is None: 1227 return False 1228 if self._changing or self.IsMinimized(): 1229 return False 1230 if not self.InStack(): 1231 if self.GetStackID(): 1232 return False 1233 if self.GetAlign() != uiconst.RELATIVE: 1234 return False 1235 return True 1236 1237 def RegisterPositionAndSize(self, key = None, windowID = None): 1238 if not self.IsRegisteringPositionAndSizeAllowed(): 1239 return 1240 l, t = self._GetPositionToRegister() 1241 w, h = self._GetSizeToRegister() 1242 self._RegisterWindowSizeAndPositionSetting(l, t, w, h, windowID) 1243 1244 def RegisterSize(self): 1245 if not self.IsRegisteringPositionAndSizeAllowed(): 1246 return 1247 width, height = self._GetSizeToRegister() 1248 self._RegisterWindowSizeAndPositionSetting(width=width, height=height) 1249 1250 def _GetPositionToRegister(self): 1251 if self.stacked: 1252 l, t = self.stack.left, self.stack.top 1253 else: 1254 l, t = self.left, self.top 1255 if l is not None: 1256 l = self._AccountForSideAutoSnapDistance(l) 1257 return (l, t) 1258 1259 def _AccountForSideAutoSnapDistance(self, l): 1260 dw, dh = uicore.desktop.width, uicore.desktop.height 1261 leftOffset, rightOffset = self.GetSideOffset() 1262 if l in (leftOffset, leftOffset + 16): 1263 l -= leftOffset 1264 elif l + self.width in (dw - rightOffset, dw - rightOffset - 16): 1265 l += rightOffset 1266 return l 1267 1268 def _GetSizeToRegister(self): 1269 if self.stacked: 1270 w, h = self.stack.width, self.stack.height 1271 else: 1272 w, h = self.width, self.height 1273 if self.IsCollapsed(): 1274 h = None 1275 return (w, h) 1276 1277 def _RegisterWindowSizeAndPositionSetting(self, left = None, top = None, width = None, height = None, windowID = None): 1278 if windowID is None: 1279 windowID = self._GetWindowID() 1280 allWindows = settings.char.windows.Get('windowSizesAndPositions_1', {}) 1281 regLeft, regTop, regWidth, regHeight, _, _ = self.GetRegisteredPositionAndSizeByClass(windowID) 1282 allWindows[windowID] = (left if left is not None else regLeft, 1283 top if top is not None else regTop, 1284 width if width is not None else regWidth, 1285 height if height is not None else regHeight, 1286 uicore.desktop.width, 1287 uicore.desktop.height) 1288 settings.char.windows.Set('windowSizesAndPositions_1', allWindows) 1289 1290 def _GetWindowID(self): 1291 if type(self.windowID) == tuple: 1292 windowID, _ = self.windowID 1293 else: 1294 windowID = self.windowID 1295 return windowID 1296 1297 def SetFixedHeightFromContentHeight(self, height): 1298 window_controls_height = self.__window_controls_cont.padTop + self.__window_controls_cont.padBottom 1299 fixed_height = height + self.header_height + window_controls_height 1300 self.SetFixedHeight(fixed_height, force=True) 1301 1302 def SetFixedHeight(self, height = None, force = False): 1303 if self._fixedHeight != height or force: 1304 self._fixedHeight = height 1305 if height is not None and not self.stacked: 1306 self.height = height 1307 self.Prepare_ScaleAreas_() 1308 self._emit_fixed_height_changed() 1309 1310 def SetFixedWidth(self, width = None): 1311 if self._fixedWidth != width: 1312 self._fixedWidth = width 1313 if width is not None and not self.stacked: 1314 self.width = width 1315 self.Prepare_ScaleAreas_() 1316 self._emit_fixed_width_changed() 1317 1318 def GetMinSize(self, *args, **kw): 1319 width, height = (0, 0) 1320 if self.sr.headerParent and self.sr.headerParent.state != uiconst.UI_HIDDEN: 1321 height += self.sr.headerParent.height 1322 return (width, height) 1323 1324 def IsCurrentDialog(self): 1325 return getattr(self, 'isDialog', False) and (not getattr(self, 'isModal', False) or uicore.registry.GetModalWindow() == self) 1326 1327 def Close(self, setClosed = False, *args, **kwds): 1328 if self.__closing: 1329 return 1330 self.__closing = True 1331 if setClosed: 1332 self._SetOpen(False) 1333 sm.ScatterEvent('OnWindowClosed', self.windowID, self.windowInstanceID, self.__class__) 1334 if self.__modal_result: 1335 self._SetModalResult(uiconst.ID_CLOSE) 1336 self.state = uiconst.UI_HIDDEN 1337 if self.__header is not None: 1338 self.__header.unmount(self) 1339 self.__header.Close() 1340 self.__header = None 1341 modalParent = self.sr.modalParent 1342 stack = self.stack 1343 super(Window, self).Close() 1344 if uicore.registry.GetActive() == self: 1345 if stack is not None: 1346 uicore.registry.SetFocus(stack) 1347 else: 1348 uicore.registry.SetFocus(None) 1349 if self.__modal_result: 1350 self._SetModalResult(uiconst.ID_CLOSE) 1351 if modalParent is not None and not modalParent.destroyed: 1352 modalParent.Close() 1353 uicore.registry.UnregisterWindow(self) 1354 self.UpdateIntersectionBackground() 1355 if stack is not None and not stack.destroyed: 1356 stack.Check(checknone=1) 1357 1358 def HasPendingModalResult(self): 1359 return bool(self.__modal_result) 1360 1361 def CloseByUser(self, *args): 1362 if self.closing: 1363 return 1364 if not self.killable or is_blocked('close', self.windowID): 1365 return 1366 self._LogWindowClosed() 1367 PlaySound(uiconst.SOUND_CLOSE) 1368 self.Close(setClosed=True) 1369 1370 def _OnResize(self, *args, **kw): 1371 super(Window, self)._OnResize(*args) 1372 self.UpdateIntersectionBackground() 1373 if self.__ready: 1374 self.RegisterPositionAndSize() 1375 if self.OnResize_: 1376 self.OnResize_(self) 1377 1378 def UpdateAlignment(self, budgetLeft = 0, budgetTop = 0, budgetWidth = 0, budgetHeight = 0, updateChildrenOnly = False): 1379 dirty = self._forceUpdateAlignment or self._alignmentDirty 1380 ret = super(Window, self).UpdateAlignment(budgetLeft, budgetTop, budgetWidth, budgetHeight, updateChildrenOnly) 1381 if dirty: 1382 for sceneCont in self.__scene_containers: 1383 if not sceneCont.destroyed: 1384 sceneCont.UpdateViewPort() 1385 1386 return ret 1387 1388 def HideHeader(self): 1389 self.collapsible = False 1390 self.show_window_controls = False 1391 if self.sr.headerParent: 1392 self.sr.headerParent.state = uiconst.UI_HIDDEN 1393 1394 def ShowHeader(self): 1395 self.collapsible = True 1396 self.show_window_controls = True 1397 if self.sr.headerParent: 1398 self.sr.headerParent.state = uiconst.UI_PICKCHILDREN 1399 1400 def ShowBackground(self): 1401 self.ShowUnderlay() 1402 1403 def HideBackground(self): 1404 self.HideUnderlay() 1405 1406 def HideUnderlay(self): 1407 if self.sr.underlay: 1408 self.sr.underlay.state = uiconst.UI_HIDDEN 1409 1410 def ShowUnderlay(self): 1411 if self.sr.underlay: 1412 self.sr.underlay.state = uiconst.UI_DISABLED 1413 1414 def Blink(self): 1415 if self.state == uiconst.UI_HIDDEN and self.sr.tab and hasattr(self.sr.tab, 'Blink'): 1416 self.sr.tab.Blink(1) 1417 1418 def GetMenu(self, *args): 1419 entries = [] 1420 if self.killable: 1421 text = MenuLabel('/Carbon/UI/Common/Close') 1422 entry = MenuEntryData(text=text, func=self.CloseByUser) 1423 entries.append(entry) 1424 if not self.stacked and self.minimizable and not getattr(self, 'isModal', 0): 1425 if self.IsMinimized(): 1426 text = MenuLabel('/Carbon/UI/Controls/Window/Maximize') 1427 else: 1428 text = MenuLabel('/Carbon/UI/Controls/Window/Minimize') 1429 entry = MenuEntryData(text=text, func=self.ToggleMinimize) 1430 entries.append(entry) 1431 from carbonui.control.contextMenu.menuDataFactory import CreateMenuDataWithEntries 1432 return CreateMenuDataWithEntries(entries) 1433 1434 def ShowLoad(self, doBlock = True): 1435 self.__hide_loading_indicator_requested = False 1436 if self.sr.loadingParent: 1437 if doBlock: 1438 self.sr.loadingParent.state = uiconst.UI_NORMAL 1439 else: 1440 self.sr.loadingParent.state = uiconst.UI_DISABLED 1441 if self.sr.loadingIndicator and hasattr(self.sr.loadingIndicator, 'Play'): 1442 if not (self.InStack() or self.GetAlign() != uiconst.RELATIVE): 1443 self.sr.loadingIndicator.sr.hint = localization.GetByLabel('/Carbon/UI/Controls/Window/Loading') 1444 self.sr.loadingIndicator.Play() 1445 if not self.closing and self.__hide_loading_indicator_requested: 1446 self.HideLoad() 1447 1448 def HideLoad(self): 1449 if self.sr.loadingIndicator and hasattr(self.sr.loadingIndicator, 'Stop'): 1450 self.sr.loadingIndicator.Stop() 1451 if self.sr.loadingParent: 1452 self.sr.loadingParent.state = uiconst.UI_HIDDEN 1453 self.__hide_loading_indicator_requested = True 1454 1455 def ShowModal(self): 1456 return self.ShowDialog(modal=True) 1457 1458 def ShowDialog(self, modal = False, state = uiconst.UI_NORMAL, fillOpacity = uiconst.DEFAULT_MODAL_OPACITY, closeWhenClicked = False, sceneSaturation = uiconst.DEFAULT_MODAL_SCENE_SATURATION): 1459 self.isDialog = True 1460 self.isModal = modal 1461 self.state = uiconst.UI_HIDDEN 1462 if modal: 1463 self.minimizable = False 1464 if self.parent and not self.parent.destroyed and self.parent.name[:8] == 'l_modal_': 1465 self.parent.SetOrder(0) 1466 else: 1467 layer = self._create_modal_layer(name='l_modal_%s' % self.name, close_when_clicked=closeWhenClicked) 1468 self.SetParent(layer) 1469 self.sr.modalParent = layer 1470 self.ModalPosition() 1471 uicore.registry.AddModalWindow(self, fillOpacity=fillOpacity, sceneSaturation=sceneSaturation) 1472 self.__modal_result = uthread.Channel() 1473 self.state = state 1474 if modal: 1475 uicore.registry.SetFocus(self) 1476 self.HideLoad() 1477 ret = self.__modal_result.receive() 1478 return ret 1479 1480 def _create_modal_layer(self, name, close_when_clicked = False): 1481 layer = Container(name=name, state=uiconst.UI_NORMAL, parent=uicore.layer.modal, idx=0) 1482 if close_when_clicked: 1483 layer.OnClick = self.CloseByUser 1484 return layer 1485 1486 def ModalPosition(self): 1487 otherModal = uicore.registry.GetModalWindow() 1488 if self.__ShouldAdjustNewModal(otherModal): 1489 self.left = otherModal.left + 16 1490 self.top = otherModal.top + 16 1491 if self.left + self.width > uicore.desktop.width: 1492 self.left = 0 1493 if self.top + self.height > uicore.desktop.height: 1494 self.top = 0 1495 else: 1496 cameraOffset = self.__class__.GetDefaultLeftOffset(self.width, align=uiconst.CENTER, left=0) 1497 self.left = (uicore.desktop.width - self.width) / 2 + cameraOffset 1498 self.top = (uicore.desktop.height - self.height) / 2 1499 1500 def __ShouldAdjustNewModal(self, otherModal): 1501 if not otherModal: 1502 return False 1503 if not getattr(otherModal, 'triggersModalAdjustment', True): 1504 return False 1505 if otherModal.state != uiconst.UI_NORMAL: 1506 return False 1507 if otherModal.parent.state != uiconst.UI_NORMAL: 1508 return False 1509 return True 1510 1511 def ButtonResult(self, button, *args): 1512 if self.IsCurrentDialog(): 1513 self.SetModalResult(button.btn_modalresult, 'ButtonResult') 1514 1515 def DefineButtons(self, buttons, okLabel = None, okFunc = 'default', args = 'self', cancelLabel = None, cancelFunc = 'default', okModalResult = 'default', default = None): 1516 if okLabel is None: 1517 okLabel = localization.GetByLabel('UI/Common/Buttons/OK') 1518 if cancelLabel is None: 1519 cancelLabel = localization.GetByLabel('UI/Common/Buttons/Cancel') 1520 buttonHeight = 32 1521 if getattr(self.sr, 'bottom', None) is None: 1522 self.sr.bottom = self.FindChild('bottom') 1523 if not self.sr.bottom: 1524 self.sr.bottom = Container(name='bottom', parent=self.GetMainArea(), align=uiconst.TOBOTTOM, padTop=4, idx=0) 1525 if self.sr.bottom is None: 1526 return 1527 self.sr.bottom.Flush() 1528 if buttons is None: 1529 self.sr.bottom.state = uiconst.UI_HIDDEN 1530 return 1531 self.sr.bottom.height = buttonHeight 1532 if okModalResult == 'default': 1533 okModalResult = uiconst.ID_OK 1534 if okFunc == 'default': 1535 okFunc = self.ConfirmFunction 1536 if cancelFunc == 'default': 1537 cancelFunc = self.ButtonResult 1538 1539 def create_ok_button(): 1540 is_ok_default = okModalResult == default if default is not None else True 1541 return Button(name='ok_dialog_button', label=okLabel, func=okFunc, args=args, btn_modalresult=okModalResult, btn_default=is_ok_default, variant=ButtonVariant.PRIMARY if is_ok_default else ButtonVariant.NORMAL) 1542 1543 def create_cancel_button(): 1544 is_cancel_default = uiconst.ID_CANCEL == default if default is not None else False 1545 return Button(name='cancel_dialog_button', label=cancelLabel, func=cancelFunc, args=args, btn_modalresult=uiconst.ID_CANCEL, btn_default=is_cancel_default, btn_cancel=True, variant=ButtonVariant.PRIMARY if is_cancel_default else ButtonVariant.NORMAL) 1546 1547 def create_close_button(): 1548 is_close_default = uiconst.ID_CLOSE == default if default is not None else False 1549 return Button(name='close_dialog_button', label=localization.GetByLabel('UI/Common/Buttons/Close'), func=self.CloseByUser, args=args, btn_modalresult=uiconst.ID_CLOSE, btn_default=is_close_default, btn_cancel=True, variant=ButtonVariant.PRIMARY if is_close_default else ButtonVariant.NORMAL) 1550 1551 def create_yes_button(): 1552 is_yes_default = uiconst.ID_YES == default if default is not None else True 1553 return Button(name='yes_dialog_button', label=localization.GetByLabel('UI/Common/Buttons/Yes'), func=self.ButtonResult, args=args, btn_modalresult=uiconst.ID_YES, btn_default=is_yes_default, variant=ButtonVariant.PRIMARY if is_yes_default else ButtonVariant.NORMAL) 1554 1555 def create_no_button(): 1556 is_no_default = uiconst.ID_NO == default if default is not None else False 1557 return Button(name='no_dialog_button', label=localization.GetByLabel('UI/Common/Buttons/No'), func=self.ButtonResult, args=args, btn_modalresult=uiconst.ID_NO, btn_default=is_no_default, variant=ButtonVariant.PRIMARY if is_no_default else ButtonVariant.NORMAL) 1558 1559 if isinstance(buttons, (types.ListType, types.TupleType)): 1560 button_data = [] 1561 for btn in buttons: 1562 is_default = btn.id == default if default is not None else False 1563 button_data.append(Button(label=btn.label, func=self.ButtonResult, args=None, btn_modalresult=btn.id, btn_default=is_default, btn_cancel=btn.id == uiconst.ID_CANCEL, variant=ButtonVariant.PRIMARY if is_default else ButtonVariant.NORMAL)) 1564 1565 elif buttons == uiconst.OK: 1566 button_data = [create_ok_button()] 1567 elif buttons == uiconst.OKCANCEL: 1568 button_data = [create_ok_button(), create_cancel_button()] 1569 elif buttons == uiconst.OKCLOSE: 1570 button_data = [create_ok_button(), create_close_button()] 1571 elif buttons == uiconst.YESNO: 1572 button_data = [create_yes_button(), create_no_button()] 1573 elif buttons == uiconst.YESNOCANCEL: 1574 button_data = [create_yes_button(), create_no_button(), create_cancel_button()] 1575 elif buttons == uiconst.CLOSE: 1576 button_data = [create_close_button()] 1577 elif isinstance(okLabel, (types.ListType, types.TupleType)): 1578 button_data = [] 1579 for index in xrange(len(okLabel)): 1580 label = okLabel[index] 1581 additionalArguments = {'Function': okFunc, 1582 'Arguments': args, 1583 'Cancel Label': cancelLabel, 1584 'Cancel Function': cancelFunc, 1585 'Modal Result': okModalResult, 1586 'Default': default} 1587 for argName in additionalArguments: 1588 if isinstance(additionalArguments[argName], (types.ListType, types.TupleType)) and len(additionalArguments[argName]) > index: 1589 additionalArguments[argName] = additionalArguments[argName][index] 1590 1591 is_default = additionalArguments['Modal Result'] == default if default is not None else additionalArguments['Default'] 1592 button_data.append(Button(label=label, func=additionalArguments['Function'], args=additionalArguments['Arguments'], btn_modalresult=additionalArguments['Modal Result'], btn_default=is_default, btn_cancel=additionalArguments['Modal Result'] == uiconst.ID_CANCEL, variant=ButtonVariant.PRIMARY if is_default else ButtonVariant.NORMAL)) 1593 1594 else: 1595 button_data = [create_ok_button()] 1596 buttonGroup = ButtonGroup(parent=self.sr.bottom, align=uiconst.TOBOTTOM, buttons=button_data, button_size_mode=ButtonSizeMode.STRETCH) 1597 self.sr.bottom.height = max(buttonHeight, buttonGroup.height) 1598 self.sr.bottom.state = uiconst.UI_PICKCHILDREN 1599 1600 def ConfirmFunction(self, button, *args): 1601 uicore.registry.Confirm(button) 1602 1603 def SetScope(self, scope): 1604 self.scope = scope 1605 1606 def SetModalResult(self, result, caller = None): 1607 if self.__modal_result: 1608 self._SetModalResult(result) 1609 self.Close() 1610 1611 def _SetModalResult(self, result): 1612 if self.__modal_result: 1613 uicore.registry.RemoveModalWindow(self) 1614 self.__modal_result.send(result) 1615 self.__modal_result = None 1616 1617 def MakeUnResizeable(self): 1618 self._resizeable = False 1619 self.Prepare_ScaleAreas_() 1620 self.MakeUnstackable() 1621 1622 def MakeUnstackable(self): 1623 self.__stackable = False 1624 1625 def MakeStackable(self): 1626 self.__stackable = True 1627 1628 def IsResizeable(self): 1629 return self._resizeable and not self.IsLocked() 1630 1631 def SetMinSize(self, size, refresh = 0): 1632 self.minsize = size 1633 if self.GetAlign() == uiconst.RELATIVE and not self.InStack(): 1634 if not self.IsCollapsed(): 1635 if self.height < self.minsize[1]: 1636 self.height = self.minsize[1] 1637 if self.width < self.minsize[0]: 1638 self.width = self.minsize[0] 1639 if refresh: 1640 self.width, self.height = self.minsize 1641 if self.stacked: 1642 self.stack.SetMinWH() 1643 1644 def SetMaxSize(self, size, refresh = 0): 1645 self.maxsize = size 1646 maxWidth, maxHeight = size 1647 if self.GetAlign() == uiconst.RELATIVE: 1648 if not self.IsCollapsed(): 1649 if maxWidth is not None and self.width > maxWidth: 1650 self.width = maxWidth 1651 if maxHeight is not None and self.height > maxHeight: 1652 self.height = maxHeight 1653 if refresh: 1654 if maxWidth is not None: 1655 self.width = maxWidth 1656 if maxHeight is not None: 1657 self.height = maxHeight 1658 if self.stacked: 1659 self.stack.Check() 1660 1661 def CheckMaxSize(self): 1662 maxWidth, maxHeight = self.maxsize 1663 if maxWidth and self.width > maxWidth: 1664 self.width = maxWidth 1665 if maxHeight and self.height > maxHeight: 1666 self.height = maxHeight 1667 1668 def _SetCaptionText(self, caption): 1669 if localization.IsValidLabel(caption): 1670 self.__caption = localization.GetByLabel(caption) 1671 else: 1672 self.__caption = caption 1673 1674 def LockHeight(self, height): 1675 self._fixedHeight = height 1676 if not self.InStack(): 1677 self.height = height 1678 1679 def UnlockHeight(self): 1680 self._fixedHeight = None 1681 1682 def LockWidth(self, width): 1683 self._fixedWidth = width 1684 if not self.stacked: 1685 self.width = width 1686 1687 def UnlockWidth(self): 1688 self._fixedWidth = None 1689 1690 def UpdateIntersectionBackground(self): 1691 if not self.InStack(): 1692 sm.GetService('window').UpdateIntersectionBackground() 1693 1694 def Maximize(self, retainOrder = False, *args, **kwds): 1695 if self.closing or self._changing: 1696 return 1697 if is_blocked('restore', self.windowID): 1698 return 1699 self._changing = True 1700 if self.stacked: 1701 self._SetMaximized() 1702 self.stack.ShowWnd(self) 1703 self.stack.Maximize() 1704 self._changing = False 1705 return 1706 self.OnStartMaximize_(self) 1707 if self.IsCollapsed(): 1708 self.Expand(0) 1709 wasMinimized = self.IsMinimized() 1710 if not retainOrder: 1711 uicore.registry.SetFocus(self) 1712 self._SetMaximized() 1713 self.state = uiconst.UI_NORMAL 1714 self.InitializeSize() 1715 self.InitializeStatesAndPosition() 1716 kick = [ w for w in self.Find('trinity.Tr2Sprite2dContainer') + self.Find('trinity.Tr2Sprite2d') if hasattr(w, '_OnResize') ] 1717 for each in kick: 1718 if hasattr(each, '_OnResize'): 1719 each._OnResize() 1720 1721 self.OnEndMaximize_(self) 1722 self._changing = False 1723 self._NotifyOfMaximized(wasMinimized) 1724 self.UpdateIntersectionBackground() 1725 1726 def _NotifyOfMaximized(self, wasMinimized): 1727 sm.ScatterEvent('OnWindowMaximized', self, wasMinimized) 1728 1729 def Minimize(self, animate = True): 1730 if not self.minimizable: 1731 return 1732 if self.stacked: 1733 return self.stack.Minimize(animate=animate) 1734 PlaySound(uiconst.SOUND_COLLAPSE) 1735 uicore.registry.SetFocus(None) 1736 self._Minimize(animate=animate) 1737 self.UpdateIntersectionBackground() 1738 1739 def _Minimize(self, animate = True): 1740 if self.closing or self.IsMinimized() or self._changing: 1741 return 1742 self.OnStartMinimize_(self) 1743 self._changing = True 1744 self._SetMinimized() 1745 if animate: 1746 self._AnimateMinimize() 1747 self.state = uiconst.UI_HIDDEN 1748 self.OnEndMinimize_(self) 1749 self._changing = False 1750 self._NotifyOfMinimized() 1751 1752 def _NotifyOfMinimized(self): 1753 sm.ScatterEvent('OnWindowMinimized', self) 1754 1755 def _AnimateMinimize(self): 1756 x, y = sm.GetService('neocom').GetMinimizeToPos(self) 1757 x = float(x) / uicore.desktop.width 1758 y = float(y) / uicore.desktop.height 1759 t = Transform(parent=uicore.layer.main, state=uiconst.UI_DISABLED, align=uiconst.TOALL, scalingCenter=(x, y), idx=0) 1760 wasCacheContent = self.cacheContents 1761 self.cacheContents = False 1762 self.SetParent(t) 1763 animations.Tr2DFlipOut(t, duration=0.3) 1764 animations.FadeOut(t, duration=0.25, sleep=True) 1765 self.SetParent(uicore.layer.main) 1766 self.cacheContents = wasCacheContent 1767 t.Close() 1768 1769 def IsMinimized(self): 1770 if self.stacked: 1771 return bool(self.stack.IsMinimized()) 1772 return bool(self.GetRegisteredState('minimized')) 1773 1774 def _SetMinimized(self): 1775 self.RegisterState('minimized', True) 1776 1777 def _SetMaximized(self): 1778 self.RegisterState('minimized', False) 1779 1780 def _SetCollapsed(self, isCollapsed): 1781 self.RegisterState('collapsed', isCollapsed) 1782 self.__collapsed = bool(isCollapsed) 1783 self._emit_on_collapsed_changed() 1784 1785 def _SetOpen(self, isOpen): 1786 self.RegisterState('open', isOpen) 1787 1788 def _SetHovered(self, isHovered): 1789 wasHovered = self.__hovered 1790 self.__hovered = isHovered 1791 if not wasHovered and isHovered: 1792 sm.ScatterEvent('OnWindowMouseEnter', self.windowID) 1793 elif wasHovered and not isHovered: 1794 sm.ScatterEvent('OnWindowMouseExit', self.windowID) 1795 1796 def IsHovered(self): 1797 return self.__hovered 1798 1799 def OnMouseEnter(self, *args): 1800 self._SetHovered(isHovered=True) 1801 1802 def OnMouseExit(self, *args): 1803 self._SetHovered(isHovered=False) 1804 1805 def OnMouseDown(self, btnNum, *args): 1806 if btnNum != uiconst.MOUSELEFT: 1807 return 1808 self.OnMouseDown_(self) 1809 self.dragMousePosition = (uicore.uilib.x, uicore.uilib.y) 1810 if self.IsLocked(): 1811 self.DisableDrag() 1812 else: 1813 self.EnableDrag() 1814 self.SetOrder(0) 1815 1816 def GetDragClipRects(self, shiftGroup, ctrlGroup): 1817 ml, mt, mw, mh = self.GetAbsolute() 1818 sl, st, sw, sh = self.GetGroupAbsolute(shiftGroup) 1819 cl, ct, cw, ch = self.GetGroupAbsolute(ctrlGroup) 1820 pl, pt, pw, ph = self.parent.GetAbsolute() 1821 x, y = self.dragMousePosition 1822 return ((0, 1823 0, 1824 pw, 1825 ph - (mt + self.GetCollapsedHeight() - y) + 1), (x - sl, 1826 y - st, 1827 pw - (sl + sw - x) + 1, 1828 ph - (st + sh - y) + 1), (x - cl, 1829 y - ct, 1830 pw - (cl + cw - x) + 1, 1831 ph - (ct + ch - y) + 1)) 1832 1833 def _BeginDrag(self): 1834 self._dragging = True 1835 ctrlDragWindows = self.FindConnectingWindows('bottom', includeLocked=False) 1836 shiftDragWindows = self.FindConnectingWindows(includeLocked=False) 1837 self.PrepareWindowsForMove(shiftDragWindows) 1838 while not self.closing and self.IsBeingDragged(): 1839 if uicore.uilib.mouseTravel > 1: 1840 break 1841 blue.pyos.synchro.Yield() 1842 1843 if self.closing or not self.IsBeingDragged() or self.__drag_started: 1844 return 1845 if ctrlDragWindows is None: 1846 ctrlDragWindows = self.FindConnectingWindows('bottom', includeLocked=False) 1847 if shiftDragWindows is None: 1848 shiftDragWindows = self.FindConnectingWindows(includeLocked=False) 1849 self.PrepareWindowsForMove(shiftDragWindows) 1850 snapGrid = None 1851 snapGroup = None 1852 snapIndicator = self.GetSnapIndicator() 1853 allGrid, myGrid, shiftGrid, ctrlGrid = self.CreateSnapGrid(shiftDragWindows, ctrlDragWindows) 1854 myRect, shiftRect, ctrlRect = self.GetDragClipRects(shiftDragWindows, ctrlDragWindows) 1855 initMouseX, initMouseY = self.dragMousePosition 1856 self.__drag_started = True 1857 while not self.closing and self.IsBeingDragged() and uicore.uilib.leftbtn and self.GetAlign() == uiconst.RELATIVE: 1858 self.state = uiconst.UI_DISABLED 1859 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 1860 ctrl = uicore.uilib.Key(uiconst.VK_CONTROL) 1861 self.left = uicore.uilib.x - initMouseX + self.preDragAbs[0] 1862 self.top = uicore.uilib.y - initMouseY + self.preDragAbs[1] 1863 for each in shiftDragWindows: 1864 if each is self: 1865 continue 1866 pl, pt, pw, ph = each.preDragAbs 1867 if shift or ctrl and each in ctrlDragWindows: 1868 each.left = uicore.uilib.x - initMouseX + pl 1869 each.top = uicore.uilib.y - initMouseY + pt 1870 else: 1871 each.left = pl 1872 each.top = pt 1873 1874 self.SetOrder(0) 1875 self.FindWindowToStackTo() 1876 if shift: 1877 snapGrid = shiftGrid 1878 snapGroup = shiftDragWindows 1879 cursorRect = shiftRect 1880 elif ctrl: 1881 cursorRect = ctrlRect 1882 snapGrid = ctrlGrid 1883 snapGroup = ctrlDragWindows 1884 else: 1885 snapGrid = myGrid 1886 snapGroup = [self] 1887 cursorRect = myRect 1888 uicore.uilib.ClipCursor(*cursorRect) 1889 self.ShowSnapEdges_Moving(snapGroup, snapGrid, snapIndicator=snapIndicator) 1890 self.OnDragTick() 1891 blue.pyos.synchro.Yield() 1892 1893 if not self.InStack() and self.IsStackable(): 1894 trystackto = self.FindWindowToStackTo() 1895 self.ClearStackIndication() 1896 if trystackto: 1897 if trystackto.stacked: 1898 trystackto.stack.CheckStackWith(self) 1899 else: 1900 trystackto.CheckStackWith(self) 1901 uicore.uilib.UnclipCursor() 1902 if self.closing: 1903 return 1904 if not self.InStack() and snapGrid and snapGroup: 1905 self.ShowSnapEdges_Moving(snapGroup, snapGrid, doSnap=True) 1906 self.CleanupParent('snapIndicator') 1907 self.ClearStackIndication() 1908 if self.InStack(): 1909 self.state = uiconst.UI_PICKCHILDREN 1910 else: 1911 self.state = uiconst.UI_NORMAL 1912 self.AdjustWindowPositionToFitScreen() 1913 if not self.closing: 1914 self.__drag_started = False 1915 1916 def AdjustWindowPositionToFitScreen(self): 1917 if self.stacked: 1918 return 1919 maxLeftAllowed = uicore.desktop.width - self.WINDOW_NEVER_OFFSCREEN_BUFFER 1920 if self.left > maxLeftAllowed: 1921 self.left = maxLeftAllowed 1922 minLeftAllowed = self.WINDOW_NEVER_OFFSCREEN_BUFFER - self.width 1923 if self.left < minLeftAllowed: 1924 self.left = minLeftAllowed 1925 maxTopAllowed = uicore.desktop.height - self.WINDOW_NEVER_OFFSCREEN_BUFFER 1926 if self.top > maxTopAllowed: 1927 self.top = maxTopAllowed 1928 minTopAllowed = self.WINDOW_NEVER_OFFSCREEN_BUFFER - self.height 1929 if self.top < minTopAllowed: 1930 self.top = minTopAllowed 1931 1932 def CreateSnapGrid(self, shiftGroup = None, ctrlGroup = None): 1933 leftOffset, rightOffset = self.GetSideOffset() 1934 allWnds = find_sibling_windows(self) 1935 desk = uicore.desktop 1936 hAxes = [0, 1937 desk.height, 1938 16, 1939 desk.height - 16] 1940 vAxes = [0, 1941 leftOffset, 1942 leftOffset + 16, 1943 desk.width - rightOffset, 1944 desk.width - 16 - rightOffset] 1945 if leftOffset < WINDOW_SNAP_DISTANCE: 1946 vAxes.pop(0) 1947 hAxesWithOutMe = hAxes[:] 1948 vAxesWithOutMe = vAxes[:] 1949 hAxesWithOutShiftGroup = hAxes[:] 1950 vAxesWithOutShiftGroup = vAxes[:] 1951 hAxesWithOutCtrlGroup = hAxes[:] 1952 vAxesWithOutCtrlGroup = vAxes[:] 1953 hLists = [hAxes, 1954 hAxesWithOutMe, 1955 hAxesWithOutShiftGroup, 1956 hAxesWithOutCtrlGroup] 1957 vLists = [vAxes, 1958 vAxesWithOutMe, 1959 vAxesWithOutShiftGroup, 1960 vAxesWithOutCtrlGroup] 1961 for wnd in allWnds: 1962 l, t, w, h = wnd.GetAbsolute() 1963 self.AddtoAxeList(wnd, vLists, l, shiftGroup, ctrlGroup) 1964 self.AddtoAxeList(wnd, vLists, l + w, shiftGroup, ctrlGroup) 1965 self.AddtoAxeList(wnd, hLists, t, shiftGroup, ctrlGroup) 1966 self.AddtoAxeList(wnd, hLists, t + h, shiftGroup, ctrlGroup) 1967 1968 self.__active_snap_grid = [(hAxes, vAxes), 1969 (hAxesWithOutMe, vAxesWithOutMe), 1970 (hAxesWithOutShiftGroup, vAxesWithOutShiftGroup), 1971 (hAxesWithOutCtrlGroup, vAxesWithOutCtrlGroup)] 1972 return self.__active_snap_grid 1973 1974 def AddtoAxeList(self, wnd, lists, val, shiftgroup, ctrlgroup): 1975 all, minusMe, minusShiftGroup, minusCtrlGroup = lists 1976 if val not in all: 1977 all.append(val) 1978 if wnd != self and val not in minusMe: 1979 minusMe.append(val) 1980 if shiftgroup and wnd not in shiftgroup and val not in minusShiftGroup: 1981 minusShiftGroup.append(val) 1982 if ctrlgroup and wnd not in ctrlgroup and val not in minusCtrlGroup: 1983 minusCtrlGroup.append(val) 1984 1985 def ShowSnapEdges_Scaling(self, snapGrid, showSnap = True, doSnap = False): 1986 if not self.__scale_sides: 1987 return 1988 horizontal, vertical = snapGrid 1989 snapdist = WINDOW_SNAP_DISTANCE 1990 match = {} 1991 for side in self.__scale_sides: 1992 wnd = self 1993 minLDist = 1000 1994 minRDist = 1000 1995 minTDist = 1000 1996 minBDist = 1000 1997 wl, wt, ww, wh = wnd.GetAbsolute() 1998 if showSnap: 1999 snapIndicator = wnd.GetSnapIndicator() 2000 snapIndicator.left = wl 2001 snapIndicator.top = wt 2002 snapIndicator.width = ww 2003 snapIndicator.height = wh 2004 for each in snapIndicator.children: 2005 each.state = uiconst.UI_HIDDEN 2006 2007 else: 2008 wnd.HideSnapIndicator() 2009 if side in ('top', 'bottom'): 2010 for hAxe in horizontal: 2011 tDist = abs(hAxe - wt) 2012 bDist = abs(hAxe - (wt + wh)) 2013 if side == 'top' and tDist <= snapdist and tDist < minTDist: 2014 minTDist = tDist 2015 match[side, wnd] = hAxe 2016 elif side == 'bottom' and bDist <= snapdist and bDist < minBDist: 2017 minBDist = bDist 2018 match[side, wnd] = hAxe 2019 2020 elif side in ('left', 'right'): 2021 for vAxe in vertical: 2022 lDist = abs(vAxe - wl) 2023 rDist = abs(vAxe - (wl + ww)) 2024 if side == 'left' and lDist <= snapdist and lDist < minLDist: 2025 minLDist = lDist 2026 match[side, wnd] = vAxe 2027 elif side == 'right' and rDist <= snapdist and rDist < minRDist: 2028 minRDist = rDist 2029 match[side, wnd] = vAxe 2030 2031 if showSnap or doSnap: 2032 checkMultipleSideSnap = {} 2033 for side, wnd in match.iterkeys(): 2034 if wnd not in checkMultipleSideSnap: 2035 checkMultipleSideSnap[wnd] = [] 2036 snapValue = match[side, wnd] 2037 wl, wt, ww, wh = wnd.GetAbsolute() 2038 minH = wnd.GetMinHeight() 2039 snapIndicator = wnd.GetSnapIndicator() 2040 snapIndicator.state = uiconst.UI_DISABLED 2041 snapIndicator.SetOrder(1) 2042 if side == 'left': 2043 if doSnap: 2044 wnd.left = snapValue 2045 if wnd.IsResizeable(): 2046 wnd.width = wl - snapValue + ww 2047 if showSnap: 2048 snapIndicator.left = snapValue - 2 2049 snapIndicator.width = wl - snapValue + ww + 4 2050 snapIndicator.GetChild('sLeft').state = uiconst.UI_DISABLED 2051 if side == 'right': 2052 if doSnap: 2053 if wnd.IsResizeable(): 2054 wnd.width = snapValue - wl 2055 if showSnap: 2056 snapIndicator.width = snapValue - wl + 4 2057 snapIndicator.GetChild('sRight').state = uiconst.UI_DISABLED 2058 if side == 'top': 2059 if doSnap: 2060 wnd.top = snapValue 2061 if wnd.IsResizeable(): 2062 wnd.height = wnd._fixedHeight or max(minH, wt - snapValue + wh) 2063 if showSnap: 2064 snapIndicator.top = snapValue - 2 2065 snapIndicator.height = wt - snapValue + wh + 4 2066 snapIndicator.GetChild('sTop').state = uiconst.UI_DISABLED 2067 if side == 'bottom': 2068 if doSnap: 2069 if wnd.IsResizeable(): 2070 wnd.height = wnd._fixedHeight or max(minH, snapValue - wt) 2071 if showSnap: 2072 snapIndicator.height = snapValue - wt + 4 2073 snapIndicator.GetChild('sBottom').state = uiconst.UI_DISABLED 2074 checkMultipleSideSnap[wnd].append(side) 2075 2076 def SetActive(self, *args): 2077 if self.stacked: 2078 self.stack.SetActive() 2079 self.ActivateUnderlay() 2080 if self.display: 2081 self.SetNotBlinking() 2082 self.__active = True 2083 self.Prepare_ScaleAreas_() 2084 self.OnSetActive_(self) 2085 self.OnWindowAboveSetActive() 2086 if not self.is_stack: 2087 self._LogWindowEventFocused() 2088 self.__focused_at_timestamp = gametime.GetWallclockTime() 2089 2090 def OnSetInactive(self, *args): 2091 if self.stacked: 2092 self.stack.OnSetInactive() 2093 self.DeactivateUnderlay() 2094 self.__active = False 2095 self.Prepare_ScaleAreas_() 2096 self.OnWindowAboveSetInactive() 2097 if not self.is_stack: 2098 self._LogWindowUnfocused() 2099 2100 def ActivateUnderlay(self): 2101 if self.sr.underlay: 2102 self.sr.underlay.AnimEntry() 2103 2104 def DeactivateUnderlay(self): 2105 if self.sr.underlay: 2106 self.sr.underlay.AnimExit() 2107 2108 def HideSnapIndicator(self): 2109 snapIndicator = self.parent.FindChild('snapIndicator') 2110 if snapIndicator is not None: 2111 snapIndicator.Close() 2112 2113 def GetSnapIndicator(self): 2114 snapIndicator = self.parent.FindChild('snapIndicator') 2115 if snapIndicator is None: 2116 snapIndicator = Container(parent=self.parent, color=(0.0, 1.0, 0.0, 1.0), align=uiconst.TOPLEFT, name='snapIndicator') 2117 for label, align, iconPath in [('sLeftTop', uiconst.TOPLEFT, 'res:/UI/Texture/Icons/1_16_1.png'), 2118 ('sRightTop', uiconst.TOPRIGHT, 'res:/UI/Texture/Icons/1_16_3.png'), 2119 ('sRightBottom', uiconst.BOTTOMRIGHT, 'res:/UI/Texture/Icons/1_16_35.png'), 2120 ('sLeftBottom', uiconst.BOTTOMLEFT, 'res:/UI/Texture/Icons/1_16_33.png'), 2121 ('sLeft', uiconst.CENTERLEFT, 'res:/UI/Texture/Icons/1_16_17.png'), 2122 ('sTop', uiconst.CENTERTOP, 'res:/UI/Texture/Icons/1_16_2.png'), 2123 ('sRight', uiconst.CENTERRIGHT, 'res:/UI/Texture/Icons/1_16_19.png'), 2124 ('sBottom', uiconst.CENTERBOTTOM, 'res:/UI/Texture/Icons/1_16_34.png')]: 2125 Sprite(parent=snapIndicator, name=label, align=align, state=uiconst.UI_HIDDEN, texturePath=iconPath, width=16, height=16) 2126 2127 return snapIndicator 2128 2129 def GetStackClass(self): 2130 from carbonui.window.stack import WindowStack 2131 return WindowStack 2132 2133 def IndicateStackable(self, wnd = None): 2134 if wnd is None: 2135 if self.sr.snapIndicator: 2136 animations.FadeOut(self.sr.snapIndicator, duration=0.2, callback=self.sr.snapIndicator.Close) 2137 self.sr.snapIndicator = None 2138 return 2139 if not wnd.IsStackable() or not self.IsStackable(): 2140 return 2141 if self.sr.snapIndicator is None: 2142 margin_left, margin_top, margin_right, _ = wnd.GetWindowBorderPadding() 2143 border_left, border_top, border_right, _ = wnd.GetWindowBorderSize() 2144 padding = (margin_left + border_left, 2145 margin_top + border_top, 2146 margin_right + border_right, 2147 0) 2148 self.sr.snapIndicator = Fill(align=uiconst.TOTOP_NOPUSH, state=uiconst.UI_DISABLED, color=eveThemeColor.THEME_ACCENT, opacity=0.0, outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.3, height=wnd.header_height, padding=padding, idx=0) 2149 animations.FadeTo(self.sr.snapIndicator, startVal=0.0, endVal=0.4, duration=0.2) 2150 si = self.sr.snapIndicator 2151 si.state = uiconst.UI_DISABLED 2152 if si.parent != wnd: 2153 Transplant(si, wnd, idx=0) 2154 else: 2155 si.SetOrder(0) 2156 2157 def ClearStackIndication(self): 2158 self.IndicateStackable(None) 2159 2160 def ShowSnapEdges_Moving(self, snapGroup, snapGrid, snapIndicator = None, doSnap = False): 2161 if snapGrid is None: 2162 return 2163 l, t, w, h = gl, gt, gw, gh = self.GetGroupAbsolute(snapGroup) 2164 snapdist = WINDOW_SNAP_DISTANCE 2165 lSnap = None 2166 rSnap = None 2167 tSnap = None 2168 bSnap = None 2169 minLDist = 1000 2170 minRDist = 1000 2171 minTDist = 1000 2172 minBDist = 1000 2173 horizontal, vertical = snapGrid 2174 for hAxe in horizontal: 2175 tDist = abs(hAxe - t) 2176 bDist = abs(hAxe - (t + h)) 2177 if tDist <= snapdist and tDist < minTDist: 2178 tSnap = hAxe 2179 minTDist = tDist 2180 elif bDist <= snapdist and bDist < minBDist: 2181 bSnap = hAxe 2182 minBDist = bDist 2183 2184 for vAxe in vertical: 2185 lDist = abs(vAxe - l) 2186 rDist = abs(vAxe - (l + w)) 2187 if lDist <= snapdist and lDist < minLDist: 2188 lSnap = vAxe 2189 minLDist = lDist 2190 elif rDist <= snapdist and rDist < minRDist: 2191 rSnap = vAxe 2192 minRDist = rDist 2193 2194 if tSnap is not None: 2195 t = tSnap 2196 if bSnap is not None: 2197 h = bSnap - tSnap 2198 elif bSnap is not None: 2199 t = bSnap - h 2200 if lSnap is not None: 2201 l = lSnap 2202 if rSnap is not None: 2203 w = rSnap - lSnap 2204 elif rSnap is not None: 2205 l = rSnap - w 2206 if snapIndicator and not snapIndicator.destroyed: 2207 snapIndicator.width = w + 6 2208 snapIndicator.height = h + 6 2209 snapIndicator.left = l - 2 2210 snapIndicator.top = t - 2 2211 for each in snapIndicator.children: 2212 each.state = uiconst.UI_HIDDEN 2213 2214 snapIndicator.SetOrder(1) 2215 if lSnap is not None: 2216 snapIndicator.GetChild('sLeft').state = uiconst.UI_DISABLED 2217 if rSnap is not None: 2218 snapIndicator.GetChild('sRight').state = uiconst.UI_DISABLED 2219 if tSnap is not None: 2220 snapIndicator.GetChild('sTop').state = uiconst.UI_DISABLED 2221 if bSnap is not None: 2222 snapIndicator.GetChild('sBottom').state = uiconst.UI_DISABLED 2223 snapIndicator.state = uiconst.UI_DISABLED 2224 leftOffset, rightOffset = self.GetSideOffset() 2225 cornerSnap = '' 2226 if tSnap in (0, 16): 2227 cornerSnap = 'top' 2228 elif bSnap in (uicore.desktop.height, uicore.desktop.height - 16): 2229 cornerSnap = 'bottom' 2230 if cornerSnap: 2231 if lSnap in (leftOffset, leftOffset + 16): 2232 cornerSnap = cornerSnap + 'left' 2233 elif rSnap in (uicore.desktop.width, uicore.desktop.width - 16): 2234 cornerSnap = cornerSnap + 'right' 2235 if doSnap: 2236 scaleX = float(w) / gw 2237 scaleY = float(h) / gh 2238 diffX = l - gl 2239 diffY = t - gt 2240 for wnd in snapGroup: 2241 wnd.left += diffX 2242 wnd.top += diffY 2243 if wnd.IsResizeable(): 2244 wnd.width = int(wnd.width * scaleX) 2245 wnd.height = int(wnd.height * scaleY) 2246 2247 for wnd in snapGroup: 2248 if wnd._fixedHeight and wnd.height != wnd._fixedHeight: 2249 diff = wnd.height - wnd._fixedHeight 2250 bottomAlignedWindows = wnd.FindConnectingWindows('bottom') 2251 wnd.height -= diff 2252 for each in bottomAlignedWindows[1:]: 2253 each.top -= diff 2254 2255 if wnd._fixedWidth and wnd.width != wnd._fixedWidth: 2256 diff = wnd.width - wnd._fixedWidth 2257 rightAlignedWindows = wnd.FindConnectingWindows('right') 2258 wnd.width -= diff 2259 for each in rightAlignedWindows[1:]: 2260 each.left -= diff 2261 2262 def FindWindowToStackTo(self): 2263 over = uicore.uilib.mouseOver 2264 if over is self: 2265 return None 2266 over = GetWindowAbove(over) 2267 if not isinstance(over, Window) or not over.IsStackable(): 2268 self.ClearStackIndication() 2269 return None 2270 if over.stacked: 2271 over = over.stack 2272 l, t, w, h = over.GetAbsolute() 2273 sl, st, sw, sh = self.GetAbsolute() 2274 if (l < sl < l + w or l < sl + sw < l + w) and t <= st <= t + over.header_height: 2275 self.IndicateStackable(over) 2276 return over 2277 self.ClearStackIndication() 2278 2279 def IsStackable(self): 2280 if self.__stackable and not self.IsLocked(): 2281 shiftonly = settings.user.ui.Get('stackwndsonshift', 0) 2282 if shiftonly: 2283 return uicore.uilib.Key(uiconst.VK_SHIFT) 2284 return 1 2285 return 0 2286 2287 def OnMouseUp(self, *args): 2288 self.ClearStackIndication() 2289 self.CleanupParent('snapIndicator') 2290 uicore.uilib.UnclipCursor() 2291 self._dragging = False 2292 self._dragEnabled = False 2293 self.__drag_started = False 2294 self.RegisterPositionAndSize() 2295 2296 def OnDblClick(self, *args): 2297 if getattr(self, 'isDialog', False): 2298 return 2299 if uicore.uilib.y - self.top < self.header_height: 2300 self.ToggleCollapse() 2301 2302 def ToggleCollapse(self): 2303 if not self.collapsible: 2304 return 2305 self.ResetToggleState() 2306 if self.collapsed: 2307 self.Expand() 2308 PlaySound(uiconst.SOUND_EXPAND) 2309 else: 2310 self.Collapse() 2311 PlaySound(uiconst.SOUND_COLLAPSE) 2312 2313 def ToggleMinimize(self): 2314 if self.IsMinimized(): 2315 self.Maximize() 2316 elif self.minimizable: 2317 parChildren = self.GetParentLayer().children 2318 if self.InStack(): 2319 if parChildren and parChildren[0] != self.stack: 2320 uicore.registry.SetFocus(self) 2321 self.stack.ShowWnd(self) 2322 elif self.stack.GetActiveWindow() != self: 2323 self.stack.ShowWnd(self) 2324 else: 2325 self.Minimize() 2326 elif parChildren and parChildren[0] != self: 2327 uicore.registry.SetFocus(self) 2328 else: 2329 self.Minimize() 2330 2331 def GetParentLayer(self): 2332 if self.InStack(): 2333 return self.stack.parent 2334 else: 2335 return self.parent 2336 2337 def ResetToggleState(self): 2338 uicore.registry.ResetToggleStateForWnd(getattr(self, 'windowID', None)) 2339 2340 def GetCollapsedHeight(self): 2341 _, margin_top, _, margin_bottom = self.GetWindowBorderPadding() 2342 _, border_top, _, border_bottom = self.GetWindowBorderSize() 2343 return margin_top + border_top + WindowHeaderBase.COLLAPSED_HEIGHT + border_bottom + margin_bottom 2344 2345 def Collapse(self, forceCollapse = False, checkchain = 1, *args): 2346 if not self.collapsible or not forceCollapse and self.collapsed: 2347 return 2348 if self.sr.bottom: 2349 self.sr.bottom.state = uiconst.UI_HIDDEN 2350 if self.sr.main: 2351 self.sr.main.state = uiconst.UI_HIDDEN 2352 if not self.parent or not self.collapsible or self.collapsed: 2353 return 2354 if self.stacked: 2355 return self.stack.Collapse() 2356 bottomAlignedWindows = self.FindConnectingWindows('bottom') 2357 allAlignedWindows = self.FindConnectingWindows() 2358 gl, gt, gw, gh = self.GetGroupAbsolute(allAlignedWindows) 2359 ch = self.GetCollapsedHeight() 2360 heightDiff = self.height - ch 2361 self._SetCollapsed(True) 2362 self.LockHeight(ch) 2363 alignedToBottom = False 2364 alignedToTop = False 2365 pl, pt, pw, ph = self.parent.GetAbsolute() 2366 if gt in (0, 16): 2367 alignedToTop = True 2368 elif gt + gh in (ph, ph - 16): 2369 alignedToBottom = True 2370 if alignedToBottom: 2371 topAlignedWindows = self.FindConnectingWindows('top') 2372 for wnd in topAlignedWindows: 2373 wnd.top += heightDiff 2374 2375 else: 2376 for wnd in bottomAlignedWindows: 2377 if wnd == self: 2378 continue 2379 wnd.top -= heightDiff 2380 2381 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 2382 if shift: 2383 affected = allAlignedWindows 2384 for each in affected: 2385 if each != self: 2386 each.Collapse() 2387 2388 self.OnCollapsed(self) 2389 self.Prepare_ScaleAreas_() 2390 2391 def Expand(self, *args): 2392 if not self.parent or not self.IsCollapsed(): 2393 return 2394 if self.stacked: 2395 return self.stack.Expand(*args) 2396 self.UnlockHeight() 2397 bottomAlignedWindows = self.FindConnectingWindows('bottom') 2398 gl, gt, gw, gh = self.GetGroupAbsolute(bottomAlignedWindows) 2399 pl, pt, pw, ph = self.parent.GetAbsolute() 2400 alignedToBottom = False 2401 if gt + gh in (ph, ph - 16): 2402 alignedToBottom = True 2403 left, top, width, height, dw, dh = self.GetRegisteredPositionAndSize() 2404 height = max(height, self.GetMinHeight()) 2405 heightDiff = height - self.height 2406 self._SetCollapsed(False) 2407 self.height = height 2408 if alignedToBottom: 2409 topAlignedWindows = self.FindConnectingWindows('top') 2410 for wnd in topAlignedWindows: 2411 wnd.top = max(0, wnd.top - heightDiff) 2412 2413 else: 2414 for wnd in bottomAlignedWindows: 2415 if wnd == self: 2416 continue 2417 wnd.top = min(wnd.top + heightDiff, uicore.desktop.height - wnd.height) 2418 2419 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 2420 if shift: 2421 affected = self.FindConnectingWindows() 2422 for each in affected: 2423 if each != self: 2424 each.Expand() 2425 2426 self.OnExpanded(self) 2427 self.ValidateWindows() 2428 self.Prepare_ScaleAreas_() 2429 if self.sr.bottom: 2430 self.sr.bottom.state = uiconst.UI_PICKCHILDREN 2431 if self.sr.main: 2432 self.sr.main.state = uiconst.UI_PICKCHILDREN 2433 2434 def OnCompactModeEnabled(self): 2435 pass 2436 2437 def OnCompactModeDisabled(self): 2438 pass 2439 2440 def ValidateWindows(self): 2441 d = uicore.desktop 2442 all = uicore.registry.GetValidWindows(getModals=1, floatingOnly=True) 2443 for wnd in all: 2444 if wnd.GetAlign() != uiconst.RELATIVE: 2445 continue 2446 wnd.left = max(-wnd.width + 64, min(d.width - 64, wnd.left)) 2447 wnd.top = max(0, min(d.height - wnd.GetCollapsedHeight(), wnd.top)) 2448 2449 def CheckStackWith(self, dropWnd): 2450 if not self.IsStackable(): 2451 return 2452 if self.sr.modalParent is not None or dropWnd.sr.modalParent is not None or dropWnd == self: 2453 return 2454 if self.state == uiconst.UI_HIDDEN: 2455 return 2456 if dropWnd.closing: 2457 return 2458 wnds = [(self, 0)] 2459 kill = [] 2460 from carbonui.window.stack import WindowStack 2461 if isinstance(dropWnd, WindowStack): 2462 for wnd in dropWnd.GetWindows(): 2463 wnds.append((wnd, wnd.state == uiconst.UI_NORMAL)) 2464 2465 kill.append(dropWnd) 2466 else: 2467 wnds.append((dropWnd, 1)) 2468 self._ConstructStack(wnds, kill) 2469 2470 def CheckWndPos(self, i = 0): 2471 if self.parent is None or self.parent.destroyed or i == 10: 2472 return 2473 if self.locked: 2474 return 2475 for each in self.parent.children: 2476 if each != self and each.state == uiconst.UI_NORMAL: 2477 if each.left == self.left and each.top == self.top: 2478 self.left = self.left + POSOVERLAPSHIFT 2479 self.top = self.top + POSOVERLAPSHIFT 2480 if self.left + self.width > uicore.desktop.width: 2481 self.left = uicore.desktop.width - self.width 2482 if self.top + self.height > uicore.desktop.height: 2483 self.top = uicore.desktop.height - self.height 2484 self.CheckWndPos(i + 1) 2485 break 2486 2487 def _ConstructStack(self, wnds, kill, group = None, groupidx = None): 2488 stack = uicore.registry.GetStack(str(uthread.uniqueId()), self.GetStackClass()) 2489 if not stack or stack.closing: 2490 return 2491 for _wnd in wnds: 2492 wnd, show = _wnd 2493 stack.InsertWnd(wnd, 1, show) 2494 2495 for each in kill: 2496 if each is not None and not each.destroyed: 2497 each.Close() 2498 2499 uicore.registry.SetFocus(stack) 2500 2501 def SetHeight(self, height): 2502 if self.GetAlign() == uiconst.RELATIVE and height != self.height: 2503 self.height = height 2504 2505 def SetHeight_PushOrPullWindowsBelow(self, newHeight): 2506 if self.GetAlign() == uiconst.RELATIVE and newHeight != self.height: 2507 bottomAlignedWindows = self.FindConnectingWindows('bottom') 2508 heightDiff = newHeight - self.height 2509 self.height = newHeight 2510 for wnd in bottomAlignedWindows: 2511 if wnd == self: 2512 continue 2513 wnd.top += heightDiff 2514 2515 def GetMinWidth(self): 2516 minWidth = self._GetMinWidth() 2517 if self._fixedWidth: 2518 return min(self._fixedWidth, minWidth) 2519 w, h = self.GetMinSize() 2520 return max(w, minWidth) 2521 2522 def _GetMinWidth(self): 2523 return self.minsize[0] 2524 2525 def GetMinHeight(self): 2526 if self._fixedHeight: 2527 return min(self._fixedHeight, self._GetMinHeight()) 2528 w, h = self.GetMinSize() 2529 return max(h, self.minsize[1]) 2530 2531 def _GetMinHeight(self): 2532 return self.minsize[1] 2533 2534 def GetMaxWidth(self): 2535 if self._fixedWidth: 2536 return self._fixedWidth 2537 return self.maxsize[0] or sys.maxint 2538 2539 def GetMaxHeight(self): 2540 if self._fixedHeight: 2541 return self._fixedHeight 2542 return self.maxsize[1] or sys.maxint 2543 2544 def FindConnectingWindows(self, fromSide = None, wnds = None, validWnds = None, getParallelSides = 0, fullSideOnly = 0, includeLocked = True): 2545 if validWnds is None: 2546 validWnds = find_sibling_windows(self) 2547 validWnds.insert(0, self) 2548 l, t, w, h = self.GetAbsolute() 2549 fromWndCorners = [(l, t), 2550 (l + w, t), 2551 (l + w, t + h), 2552 (l, t + h)] 2553 if fromSide == 'left': 2554 validCornerPairs = [(3, 2), (0, 1)] 2555 if getParallelSides: 2556 validCornerPairs += [(3, 0), (0, 3)] 2557 elif fromSide == 'right': 2558 validCornerPairs = [(1, 0), (2, 3)] 2559 if getParallelSides: 2560 validCornerPairs += [(1, 2), (2, 1)] 2561 elif fromSide == 'top': 2562 validCornerPairs = [(0, 3), (1, 2)] 2563 if getParallelSides: 2564 validCornerPairs += [(0, 1), (1, 0)] 2565 elif fromSide == 'bottom': 2566 validCornerPairs = [(2, 1), (3, 0)] 2567 if getParallelSides: 2568 validCornerPairs += [(3, 2), (2, 3)] 2569 else: 2570 validCornerPairs = [(3, 2), 2571 (0, 1), 2572 (1, 0), 2573 (2, 3), 2574 (0, 3), 2575 (1, 2), 2576 (2, 1), 2577 (3, 0)] 2578 wnds = wnds or [] 2579 if self not in wnds: 2580 wnds.append(self) 2581 for wnd in validWnds: 2582 if wnd in wnds: 2583 continue 2584 wl, wt, ww, wh = wnd.GetAbsolute() 2585 wndCorners = ((wl, wt), 2586 (wl + ww, wt), 2587 (wl + ww, wt + wh), 2588 (wl, wt + wh)) 2589 m = 0 2590 for c1, c2 in validCornerPairs: 2591 c1Pos = fromWndCorners[c1] 2592 c2Pos = wndCorners[c2] 2593 if c1Pos == c2Pos: 2594 if not fullSideOnly or m == 1: 2595 if getParallelSides: 2596 wnd.FindConnectingWindows(None, wnds, validWnds, getParallelSides, fullSideOnly) 2597 else: 2598 wnd.FindConnectingWindows(fromSide, wnds, validWnds, getParallelSides, fullSideOnly) 2599 break 2600 m += 1 2601 2602 if not includeLocked: 2603 wnds = [ wnd for wnd in wnds if not wnd.IsLocked() ] 2604 return wnds 2605 2606 def PrepareWindowsForMove(self, wnds): 2607 for each in wnds: 2608 each.preDragAbs = each.GetAbsolute() 2609 each.preDragCursorPos = (uicore.uilib.x, uicore.uilib.y) 2610 each.SetOrder(0) 2611 2612 def CleanupParent(self, what): 2613 for each in self.parent.children[:]: 2614 if each.name == what: 2615 each.Close() 2616 2617 def FindMinMaxScaling(self, sides): 2618 scaleH, scaleV, scaleAbove, followL, followR, followT, followB, all = self.sortedScaleWindows 2619 pl, pt, pw, ph = self.parent.GetAbsolute() 2620 myMinX = minX = 0 2621 myMaxX = maxX = pw 2622 myMinY = minY = 0 2623 myMaxY = maxY = ph 2624 for wnd in scaleH + [self]: 2625 spdl, spdt, spdw, spdh = wnd.preDragAbs 2626 wndMinWidth = wnd.GetMinWidth() 2627 wndMaxWidth = wnd.GetMaxWidth() 2628 if 'left' in sides: 2629 minX = max(minX, spdl + spdw - wndMaxWidth) 2630 maxX = min(maxX, spdl + spdw - wndMinWidth) 2631 elif 'right' in sides: 2632 minX = max(minX, spdl + wndMinWidth) 2633 maxX = min(maxX, spdl + wndMaxWidth) 2634 2635 for wnd in scaleV + [self]: 2636 spdl, spdt, spdw, spdh = wnd.preDragAbs 2637 wndMinHeight = wnd.GetMinHeight() 2638 wndMaxHeight = wnd.GetMaxHeight() 2639 if 'top' in sides: 2640 minY = max(minY, spdt + spdh - wndMaxHeight) 2641 maxY = min(maxY, spdt + spdh - wndMinHeight) 2642 elif 'bottom' in sides: 2643 minY = max(minY, spdt + wndMinHeight) 2644 maxY = min(maxY, spdt + wndMaxHeight) 2645 2646 for wnd in scaleAbove: 2647 spdl, spdt, spdw, spdh = wnd.preDragAbs 2648 wndMinHeight = wnd.GetMinHeight() 2649 wndMaxHeight = wnd.GetMaxHeight() 2650 minY = max(minY, spdt + wndMinHeight) 2651 maxY = min(maxY, spdt + wndMaxHeight) 2652 2653 spdl, spdt, spdw, spdh = self.preDragAbs 2654 myMinWidth = self.GetMinWidth() 2655 myMinHeight = self.GetMinHeight() 2656 myMaxWidth = self.GetMaxWidth() 2657 myMaxHeight = self.GetMaxHeight() 2658 if 'top' in sides: 2659 myMaxY = min(myMaxY, spdt + spdh - myMinHeight) 2660 myMinY = max(myMinY, spdt + spdh - myMaxHeight) 2661 for wnd in followT: 2662 pdl, pdt, pdw, pdh = wnd.preDragAbs 2663 minY = max(minY, spdt - pdt) 2664 2665 elif 'bottom' in sides: 2666 myMinY = max(myMinY, spdt + myMinHeight) 2667 myMaxY = min(myMaxY, spdt + myMaxHeight) 2668 for wnd in followB: 2669 pdl, pdt, pdw, pdh = wnd.preDragAbs 2670 maxY = min(maxY, spdt + spdh + (ph - (pdt + pdh))) 2671 2672 if 'left' in sides: 2673 myMaxX = min(myMaxX, spdl + spdw - myMinWidth) 2674 myMinX = max(myMinX, spdl + spdw - myMaxWidth) 2675 for wnd in followL: 2676 pdl, pdt, pdw, pdh = wnd.preDragAbs 2677 minX = max(minX, spdl - pdl) 2678 2679 elif 'right' in sides: 2680 myMinX = max(myMinX, spdl + myMinWidth) 2681 myMaxX = min(myMaxX, spdl + myMaxWidth) 2682 for wnd in followR: 2683 pdl, pdt, pdw, pdh = wnd.preDragAbs 2684 maxX = min(maxX, spdl + spdw + (pw - (pdl + pdw))) 2685 2686 return ((minX, 2687 minY, 2688 maxX, 2689 maxY), (myMinX, 2690 myMinY, 2691 myMaxX, 2692 myMaxY)) 2693 2694 def ModifyRect(self, sides): 2695 l, t, w, h = self.GetAbsolute() 2696 mx = uicore.uilib.x 2697 my = uicore.uilib.y 2698 rh = rv = 0 2699 if 'right' in sides: 2700 rh = l + w - mx 2701 elif 'left' in sides: 2702 rh = l - mx 2703 if 'bottom' in sides: 2704 rv = t + h - my 2705 elif 'top' in sides: 2706 rv = t - my 2707 return (int(rh), 2708 int(rv), 2709 int(rh), 2710 int(rv)) 2711 2712 @telemetry.ZONE_METHOD 2713 def UpdateClipCursor(self, rect, mrect): 2714 ml, mt, mr, mb = mrect 2715 rl, rt, rr, rb = rect 2716 uicore.uilib.ClipCursor(rl - ml, rt - mt, rr - mr, rb - mb) 2717 2718 def GetSidesFromScalerName(self, sName): 2719 ret = [] 2720 for s in ['Left', 2721 'Top', 2722 'Right', 2723 'Bottom']: 2724 if s in sName: 2725 ret.append(s.lower()) 2726 2727 return ret 2728 2729 def StartScale(self, sender, btn, *args): 2730 if btn == uiconst.MOUSELEFT: 2731 sides = self.GetSidesFromScalerName(sender.name) 2732 self._StartScale(sides=sides) 2733 2734 def _StartScale(self, sides): 2735 if not self.IsResizeable() or self.InStack(): 2736 return 2737 self.__scale_sides = sides 2738 self.sortedScaleWindows = self.SortScaleWindows(self.__scale_sides) 2739 self.minmaxScale = self.FindMinMaxScaling(self.__scale_sides) 2740 self.CreateSnapGrid(self.sortedScaleWindows[-1]) 2741 self._emit_on_start_scale() 2742 self.OnStartScale_(self) 2743 self._scaling = True 2744 uthread.new(self.OnScale) 2745 2746 def SortScaleWindows(self, sides): 2747 wnds = [] 2748 for side in sides: 2749 wnds += self.FindConnectingWindows(side, getParallelSides=1) 2750 2751 self.PrepareWindowsForMove(wnds) 2752 ml, mt, mw, mh = self.GetAbsolute() 2753 scaleWidthMeH = [] 2754 scaleWidthMeV = [] 2755 onLeft = [] 2756 onRight = [] 2757 onBottom = [] 2758 onTop = [] 2759 all = [self] 2760 scaleAbove = [] 2761 for wnd in wnds: 2762 if wnd == self or wnd in all: 2763 continue 2764 l, t, w, h = wnd.GetAbsolute() 2765 if l == ml and w == mw: 2766 scaleWidthMeH.append(wnd) 2767 elif l >= ml + mw: 2768 onRight.append(wnd) 2769 elif l + w <= ml: 2770 onLeft.append(wnd) 2771 elif 'right' in sides: 2772 onRight.append(wnd) 2773 elif 'left' in sides: 2774 onLeft.append(wnd) 2775 if t == mt and h == mh: 2776 scaleWidthMeV.append(wnd) 2777 elif t >= mt + mh: 2778 onBottom.append(wnd) 2779 elif t + h == mt and 'top' in sides: 2780 scaleAbove.append(wnd) 2781 elif t == mt and 'top' in sides: 2782 onTop.append(wnd) 2783 all.append(wnd) 2784 2785 return (scaleWidthMeH, 2786 scaleWidthMeV, 2787 scaleAbove, 2788 onLeft, 2789 onRight, 2790 onTop, 2791 onBottom, 2792 all) 2793 2794 @telemetry.ZONE_METHOD 2795 def OnScale(self, *args): 2796 mRect = self.ModifyRect(self.__scale_sides) 2797 while self._scaling and uicore.uilib.leftbtn and self and not self.closing: 2798 diffx = uicore.uilib.x - self.preDragCursorPos[0] 2799 diffy = uicore.uilib.y - self.preDragCursorPos[1] 2800 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 2801 allMinMaxRect, myMinMaxRect = self.minmaxScale 2802 if shift: 2803 snapGrid = self.__active_snap_grid[2] 2804 rect = allMinMaxRect 2805 else: 2806 snapGrid = self.__active_snap_grid[1] 2807 rect = myMinMaxRect 2808 self.UpdateClipCursor(rect, mRect) 2809 if not shift: 2810 for wnd in self.sortedScaleWindows[-1]: 2811 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2812 wnd.left = wpdl 2813 wnd.top = wpdt 2814 wnd.width = wpdw 2815 wnd.height = wpdh 2816 2817 scaleH, scaleV, scaleAbove, followL, followR, followT, followB = ([], 2818 [], 2819 [], 2820 [], 2821 [], 2822 [], 2823 []) 2824 else: 2825 scaleH, scaleV, scaleAbove, followL, followR, followT, followB, all = self.sortedScaleWindows 2826 for side in self.__scale_sides: 2827 if side in ('left', 'right') and self.GetMinWidth() != self.GetMaxWidth(): 2828 for wnd in scaleH + [self]: 2829 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2830 if side == 'left': 2831 wnd.left = wpdl + diffx 2832 if wnd.IsResizeable(): 2833 wnd.width = wnd._fixedWidth or wpdw - diffx 2834 elif side == 'right': 2835 if wnd.IsResizeable(): 2836 wnd.width = wnd._fixedWidth or wpdw + diffx 2837 2838 for wnd in [followR, followL][side == 'left']: 2839 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2840 wnd.left = wpdl + diffx 2841 2842 if side in ('top', 'bottom') and self.GetMinHeight() != self.GetMaxHeight(): 2843 for wnd in scaleV + [self]: 2844 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2845 if side == 'top': 2846 if wnd.IsResizeable(): 2847 wnd.height = wnd._fixedHeight or wpdh - diffy 2848 wnd.top = wpdt + diffy 2849 elif side == 'bottom': 2850 if wnd.IsResizeable(): 2851 wnd.height = wnd._fixedHeight or wpdh + diffy 2852 2853 for wnd in [followB, followT][side == 'top']: 2854 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2855 wnd.top = wpdt + diffy 2856 2857 for wnd in scaleAbove: 2858 wpdl, wpdt, wpdw, wpdh = wnd.preDragAbs 2859 if wnd.IsResizeable(): 2860 wnd.height = wnd._fixedHeight or wpdh + diffy 2861 2862 self.ShowSnapEdges_Scaling(snapGrid) 2863 self.OnScale_(self) 2864 self._OnResize() 2865 blue.pyos.synchro.SleepWallclock(1) 2866 2867 self.ValidateWindows() 2868 2869 def EndScale(self, sender, *args): 2870 self.CleanupParent('snapIndicator') 2871 if not self.IsResizeable() or self.InStack(): 2872 return 2873 self._scaling = False 2874 uicore.uilib.UnclipCursor() 2875 if self.closing: 2876 return 2877 if self.__active_snap_grid: 2878 snapGrid = self.__active_snap_grid[1] 2879 self.ShowSnapEdges_Scaling(snapGrid, showSnap=False, doSnap=True) 2880 self.RegisterPositionAndSize() 2881 self._emit_on_end_scale() 2882 self.OnEndScale_(self) 2883 2884 def GetGroupAbsolute(self, group): 2885 return self.GetGroupRect(group, 1) 2886 2887 def OnResize_(self, *args): 2888 self.OnResizeUpdate(self) 2889 2890 def OnResizeUpdate(self, *args): 2891 pass 2892 2893 def OnScale_(self, wnd, *args): 2894 pass 2895 2896 def OnStartScale_(self, wnd, *args): 2897 pass 2898 2899 def OnEndScale_(self, wnd, *args): 2900 pass 2901 2902 def OnMouseDown_(self, what): 2903 pass 2904 2905 def OnStartMinimize_(self, *args): 2906 pass 2907 2908 def OnEndMinimize_(self, *args): 2909 pass 2910 2911 def OnStartMaximize_(self, *args): 2912 pass 2913 2914 def OnEndMaximize_(self, *args): 2915 pass 2916 2917 def OnSetActive_(self, *args): 2918 pass 2919 2920 def OnCollapsed(self, wnd, *args): 2921 pass 2922 2923 def OnExpanded(self, wnd, *args): 2924 pass 2925 2926 def OnDragTick(self, *args): 2927 pass 2928 2929 def GetIntersectingWindows(self): 2930 all = uicore.registry.GetWindows() 2931 ml, mt, mw, mh = self.GetAbsolute() 2932 intersecting = [] 2933 for otherWindow in all: 2934 if otherWindow is self: 2935 continue 2936 if otherWindow.stacked: 2937 continue 2938 if otherWindow.IsHidden(): 2939 continue 2940 ol, ot, ow, oh = otherWindow.GetAbsolute() 2941 if not (ml <= ol < ml + mw or ml < ol + ow <= ml + mw or ml >= ol and ol + ow > ml + mw): 2942 continue 2943 if not (mt <= ot < mt + mh or mt < ot + oh <= mt + mh or mt >= ot and ot + oh > mt + mh): 2944 continue 2945 intersecting.append(otherWindow) 2946 2947 return intersecting 2948 2949 @classmethod 2950 def GetTopRight_TopOffset(cls): 2951 leftpush, rightpush = cls.GetSideOffset() 2952 cornerWnd = None 2953 for each in uicore.layer.main.children: 2954 if not isinstance(each, Window) or each.state == uiconst.UI_HIDDEN: 2955 continue 2956 if each.left + each.width in (uicore.desktop.width - rightpush, uicore.desktop.width - rightpush - 16): 2957 if each.top in (0, 16): 2958 cornerWnd = each 2959 break 2960 2961 if cornerWnd: 2962 bottomAlignedWindows = cornerWnd.FindConnectingWindows('bottom') 2963 if bottomAlignedWindows: 2964 groupRect = cls.GetGroupRect(bottomAlignedWindows) 2965 return groupRect[3] 2966 2967 @classmethod 2968 def GetBottomLeft_TopOffset(cls): 2969 leftpush, rightpush = cls.GetSideOffset() 2970 cornerWnd = None 2971 for each in uicore.layer.main.children: 2972 if not isinstance(each, Window) or each.state == uiconst.UI_HIDDEN: 2973 continue 2974 if each.left in (leftpush, leftpush + 16): 2975 if each.top + each.height in (uicore.desktop.height, uicore.desktop.height - 16): 2976 cornerWnd = each 2977 break 2978 2979 if cornerWnd: 2980 topAlignedWindows = cornerWnd.FindConnectingWindows('top') 2981 if topAlignedWindows: 2982 groupRect = cls.GetGroupRect(topAlignedWindows) 2983 return groupRect[1] 2984 2985 @classmethod 2986 def _GetDefaultCaption(cls): 2987 if cls.default_caption: 2988 if localization.IsValidLabel(cls.default_caption): 2989 return localization.GetByLabel(cls.default_caption) 2990 else: 2991 return cls.default_caption 2992 if cls.default_captionLabelPath: 2993 return localization.GetByLabel(cls.default_captionLabelPath) 2994 return cls.__name__ 2995 2996 @classmethod 2997 def GetIfOpen(cls, windowID = None, windowInstanceID = None): 2998 windowID = windowID if windowID else cls.default_windowID 2999 wnd = uicore.registry.GetWindow(windowID, windowInstanceID) 3000 return wnd 3001 3002 @classmethod 3003 def CloseIfOpen(cls, windowID = None, windowInstanceID = None): 3004 wnd = cls.GetIfOpen(windowID, windowInstanceID) 3005 if wnd: 3006 wnd.Close() 3007 3008 @classmethod 3009 def Open(cls, *args, **kwds): 3010 windowID = kwds.get('windowID', None) or cls.default_windowID 3011 windowInstanceID = kwds.get('windowInstanceID', None) 3012 if is_blocked('open', windowID): 3013 raise UserError('WindowBlockedFromOpening', {'window_name': cls._GetDefaultCaption()}) 3014 wnd = cls.GetIfOpen(windowID=windowID, windowInstanceID=windowInstanceID) 3015 if wnd: 3016 wnd.Maximize() 3017 return wnd 3018 newWindow = cls(**kwds) 3019 return newWindow 3020 3021 @classmethod 3022 def OpenBehindFullscreenViews(cls, **kwds): 3023 isSecondaryViewActive = sm.GetService('viewState').IsCurrentViewSecondary() 3024 windowID = kwds.get('windowID', cls.default_windowID) 3025 isOverlayed = GetRegisteredState(windowID, 'isOverlayed') 3026 if isSecondaryViewActive and not isOverlayed: 3027 wnd = cls.Open(openMinimized=True, idx=(-1), **kwds) 3028 sm.GetService('window').RegisterAsMinimizedByFullscreenView(wnd) 3029 else: 3030 cls.Open(**kwds) 3031 3032 @classmethod 3033 def ToggleOpenClose(cls, *args, **kwds): 3034 wnd = cls.GetIfOpen(windowID=kwds.get('windowID', None), windowInstanceID=kwds.get('windowInstanceID', None)) 3035 if wnd: 3036 wasCollapsed = wnd.IsCollapsed() 3037 if wasCollapsed: 3038 wnd.Expand() 3039 if wnd.stacked: 3040 if wnd.stack.GetActiveWindow() != wnd: 3041 wnd.Maximize() 3042 return wnd 3043 obscured = wnd.stack.ObscuredByOtherWindows() 3044 else: 3045 obscured = wnd.ObscuredByOtherWindows() 3046 if wnd.IsMinimized(): 3047 wnd.Maximize() 3048 uicore.registry.SetFocus(wnd) 3049 return wnd 3050 if obscured: 3051 uicore.registry.SetFocus(wnd) 3052 return wnd 3053 if not wasCollapsed: 3054 wnd.CloseByUser() 3055 else: 3056 return cls.Open(*args, **kwds) 3057 3058 def ObscuredByOtherWindows(self): 3059 intersecting = self.GetIntersectingWindows() 3060 for wnd in intersecting: 3061 if self not in uicore.layer.main.children: 3062 return False 3063 if wnd not in uicore.layer.main.children: 3064 continue 3065 if uicore.layer.main.children.index(self) > uicore.layer.main.children.index(wnd): 3066 return True 3067 3068 return False 3069 3070 @classmethod 3071 def IsOpen(cls, windowID = None, windowInstanceID = None): 3072 wnd = cls.GetIfOpen(windowID, windowInstanceID) 3073 return bool(wnd) 3074 3075 @classmethod 3076 def IsOpenByWindowClass(cls): 3077 wnd = uicore.registry.GetWindowByClass(cls) 3078 return bool(wnd) 3079 3080 @classmethod 3081 def GetRegisteredOrDefaultStackID(cls, windowID = None): 3082 windowID = windowID or cls.default_windowID 3083 if windowID: 3084 all = settings.char.windows.Get('stacksWindows', {}) 3085 if windowID in all: 3086 return all[windowID] 3087 return all.get(windowID, cls.default_stackID) 3088 3089 def GetRegisteredPositionAndSize(self): 3090 return self.GetRegisteredPositionAndSizeByClass(self.windowID) 3091 3092 @classmethod 3093 def GetRegisteredPositionAndSizeByClass(cls, windowID = None): 3094 windowID = windowID or cls.default_windowID 3095 if type(windowID) == tuple: 3096 windowID, subWindowID = windowID 3097 all = settings.char.windows.Get('windowSizesAndPositions_1', {}) 3098 usingDefault = 1 3099 if windowID and windowID in all: 3100 left, top, width, height, cdw, cdh = all[windowID] 3101 usingDefault = 0 3102 else: 3103 cdw, cdh = uicore.desktop.width, uicore.desktop.height 3104 if usingDefault: 3105 left, top, width, height = cls.GetDefaultSizeAndPosition() 3106 pushleft = cls.GetDefaultLeftOffset(width=width, align=uiconst.CENTER, left=left) 3107 if pushleft < 0: 3108 left = max(0, left + pushleft) 3109 elif pushleft > 0: 3110 left = min(left + pushleft, uicore.desktop.width - width) 3111 dw, dh = uicore.desktop.width, uicore.desktop.height 3112 if cdw != dw: 3113 wDiff = dw - cdw 3114 if left + width in (cdw, cdw - 16): 3115 left += wDiff 3116 elif left not in (0, 16): 3117 oldCenterX = (cdw - width) / 2 3118 xPortion = oldCenterX / float(cdw) 3119 newCenterX = int(xPortion * dw) 3120 cxDiff = newCenterX - oldCenterX 3121 left += cxDiff 3122 if cdh != dh: 3123 hDiff = dh - cdh 3124 if top in (0, 16): 3125 pass 3126 elif top + height in (cdh, cdh - 16): 3127 top += hDiff 3128 else: 3129 oldCenterY = (cdh - height) / 2 3130 yPortion = oldCenterY / float(cdh) 3131 newCenterY = int(yPortion * dh) 3132 cyDiff = newCenterY - oldCenterY 3133 top += cyDiff 3134 return (left, 3135 top, 3136 width, 3137 height, 3138 dw, 3139 dh) 3140 3141 @classmethod 3142 def GetGroupRect(cls, group, getAbsolute = 0): 3143 if not len(group): 3144 return (0, 0, 0, 0) 3145 l, t, w, h = group[0].GetAbsolute() 3146 r = l + w 3147 b = t + h 3148 for wnd in group[1:]: 3149 wl, wt, ww, wh = wnd.GetAbsolute() 3150 l = min(l, wl) 3151 t = min(t, wt) 3152 r = max(r, wl + ww) 3153 b = max(b, wt + wh) 3154 3155 if getAbsolute: 3156 return (l, 3157 t, 3158 r - l, 3159 b - t) 3160 return (l, 3161 t, 3162 r, 3163 b) 3164 3165 @classmethod 3166 def GetDefaultSizeAndPosition(cls): 3167 dw = uicore.desktop.width 3168 dh = uicore.desktop.height 3169 if cls.default_fixedWidth: 3170 width = cls.default_fixedWidth 3171 elif callable(cls.default_width): 3172 width = cls.default_width() 3173 else: 3174 width = cls.default_width 3175 if cls.default_fixedHeight: 3176 height = cls.default_fixedHeight 3177 elif callable(cls.default_height): 3178 height = cls.default_height() 3179 else: 3180 height = cls.default_height 3181 if cls.default_left == '__center__': 3182 left = (dw - width) / 2 3183 elif cls.default_left == '__right__': 3184 left = dw - width 3185 elif callable(cls.default_left): 3186 left = cls.default_left() 3187 else: 3188 left = cls.default_left 3189 if cls.default_top == '__center__': 3190 top = (dh - height) / 2 3191 elif cls.default_top == '__bottom__': 3192 top = dh - height 3193 elif callable(cls.default_top): 3194 top = cls.default_top() 3195 else: 3196 top = cls.default_top 3197 return (left, 3198 top, 3199 width, 3200 height) 3201 3202 @classmethod 3203 def GetDefaultLeftOffset(cls, width, align = None, left = 0): 3204 return sm.GetService('window').GetCameraLeftOffset(width, align, left) 3205 3206 def RegisterSceneContainer(self, sceneCont): 3207 self.__scene_containers.add(sceneCont) 3208 3209 def UnregisterSceneContainer(self, sceneCont): 3210 if sceneCont in self.__scene_containers: 3211 self.__scene_containers.remove(sceneCont) 3212 3213 def Flush(self): 3214 mainArea = self.GetMainArea() 3215 if mainArea is not None: 3216 mainArea.Flush() 3217 3218 @EatsExceptions('protoClientLogs') 3219 def _LogWindowEventOpened(self): 3220 if not self.analyticID: 3221 return 3222 message_bus = WindowMessenger(sm.GetService('publicGatewaySvc')) 3223 message_bus.window_opened(self.analyticID) 3224 3225 @EatsExceptions('protoClientLogs') 3226 def _LogWindowClosed(self): 3227 if not self.__opened_at_timestamp or not self.analyticID: 3228 return 3229 seconds, nanos = self.SplitBlueTimeIntoDecimalsAndFractions(self.__opened_at_timestamp) 3230 message_bus = WindowMessenger(sm.GetService('publicGatewaySvc')) 3231 message_bus.window_closed(self.analyticID, seconds, nanos) 3232 3233 @EatsExceptions('protoClientLogs') 3234 def _LogWindowEventFocused(self): 3235 if not self.analyticID: 3236 return 3237 message_bus = WindowMessenger(sm.GetService('publicGatewaySvc')) 3238 message_bus.window_focused(self.analyticID) 3239 3240 @EatsExceptions('protoClientLogs') 3241 def _LogWindowUnfocused(self): 3242 if not self.__focused_at_timestamp or not self.analyticID: 3243 return 3244 seconds, nanos = self.SplitBlueTimeIntoDecimalsAndFractions(self.__focused_at_timestamp) 3245 message_bus = WindowMessenger(sm.GetService('publicGatewaySvc')) 3246 message_bus.window_unfocused(self.analyticID, seconds, nanos) 3247 3248 @staticmethod 3249 def SplitBlueTimeIntoDecimalsAndFractions(timestamp): 3250 if timestamp is None: 3251 return 3252 full_duration = gametime.GetSecondsSinceWallclockTime(timestamp) 3253 fractions, integer = math.modf(full_duration) 3254 return (int(integer), int(fractions * 1000000000.0)) 3255 3256 def GetWindowSizeForContentSize(self, width = 0, height = 0): 3257 left, top, right, bottom = self.GetContentToWindowEdgePadding() 3258 if self.extend_content_into_header: 3259 height = max(height, self.header_height) 3260 return (width + left + right, height + top + bottom) 3261 3262 def GetTotalContentPadding(self): 3263 pad_top = self.content.padTop 3264 if not self.extend_content_into_header: 3265 pad_top += self.header_height 3266 return (self.content.padLeft, 3267 pad_top, 3268 self.content.padRight, 3269 self.content.padBottom) 3270 3271 def GetContentToWindowEdgePadding(self): 3272 left, top, right, bottom = self.GetTotalContentPadding() 3273 margin_left, margin_top, margin_right, margin_bottom = self.GetWindowBorderPadding() 3274 border_left, border_top, border_right, border_bottom = self.GetWindowBorderSize() 3275 return (left + border_left + margin_left, 3276 top + border_top + margin_top, 3277 right + border_right + margin_right, 3278 bottom + border_bottom + margin_bottom) 3279 3280 def GetWindowBorderSize(self): 3281 return (1, 1, 1, 1) 3282 3283 def GetWindowBorderPadding(self): 3284 return (1, 1, 1, 1) 3285 3286 def _SetHeader(self, header): 3287 if self.closing: 3288 raise RuntimeError("Attempting to assign a header to a window that's in the process of closing, or already closed") 3289 if self.__header is not None: 3290 self.__header.SetParent(None) 3291 self.__header.unmount(self) 3292 self.__header = header 3293 self.__header.align = uiconst.TOTOP 3294 self.__header.SetParent(self.sr.headerParent) 3295 self.__header.mount(self) 3296 self._UpdateContentPadding() 3297 3298 def _OnCaptionChanged(self): 3299 if self.sr.tab and hasattr(self.sr.tab, 'SetLabel'): 3300 self.sr.tab.SetLabel(self.caption) 3301 3302 def _UpdateContentPadding(self): 3303 if self.closing: 3304 return 3305 if self.stacked: 3306 header = self.stack.header 3307 else: 3308 header = self.header 3309 if header: 3310 self.__header_has_sufficient_bottom_padding = header.HAS_SUFFICIENT_BOTTOM_PADDING 3311 self._UpdateHeaderInset() 3312 old_padding = self.__previous_content_padding 3313 new_padding = self.content_padding 3314 self.__previous_content_padding = new_padding 3315 if self.__apply_content_padding: 3316 self.content.padding = new_padding 3317 else: 3318 self.content.padding = 0 3319 if old_padding is not None and old_padding != new_padding: 3320 self._emit_on_content_padding_changed() 3321 3322 def _UpdateHeaderInset(self, silent = False): 3323 if not self.closing: 3324 header_inset = self._ComputeHeaderInset() 3325 if self.__header_inset != header_inset: 3326 self.__header_inset = header_inset 3327 if not silent: 3328 self._emit_on_header_inset_changed() 3329 3330 def _ComputeHeaderInset(self): 3331 inset_left, _, inset_right, _ = self.content_padding 3332 if self.__window_controls is not None and self.__window_controls.display: 3333 inset_right = max(inset_right, self.__window_controls.reserved_width) 3334 return (inset_left, inset_right) 3335 3336 def __on_global_window_margin_mode_changed(self, margin_mode): 3337 if not self.closing: 3338 self._UpdateContentPadding() 3339 if self.__on_margin_mode_changed is not None: 3340 self.__on_margin_mode_changed(self) 3341 3342 def __on_header_parent_size_changed(self): 3343 if not self.closing: 3344 height = self.sr.headerParent.height 3345 if self.__previous_header_height != height: 3346 self.__previous_header_height = height 3347 self.__window_controls_cont.height = height 3348 self._emit_on_header_height_changed() 3349 3350 @property 3351 def iconNum(self): 3352 return self.icon 3353 3354 @iconNum.setter 3355 def iconNum(self, value): 3356 self.icon = value 3357 3358 def GetMainArea(self): 3359 return self.content 3360 3361 def IsCollapsed(self): 3362 return self.collapsed 3363 3364 def IsCompact(self): 3365 return self.compact 3366 3367 def IsCompactable(self): 3368 return self.compactable 3369 3370 def Compact(self): 3371 self.compact = True 3372 3373 def UnCompact(self): 3374 self.compact = False 3375 3376 def GetCaption(self, update = 1): 3377 return self.caption or '' 3378 3379 def SetCaption(self, caption, *args, **kwds): 3380 if localization.IsValidLabel(caption): 3381 caption = localization.GetByLabel(caption) 3382 self.caption = caption 3383 3384 def InStack(self): 3385 return self.stacked 3386 3387 def IsKillable(self): 3388 return self.killable 3389 3390 def MakeKillable(self): 3391 self.killable = True 3392 3393 def MakeUnKillable(self): 3394 self.killable = False 3395 3396 def IsLocked(self): 3397 return self.locked 3398 3399 def IsLockable(self): 3400 return self.lockable 3401 3402 def Lock(self): 3403 self.locked = True 3404 3405 def Unlock(self): 3406 self.locked = False 3407 3408 def HideHeaderButtons(self): 3409 self.show_window_controls = False 3410 3411 def GetStack(self): 3412 return self.stack 3413 3414 def IsMinimizable(self): 3415 if is_blocked('minimize', self.windowID): 3416 return False 3417 return self.minimizable 3418 3419 def MakeUnMinimizable(self): 3420 self.minimizable = False 3421 3422 def MakeCollapseable(self): 3423 self.collapsible = True 3424 3425 def MakeUncollapseable(self): 3426 self.collapsible = False 3427 3428 def IsOverlayable(self): 3429 return self.overlayable