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

scrollContainer.py (21747B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\scrollContainer.py
      2 import logging
      3 import mathext
      4 import signals
      5 import uthread2
      6 from carbonui import TextAlign, uiconst, Align
      7 from carbonui.control.baseScrollContEntry import LazyLoadVerticalMixin
      8 from carbonui.control.scrollbar import Scrollbar
      9 from carbonui.decorative.panelUnderlay import PanelUnderlay
     10 from carbonui.primitives.container import Container
     11 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     12 from carbonui.uianimations import animations
     13 from carbonui.uiconst import Axis
     14 from carbonui.uicore import uicore
     15 from eve.client.script.ui.control.eveLabel import EveCaptionLarge
     16 logger = logging.getLogger(__name__)
     17 
     18 class ScrollContainer(Container):
     19     __guid__ = 'uicls.ScrollContainer'
     20     default_name = 'scrollContainer'
     21     default_pushContent = True
     22     default_state = uiconst.UI_NORMAL
     23     default_showUnderlay = False
     24     default_scrollBarColor = None
     25     default_alignMode = None
     26     default_scrollBarPadding = 0
     27     default_innerPadding = None
     28     default_centerContent = False
     29     default_scrollBarDisabled = False
     30     dragHoverScrollAreaSize = 30
     31     dragHoverScrollSpeed = 60.0
     32     isTabStop = True
     33     _scrollbar_vertical = None
     34     _scrollbar_horizontal = None
     35 
     36     def ApplyAttributes(self, attributes):
     37         super(ScrollContainer, self).ApplyAttributes(attributes)
     38         pushContent = attributes.get('pushContent', self.default_pushContent)
     39         showUnderlay = attributes.Get('showUnderlay', self.default_showUnderlay)
     40         self.fixedColor = attributes.get('scrollBarColor', self.default_scrollBarColor)
     41         alignMode = attributes.get('alignMode', self.default_alignMode)
     42         self.scrollBarPadding = attributes.get('scrollBarPadding', self.default_scrollBarPadding)
     43         self._innerPadding = attributes.get('innerPadding', self.default_innerPadding)
     44         self._centerContent = attributes.get('centerContent', self.default_centerContent)
     45         self.scrollbarsDisabled = self.default_scrollBarDisabled
     46         self.scrollToVerticalPending = None
     47         self.scrollToHorizontalPending = None
     48         self.noResultsContainer = None
     49         self.noResultsLabel = None
     50         self.onDownButtonSignal = signals.Signal(__name__ + '_onDownButtonSignal')
     51         self.onUpButtonSignal = signals.Signal(__name__ + '_onUpButtonSignal')
     52         self.onDropDataSignal = signals.Signal(__name__ + '_onDropDataSignal')
     53         self.onDragEnterSignal = signals.Signal(__name__ + '_onDragEnterSignal')
     54         self.onDragExitSignal = signals.Signal(__name__ + '_onDragExitSignal')
     55         self.onSizeChangeSignal = signals.Signal(__name__ + '_onSizeChangeSignal')
     56         self._ConstructVerticalScrollBar(pushContent)
     57         self._ConstructHorizontalScrollBar(pushContent)
     58         self.clipCont = Container(name='clipCont', parent=self, clipChildren=True)
     59         self.mainCont = ContainerAutoSize(name='mainCont', parent=self.clipCont, state=uiconst.UI_NORMAL, alignMode=alignMode, align=alignMode or ContainerAutoSize.default_align, padding=self._innerPadding)
     60         self.mainCont._OnSizeChange_NoBlock = self._OnMainContSizeChange
     61         self.mainCont.OnDropData = self.OnDropData
     62         self.children.insert = self._InsertChild
     63         self.children.append = self._AppendChild
     64         self.children.remove = self._RemoveChild
     65         self._mouseHoverCookie = uicore.uilib.RegisterForTriuiEvents(uiconst.UI_MOUSEHOVER, self.OnGlobalMouseHover)
     66         self.CheckConstructUnderlay(showUnderlay)
     67 
     68     def _update_children_alignment(self, sizeChange, forceUpdate):
     69         super(ScrollContainer, self)._update_children_alignment(sizeChange, forceUpdate)
     70         self._check_lazy_load_entries()
     71 
     72     @property
     73     def innerPadding(self):
     74         return self._innerPadding
     75 
     76     @innerPadding.setter
     77     def innerPadding(self, value):
     78         if self._innerPadding != value:
     79             self._innerPadding = value
     80             self.mainCont.padding = self._innerPadding if self._innerPadding is not None else 0
     81 
     82     def _ConstructHorizontalScrollBar(self, pushContent):
     83         self._scrollbar_horizontal = Scrollbar(parent=self, align=uiconst.TOBOTTOM, axis=Axis.HORIZONTAL, padTop=8 if pushContent else 0, on_scroll_fraction_changed=self._on_scrollbar_scroll_fraction_changed)
     84 
     85     def _ConstructVerticalScrollBar(self, pushContent):
     86         self._scrollbar_vertical = Scrollbar(parent=self, align=uiconst.TORIGHT, axis=Axis.VERTICAL, padLeft=8 if pushContent else 0, on_scroll_fraction_changed=self._on_scrollbar_scroll_fraction_changed)
     87 
     88     def _on_scrollbar_scroll_fraction_changed(self, scrollbar):
     89         if scrollbar.axis == Axis.VERTICAL:
     90             self._OnVerticalScrollBar(scrollbar.scroll_fraction)
     91         elif scrollbar.axis == Axis.HORIZONTAL:
     92             self._OnHorizontalScrollBar(scrollbar.scroll_fraction)
     93 
     94     def CheckConstructUnderlay(self, showUnderlay):
     95         if showUnderlay:
     96             self.underlay = PanelUnderlay(bgParent=self)
     97         else:
     98             self.underlay = None
     99 
    100     def Close(self, *args):
    101         try:
    102             uicore.uilib.UnregisterForTriuiEvents(self._mouseHoverCookie)
    103         except Exception as e:
    104             logger.exception(e)
    105         finally:
    106             Container.Close(self, *args)
    107 
    108         try:
    109             del self.mainCont._OnSizeChange_NoBlock
    110         except AttributeError:
    111             pass
    112 
    113     def _InsertChild(self, idx, obj):
    114         self.mainCont.children.insert(idx, obj)
    115         if not self.mainCont.alignMode:
    116             self.mainCont.align = obj.align
    117 
    118     def _AppendChild(self, obj):
    119         self.mainCont.children.append(obj)
    120         if not self.mainCont.alignMode:
    121             self.mainCont.align = obj.align
    122 
    123     def _RemoveChild(self, obj):
    124         self.mainCont.children.remove(obj)
    125 
    126     def OnGlobalMouseHover(self, obj, *args):
    127         if uicore.IsDragging() and (obj == self or obj.IsUnder(self.mainCont)):
    128             l, t, w, h = self.GetAbsolute()
    129             if self.IsVerticalScrollBarVisible() and h > 0:
    130                 fraction = self.dragHoverScrollSpeed / float(h)
    131                 y = uicore.uilib.y - t
    132                 if y <= self.dragHoverScrollAreaSize:
    133                     self.ScrollMoveVertical(-fraction)
    134                 elif y > h - self.dragHoverScrollAreaSize:
    135                     self.ScrollMoveVertical(fraction)
    136             if self.IsHorizontalScrollBarVisible() and w > 0:
    137                 fraction = self.dragHoverScrollSpeed / float(w)
    138                 x = uicore.uilib.x - l
    139                 if x <= self.dragHoverScrollAreaSize:
    140                     self.ScrollMoveHorizontal(-fraction)
    141                 elif x > w - self.dragHoverScrollAreaSize:
    142                     self.ScrollMoveHorizontal(fraction)
    143         return True
    144 
    145     def _OnSizeChange_NoBlock(self, width, height):
    146         main_cont_width, main_cont_height = self.mainCont.GetCurrentAbsoluteSize()
    147         self._retain_scroll_position_on_resize(main_cont_width, main_cont_height)
    148         self._UpdateHandleSizesAndPosition(width, height, updatePos=False)
    149 
    150     def _OnMainContSizeChange(self, width, height):
    151         self._retain_scroll_position_on_resize(width, height)
    152         self._UpdateScrollbars()
    153         self.onSizeChangeSignal(width, height)
    154 
    155     def _check_lazy_load_entries(self):
    156         any_lazy_loaded = False
    157         for entry in self.mainCont.children:
    158             if isinstance(entry, LazyLoadVerticalMixin):
    159                 if entry.check_lazy_load(self.clipCont):
    160                     any_lazy_loaded = True
    161                 elif any_lazy_loaded:
    162                     return
    163 
    164     def _retain_scroll_position_on_resize(self, width, height):
    165         clip_width, clip_height = self.clipCont.GetAbsoluteSize()
    166         scrollable_size_vertical = height - clip_height
    167         if scrollable_size_vertical <= 0.0:
    168             scroll_fraction = 0.0
    169         else:
    170             offset = 0
    171             if self.mainCont.align in (uiconst.CENTER, uiconst.CENTERLEFT, uiconst.CENTERRIGHT):
    172                 offset = scrollable_size_vertical / 2.0
    173             scroll_fraction = mathext.clamp(value=float(-(self.mainCont.top - offset)) / scrollable_size_vertical, low=0.0, high=1.0)
    174         if mathext.is_close(scroll_fraction, self._scrollbar_vertical.scroll_fraction):
    175             self._OnVerticalScrollBar(scroll_fraction)
    176         else:
    177             self._scrollbar_vertical.scroll_fraction = scroll_fraction
    178         scrollable_size_horizontal = width - clip_width
    179         if scrollable_size_horizontal <= 0.0:
    180             scroll_fraction = 0.0
    181         else:
    182             offset = 0
    183             if self.mainCont.align in (uiconst.CENTER, uiconst.CENTERTOP, uiconst.CENTERBOTTOM):
    184                 offset = scrollable_size_horizontal / 2.0
    185             scroll_fraction = mathext.clamp(value=float(-(self.mainCont.left - offset)) / scrollable_size_horizontal, low=0.0, high=1.0)
    186         if mathext.is_close(scroll_fraction, self._scrollbar_horizontal.scroll_fraction):
    187             self._OnHorizontalScrollBar(scroll_fraction)
    188         else:
    189             self._scrollbar_horizontal.scroll_fraction = scroll_fraction
    190 
    191     def OnDropData(self, dragSource, dragData):
    192         self.onDropDataSignal(dragSource, dragData)
    193 
    194     def OnDragEnter(self, dragSource, dragData):
    195         self.onDragEnterSignal(dragSource, dragData)
    196 
    197     def OnDragExit(self, dragSource, dragData):
    198         self.onDragExitSignal(dragSource, dragData)
    199 
    200     def Flush(self):
    201         self.mainCont.Flush()
    202         self.HideNoContentHint()
    203 
    204     def DisableScrollbars(self):
    205         self.scrollbarsDisabled = True
    206         self._UpdateScrollbars()
    207 
    208     def EnableScrollbars(self):
    209         self.scrollbarsDisabled = False
    210         self._UpdateScrollbars()
    211 
    212     def _UpdateScrollbars(self):
    213         w, h = self.GetAbsoluteSize()
    214         self._UpdateHandleSizesAndPosition(w, h)
    215 
    216     def _GetMainContWidth(self):
    217         width, _ = self.mainCont.GetCurrentAbsoluteSize()
    218         return width + self.mainCont.padLeft + self.mainCont.padRight
    219 
    220     def _GetMainContHeight(self):
    221         _, height = self.mainCont.GetCurrentAbsoluteSize()
    222         return height + self.mainCont.padTop + self.mainCont.padBottom
    223 
    224     def _UpdateHandleSizesAndPosition(self, width, height, updatePos = True):
    225         mainWidth = self._GetMainContWidth()
    226         mainHeight = self._GetMainContHeight()
    227         if mainHeight > 0 and not self.scrollbarsDisabled:
    228             size = float(height) / mainHeight
    229         else:
    230             size = 1.0
    231         size = mathext.clamp(size, 0.0, 1.0)
    232         self._scrollbar_vertical.handle_size_fraction = size
    233         self._scrollbar_vertical.display = not mathext.is_close(size, 1.0)
    234         if mainWidth != 0 and not self.scrollbarsDisabled:
    235             size = float(width) / mainWidth
    236         else:
    237             size = 1.0
    238         size = mathext.clamp(size, 0.0, 1.0)
    239         self._scrollbar_horizontal.handle_size_fraction = size
    240         self._scrollbar_horizontal.display = not mathext.is_close(size, 1.0)
    241         if self.IsHorizontalScrollBarVisible() and self.IsVerticalScrollBarVisible():
    242             self._scrollbar_vertical.padBottom = self._scrollbar_horizontal.height
    243         else:
    244             self._scrollbar_vertical.padBottom = 0
    245 
    246     def _OnVerticalScrollBar(self, posFraction):
    247         w, h = self.clipCont.GetAbsoluteSize()
    248         posFraction = max(0.0, min(posFraction, 1.0))
    249         mainHeight = self._GetMainContHeight()
    250         offset = 0
    251         if self.mainCont.align in (uiconst.CENTER, uiconst.CENTERLEFT, uiconst.CENTERRIGHT):
    252             offset = (mainHeight - h) / 2.0
    253         if mainHeight <= h:
    254             if self._centerContent:
    255                 self.mainCont.top = int(round((h - mainHeight) / 2.0)) + offset
    256             else:
    257                 self.mainCont.top = 0
    258         else:
    259             self.mainCont.top = -posFraction * (mainHeight - h) + offset
    260         self._check_update_sticky_children()
    261         self.OnScrolledVertical(posFraction)
    262 
    263     def _check_update_sticky_children(self):
    264         for c in self.mainCont.children:
    265             if c.align == Align.TOTOP_STICKY:
    266                 c.FlagAlignmentDirty()
    267 
    268         uthread2.start_tasklet(self._check_lazy_load_entries)
    269 
    270     def _OnHorizontalScrollBar(self, posFraction):
    271         w, h = self.clipCont.GetAbsoluteSize()
    272         posFraction = max(0.0, min(posFraction, 1.0))
    273         mainWidth = self._GetMainContWidth()
    274         offset = 0
    275         if self.mainCont.align in (uiconst.CENTER, uiconst.CENTERTOP, uiconst.CENTERBOTTOM):
    276             offset = (mainWidth - w) / 2.0
    277         if mainWidth <= w:
    278             if self._centerContent:
    279                 self.mainCont.left = int(round((w - mainWidth) / 2.0)) + offset
    280             else:
    281                 self.mainCont.left = 0
    282         else:
    283             self.mainCont.left = -posFraction * (mainWidth - w) + offset
    284         uthread2.start_tasklet(self._check_lazy_load_entries)
    285         self.OnScrolledHorizontal(posFraction)
    286 
    287     def OnScrolledHorizontal(self, posFraction):
    288         pass
    289 
    290     def OnScrolledVertical(self, posFraction):
    291         pass
    292 
    293     def ScrollToVertical(self, posFraction):
    294         if posFraction is None:
    295             return
    296         if self._alignmentDirty:
    297             self.scrollToVerticalPending = posFraction
    298         elif self.IsVerticalScrollBarVisible():
    299             self._scrollbar_vertical.scroll_to_fraction(posFraction)
    300 
    301     def ScrollToHorizontal(self, posFraction):
    302         if posFraction is None:
    303             return
    304         if self._alignmentDirty:
    305             self.scrollToHorizontalPending = posFraction
    306         elif self.IsHorizontalScrollBarVisible():
    307             self._scrollbar_horizontal.scroll_to_fraction(posFraction)
    308 
    309     def GetPositionVertical(self):
    310         return self._scrollbar_vertical.scroll_fraction
    311 
    312     def GetPositionHorizontal(self):
    313         return self._scrollbar_horizontal.scroll_fraction
    314 
    315     def UpdateAlignment(self, *args, **kwds):
    316         ret = Container.UpdateAlignment(self, *args, **kwds)
    317         if self.scrollToVerticalPending:
    318             self._scrollbar_vertical.scroll_fraction = self.scrollToVerticalPending
    319         self.scrollToVerticalPending = None
    320         if self.scrollToHorizontalPending:
    321             self._scrollbar_horizontal.scroll_fraction = self.scrollToHorizontalPending
    322         self.scrollToHorizontalPending = None
    323         return ret
    324 
    325     def ScrollMoveVertical(self, moveFraction):
    326         self._scrollbar_vertical.scroll_to_fraction(mathext.clamp(self._scrollbar_vertical.scroll_fraction + moveFraction, 0.0, 1.0))
    327 
    328     def ScrollMoveHorizontal(self, moveFraction):
    329         self._scrollbar_horizontal.scroll_to_fraction(mathext.clamp(self._scrollbar_horizontal.scroll_fraction + moveFraction, 0.0, 1.0))
    330 
    331     def OnMouseWheel(self, dz, *args):
    332         scroll_pixels = -dz * 0.42
    333         wasScrolled = self._scroll_by_pixels(scroll_pixels)
    334         return wasScrolled
    335 
    336     def _scroll_by_pixels(self, scroll_pixels):
    337         if len(self.mainCont.children) == 0:
    338             return False
    339         if self.IsVerticalScrollBarVisible():
    340             scrollable_height = self._get_scrollable_height()
    341             scroll_proportion = scroll_pixels / float(scrollable_height)
    342             self.ScrollMoveVertical(mathext.clamp(scroll_proportion, -1.0, 1.0))
    343             return True
    344         if self.IsHorizontalScrollBarVisible():
    345             scrollable_width = self._get_scrollable_width()
    346             scroll_proportion = scroll_pixels / float(scrollable_width)
    347             self.ScrollMoveHorizontal(mathext.clamp(scroll_proportion, -1.0, 1.0))
    348             return True
    349         return False
    350 
    351     def _get_scrollable_height(self):
    352         _, clip_height = self.clipCont.GetAbsoluteSize()
    353         return max(0, self._GetMainContHeight() - clip_height)
    354 
    355     def _get_scrollable_width(self):
    356         clip_width, _ = self.clipCont.GetAbsoluteSize()
    357         return max(0, self._GetMainContWidth() - clip_width)
    358 
    359     def IsHorizontalScrollBarVisible(self):
    360         return self._scrollbar_horizontal and self._scrollbar_horizontal.display
    361 
    362     def IsVerticalScrollBarVisible(self):
    363         return self._scrollbar_vertical and self._scrollbar_vertical.display
    364 
    365     def OnKeyDown(self, key, flag):
    366         if key == uiconst.VK_PRIOR:
    367             self.ScrollByPage(up=True)
    368         elif key == uiconst.VK_NEXT:
    369             self.ScrollByPage(up=False)
    370 
    371     def ScrollByPage(self, up = True):
    372         if not self.IsVerticalScrollBarVisible():
    373             return
    374         _, h = self.clipCont.GetAbsoluteSize()
    375         if up:
    376             h *= -1
    377         self._scroll_by_pixels(h)
    378 
    379     def ShowNoContentHint(self, hint):
    380         if not hint:
    381             if self.noResultsContainer:
    382                 self.noResultsContainer.Hide()
    383             return
    384         isNew = self.noResultsLabel is None or self.noResultsLabel.GetText() != hint
    385         if self.noResultsContainer is None:
    386             self.ConstructNoContentContainer()
    387         self.noResultsLabel.SetText(hint)
    388         self.noResultsContainer.SetState(uiconst.UI_DISABLED)
    389         if isNew:
    390             animations.FadeTo(self.noResultsContainer, 0.0, 1.0, duration=0.3)
    391 
    392     def HideNoContentHint(self):
    393         if self.noResultsContainer:
    394             self.noResultsContainer.Close()
    395             self.noResultsContainer = None
    396             self.noResultsLabel = None
    397 
    398     def ConstructNoContentContainer(self):
    399         self.noResultsContainer = ContainerAutoSize(name='noResultsContainer', parent=self.clipCont, align=uiconst.VERTICALLY_CENTERED)
    400         self.noResultsLabel = EveCaptionLarge(name='noResultsLabel', parent=self.noResultsContainer, align=uiconst.TOTOP, textAlign=TextAlign.CENTER, padding=16, opacity=0.3)
    401 
    402     def OnUp(self):
    403         self.onUpButtonSignal()
    404 
    405     def OnDown(self):
    406         self.onDownButtonSignal()
    407 
    408     def ScrollToRevealChildHorizontal(self, child):
    409         child_left = 0
    410         for c in self.mainCont.children:
    411             child_left += c.padLeft
    412             if c is child:
    413                 break
    414             w, _ = c.GetCurrentAbsoluteSize()
    415             child_left += w + c.padRight
    416 
    417         clip_width, _ = self.clipCont.GetCurrentAbsoluteSize()
    418         overflow_width = self._GetMainContWidth() - clip_width
    419         if overflow_width == 0:
    420             return
    421         child_width, _ = child.GetCurrentAbsoluteSize()
    422         fraction_scroll_left = abs(self.mainCont.left) / float(overflow_width)
    423         fraction_child_left = child_left / float(overflow_width)
    424         fraction_child_bottom = max(0.0, (child_left + child_width - clip_width) / float(overflow_width))
    425         if fraction_child_left <= fraction_scroll_left:
    426             self.ScrollToVertical(fraction_child_left)
    427         elif fraction_child_bottom > fraction_scroll_left:
    428             self.ScrollToVertical(fraction_child_bottom)
    429 
    430     def ScrollToRevealChildVertical(self, child):
    431         _, clip_height, overflow_height = self._GetClipHeights()
    432         if overflow_height == 0:
    433             return
    434         child_top, child_bottom, scroll_top = self._GetChildPositionFractionsInsideScroll(child, clip_height, overflow_height)
    435         if child_top <= scroll_top:
    436             self.ScrollToVertical(child_top)
    437         elif child_bottom > scroll_top:
    438             self.ScrollToVertical(child_bottom)
    439 
    440     def _GetChildPositionFractionsInsideScroll(self, child, clip_height, overflow_height):
    441         child_top, child_bottom = self._GetChildPositionsInsideScroll(child)
    442         fraction_child_top = child_top / float(overflow_height)
    443         fraction_child_bottom = max(0.0, (child_bottom - clip_height) / float(overflow_height))
    444         fraction_scroll_top = abs(self.mainCont.top) / float(overflow_height)
    445         return (fraction_child_top, fraction_child_bottom, fraction_scroll_top)
    446 
    447     def _GetChildPositionsInsideScroll(self, child):
    448         child_top = 0
    449         for c in self.mainCont.children:
    450             child_top += c.padTop
    451             if c is child:
    452                 break
    453             _, h = c.GetCurrentAbsoluteSize()
    454             child_top += h + c.padBottom
    455 
    456         _, child_height = child.GetCurrentAbsoluteSize()
    457         child_bottom = child_top + child_height
    458         return (child_top, child_bottom)
    459 
    460     def _GetClipHeights(self):
    461         main_height = self._GetMainContHeight()
    462         _, clip_height = self.clipCont.GetCurrentAbsoluteSize()
    463         overflow_height = main_height - clip_height
    464         return (main_height, clip_height, overflow_height)
    465 
    466     def IsChildVisible(self, child):
    467         if not child.display:
    468             return False
    469         main_height, clip_height, overflow_height = self._GetClipHeights()
    470         if main_height == 0:
    471             return False
    472         if overflow_height == 0:
    473             return True
    474         child_top, child_bottom = self._GetChildPositionsInsideScroll(child)
    475         scroll_top = abs(self.mainCont.top)
    476         scroll_bottom = scroll_top + clip_height
    477         return child_top < scroll_bottom and child_bottom > scroll_top
    478 
    479     def GetPositionVerticalPixels(self):
    480         return self._scrollbar_vertical.scroll_fraction * self._get_scrollable_height()
    481 
    482     def GetPositionHorizontalPixels(self):
    483         return self._scrollbar_horizontal.scroll_fraction * self._get_scrollable_width()
    484 
    485     def ScrollToVerticalPixels(self, position):
    486         scrollable_height = self._get_scrollable_height()
    487         if scrollable_height > 0:
    488             fraction = mathext.clamp(position / float(scrollable_height), 0.0, 1.0)
    489             self.ScrollToVertical(fraction)
    490 
    491     def ScrollToHorizontalPixels(self, position):
    492         scrollable_width = self._get_scrollable_width()
    493         if scrollable_width > 0:
    494             fraction = mathext.clamp(position / float(scrollable_width), 0.0, 1.0)
    495             self.ScrollToHorizontal(fraction)