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

helpPointerSvc.py (29659B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\pointerTool\helpPointerSvc.py
      2 import re
      3 import blue
      4 import neocom2.btnIDs as btnIDs
      5 import carbonui.const as uiconst
      6 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
      7 import eveexceptions
      8 import log
      9 import mathext
     10 import uthread
     11 from carbon.common.script.sys.service import Service
     12 from carbon.common.script.util.timerstuff import AutoTimer
     13 from carbonui.uicore import uicore
     14 from eve.client.script.ui.inflight.selectedItemConst import ICON_ID_AND_CMD_BY_ACTIONID
     15 from eve.client.script.ui.shared.agencyNew.contentGroups import contentGroupProvider
     16 from eve.client.script.ui.shared.agencyNew.contentGroups.contentGroupConst import contentGroupNameByID
     17 import eve.client.script.ui.shared.mapView.categories.const as mapFilterConst
     18 from eve.client.script.ui.shared.neocom.neocom.btnData.btnDataRaw import BTNDATARAW_BY_ID
     19 from eve.client.script.ui.shared.neocom.neocom.buttons.buttonEveMenu import ButtonEveMenu
     20 from eve.client.script.ui.shared.neocom.neocom.neocomConst import BTNTYPE_GROUP, BTNTYPE_CMD, BTNTYPE_INVENTORY, BTNTYPE_CHAT, RAWDATA_SKILLS, BTNTYPE_CAREER_PROGRAM
     21 from eve.client.script.ui.shared.neocom.neocom.neocomRawData import GetEveMenuRawData
     22 from eve.client.script.ui.shared.pointerTool.entry import PointerWndEntry
     23 from eve.client.script.ui.shared.pointerTool.link import SCHEME_HELP_POINTER
     24 from eve.client.script.ui.shared.pointerTool.message_bus.helpPointerMessenger import HelpPointerMessenger
     25 from eve.client.script.ui.shared.pointerTool.pointerObject import GetPointerObjectFromAuthoredPointer, GetPointerObjectFromActions, GetPointerObjectForStationSvc, GetPointerObjectForAgencyTab, GetPointerObjectForNeocom, GetPointerObjectForAgencyCard, GetPointerObjectForSkillPlan, GetPointerObjectForSkillPlanFaction, GetPointerObjectForSkillPlanCareer, GetPointerObjectMapCategory, GetPointerObjectMapFilter
     26 from eve.client.script.ui.shared.pointerTool.pointerOverlay import PointerOverlay
     27 from eve.client.script.ui.shared.pointerTool.pointerToolUtil import GetFilteredNodes, TextAndTexture
     28 from eve.client.script.ui.shared.pointerTool.textContainerWithSubIcon import PointerContainerWithPath
     29 from eve.client.script.ui.shared.pointerTool.pointerToolSignals import on_reset
     30 from eve.client.script.ui.station.stationServiceConst import serviceDataByNameID
     31 from eve.common.script.sys.idCheckers import IsNPCCorporation
     32 from eveexceptions import UserError
     33 from expiringdict import ExpiringDict
     34 from fsdBuiltData.common.uiHelpPointersFSDLoader import UiHelpPointersFSDLoader
     35 from localization import GetByLabel
     36 from skills.skillplan.skillPlanService import GetSkillPlanSvc
     37 from uihighlighting import UiHighlightDirections
     38 from uihighlighting.ui.uipointer import CONTENT_CONTAINER_PADDING, UIPOINTER_WIDTH
     39 NEOCOM_E_ICON = 'res:/UI/Texture/icons/79_64_11.png'
     40 urlText = 'a href="{}:'.format(SCHEME_HELP_POINTER)
     41 POINTER_TAG_PATTERN = '<%s[\\w.]+">' % urlText
     42 POINTER_URL_END = '">'
     43 
     44 class HelpPointerSvc(Service):
     45     __guid__ = 'svc.helpPointer'
     46     __servicename__ = 'helpPointer'
     47     __displayname__ = 'Help Pointer Service'
     48 
     49     def __init__(self):
     50         self._action_label_paths_by_element_name = None
     51         self._agency_label_by_element_name = None
     52         self._all_pointers_by_element_name = None
     53         self._highlight_by_element_name = None
     54         self._loading = False
     55         self._neocom_pointers_by_element_name = None
     56         self._ready = False
     57         self._station_service_text_by_element_name = None
     58         self._skill_plans_by_name = None
     59         self.pendingPointers = ExpiringDict(100, 5)
     60         self.pendingThread = None
     61         self.pointerOverlay = None
     62         self.utilMenuHighlights = ExpiringDict(100, 5)
     63         super(HelpPointerSvc, self).__init__()
     64 
     65     def GetActionLabelPathsByElementName(self):
     66         return self.action_label_paths_by_element_name
     67 
     68     @property
     69     def action_label_paths_by_element_name(self):
     70         self._ensure_loaded()
     71         return self._action_label_paths_by_element_name
     72 
     73     def GetHighlightByElementName(self):
     74         return self.highlight_by_element_name
     75 
     76     @property
     77     def highlight_by_element_name(self):
     78         self._ensure_loaded()
     79         return self._highlight_by_element_name
     80 
     81     def GetStationServiceTextByElementName(self):
     82         return self.station_service_text_by_element_name
     83 
     84     @property
     85     def station_service_text_by_element_name(self):
     86         self._ensure_loaded()
     87         return self._station_service_text_by_element_name
     88 
     89     def GetAgencyLabelByElementName(self):
     90         return self.agency_label_by_element_name
     91 
     92     @property
     93     def agency_label_by_element_name(self):
     94         self._ensure_loaded()
     95         return self._agency_label_by_element_name
     96 
     97     def GetNeocomPointersByElementName(self):
     98         return self.neocom_pointers_by_element_name
     99 
    100     @property
    101     def neocom_pointers_by_element_name(self):
    102         self._ensure_loaded()
    103         return self._neocom_pointers_by_element_name
    104 
    105     @property
    106     def skill_plans_by_name(self):
    107         self._ensure_loaded()
    108         return self._skill_plans_by_name
    109 
    110     def GetSkillPlansByElementName(self):
    111         return self.skill_plans_by_name
    112 
    113     def GetAllPointersByElementName(self):
    114         return self.all_pointers_by_element_name
    115 
    116     def GetMapPointersByName(self):
    117         return self.map_pointers_by_name
    118 
    119     @property
    120     def map_pointers_by_name(self):
    121         self._ensure_loaded()
    122         return self._map_pointers_by_name
    123 
    124     @property
    125     def all_pointers_by_element_name(self):
    126         self._ensure_loaded()
    127         return self._all_pointers_by_element_name
    128 
    129     def reset(self):
    130         self._ready = False
    131         self._loading = False
    132         on_reset()
    133 
    134     def _ensure_loaded(self):
    135         if self._ready:
    136             return
    137         if self._loading:
    138             while self._loading:
    139                 blue.synchro.Yield()
    140 
    141             return
    142         self._loading = True
    143         try:
    144             self._load_data()
    145             self._ready = True
    146         finally:
    147             self._loading = False
    148 
    149     def _load_data(self):
    150         higlights_data = UiHelpPointersFSDLoader.GetData()
    151         self._highlight_by_element_name = {x.uiElementName:GetPointerObjectFromAuthoredPointer(x) for x in higlights_data.itervalues()}
    152         self._action_label_paths_by_element_name = self._load_all_action_options_pointers()
    153         self._station_service_text_by_element_name = self._load_station_services_by_unique_name()
    154         self._agency_label_by_element_name = self._load_agency_pointers()
    155         self._neocom_pointers_by_element_name = self._load_neocom_buttons_by_pointer()
    156         self._skill_plans_by_name = self._load_skill_plans_pointers()
    157         self._map_pointers_by_name = self._load_map_pointers()
    158         self._all_pointers_by_element_name = self._action_label_paths_by_element_name.copy()
    159         self._all_pointers_by_element_name.update(self._station_service_text_by_element_name)
    160         self._all_pointers_by_element_name.update(self._agency_label_by_element_name)
    161         self._all_pointers_by_element_name.update(self._neocom_pointers_by_element_name)
    162         self._all_pointers_by_element_name.update(self._highlight_by_element_name)
    163         self._all_pointers_by_element_name.update(self._skill_plans_by_name)
    164         self._all_pointers_by_element_name.update(self._map_pointers_by_name)
    165 
    166     def _load_station_services_by_unique_name(self):
    167         wanted = [serviceDataByNameID['charcustomization'],
    168          serviceDataByNameID['medical'],
    169          serviceDataByNameID['repairshop'],
    170          serviceDataByNameID['reprocessingPlant'],
    171          serviceDataByNameID['navyoffices'],
    172          serviceDataByNameID['insurance'],
    173          serviceDataByNameID['lpstore'],
    174          serviceDataByNameID['securityoffice']]
    175         servicesByUniqueName = {}
    176         for serviceInfo in wanted:
    177             pointerObj = GetPointerObjectForStationSvc(serviceInfo)
    178             servicesByUniqueName[pointerObj.uiElementName] = pointerObj
    179 
    180         return servicesByUniqueName
    181 
    182     def _load_all_action_options_pointers(self):
    183         ret = {}
    184         for labelPath, action in ICON_ID_AND_CMD_BY_ACTIONID.iteritems():
    185             pointerObj = GetPointerObjectFromActions(labelPath, action)
    186             if pointerObj is not None:
    187                 ret[pointerObj.uiElementName] = pointerObj
    188 
    189         return ret
    190 
    191     def _load_agency_pointers(self):
    192         ret = {}
    193         rootContentGroup = contentGroupProvider.GetRootContentGroup()
    194         for g in rootContentGroup.children:
    195             if not g.IsContentAvailable():
    196                 continue
    197             pointerObject = GetPointerObjectForAgencyTab(g)
    198             ret[pointerObject.uiElementName] = pointerObject
    199             self._add_agency_card_children(ret, g.children)
    200 
    201         return ret
    202 
    203     def _add_agency_card_children(self, pointerDict, groupChildren, level = 0):
    204         for eachChild in groupChildren:
    205             contentGroupID = eachChild.contentGroupID
    206             namePath = contentGroupNameByID.get(contentGroupID, None)
    207             if namePath and eachChild.IsVisible():
    208                 pointerObject = GetPointerObjectForAgencyCard(eachChild)
    209                 pointerDict[pointerObject.uiElementName] = pointerObject
    210             self._add_agency_card_children(pointerDict, eachChild.children, level=level + 1)
    211 
    212     def _load_skill_plans_pointers(self):
    213         ret = {}
    214         allCertifiedSkillPlans = GetSkillPlanSvc().GetAllCertified()
    215         for eachPlan in allCertifiedSkillPlans.itervalues():
    216             pointerObject = GetPointerObjectForSkillPlan(eachPlan)
    217             ret[pointerObject.uiElementName] = pointerObject
    218             pointerObject = GetPointerObjectForSkillPlanFaction(eachPlan)
    219             if pointerObject:
    220                 ret[pointerObject.uiElementName] = pointerObject
    221             pointerObject = GetPointerObjectForSkillPlanCareer(eachPlan)
    222             if pointerObject:
    223                 ret[pointerObject.uiElementName] = pointerObject
    224 
    225         return ret
    226 
    227     def _load_map_pointers(self):
    228         ret = {}
    229         groups = mapFilterConst.GROUP_CONTENT + mapFilterConst.GROUP_STATISTICS + [mapFilterConst.CATEGORY_FAVORITES]
    230         for groupID in groups:
    231             pointerObject = GetPointerObjectMapCategory(groupID)
    232             ret[pointerObject.uiElementName] = pointerObject
    233 
    234         for category_id, filterFunc in mapFilterConst.CATEGORY_FILTERS.iteritems():
    235             for f in filterFunc():
    236                 pointerObject = GetPointerObjectMapFilter(f)
    237                 ret[pointerObject.uiElementName] = pointerObject
    238 
    239         return ret
    240 
    241     def _load_neocom_buttons_by_pointer(self):
    242         from eve.client.script.ui.shared.neocom.neocom.btnData.btnDataRaw import BTNDATARAW_BY_ID
    243         neocomDataByPointerName = {}
    244         allValidBtnIDs = set()
    245         btnData = GetEveMenuRawData() + list(RAWDATA_SKILLS) + [(BTNTYPE_CHAT, 'chat', None)]
    246         self._add_valid_buttons_for_data(btnData, allValidBtnIDs)
    247         validBtnData = []
    248         for eachBtnID in allValidBtnIDs:
    249             eachData = BTNDATARAW_BY_ID.get(eachBtnID, None)
    250             if not eachData or not uicore.cmd.IsCommandAllowed(eachData.cmdName):
    251                 continue
    252             validBtnData.append((eachBtnID, eachData))
    253 
    254         fixedBtnData = sm.GetService('neocom').GetFixedButtonData()
    255         if fixedBtnData:
    256             for eachDataNode in fixedBtnData.children:
    257                 validBtnData.append((eachDataNode.id, eachDataNode))
    258 
    259         for eachBtnID, eachData in validBtnData:
    260             cmd = uicore.cmd.commandMap.GetCommandByName(eachData.cmdName)
    261             if cmd:
    262                 text = cmd.GetName()
    263             elif eachData and eachData.label is not None:
    264                 text = GetByLabel(eachData.label)
    265             else:
    266                 continue
    267             pointerObject = GetPointerObjectForNeocom(eachBtnID, eachData, text)
    268             neocomDataByPointerName[pointerObject.uiElementName] = pointerObject
    269 
    270         return neocomDataByPointerName
    271 
    272     def _add_valid_buttons_for_data(self, btnData, validBtns):
    273         for each in btnData:
    274             btnType, btnID, btnChildren = each
    275             if btnType in (BTNTYPE_CMD,
    276              BTNTYPE_INVENTORY,
    277              BTNTYPE_CHAT,
    278              BTNTYPE_CAREER_PROGRAM):
    279                 validBtns.add(btnID)
    280             if btnType == BTNTYPE_GROUP and btnChildren:
    281                 self._add_valid_buttons_for_data(btnChildren, validBtns)
    282 
    283     def ActivateHelperPointer(self, pointerUniqueName, sourceLocation = 0, displayTime = 2):
    284         self.LogPointerCreated(pointerUniqueName, sourceLocation)
    285         self._ActivateHelperPointer(pointerUniqueName, displayTime)
    286 
    287     def _ActivateHelperPointer(self, pointerUniqueName, displayTime = 2, isFirstCall = True):
    288         myHighlight = self.GetAuthoredHighlightByName(pointerUniqueName)
    289         if myHighlight:
    290             textAndTexture = myHighlight.GetTexAndTexture()
    291         elif pointerUniqueName in self.action_label_paths_by_element_name:
    292             pointerObject = self.action_label_paths_by_element_name[pointerUniqueName]
    293             textAndTexture = pointerObject.GetTexAndTexture()
    294         elif pointerUniqueName in self.station_service_text_by_element_name:
    295             pointerObject = self.station_service_text_by_element_name[pointerUniqueName]
    296             textAndTexture = pointerObject.GetTexAndTexture()
    297         elif pointerUniqueName in self.agency_label_by_element_name:
    298             pointerObject = self.agency_label_by_element_name[pointerUniqueName]
    299             textAndTexture = pointerObject.GetTexAndTexture()
    300         elif pointerUniqueName in self.skill_plans_by_name:
    301             pointerObject = self.skill_plans_by_name[pointerUniqueName]
    302             textAndTexture = pointerObject.GetTexAndTexture()
    303         elif pointerUniqueName in self.map_pointers_by_name:
    304             pointerObject = self.map_pointers_by_name[pointerUniqueName]
    305             textAndTexture = pointerObject.GetTexAndTexture()
    306         elif pointerUniqueName.startswith(pConst.NEOCOM_PREFIX):
    307             neocomID = pointerUniqueName.replace(pConst.NEOCOM_PREFIX, '')
    308             btnData = sm.GetService('neocom').GetBtnData(neocomID)
    309             if btnData and btnData.cmdName is not None:
    310                 cmd = uicore.cmd.commandMap.GetCommandByName(btnData.cmdName)
    311                 textAndTexture = TextAndTexture(cmd.GetName(), getattr(btnData, 'iconPath', None))
    312             elif btnData and btnData.label is not None:
    313                 textAndTexture = TextAndTexture(btnData.label, getattr(btnData, 'iconPath', None))
    314             else:
    315                 if pointerUniqueName in self.neocom_pointers_by_element_name:
    316                     label = getattr(self.neocom_pointers_by_element_name[pointerUniqueName], 'label', None)
    317                     if label:
    318                         notifyText = GetByLabel('UI/Help/PointerWndNotOnScreen', elementName=label)
    319                         raise UserError('CustomNotify', {'notify': notifyText})
    320                 log.LogWarn('PointerWnd: Invalid pointer, pointerUniqueName=%s' % pointerUniqueName)
    321                 raise UserError('CustomNotify', {'notify': GetByLabel('UI/Help/PointerWndInvalidPointer')})
    322         else:
    323             log.LogWarn('PointerWnd: Invalid pointer, pointerUniqueName=%s' % pointerUniqueName)
    324             raise UserError('CustomNotify', {'notify': GetByLabel('UI/Help/PointerWndInvalidPointer')})
    325         self.ShowPointer(pointerUniqueName, textAndTexture, displayTime, isFirstCall)
    326 
    327     def ShowPointer(self, pointerUniqueName, uiPointerTextAndTexture, displayTime, isFirstCall = True):
    328         if pointerUniqueName is None or pointerUniqueName == '':
    329             return
    330         pointToElement, newPointerName, extraLines, scopeWarnings, chainElements = self.FindElementToPointToAndScopeCheck(pointerUniqueName)
    331         from carbonui.control.window import Window
    332         if isinstance(pointToElement, Window):
    333             newPointerName = pointToElement.name
    334         if not pointToElement or not pointToElement.IsVisible():
    335             notifyText = '<br>'.join([GetByLabel('UI/Help/PointerWndNotOnScreen', elementName=uiPointerTextAndTexture.GetText())] + scopeWarnings)
    336             raise UserError('CustomNotify', {'notify': notifyText})
    337         subTextLines = self.GetSubText(pointerUniqueName, pointToElement, extraLines, chainElements)
    338         pointerNameToFind = newPointerName or pointerUniqueName
    339         defaultDirection = self.GetDirection(pointerNameToFind, pointToElement)
    340         uthread.new(self._ShowPointerThread, pointerNameToFind, uiPointerTextAndTexture, subTextLines, displayTime, defaultDirection, not bool(chainElements))
    341         if self.IsMenuHighlight(pointerUniqueName):
    342             self.AddUniqueNameToUtilMenuHighlights(pointerUniqueName)
    343         if isFirstCall and chainElements:
    344             self.pendingPointers[pointerUniqueName] = True
    345             if self.pendingThread is None:
    346                 self.pendingThread = AutoTimer(500, self.ShowPendingPointersThread)
    347 
    348     def FindElementToPointToAndScopeCheck(self, pointerName):
    349         elementKeyVal = sm.GetService('uipointerSvc').FindElementToPointTo(pointerName.split('.'), blinkNeocom=False, findWindow=True)
    350         element = elementKeyVal.pointToElement if elementKeyVal else None
    351         extraLines = getattr(elementKeyVal, 'extraTextLines', [])
    352         scopeWarningListEmpty = []
    353         chainElementsEmpty = []
    354         if element and element.IsVisible():
    355             return (element,
    356              None,
    357              extraLines,
    358              scopeWarningListEmpty,
    359              chainElementsEmpty)
    360         if element and not element.IsVisible() and not pointerName.startswith(pConst.NEOCOM_PREFIX):
    361             newPointerName = pConst.GetUniqueNeocomPointerName(pointerName)
    362             newElementKeyVal = sm.GetService('uipointerSvc').FindElementToPointTo(newPointerName.split('.'), blinkNeocom=False)
    363             if newElementKeyVal and newElementKeyVal.pointToElement:
    364                 return (newElementKeyVal.pointToElement,
    365                  newPointerName,
    366                  extraLines,
    367                  scopeWarningListEmpty,
    368                  chainElementsEmpty)
    369         if not element or not element.IsVisible():
    370             scopeWarnings = self.GetScopeWarnings(pointerName)
    371             if scopeWarnings:
    372                 return (None,
    373                  None,
    374                  [],
    375                  scopeWarnings,
    376                  chainElementsEmpty)
    377             from eve.client.script.ui.shared.pointerTool.pointerChains import FindChainForPointer
    378             pointerChain = FindChainForPointer(pointerName)
    379             chainElements = []
    380             for eachPointerName in reversed(pointerChain):
    381                 nextElementKeyVal = sm.GetService('uipointerSvc').FindElementToPointTo(eachPointerName.split('.'), blinkNeocom=False, findWindow=True)
    382                 chainElements.insert(0, eachPointerName)
    383                 if nextElementKeyVal and nextElementKeyVal.pointToElement and nextElementKeyVal.pointToElement.IsVisible():
    384                     return (nextElementKeyVal.pointToElement,
    385                      eachPointerName,
    386                      extraLines,
    387                      scopeWarningListEmpty,
    388                      chainElements)
    389 
    390         return (None,
    391          None,
    392          extraLines,
    393          scopeWarningListEmpty,
    394          chainElementsEmpty)
    395 
    396     def GetAuthoredHighlightByName(self, pointerName):
    397         return self.highlight_by_element_name.get(pointerName, None)
    398 
    399     def GetDirection(self, pointerName, pointToElement = None):
    400         from carbonui.control.window import Window
    401         if isinstance(pointToElement, Window):
    402             return UiHighlightDirections.UP
    403         if pointerName in self.agency_label_by_element_name:
    404             return UiHighlightDirections.UP
    405         if pointerName in self.agency_label_by_element_name:
    406             return UiHighlightDirections.UP
    407         myHighlight = self.all_pointers_by_element_name.get(pointerName, None)
    408         if myHighlight:
    409             return myHighlight.defaultDirection
    410 
    411     def GetOffset(self, pointerName):
    412         if pointerName in self.action_label_paths_by_element_name:
    413             return -12
    414         myHighlight = self.GetAuthoredHighlightByName(pointerName)
    415         if myHighlight:
    416             return myHighlight.offset
    417 
    418     def IsMenuHighlight(self, pointerUniqueName):
    419         myHighlight = self.GetAuthoredHighlightByName(pointerUniqueName)
    420         if myHighlight:
    421             if myHighlight.isMenuOption:
    422                 return True
    423         return False
    424 
    425     def GetScopeWarnings(self, pointerName):
    426         if pointerName in self.action_label_paths_by_element_name and not session.solarsystemid:
    427             return [GetByLabel('UI/HelpPointers/Wnd/ScopeInSpace')]
    428         myHighlight = self.GetAuthoredHighlightByName(pointerName)
    429         if not myHighlight:
    430             return ''
    431         pointerScope = myHighlight.pointerScope
    432         if not pointerScope:
    433             return ''
    434         scopeWarningList = []
    435         scope = [ x for x in pointerScope ]
    436         if 'Fleet' in scope and not session.fleetid:
    437             scopeWarningList.append(GetByLabel('UI/HelpPointers/Wnd/ScopeFleet'))
    438         if 'Docked' in scope and session.solarsystemid:
    439             scopeWarningList.append(GetByLabel('UI/HelpPointers/Wnd/ScopeDocked'))
    440         if 'InSpace' in scope and not session.solarsystemid:
    441             scopeWarningList.append(GetByLabel('UI/HelpPointers/Wnd/ScopeInSpace'))
    442         if 'PlayerCorp' in scope and IsNPCCorporation(session.corpid):
    443             scopeWarningList.append(GetByLabel('UI/HelpPointers/Wnd/ScopeInPlayerCorp'))
    444         return scopeWarningList
    445 
    446     def GetNameElements(self, pointerName):
    447         nameElements = pointerName.split('.')
    448         return nameElements
    449 
    450     def GetSubText(self, pointerName, pointToElement, extraLines, chainElements):
    451         extraTextList = []
    452         for x in extraLines or ():
    453             extraTextList.append(TextAndTexture(x, indentChar=''))
    454 
    455         extraTextList += self.FindSubTextAndIconForNeocomPointer(pointerName, pointToElement)
    456         for eachPointerName in chainElements:
    457             if eachPointerName in self.highlight_by_element_name:
    458                 element = self.highlight_by_element_name[eachPointerName]
    459                 extraTextList.append(TextAndTexture(element.label, element.texturePath, element.iconSizes, iconData=element.iconData))
    460             else:
    461                 textPath = self.FindSubTextAndIconForNeocomPointer(eachPointerName, pointToElement)
    462                 if textPath:
    463                     extraTextList = textPath + extraTextList
    464                 else:
    465                     pointerObject = self.all_pointers_by_element_name.get(eachPointerName, None)
    466                     pointerText = pointerObject.label if pointerObject else ''
    467                     extraTextList.append(TextAndTexture(pointerText, pointerObject.texturePath, pointerObject.iconSizes, iconData=pointerObject.iconData))
    468 
    469         return extraTextList
    470 
    471     def FindSubTextAndIconForNeocomPointer(self, pointerName, pointToElement):
    472         if not isinstance(pointToElement, ButtonEveMenu) or not pointerName.startswith('neocom.'):
    473             return []
    474         nameElements = self.GetNameElements(pointerName)
    475         wndID = nameElements[1]
    476         actualBtn = pointToElement.btnData.GetBtnDataByTypeAndID(wndID, recursive=True)
    477         if actualBtn and getattr(actualBtn, 'parent', None):
    478             label = getattr(actualBtn.parent, 'label', None)
    479             if label:
    480                 iconPath = getattr(actualBtn.parent, 'iconPath', None)
    481                 pathList = [TextAndTexture(GetByLabel('UI/Help/PointerWndNeocomHeader'), NEOCOM_E_ICON), TextAndTexture(label, iconPath), TextAndTexture(actualBtn.label, actualBtn.iconPath)]
    482                 return pathList
    483         return []
    484 
    485     def _ShowPointerThread(self, pointerName, uiPointerTextAndTexture, subTextLines, displayTime, defaultDirection = None, finalPointer = True):
    486         offset = self.GetOffset(pointerName)
    487         highlightingSvc = sm.GetService('uiHighlightingService')
    488         if finalPointer:
    489             fadeoutTime = displayTime
    490         else:
    491             fadeoutTime = 0.75
    492         iconSize = 24
    493         maxTextWidth = 0
    494         if uiPointerTextAndTexture:
    495             maxTextWidth = uiPointerTextAndTexture.GetMaxWidth(0, iconSize)
    496         if subTextLines:
    497             maxSubLines = max((x.GetMaxWidth(i, iconSize) for i, x in enumerate(subTextLines)))
    498             maxTextWidth = max(maxTextWidth, maxSubLines)
    499         maxTextWidth += 2 * CONTENT_CONTAINER_PADDING
    500         defaultPointerWidth = UIPOINTER_WIDTH - 2 * CONTENT_CONTAINER_PADDING
    501         pointerWidth = mathext.clamp(maxTextWidth, defaultPointerWidth, 2 * UIPOINTER_WIDTH - 2 * CONTENT_CONTAINER_PADDING)
    502         highlight_content = PointerContainerWithPath(align=uiconst.TOLEFT, name='textContainer', width=pointerWidth, height=0, titleAndIcon=uiPointerTextAndTexture, textAndIconObjects=subTextLines, iconSize=iconSize)
    503         highlightingSvc.custom_highlight_ui_element_by_name(ui_element_name=pointerName, offset=offset, highlight_content=highlight_content, fadeout_seconds=fadeoutTime, allowOffscreenPointing=True, default_direction=defaultDirection, idx=0)
    504 
    505     def ShowPendingPointersThread(self):
    506         pointersFound = False
    507         try:
    508             for pointerName in self.pendingPointers.iterkeys():
    509                 if self.pendingPointers.get(pointerName, False):
    510                     pointersFound = True
    511                     self._ActivateHelperPointer(pointerName, isFirstCall=False)
    512 
    513             if not pointersFound:
    514                 self.pendingThread = None
    515         except Exception:
    516             self.pendingPointers.clear()
    517             self.pendingThread = None
    518             raise
    519 
    520     def SearchPointers(self, searchStr):
    521         filteredNodes = GetFilteredNodes(searchStr, sourceLocation=pConst.SOURCE_LOCATION_SEARCH)
    522         if filteredNodes:
    523             from eve.client.script.ui.control.entries.util import GetFromClass
    524             from eve.client.script.ui.control.listgroup import ListGroup
    525             from eve.client.script.ui.util.searchUtil import GetScrollListGroup
    526             data = GetScrollListGroup(filteredNodes, PointerWndEntry, GetByLabel('UI/Help/PointerWndUiElementsSearch'), 'uiPointers')
    527             return ([GetFromClass(ListGroup, data)], len(filteredNodes))
    528         return ([], 0)
    529 
    530     def FindLocalChatWindow(self, uniqueUiName):
    531         return self._FindChatWnd('chatchannel_local', uniqueUiName)
    532 
    533     def FindCorpChatWindow(self, uniqueUiName):
    534         return self._FindChatWnd('chatchannel_corp', uniqueUiName)
    535 
    536     def FindFleetChatWindow(self, uniqueUiName):
    537         return self._FindChatWnd('chatchannel_fleet', uniqueUiName)
    538 
    539     def _FindChatWnd(self, windowID, uniqueUiName):
    540         from chat.client.window import BaseChatWindow
    541         wnd = BaseChatWindow.GetIfOpen(windowID=windowID)
    542         if wnd and not wnd.destroyed:
    543             wnd.uniqueUiName = uniqueUiName
    544             if hasattr(wnd, 'InStack') and wnd.InStack():
    545                 return wnd.sr.tab
    546             return wnd
    547 
    548     @eveexceptions.EatsExceptions('protoClientLogs')
    549     def LogPointerCreated(self, pointerUniqueName, sourceLocation):
    550         message_bus = HelpPointerMessenger(sm.GetService('publicGatewaySvc'))
    551         message_bus.pointer_created(pointerUniqueName, sourceLocation)
    552 
    553     @eveexceptions.EatsExceptions('protoClientLogs')
    554     def LogPointerLinkCreated(self, pointerUniqueName):
    555         message_bus = HelpPointerMessenger(sm.GetService('publicGatewaySvc'))
    556         message_bus.link_created(pointerUniqueName)
    557 
    558     def FindTagToIgnore(self, text):
    559         if text.find(SCHEME_HELP_POINTER) < 0:
    560             return []
    561         matches = re.findall(POINTER_TAG_PATTERN, text)
    562         tagsToIgnore = []
    563         for eachMatch in matches:
    564             pointerName = eachMatch.replace('<%s' % urlText, '')
    565             if pointerName.endswith(POINTER_URL_END):
    566                 pointerName = pointerName.rstrip(POINTER_URL_END)
    567             if self._IsValidPointerName(pointerName):
    568                 tag = '%s%s"' % (urlText, pointerName)
    569                 tagsToIgnore.append(tag)
    570 
    571         if tagsToIgnore:
    572             tagsToIgnore.append('/a')
    573         return tagsToIgnore
    574 
    575     def _IsValidPointerName(self, pointerName):
    576         if pointerName in self.highlight_by_element_name:
    577             return True
    578         if pointerName in self.all_pointers_by_element_name:
    579             return True
    580         if pointerName.startswith(pConst.NEOCOM_PREFIX):
    581             neocomID = pointerName.replace(pConst.NEOCOM_PREFIX, '')
    582             btnData = BTNDATARAW_BY_ID.get(neocomID)
    583             if btnData and btnData.cmdName is not None:
    584                 return True
    585         return False
    586 
    587     def IsUtilMenuEntryHighlighted(self, uniqueUiName):
    588         return uniqueUiName in self.utilMenuHighlights
    589 
    590     def AddUniqueNameToUtilMenuHighlights(self, uniqueUiName):
    591         self.utilMenuHighlights[uniqueUiName] = True
    592 
    593     def GetPointerOverlay(self, create = False):
    594         if self.pointerOverlay is None and create:
    595             self.pointerOverlay = PointerOverlay()
    596         return self.pointerOverlay
    597 
    598     def HidePointerOverlay(self):
    599         self.LogInfo('cmd:UI Pointer overlay: unload callback called')
    600         pointerHelper = self.GetPointerOverlay()
    601         if pointerHelper:
    602             self.LogInfo('cmd:UI Pointer overlay: hide overlay 1')
    603             pointerHelper.HideOverlay()
    604             self.LogInfo('cmd:Pointer overlay: hide overlay 2')