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

scrollentries.py (35430B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\scrollentries.py
      2 import carbonui.const as uiconst
      3 import localization
      4 import log
      5 import trinity
      6 from carbon.client.script.environment.AudioUtil import PlaySound
      7 from carbon.common.script.util.timerstuff import AutoTimer
      8 from carbonui import uiconst
      9 from carbonui.control.inlines import get_inline_deco_class
     10 from carbonui.control.label import LabelCore
     11 from carbonui.control.link import Link
     12 from carbonui.fontconst import DEFAULT_FONTSIZE
     13 from carbonui.primitives.container import Container
     14 from carbonui.primitives.fill import Fill
     15 from carbonui.primitives.sprite import Sprite
     16 from carbonui.uicore import uicore
     17 from carbonui.util.bunch import Bunch
     18 from carbonui.util.stringManip import GetAsUnicode
     19 from carbonui.util.various_unsorted import GetBrowser, MapIcon
     20 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay
     21 from menu import MenuLabel
     22 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     23 
     24 class SE_BaseClassCore(Container):
     25     labelLeftDefault = uiconst.LABELTABMARGIN
     26     __guid__ = 'uicontrols.SE_BaseClassCore'
     27     default_name = 'scrollentry'
     28     default_align = uiconst.TOTOP
     29     default_className = 'SE_Generic'
     30     default_showHilite = True
     31     default_highlightClass = ListEntryUnderlay
     32     sound_hover = uiconst.SOUND_ENTRY_HOVER
     33     sound_select = uiconst.SOUND_ENTRY_SELECT
     34 
     35     def ApplyAttributes(self, attributes):
     36         if 'className' not in attributes:
     37             attributes.className = self.default_className
     38         Container.ApplyAttributes(self, attributes)
     39         self._hiliteFill = None
     40         self._isSelected = False
     41         self._showHilite = attributes.get('showHilite', self.default_showHilite)
     42         self._highlightClass = attributes.get('highlightClass', self.default_highlightClass)
     43 
     44     def GetTooltipPanelClassInfo(self):
     45         if self.sr.node and self.sr.node.tooltipPanelClassInfo:
     46             return self.sr.node.tooltipPanelClassInfo
     47 
     48     def GetTooltipPointer(self):
     49         if self.sr.node and self.sr.node.tooltipPanelClassInfo:
     50             return getattr(self.sr.node.tooltipPanelClassInfo, 'tooltipPointer', None)
     51         return uiconst.POINT_RIGHT_2
     52 
     53     def ConstructHiliteFill(self):
     54         if not self._hiliteFill:
     55             self._hiliteFill = self._highlightClass(name='selectionHighlight', bgParent=self)
     56 
     57     def ShowHilite(self, animate = True):
     58         if not self._showHilite:
     59             return
     60         self.ConstructHiliteFill()
     61         self._hiliteFill.set_hovered(True, animate)
     62 
     63     def OnMouseEnter(self, *args):
     64         if self.sound_hover and self._showHilite:
     65             PlaySound(self.sound_hover)
     66         self.ShowHilite()
     67 
     68     def HideHilite(self, animate = True):
     69         if self._hiliteFill:
     70             self._hiliteFill.set_hovered(False, animate)
     71 
     72     def OnMouseExit(self, *args):
     73         self.HideHilite()
     74 
     75     def Select(self, animate = True):
     76         if self._isSelected:
     77             return
     78         self.ConstructHiliteFill()
     79         self._isSelected = True
     80         self._hiliteFill.Select(animate)
     81 
     82     def Deselect(self, animate = True):
     83         if not self._isSelected:
     84             return
     85         if self._hiliteFill:
     86             self._hiliteFill.Deselect(animate)
     87         self._isSelected = False
     88 
     89     def IsMouseInsideEntry(self):
     90         if uicore.uilib.mouseOver != self and not uicore.uilib.mouseOver.IsUnder(self):
     91             return False
     92         return True
     93 
     94     @classmethod
     95     def GetCopyData(cls, node):
     96         return ''
     97 
     98 
     99 class SE_SpaceCore(SE_BaseClassCore):
    100     __params__ = ['height']
    101     default_showHilite = False
    102 
    103     def Load(self, node):
    104         self.sr.node = node
    105 
    106     def GetDynamicHeight(node, width):
    107         return node.height
    108 
    109 
    110 class SE_GenericCore(SE_BaseClassCore):
    111     __guid__ = 'uicontrols.SE_GenericCore'
    112     __params__ = ['label']
    113 
    114     def ApplyAttributes(self, attributes):
    115         SE_BaseClassCore.ApplyAttributes(self, attributes)
    116         if uicore.fontHandler:
    117             labelClass = uicore.fontHandler.defaultLabelClass
    118         else:
    119             labelClass = LabelCore
    120         self.sr.label = labelClass(name='text', text='', parent=self, pos=(self.labelLeftDefault,
    121          0,
    122          0,
    123          0), state=uiconst.UI_DISABLED, align=uiconst.CENTERLEFT, maxLines=1)
    124 
    125     def Load(self, node):
    126         self.hint = node.get('hint', '')
    127         self.confirmOnDblClick = node.get('confirmOnDblClick', 0)
    128         if node.get('selected', 0):
    129             self.Select()
    130         else:
    131             self.Deselect()
    132         self.sr.label.busy = True
    133         self.sr.label.left = 5 + 16 * node.get('sublevel', 0)
    134         self.sr.label.maxLines = node.get('maxLines', 1)
    135         self.sr.label.letterspace = node.get('letterspace', 0)
    136         self.sr.label.shadow = node.get('letterspace', None)
    137         if node.fontStyle:
    138             self.sr.label.fontStyle = node.fontStyle
    139         if node.fontsize:
    140             self.sr.label.fontsize = node.fontsize
    141         if node.fontcolor:
    142             self.sr.label.SetRGBA(*node.fontcolor)
    143         self.sr.label.busy = False
    144         self.sr.label.text = node.label
    145         if node.get('disabled', None):
    146             self.opacity = 0.5
    147             self.state = uiconst.UI_DISABLED
    148         else:
    149             self.opacity = 1.0
    150             self.state = uiconst.UI_NORMAL
    151         if node.get('OnDblClick', None) or getattr(self, 'confirmOnDblClick', None):
    152             self.EnableDblClick()
    153         else:
    154             self.DisableDblClick()
    155 
    156     def GetDynamicHeight(node, width):
    157         height = uicore.font.GetTextHeight(node.label, width=width - 5 + 16 * node.get('sublevel', 0), fontStyle=node.get('fontStyle', None), fontsize=node.get('fontsize', DEFAULT_FONTSIZE), letterspace=node.get('letterspace', 0), maxLines=node.get('maxLines', 1)) + 4
    158         return height
    159 
    160     def OnMouseHover(self, *args):
    161         if self.sr.get('node', None) and self.sr.node.get('OnMouseHover', None):
    162             self.sr.node.OnMouseHover(self)
    163 
    164     def OnMouseEnter(self, *args):
    165         SE_BaseClassCore.OnMouseEnter(self, *args)
    166         if self.sr.get('node', None) and self.sr.node.get('OnMouseEnter', None):
    167             self.sr.node.OnMouseEnter(self)
    168 
    169     def OnMouseExit(self, *args):
    170         SE_BaseClassCore.OnMouseExit(self, *args)
    171         if self.sr.get('node', None) and self.sr.node.get('OnMouseExit', None):
    172             self.sr.node.OnMouseExit(self)
    173 
    174     def OnClick(self, *args):
    175         if self.sr.get('node', None):
    176             if self.sr.node.get('OnClick', None):
    177                 self.sr.node.OnClick(self)
    178 
    179     def EnableDblClick(self):
    180         self.OnDblClick = self.DblClick
    181 
    182     def DisableDblClick(self):
    183         self.OnDblClick = None
    184 
    185     def DblClick(self, *args):
    186         if self.sr.node:
    187             self.sr.node.scroll.SelectNode(self.sr.node)
    188             if self.sr.node.get('OnDblClick', None):
    189                 self.sr.node.OnDblClick(self)
    190             elif getattr(self, 'confirmOnDblClick', None):
    191                 uicore.registry.Confirm(self)
    192 
    193     def OnMouseDown(self, *args):
    194         SE_BaseClassCore.OnMouseDown(self, *args)
    195         self.sr.node.scroll.SelectNode(self.sr.node)
    196         prompt_player_fsd_dialog('ListEntryClick')
    197         if self.sr.get('node', None) and self.sr.node.get('OnMouseDown', None):
    198             self.sr.node.OnMouseDown(self)
    199 
    200     def OnMouseUp(self, *args):
    201         SE_BaseClassCore.OnMouseUp(self, *args)
    202         if self.sr.get('node', None) and self.sr.node.get('OnMouseUp', None):
    203             self.sr.node.OnMouseUp(self)
    204 
    205     def GetMenu(self):
    206         if self.sr.get('node', None) and self.sr.node.get('OnGetMenu', None):
    207             return self.sr.node.OnGetMenu(self)
    208         return []
    209 
    210 
    211 class SE_TextlineCore(SE_BaseClassCore, Link):
    212     __guid__ = 'uicontrols.SE_TextlineCore'
    213     default_showHilite = False
    214     USECACHE = False
    215 
    216     def ApplyAttributes(self, attributes):
    217         SE_BaseClassCore.ApplyAttributes(self, attributes)
    218         self.gotSurface = False
    219         self.selectingtext = 0
    220         self.sr.textcursor = None
    221         self.sr.cursortimer = None
    222         self.sr.textselection = None
    223         self.Prepare_()
    224 
    225     def Prepare_(self, *args):
    226         self.sr.sprite = None
    227         self.sr.inlines = Container(name='inlines', parent=self)
    228         self.sr.links = Container(name='links', parent=self)
    229         self.sr.textselection = None
    230 
    231     def _OnClose(self):
    232         if self.destroyed:
    233             return
    234         self.Unload()
    235         if self.sr.node:
    236             for inline, x in self.sr.node.Get('inlines', []):
    237                 control = inline.control
    238                 if control and getattr(control, '__guid__', '').startswith('uicls.SE_'):
    239                     inline.control = None
    240                     control.Close()
    241 
    242         SE_BaseClassCore._OnClose(self)
    243 
    244     def Load(self, node):
    245         self.sr.links.Flush()
    246         self.leftM = 0
    247         self.sr.hiliteLinks = []
    248         self.RenderLine()
    249         self.LoadInlines()
    250         if not self or self.destroyed:
    251             return
    252         self.UpdateSelectionHilite()
    253         self.UpdateCursor()
    254 
    255     def OnChar(self, *args):
    256         pass
    257 
    258     def GetSprite(self):
    259         if self.sr.sprite is None:
    260             self.sr.sprite = Sprite(parent=self, state=uiconst.UI_PICKCHILDREN, spriteEffect=trinity.TR2_SFX_FONT, name='textSprite', idx=0)
    261             self.sr.sprite.OnCreate = self.OnCreate
    262             trinity.device.RegisterResource(self.sr.sprite)
    263             uicore.textObjects.add(self)
    264         return self.sr.sprite
    265 
    266     def OnCreate(self, dev):
    267         self.gotSurface = False
    268         if not self.destroyed and self.sr.node:
    269             self.Load(self.sr.node)
    270 
    271     def Unload(self):
    272         browser = GetBrowser(self)
    273         if browser and self.sr.inlines:
    274             for control in self.sr.inlines.children[:]:
    275                 if not control:
    276                     continue
    277                 if self.destroyed:
    278                     break
    279                 control.state = uiconst.UI_HIDDEN
    280                 control.SetParent(browser.sr.cacheContainer)
    281                 if hasattr(control, 'Unload') and control.loaded:
    282                     control.Unload()
    283 
    284     def LoadInlines(self):
    285         self.Unload()
    286         if not self.sr.node.scroll:
    287             return
    288         scrollwidth = self.sr.node.scroll.GetContentWidth()
    289         linewidth = self.sr.node.Get('lineWidth', 0)
    290         lineHeight = self.sr.node.Get('maxBaseHeight', 12)
    291         leftMargin = self.sr.node.Get('lpush', self.sr.node.scroll.xmargin)
    292         rightMargin = self.sr.node.Get('rpush', self.sr.node.scroll.xmargin)
    293         self.sr.inlines.left = max(0, self.leftM)
    294         from carbonui.control.editutils import parser
    295         for inline, x in self.sr.node.Get('inlines', []):
    296             control = getattr(inline, 'control', None)
    297             if control and not control.destroyed:
    298                 control.SetParent(self.sr.inlines)
    299             else:
    300                 decoClass = get_inline_deco_class(inline.attrs.type)
    301                 if not decoClass:
    302                     continue
    303                 control = self.sr.node.scroll.GetInline(ScrollEntryNode(decoClass=decoClass, attrs=inline.attrs))
    304                 if not self or self.destroyed:
    305                     return
    306                 control.SetParent(self.sr.inlines)
    307                 inline.control = control
    308             control.top = 0
    309             if inline.valign == parser.ALIGNMIDDLE:
    310                 control.top = (self.height - inline.inlineHeight) / 2
    311             elif inline.valign in (parser.ALIGNBOTTOM, parser.ALIGNSUB):
    312                 control.top = self.height - inline.inlineHeight
    313             elif inline.valign == parser.ALIGNBASELINE:
    314                 control.top = self.sr.node.Get('maxBaseLine', 12) - inline.inlineHeight
    315             control.left = int(x)
    316             control.height = inline.inlineHeight
    317             control.width = inline.inlineWidth
    318             if self.IsCentered:
    319                 control.SetAlign(uiconst.CENTER)
    320             if hasattr(control, 'Load') and not control.loaded:
    321                 control.Load()
    322             control.state = uiconst.UI_NORMAL
    323 
    324     def RenderLine(self):
    325         if not self.sr.node.scroll:
    326             return
    327         scrollwidth = self.sr.node.scroll.GetContentWidth()
    328         if self.sr.node.glyphString:
    329             linewidth = self.ReverseScaleDpi(self.sr.node.glyphString.width)
    330         else:
    331             linewidth = 0
    332         self.IsCentered = False
    333         lineHeight = self.sr.node.Get('maxBaseHeight', 12)
    334         leftMargin = self.sr.node.Get('lpush', self.sr.node.scroll.xmargin)
    335         rightMargin = self.sr.node.Get('rpush', self.sr.node.scroll.xmargin)
    336         links = self.sr.node.Get('links', [])
    337         sprite = self.GetSprite()
    338         if self.sr.node.align == 'right':
    339             sprite.left = int(scrollwidth - rightMargin - linewidth)
    340         elif self.sr.node.align == 'center':
    341             self.IsCentered = True
    342         else:
    343             sprite.left = int(leftMargin)
    344         self.leftM = sprite.left
    345         if self.sr.node.glyphString:
    346             self.ApplyPixels(linewidth, lineHeight)
    347         else:
    348             sprite.state = uiconst.UI_HIDDEN
    349         for linkAttrs in links:
    350             self.StartLink(linkAttrs)
    351 
    352     class TexResBuf(object):
    353         __slots__ = ['width',
    354          'height',
    355          'data',
    356          'pitch']
    357 
    358         def __init__(self, tuple):
    359             self.data, self.width, self.height, self.pitch = tuple
    360 
    361     def ApplyPixels(self, linewidth, lineHeight):
    362         self.sr.xMin = 0
    363         if not self.sr.node.glyphString:
    364             return
    365         node = self.sr.node
    366         glyphstring = node.glyphString
    367         bBox = node.bBox
    368         sprite = self.GetSprite()
    369         if not bBox or bBox.Width() <= 0 or bBox.Height() <= 0:
    370             sprite.state = uiconst.UI_HIDDEN
    371             return
    372         surfaceWidth = bBox.Width()
    373         surfaceHeight = glyphstring.baseHeight
    374         sprite.left += bBox.xMin
    375         if glyphstring.shadow:
    376             sx, sy, scol = glyphstring.shadow[-1]
    377             surfaceWidth += sx
    378             surfaceHeight -= sy
    379         sprite.texture = None
    380         texturePrimary = trinity.Tr2Sprite2dTexture()
    381         texturePrimary.atlasTexture = uicore.uilib.CreateTexture(surfaceWidth, surfaceHeight)
    382         sprite.texture = texturePrimary
    383         sprite.useSizeFromTexture = True
    384         try:
    385             bufferData = texturePrimary.atlasTexture.LockBuffer()
    386         except AttributeError:
    387             if texturePrimary and texturePrimary.atlasTexture:
    388                 texturePrimary.atlasTexture.UnlockBuffer()
    389                 bufferData = texturePrimary.atlasTexture.LockBuffer()
    390             else:
    391                 self.display = False
    392                 return
    393 
    394         try:
    395             buf = SE_TextlineCore.TexResBuf(bufferData)
    396             trinity.fontMan.ClearBuffer(buf.data, buf.width, buf.height, buf.pitch)
    397             glyphstring.DrawToBuf(buf, -bBox.xMin, glyphstring.baseHeight - glyphstring.baseLine)
    398         finally:
    399             texturePrimary.atlasTexture.UnlockBuffer()
    400 
    401         sprite.top = 0
    402         self.sr.xMin = bBox.xMin
    403         sprite.state = uiconst.UI_PICKCHILDREN
    404 
    405     def StartLink(self, attrs):
    406         link = Link(parent=self.sr.links)
    407         link.left = self.GetSprite().left + attrs.left
    408         link.top = self.GetSprite().top
    409         link.height = self.height - self.GetSprite().top + 1
    410         link.width = attrs.width
    411         link.state = uiconst.UI_NORMAL
    412         link.SetAlign(uiconst.RELATIVE)
    413         link.hint = unicode(attrs.hint)
    414         link.OnMouseMove = self.OnMouseMove
    415         link.OnDblClick = self.OnDblClick
    416         link.OnMouseEnter = (self.OnLinkMouseEnter, link)
    417         link.OnMouseExit = (self.LinkExit, link)
    418         link.OnMouseDown = (self.LinkDown, link)
    419         link.OnMouseUp = (self.LinkUp, link)
    420         link.cursor = uiconst.UICORSOR_FINGER
    421         link.url = attrs.url
    422         link.sr.attrs = attrs
    423         link.name = 'textlink'
    424         link.URLHandler = self.sr.node.Get('URLHandler', None)
    425         link.linkText = attrs.linkText
    426         if not attrs.Get('draggable', True):
    427             link.DisableDrag()
    428         return link
    429 
    430     def OnLinkMouseEnter(self, link, *args):
    431         PlaySound(uiconst.SOUND_BUTTON_HOVER)
    432         return self.LinkEnter(link)
    433 
    434     def LinkDown(self, link, *args):
    435         for each in self.sr.hiliteLinks:
    436             each.Flush()
    437 
    438     def LinkUp(self, link, *args):
    439         if uicore.uilib.mouseOver == link:
    440             self.LinkEnter(link)
    441 
    442     def LinkEnter(self, link, *args):
    443         browser = GetBrowser(self)
    444         if browser and browser.sr.window and hasattr(browser.sr.window, 'ShowHint'):
    445             browser.sr.window.ShowHint(link.hint or link.url)
    446         self.sr.hiliteLinks = []
    447         for entry in self.sr.node.scroll.GetNodes():
    448             if not entry.panel:
    449                 continue
    450             if entry.panel.sr.Get('links', None):
    451                 for item in entry.panel.sr.links.children:
    452                     if item.name == 'textlink' and item.url == link.url:
    453                         self.HiliteLink(item)
    454                         self.sr.hiliteLinks.append(item)
    455 
    456     def HiliteLink(self, link):
    457         if link.sr.attrs.alink_color:
    458             c = link.sr.attrs.alink_color
    459             Fill(parent=link, color=(c[0],
    460              c[1],
    461              c[2],
    462              c[3] * 0.5), pos=(-2, 0, -2, 0))
    463 
    464     def LinkExit(self, link, *args):
    465         browser = GetBrowser(self)
    466         if browser and browser.sr.window and hasattr(browser.sr.window, 'ShowHint'):
    467             browser.sr.window.ShowHint('')
    468         for each in self.sr.hiliteLinks:
    469             each.Flush()
    470 
    471     def SelectionHandlerDelegate(self, funcName, args):
    472         handler = self.sr.node.Get('SelectionHandler', None)
    473         if handler:
    474             func = getattr(handler, funcName, None)
    475             if func:
    476                 return func(*args)
    477 
    478     def GetMenu(self):
    479         self.sr.node.scroll.ShowHint('')
    480         return self.SelectionHandlerDelegate('GetMenuDelegate', (self.sr.node,))
    481 
    482     def OnMouseMove(self, *args):
    483         self.SelectionHandlerDelegate('OnMouseMoveDelegate', (self.sr.node,))
    484 
    485     def OnMouseDown(self, button, *args):
    486         if button == 0:
    487             self.SelectionHandlerDelegate('OnMouseDownDelegate', (self.sr.node,))
    488 
    489     def OnMouseUp(self, button, *args):
    490         if button == 0:
    491             self.SelectionHandlerDelegate('OnMouseUpDelegate', (self.sr.node,))
    492 
    493     def OnDropData(self, dragObj, nodes):
    494         self.SelectionHandlerDelegate('OnDropDataDelegate', (self.sr.node, nodes))
    495 
    496     def OnDragMove(self, nodes, *args):
    497         self.SelectionHandlerDelegate('OnDragMoveDelegate', (self.sr.node, nodes))
    498 
    499     def OnDragEnter(self, dragObj, nodes):
    500         self.SelectionHandlerDelegate('OnDragEnterDelegate', (self.sr.node, nodes))
    501 
    502     def OnDragExit(self, dragObj, nodes):
    503         self.SelectionHandlerDelegate('OnDragExitDelegate', (self.sr.node, nodes))
    504 
    505     def OnClick(self, *args):
    506         pass
    507 
    508     def OnDblClick(self, *args):
    509         self.SelectionHandlerDelegate('SelectWordUnderCursor', ())
    510 
    511     def OnTripleClick(self, *args):
    512         self.SelectionHandlerDelegate('SelectLineUnderCursor', ())
    513 
    514     def GetScrollAbove(self):
    515         from carbonui.control.scroll import Scroll
    516         item = self.parent
    517         while item:
    518             if isinstance(item, Scroll):
    519                 return item
    520             item = item.parent
    521 
    522     def UpdateSelectionHilite(self):
    523         if not self.sr.node:
    524             return
    525         scrollAbove = self.GetScrollAbove()
    526         f = uicore.registry.GetFocus()
    527         if not scrollAbove or scrollAbove is not f or not trinity.app.IsActive():
    528             selectionAlpha = 0.125
    529         else:
    530             selectionAlpha = 0.25
    531         if self.sr.node.selectionStartIndex is not None:
    532             if self.sr.textselection is None:
    533                 self.sr.textselection = Fill(parent=self, align=uiconst.TOPLEFT, state=uiconst.UI_HIDDEN)
    534             self.sr.textselection.SetAlpha(selectionAlpha)
    535             if self.sr.node.inlines:
    536                 left = 0
    537                 width = 0
    538                 for inline, x in self.sr.node.inlines:
    539                     width = max(width, inline.width)
    540 
    541             else:
    542                 left = uicore.font.GetWidthToIdx(self.sr.node, self.sr.node.selectionStartIndex)
    543                 right = uicore.font.GetWidthToIdx(self.sr.node, self.sr.node.selectionEndIndex)
    544                 width = uicore.ReverseScaleDpi(right - left)
    545                 left = uicore.ReverseScaleDpi(left)
    546             self.sr.textselection.left = self.leftM + left
    547             self.sr.textselection.width = width
    548             self.sr.textselection.height = self.height
    549             self.sr.textselection.top = 0
    550             self.sr.textselection.state = uiconst.UI_DISABLED
    551         elif self.sr.textselection:
    552             self.sr.textselection.state = uiconst.UI_HIDDEN
    553 
    554     def UpdateCursor(self):
    555         if self.sr.node.cursorPos is not None:
    556             sprite = self.GetSprite()
    557             if self.sr.textcursor is None:
    558                 self.sr.textcursor = Fill(parent=self, align=uiconst.TOPLEFT, state=uiconst.UI_HIDDEN, color=(1.0, 1.0, 1.0, 1.0))
    559                 self.sr.textcursor.top = 0
    560                 self.sr.textcursor.width = 1
    561             left = uicore.font.GetWidthToIdx(self.sr.node, self.sr.node.cursorPos)
    562             self.sr.textcursor.left = self.sr.inlines.left + uicore.ReverseScaleDpi(left)
    563             self.sr.textcursor.height = self.height
    564             if self.sr.cursortimer is None:
    565                 self.CursorBlink()
    566         elif self.sr.textcursor:
    567             self.sr.cursortimer = None
    568             self.sr.textcursor.state = uiconst.UI_HIDDEN
    569 
    570     def GetCursorOffset(self):
    571         if self.sr.textcursor:
    572             return self.sr.textcursor.left
    573 
    574     def CursorBlink(self):
    575         f = uicore.registry.GetFocus()
    576         if f is uicore.desktop or not trinity.app.IsActive():
    577             if self.sr.textcursor:
    578                 self.sr.textcursor.state = uiconst.UI_HIDDEN
    579             self.sr.cursortimer = None
    580             return
    581         if f and self.IsUnder(f) and self.sr.node.cursorPos is not None and self.sr.textcursor is not None:
    582             self.sr.textcursor.state = [uiconst.UI_HIDDEN, uiconst.UI_DISABLED][self.sr.textcursor.state == uiconst.UI_HIDDEN]
    583             if self.sr.cursortimer is None:
    584                 self.sr.cursortimer = AutoTimer(250, self.CursorBlink)
    585         else:
    586             self.sr.cursortimer = None
    587             self.sr.textcursor.state = uiconst.UI_HIDDEN
    588 
    589     def GetCopyData(self, fromIdx, toIdx):
    590         return uicore.font.GetNodeCopyData(self.sr.node, fromIdx, toIdx)
    591 
    592     def GetText(self, node):
    593         if node.rawText:
    594             return node.rawText
    595         text = ''.join([ glyphData[4] for glyphData in self.sr.node.glyphString if glyphData[4] != None ])
    596         node.rawText = text
    597         return text
    598 
    599     def GetDynamicHeight(node, width):
    600         return node.maxBaseHeight
    601 
    602 
    603 class SE_ListGroupCore(SE_BaseClassCore):
    604     __guid__ = 'uicontrols.SE_ListGroupCore'
    605     ENTRYHEIGHT = 18
    606 
    607     def ApplyAttributes(self, attributes):
    608         SE_BaseClassCore.ApplyAttributes(self, attributes)
    609         self.sr.entries = []
    610         self.dblclick = 0
    611         self.sr.expander = None
    612         self.sr.icon = None
    613 
    614     def _OnClose(self):
    615         SE_BaseClassCore._OnClose(self)
    616         self.sr.entries = None
    617 
    618     def Startup(self, *etc):
    619         self.Prepare_ExpanderIcon_()
    620         self.Prepare_Icon_()
    621         self.Prepare_Label_()
    622         self.Prepare_Selection_()
    623         self.Prepare_Background_()
    624 
    625     def Prepare_Label_(self):
    626         self.sr.labelClipper = Container(parent=self, pos=(0, 0, 0, 0), clipChildren=1)
    627         if uicore.fontHandler:
    628             labelClass = uicore.fontHandler.defaultLabelClass
    629         else:
    630             labelClass = LabelCore
    631         self.sr.label = labelClass(text='', parent=self.sr.labelClipper, pos=(self.labelLeftDefault,
    632          0,
    633          0,
    634          0), state=uiconst.UI_DISABLED, maxLines=1, idx=0, align=uiconst.CENTERLEFT, fontsize=12)
    635 
    636     def Prepare_Background_(self):
    637         self.sr.background = Fill(parent=self, color=(0.0, 0.0, 0.0, 0.5), pos=(0, 1, 0, 1))
    638 
    639     def Prepare_ExpanderIcon_(self):
    640         self.sr.expander = Sprite(align=uiconst.CENTERRIGHT, pos=(3, 0, 16, 16), parent=self, name='expander', idx=0)
    641         self.sr.expander.LoadIcon('ui_1_16_97')
    642         self.sr.expander.OnClick = self.Toggle
    643 
    644     def Prepare_Icon_(self):
    645         self.sr.icon = Sprite(align=uiconst.CENTERLEFT, pos=(0, 0, 16, 16), parent=self, idx=0, name='icon')
    646 
    647     def Load(self, node):
    648         self.sr.node = node
    649         self.sr.id = node.id
    650         self.sr.subitems = node.get('subitems', [])
    651         self.UpdateLabel()
    652         self.hint = node.get('hint', '')
    653         sublevel = node.get('sublevel', 0)
    654         self.sr.label.left = 20 + 16 * sublevel
    655         if self.sr.icon:
    656             self.sr.icon.left = 16 * sublevel
    657         if node.get('selected', 0):
    658             self.Select()
    659         else:
    660             self.Deselect()
    661         if self.sr.expander:
    662             self.sr.expander.state = [uiconst.UI_NORMAL, uiconst.UI_HIDDEN][node.get('hideExpander', 0)]
    663         for k, v in node.get('labelstyle', {}).iteritems():
    664             setattr(self.sr.label, k, v)
    665 
    666         if self.sr.icon:
    667             icon = node.get('showicon', '')
    668             graphicID = node.get('graphicID', None)
    669             if graphicID:
    670                 self.sr.icon.LoadIconByIconID(graphicID)
    671                 self.sr.icon.SetSize(64, 64)
    672                 self.sr.icon.state = uiconst.UI_DISABLED
    673             elif icon == 'hide':
    674                 if self.sr.icon:
    675                     self.sr.icon.state = uiconst.UI_HIDDEN
    676                 self.sr.label.left -= 12
    677             else:
    678                 MapIcon(self.sr.icon, icon or 'ui_2_32_1')
    679                 self.sr.icon.state = uiconst.UI_DISABLED
    680             self.sr.icon.width = self.sr.icon.height = 16
    681         if node.panel is not self or self is None:
    682             return
    683         self.ShowOpenState(uicore.registry.GetListGroupOpenState(self.sr.id, default=node.get('openByDefault', False)))
    684 
    685     def OnDropData(self, dragObj, nodes):
    686         if self == dragObj:
    687             return
    688         if self.sr.node.get('DropData', None):
    689             self.sr.node.DropData(self.sr.node.id, nodes)
    690             return
    691         ids = []
    692         myListGroupID = self.sr.node.id
    693         for node in nodes:
    694             guid = getattr(node, '__guid__', None)
    695             if guid not in self.sr.node.get('allowGuids', []):
    696                 log.LogWarn('dropnode.__guid__ has to be listed in group.node.allowGuids', guid, self.sr.node.get('allowGuids', []))
    697                 continue
    698             if not node.get('itemID', None):
    699                 log.LogWarn('dropitem data has to have itemID')
    700                 continue
    701             currentListGroupID = node.get('listGroupID', None)
    702             ids.append((node.itemID, currentListGroupID, myListGroupID))
    703 
    704         for itemID, currentListGroupID, myListGroupID in ids:
    705             if currentListGroupID and itemID:
    706                 uicore.registry.RemoveFromListGroup(currentListGroupID, itemID)
    707             uicore.registry.AddToListGroup(myListGroupID, itemID)
    708 
    709         if self.sr.node.get('RefreshScroll', None):
    710             self.sr.node.RefreshScroll()
    711         else:
    712             self.RefreshScroll()
    713 
    714     def Clear(self):
    715         self.sr.node.panel = None
    716 
    717     def OnClick(self, *args, **kwargs):
    718         if not self.dblclick and not self.sr.node.get('disableToggle', 0):
    719             self.Toggle()
    720         if self.sr.node and self.sr.node.scroll and self.sr.node.selectGroup:
    721             self.sr.node.scroll.SelectNode(self.sr.node)
    722         if not self.destroyed and self.sr.get('node', None) and self.sr.node.get('OnClick', None):
    723             self.sr.node.OnClick(self, *args, **kwargs)
    724 
    725     def OnMouseDown(self, *args):
    726         SE_BaseClassCore.OnMouseDown(self, *args)
    727         if self.sr.get('node', None) and self.sr.node.get('OnMouseDown', None):
    728             self.sr.node.OnMouseDown(self)
    729 
    730     def RefreshScroll(self):
    731         node = self.sr.node
    732         if node.open:
    733             if not node.get('GetContentIDList', None) or not node.get('CreateEntry', None):
    734                 return
    735             entries = node.subEntries
    736             if not entries:
    737                 self.LoadContent()
    738                 return
    739             addlist = []
    740             rmlist = []
    741             entryIDs = []
    742             self.sr.subitems = newcontent = self.sr.node.GetContentIDList(node.id)
    743             for entry in entries:
    744                 if not entry.get('id', None):
    745                     if len(newcontent):
    746                         rmlist.append(entry)
    747                     continue
    748                 if entry.id not in newcontent:
    749                     rmlist.append(entry)
    750                 else:
    751                     entryIDs.append(entry.id)
    752 
    753             for id in newcontent:
    754                 if id not in entryIDs:
    755                     newEntry = node.CreateEntry(id, node.sublevel + 1)
    756                     if newEntry is not None:
    757                         addlist.append(newEntry)
    758 
    759             if not len(newcontent) and len(node.subEntries) and node.subEntries[0].label != localization.GetByLabel('/Carbon/UI/Controls/Common/NoItem'):
    760                 noItem = self.GetNoItemEntry()
    761                 if noItem:
    762                     addlist.append(noItem)
    763             if self.sr.node:
    764                 node.scroll.RemoveNodes(rmlist)
    765                 entries += node.scroll.AddNodes(node.idx + 1, addlist)
    766                 for entry in rmlist:
    767                     entries.remove(entry)
    768 
    769                 node.subEntries = entries
    770         self.UpdateLabel()
    771 
    772     def GetNoItemEntry(self):
    773         return None
    774 
    775     def GetMenu(self):
    776         m = []
    777         node = self.sr.node
    778         if not node.get('showmenu', True):
    779             return m
    780         if not node.open:
    781             m += [(MenuLabel('/Carbon/UI/Common/Expand'), self.Toggle, ())]
    782         else:
    783             m += [(MenuLabel('/Carbon/UI/Common/Collapse'), self.Toggle, ())]
    784         if node.get('state', None) != 'locked':
    785             m += [(MenuLabel('/Carbon/UI/Controls/ScrollEntries/ChangeLabel'), self.ChangeLabel)]
    786             m += [(MenuLabel('/Carbon/UI/Controls/ScrollEntries/DeleteFolder'), self.DeleteFolder)]
    787         if node.get('MenuFunction', None):
    788             cm = node.MenuFunction(node)
    789             m += cm
    790         return m
    791 
    792     def ChangeLabel(self):
    793         newgroupName = self.GetNewGroupName()
    794         if not newgroupName or not self or self.destroyed:
    795             return
    796         if isinstance(newgroupName, dict):
    797             newgroupName = newgroupName['name']
    798         self.sr.node.label = newgroupName
    799         if self.sr.node.get('ChangeLabel', None):
    800             self.sr.node.ChangeLabel(self.sr.node.id, newgroupName)
    801         uicore.registry.ChangeListGroupLabel(self.sr.node.id, newgroupName)
    802         wnd = uicore.registry.GetWindow(unicode(self.sr.node.id))
    803         if wnd:
    804             wnd.SetCaption('     ' + newgroupName)
    805         if self.sr.node.get('DropCallback', None):
    806             self.sr.node.DropCallback(self.sr.node.id, None)
    807         if self.sr.node.get('RefreshScroll', None):
    808             self.sr.node.RefreshScroll()
    809         else:
    810             self.RefreshScroll()
    811 
    812     def GetNewGroupName(self):
    813         from eve.client.script.ui.util.utilWindows import NamePopup
    814         return NamePopup(localization.GetByLabel('/Carbon/UI/Controls/ScrollEntries/TypeInNewName'), localization.GetByLabel('/Carbon/UI/Controls/ScrollEntries/TypeInNewFolderName'))
    815 
    816     def DeleteFolder(self):
    817         id = self.sr.id
    818         if prompt_player_fsd_dialog('ConfirmDeleteFolder', {}, uiconst.YESNO, uiconst.ID_YES) == uiconst.ID_YES:
    819             if self.sr.node.get('DeleteCallback', None):
    820                 self.sr.node.DeleteCallback(self.sr.subitems)
    821             if self.sr.node.get('DeleteFolder', None):
    822                 self.sr.node.DeleteFolder(id)
    823             uicore.registry.DeleteListGroup(id)
    824             if not self or self.destroyed:
    825                 return
    826             self.CloseWindow(unicode(id))
    827             if self.sr.node.get('DropCallback', None):
    828                 self.sr.node.DropCallback(id, None)
    829             if self.sr.node.get('RefreshScroll', None):
    830                 self.sr.node.RefreshScroll()
    831 
    832     def CloseWindow(self, windowID):
    833         wnd = uicore.registry.GetWindow(windowID)
    834         if wnd:
    835             wnd.Close()
    836 
    837     def OnDragEnter(self, dragObj, nodes):
    838         if self.sr.node.get('DragEnterCallback', None):
    839             self.sr.node.DragEnterCallback(self, dragObj)
    840         elif getattr(nodes[0], '__guid__', None) in self.sr.node.get('allowGuids', []):
    841             self.Select()
    842 
    843     def OnDragExit(self, dragObj, nodes):
    844         self.Deselect()
    845 
    846     def Toggle(self, *args):
    847         node = self.sr.node
    848         if not node or node.get('toggling', 0):
    849             return
    850         node.toggling = 1
    851         w = node.panel
    852         if not w:
    853             node.toggling = 0
    854             return
    855         node.open = not node.open
    856         if node.open:
    857             self.CloseWindow(unicode(node.id))
    858         if node.open:
    859             PlaySound(uiconst.SOUND_EXPAND)
    860         else:
    861             PlaySound(uiconst.SOUND_COLLAPSE)
    862         self.ShowOpenState(node.open)
    863         self.UpdateLabel()
    864         uicore.registry.SetListGroupOpenState(node.id, node.open)
    865         node.scroll.PrepareSubContent(node)
    866         if node.get('onToggle', None):
    867             node.onToggle()
    868         node.toggling = 0
    869 
    870     def ShowOpenState(self, open_):
    871         if self.sr.expander:
    872             if open_:
    873                 MapIcon(self.sr.expander, 'ui_1_16_98')
    874             else:
    875                 MapIcon(self.sr.expander, 'ui_1_16_97')
    876 
    877     def UpdateLabel(self):
    878         node = self.sr.node
    879         if 'cleanLabel' not in node:
    880             node.cleanLabel = node.label
    881         text = node.cleanLabel
    882         if self.sr.subitems is not None and node.get('showlen', 1):
    883             text = localization.GetByLabel('/Carbon/UI/Controls/ScrollEntries/LabelWithLength', label=text, length=len(self.sr.subitems))
    884         posttext = node.get('posttext', '')
    885         if posttext:
    886             text = localization.GetByLabel('/Carbon/UI/Controls/ScrollEntries/LabelWithPostfix', label=text, postfix=posttext)
    887         self.sr.label.text = text
    888         node.label = text
    889 
    890 
    891 def ScrollEntryNode(**kw):
    892     data = Bunch(**kw)
    893     decoClass = data.get('decoClass', SE_GenericCore)
    894     data.decoClass = decoClass
    895     data.GetHeightFunction = getattr(decoClass, 'GetHeight', None)
    896     data.GetColumnWidthFunction = getattr(decoClass, 'GetColumnWidth', None)
    897     data.PreLoadFunction = getattr(decoClass, 'PreLoad', None)
    898     data.allowDynamicResize = getattr(decoClass, 'allowDynamicResize', False)
    899     if data.GetHeightFunction:
    900         data.GetHeightFunction = data.GetHeightFunction.__func__
    901     if data.PreLoadFunction:
    902         data.PreLoadFunction = data.PreLoadFunction.__func__
    903     if data.GetColumnWidthFunction:
    904         data.GetColumnWidthFunction = data.GetColumnWidthFunction.__func__
    905     if not data.charIndex and data.label:
    906         data.charIndex = GetAsUnicode(data.label).split('<t>')[0]
    907     if data.charIndex:
    908         data.charIndex = data.charIndex.lower()
    909     return data