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

infoPanelContainer.py (14902B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\infoPanels\infoPanelContainer.py
      2 import logging
      3 import blue
      4 import telemetry
      5 import carbonui.const as uiconst
      6 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
      7 import uthread
      8 import uthread2
      9 from carbonui.primitives.container import Container
     10 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     11 from carbonui.primitives.line import Line
     12 from carbonui.uicore import uicore
     13 from carbonui.util.color import Color
     14 from carbonui.control.buttonIcon import ButtonIcon
     15 from eve.client.script.ui.shared.infoPanels import infoPanelSettingsController
     16 from eve.client.script.ui.shared.infoPanels.const import infoPanelConst, infoPanelClassConst, infoPanelUIConst
     17 from eve.client.script.ui.shared.infoPanels.infoPanelDragData import InfoPanelDragData
     18 from operations.common.util import get_tutorial_category_id
     19 from uihider import get_ui_hider, UiHiderMixin
     20 logger = logging.getLogger(__name__)
     21 
     22 class InfoPanelContainer(UiHiderMixin, ContainerAutoSize):
     23     default_name = 'InfoPanelContainer'
     24     uniqueUiName = pConst.UNIQUE_NAME_INFO_PANEL
     25     ICONSIZE = 16
     26     __notifyevents__ = ['OnOperationsInitialized', 'OnUIScalingChange']
     27     default_performFitsCheck = True
     28 
     29     def ApplyAttributes(self, attributes):
     30         ContainerAutoSize.ApplyAttributes(self, attributes)
     31         self.panelClasses = []
     32         settingsID = attributes.get('settingsID', None)
     33         self.performFitsCheck = attributes.get('performFitsCheck', self.default_performFitsCheck)
     34         self.infoPanelsByTypeID = {}
     35         self.infoPanelButtonsByTypeID = {}
     36         self.isDraggingButton = False
     37         self.ConstructLayout()
     38         self.ReconstructPanels(settingsID, False)
     39         sm.RegisterNotify(self)
     40 
     41     def ConstructLayout(self):
     42         self.topCont = Container(name='topCont', parent=self, align=uiconst.TOTOP, height=self.ICONSIZE, padding=(infoPanelUIConst.LEFTPAD,
     43          0,
     44          0,
     45          5))
     46         self.dropIndicatorLine = Line(name='dropIndicatorLine', parent=self.topCont, align=uiconst.TOLEFT_NOPUSH, state=uiconst.UI_HIDDEN, color=Color.GetGrayRGBA(1.0, 0.6), padding=(0, 2, 0, 2))
     47         self.iconCont = ContainerAutoSize(name='iconCont', parent=self.topCont, state=uiconst.UI_NORMAL, align=uiconst.TOLEFT, uniqueUiName=pConst.UNIQUE_NAME_INFO_PANEL_BTNS)
     48         self.mainCont = ContainerAutoSize(name='mainCont', parent=self, align=uiconst.TOTOP)
     49 
     50     def ReconstructPanels(self, settingsID, animate = True):
     51         self.settingsID = settingsID
     52         if settingsID:
     53             self._ReconstructPanels(animate)
     54 
     55     def _GetCurrentlyAvailableInfoPanelClasses(self):
     56         panelIDs = infoPanelConst.PANELS_BY_SETTINGSID.get(self.settingsID, [])
     57         infoPanelClasses = [ infoPanelClassConst.PANEL_TYPE_ID_TO_CLASS[panelID] for panelID in panelIDs ]
     58         availableInfoPanelClasses = []
     59         for infoPanelClass in infoPanelClasses:
     60             try:
     61                 if infoPanelClass.IsAvailable():
     62                     availableInfoPanelClasses.append(infoPanelClass)
     63             except Exception as exc:
     64                 logger.exception(exc)
     65                 continue
     66 
     67         return availableInfoPanelClasses
     68 
     69     def IsPanelTypeAllowedInView(self, panelTypeID):
     70         return panelTypeID in infoPanelConst.PANELS_BY_SETTINGSID.get(self.settingsID, [])
     71 
     72     def SortPanelClasses(self):
     73         if infoPanelSettingsController.get_all_info_panel_settings(self.settingsID):
     74             self.panelClasses = sorted(self.panelClasses, key=self.GetInfoPanelClassKey)
     75 
     76     def GetInfoPanelClassKey(self, infoPanelClass):
     77         panelSettings = infoPanelSettingsController.get_all_info_panel_settings(self.settingsID)
     78         for index, entry in enumerate(panelSettings):
     79             if entry[0] == infoPanelClass.panelTypeID:
     80                 return index
     81 
     82         if infoPanelClass in self.panelClasses:
     83             return self.panelClasses.index(infoPanelClass)
     84 
     85     def OnOperationsInitialized(self, categoryID, operationID):
     86         if categoryID == get_tutorial_category_id():
     87             self.ConstructTopIcons()
     88 
     89     def OnUIScalingChange(self, *args):
     90         self._ReconstructPanels()
     91 
     92     @telemetry.ZONE_FUNCTION
     93     def ConstructTopIcons(self):
     94         self.iconCont.Flush()
     95         self.infoPanelButtonsByTypeID.clear()
     96         for infoPanelCls in self.panelClasses:
     97             self.ConstructTopIcon(infoPanelCls)
     98 
     99     def ConstructTopIcon(self, infoPanelCls):
    100         if infoPanelCls.panelTypeID in self.infoPanelButtonsByTypeID:
    101             return
    102         if not infoPanelCls.IsAvailable() or get_ui_hider().is_ui_element_hidden(infoPanelCls.uniqueUiName):
    103             return
    104         try:
    105             button = ButtonIconInfoPanel(infoPanelCls=infoPanelCls, parent=self.iconCont, controller=self, texturePath=infoPanelCls.GetTexturePath(), func=self.OnPanelContainerIconPressed, align=uiconst.TOLEFT, width=self.ICONSIZE)
    106         except:
    107             logger.exception('InfoPanelContainer::ConstructTopIcons - Unable to construct top icon for info panel class: %s' % infoPanelCls)
    108         else:
    109             self.infoPanelButtonsByTypeID[infoPanelCls.panelTypeID] = button
    110 
    111     def OnPanelContainerIconPressed(self, panelTypeID):
    112         panel = self.GetPanelByTypeID(panelTypeID)
    113         if panel:
    114             if panel.isInModeTransition:
    115                 return
    116             if panel.mode == infoPanelConst.MODE_HIDDEN:
    117                 panel.mode = infoPanelConst.MODE_NORMAL
    118             elif panel.isCollapsable:
    119                 panel.mode = infoPanelConst.MODE_HIDDEN
    120             elif panel.mode == infoPanelConst.MODE_NORMAL:
    121                 panel.mode = infoPanelConst.MODE_COMPACT
    122             else:
    123                 panel.mode = infoPanelConst.MODE_NORMAL
    124 
    125     @telemetry.ZONE_FUNCTION
    126     def _ConstructInfoPanels(self):
    127         for infoPanelCls in self.panelClasses:
    128             if not session.charid:
    129                 return
    130             self.ConstructInfoPanel(infoPanelCls)
    131 
    132         if self.performFitsCheck:
    133             self.CheckAllPanelsFit()
    134 
    135     def CheckAllPanelsFit(self, triggeredByPanel = None):
    136         uthread2.StartTasklet(self._CheckAllPanelsFit, triggeredByPanel)
    137 
    138     @telemetry.ZONE_FUNCTION
    139     def _CheckAllPanelsFit(self, triggeredByPanel = None):
    140         for mode in (infoPanelConst.MODE_COMPACT, infoPanelConst.MODE_HIDDEN):
    141             for panelTypeID, panel in self.infoPanelsByTypeID.iteritems():
    142                 if panel.mode == infoPanelConst.MODE_HIDDEN:
    143                     continue
    144                 if not self.IsLastPanelClipped():
    145                     return
    146                 if panelTypeID == triggeredByPanel:
    147                     continue
    148                 panel.mode = mode
    149                 logger.info("InfoPanelContainer::_CheckAllPanelsFit - Panels don't fit, setting panelTypeID %s mode to %s", panelTypeID, mode)
    150 
    151     def ConstructInfoPanel(self, infoPanelClass):
    152         if infoPanelClass not in self.panelClasses:
    153             self.panelClasses.append(infoPanelClass)
    154         mode = infoPanelSettingsController.get_panel_mode(self.settingsID, infoPanelClass.panelTypeID)
    155         try:
    156             panel = infoPanelClass(parent=self.mainCont, mode=mode, settingsID=self.settingsID)
    157         except:
    158             logger.exception('InfoPanelContainer::ConstructInfoPanels - Unable to construct info panel: %s' % infoPanelClass)
    159         else:
    160             panel.onModeTransitionToNormalSignal.connect(self.CheckAllPanelsFit)
    161             self.infoPanelsByTypeID[infoPanelClass.panelTypeID] = panel
    162             if not infoPanelClass.IsAvailable():
    163                 panel.Hide()
    164             self.ConstructTopIcon(infoPanelClass)
    165         finally:
    166             blue.synchro.Yield()
    167 
    168     def UpdatePanel(self, panelTypeID, ignoreViewSettings = True):
    169         panel = self.GetPanelByTypeID(panelTypeID)
    170         if not panel or panel.destroyed:
    171             panelCls = infoPanelClassConst.PANEL_TYPE_ID_TO_CLASS.get(panelTypeID, None)
    172             if panelCls.IsAvailable():
    173                 if ignoreViewSettings or self.IsPanelTypeAllowedInView(panelTypeID):
    174                     self.ConstructInfoPanel(panelCls)
    175         elif panel and not panel.IsAvailable():
    176             self.ClosePanel(panelTypeID)
    177 
    178     @telemetry.ZONE_FUNCTION
    179     def _ReconstructPanels(self, animate = False):
    180         uthread.Lock(self)
    181         self.panelClasses = self._GetCurrentlyAvailableInfoPanelClasses()
    182         try:
    183             self.SortPanelClasses()
    184             if animate:
    185                 self.mainCont.opacity = 0.0
    186             if not session.charid:
    187                 return
    188             self.mainCont.Flush()
    189             self._ConstructInfoPanels()
    190             if not session.charid:
    191                 return
    192             self.ConstructTopIcons()
    193             uicore.animations.FadeIn(self.mainCont, duration=0.6)
    194         finally:
    195             uthread.UnLock(self)
    196 
    197     @telemetry.ZONE_FUNCTION
    198     def ClosePanel(self, panelTypeID):
    199         panel = self.GetPanelByTypeID(panelTypeID)
    200         button = self.GetPanelButtonByTypeID(panelTypeID)
    201         if panel:
    202             self.infoPanelsByTypeID.pop(panelTypeID)
    203             panel.Close()
    204         if button:
    205             self.infoPanelButtonsByTypeID.pop(panelTypeID)
    206             button.Close()
    207 
    208     def GetPanelByTypeID(self, panelTypeID):
    209         return self.infoPanelsByTypeID.get(panelTypeID, None)
    210 
    211     def GetPanelButtonByTypeID(self, panelTypeID):
    212         return self.infoPanelButtonsByTypeID.get(panelTypeID, None)
    213 
    214     def OnButtonDragStart(self, infoPanelCls):
    215         self.isDraggingButton = infoPanelCls
    216         uicore.uilib.RegisterForTriuiEvents(uiconst.UI_MOUSEMOVE, self.OnButtonDragMove)
    217 
    218     def OnButtonDragEnd(self, infoPanelCls):
    219         self.dropIndicatorLine.Hide()
    220         self.isDraggingButton = False
    221         if self.IsDraggingOverIcons():
    222             idx = self.GetDropIconIdx()
    223             dragId = self.GetCurrentPanelTypes().index(infoPanelCls.panelTypeID)
    224             if dragId < idx:
    225                 idx -= 1
    226             if idx < len(self.mainCont.children):
    227                 currAtIdx = self.mainCont.children[idx]
    228                 oldTypeID = currAtIdx.panelTypeID
    229             else:
    230                 oldTypeID = None
    231             self.MovePanelInFrontOf(infoPanelCls, oldTypeID)
    232 
    233     @telemetry.ZONE_FUNCTION
    234     def MovePanelInFrontOf(self, infoPanelCls, oldTypeID = None):
    235         panelSettings = infoPanelSettingsController.get_all_info_panel_settings(self.settingsID)
    236         entry = infoPanelSettingsController.get_panel_settings_entry_by_type(panelSettings, infoPanelCls.panelTypeID)
    237         if oldTypeID:
    238             idx = panelSettings.index(infoPanelSettingsController.get_panel_settings_entry_by_type(panelSettings, oldTypeID))
    239         else:
    240             idx = len(self.mainCont.children)
    241         oldIdx = panelSettings.index(infoPanelSettingsController.get_panel_settings_entry_by_type(panelSettings, infoPanelCls.panelTypeID))
    242         if oldIdx == idx:
    243             return
    244         panelSettings.pop(oldIdx)
    245         panelSettings.insert(idx, entry)
    246         infoPanelSettingsController.save_info_panel_setting(self.settingsID, panelSettings)
    247         self._ReconstructPanels(animate=True)
    248 
    249     def OnButtonDragMove(self, *args):
    250         if not self.isDraggingButton:
    251             return False
    252         if self.IsDraggingOverIcons():
    253             self.dropIndicatorLine.state = uiconst.UI_DISABLED
    254             self.SetDropIndicatorLinePosition()
    255         else:
    256             self.dropIndicatorLine.Hide()
    257         return True
    258 
    259     def IsDraggingOverIcons(self):
    260         return uicore.uilib.mouseOver.IsUnder(self.iconCont) or uicore.uilib.mouseOver == self.iconCont
    261 
    262     def GetCurrentPanelTypes(self):
    263         return [ panel.panelTypeID for panel in self.panelClasses ]
    264 
    265     def SetDropIndicatorLinePosition(self):
    266         idx = self.GetDropIconIdx()
    267         dragIdx = self.GetCurrentPanelTypes().index(self.isDraggingButton.panelTypeID)
    268         if idx in (dragIdx, dragIdx + 1):
    269             self.dropIndicatorLine.Hide()
    270         else:
    271             self.dropIndicatorLine.Show()
    272         numIcons = self.GetNumVisible()
    273         left, _, width, _ = self.iconCont.GetAbsolute()
    274         self.dropIndicatorLine.left = idx * (width / numIcons) - 2
    275 
    276     def GetDropIconIdx(self):
    277         numIcons = self.GetNumVisible()
    278         left, _, width, _ = self.iconCont.GetAbsolute()
    279         x = uicore.uilib.x - left
    280         numSlots = numIcons * 2
    281         pos = max(0, min(x / float(width), 1.0))
    282         idx = numSlots * pos
    283         idx = int(float(idx) / 2 + 0.5)
    284         return idx
    285 
    286     def GetNumVisible(self):
    287         return len([ child for child in self.iconCont.children if child.display ])
    288 
    289     def IsLastPanelClipped(self):
    290         if self.destroyed:
    291             return False
    292         if not self.mainCont.children:
    293             return False
    294         lastChild = self.GetLastVisiblePanel()
    295         if not lastChild:
    296             return False
    297         _, pt, _, ph = self.parent.GetAbsolute()
    298         if ph <= 0:
    299             logger.warn("InfoPanelContainer::IsLastPanelClipped: Container parent height is %s (zero or less) so don't collapse any panels", ph)
    300             return False
    301         _, t, _, h = lastChild.GetAbsolute()
    302         return t - pt + h > ph
    303 
    304     def GetLastVisiblePanel(self):
    305         children = self.mainCont.children[:]
    306         children.reverse()
    307         for child in children:
    308             if child.mode != infoPanelConst.MODE_HIDDEN:
    309                 return child
    310 
    311 
    312 class ButtonIconInfoPanel(ButtonIcon):
    313     __notifyevents__ = ['OnInfoPanelSettingChanged']
    314     default_padRight = 4
    315     default_iconSize = 18
    316     isDragObject = True
    317 
    318     def ApplyAttributes(self, attributes):
    319         ButtonIcon.ApplyAttributes(self, attributes)
    320         sm.RegisterNotify(self)
    321         self.controller = attributes.controller
    322         self.infoPanelCls = attributes.infoPanelCls
    323         self.UpdateMode(self.GetInfoPanelMode())
    324 
    325     def OnClick(self, *args):
    326         self.func(self.infoPanelCls.panelTypeID)
    327 
    328     def GetHint(self):
    329         return self.infoPanelCls.GetClassHint()
    330 
    331     def OnInfoPanelSettingChanged(self, panelTypeID, mode):
    332         if panelTypeID == self.infoPanelCls.panelTypeID:
    333             self.UpdateMode(mode)
    334 
    335     def UpdateMode(self, mode):
    336         if mode == infoPanelConst.MODE_HIDDEN:
    337             self.SetSelected()
    338         else:
    339             self.SetDeselected()
    340 
    341     def GetInfoPanelMode(self):
    342         return infoPanelSettingsController.get_panel_mode(self.controller.settingsID, self.infoPanelCls.panelTypeID)
    343 
    344     def GetDragData(self):
    345         self.controller.OnButtonDragStart(self.infoPanelCls)
    346         return (InfoPanelDragData(self.infoPanelCls),)
    347 
    348     def OnEndDrag(self, *args):
    349         ButtonIcon.OnEndDrag(self, *args)
    350         self.controller.OnButtonDragEnd(self.infoPanelCls)
    351 
    352     def OnDblClick(self, *args):
    353         pass