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

spiffy.py (15394B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\spiffy.py
      2 from __future__ import print_function
      3 import sys
      4 import log
      5 import types
      6 import uthread
      7 from carbon.client.script.environment.AudioUtil import PlaySound
      8 from carbon.common.script.util import timerstuff
      9 from carbonui import uiconst
     10 from carbonui.control.contextMenu.menuUtil import ClearMenuLayer
     11 from carbonui.window.underlay import WindowUnderlay
     12 from carbonui.primitives.container import Container
     13 from carbonui.primitives.fill import Fill
     14 from carbonui.primitives.line import Line
     15 from carbonui.primitives.sprite import Sprite
     16 from carbonui.uicore import uicore
     17 from eve.client.script.ui.control import eveIcon, eveLabel
     18 from eve.client.script.ui.util import uix
     19 ENTRY_HASSUBMENU = 1
     20 ENTRY_ISDYNAMIC = 2
     21 ENTRY_VADJUST = 4
     22 ADDTOP = 2
     23 MENUWIDTH = 64
     24 BARWIDTH = 24
     25 TRACEWIDTH = 7
     26 HILITEALPHA = 0.25
     27 GHOSTALPHA = 0.5
     28 SPACER = 4
     29 
     30 def MenuHeader(label, **kw):
     31     entry = {'label': label,
     32      'flags': ENTRY_VADJUST,
     33      'height': 16,
     34      'hilited': 2,
     35      'disabled': True}
     36     entry.update(kw)
     37     return entry
     38 
     39 
     40 class MenuEntry(Container):
     41     default_height = 14
     42     default_name = 'entry'
     43     default_align = uiconst.TOTOP
     44     default_state = uiconst.UI_NORMAL
     45 
     46     def ApplyAttributes(self, attributes):
     47         Container.ApplyAttributes(self, attributes)
     48         triangleRight = Sprite(parent=self, name='TriangleRight', pos=(3, 3, 10, 10), align=uiconst.TOPRIGHT, state=uiconst.UI_HIDDEN, texturePath='res:/UI/Texture/Shared/triangleRight.png')
     49 
     50     def Setup(self, entry, menuobj = None, fontsize = None, addleft = 3):
     51         self.hilited = self.ghosted = self.disabled = False
     52         self.flags = 0
     53         self.action = self.args = self.iconmap = None
     54         self.iconmapscaling = 0.25
     55         self.fontsize = fontsize
     56         self.menuobj = menuobj
     57         if type(entry) == types.DictType:
     58             for k, v in entry.iteritems():
     59                 setattr(self, k, v)
     60 
     61         elif type(entry) == types.TupleType:
     62             label = entry[0]
     63             if type(label) == types.TupleType:
     64                 self.label = label[0]
     65                 if len(label) > 1:
     66                     self.iconmap = label[1]
     67                     if len(label) > 2:
     68                         self.iconmapscaling = label[2]
     69                 else:
     70                     self.iconmap = 'ui_9_64_14'
     71             else:
     72                 self.label = label
     73                 self.iconmap = None
     74             action = entry[1]
     75             if type(action) == types.TupleType:
     76                 if action[0] == 'isDynamic':
     77                     self.flags |= ENTRY_HASSUBMENU | ENTRY_ISDYNAMIC
     78                     self.action = action[1]
     79                     if len(action) > 2:
     80                         self.args = action[2]
     81                 else:
     82                     raise TypeError('Unsupported submenu type')
     83             elif type(action) == types.ListType:
     84                 self.flags |= ENTRY_HASSUBMENU
     85                 self.action = action
     86             elif callable(action) and not self.disabled:
     87                 self.action = action
     88                 if len(entry) >= 3:
     89                     self.args = entry[2]
     90             else:
     91                 self.action = None
     92         else:
     93             raise TypeError('Unsupported entry definition type')
     94         if self.fontsize:
     95             self.hspace = 0
     96         elif self.height <= 16:
     97             self.fontsize = 10
     98             self.hspace = 1
     99         else:
    100             self.fontsize = 12
    101             self.hspace = 1
    102         self.name = self.label
    103         if not self.action:
    104             self.disabled = True
    105         if self.disabled and not self.hilited:
    106             self.ghosted = True
    107         if hasattr(self, 'OnPreCreate'):
    108             self.OnPreCreate(self)
    109         self.sr.leftedge = Container(name='push', parent=self, width=addleft, state=uiconst.UI_DISABLED, align=uiconst.TOLEFT)
    110         if self.iconmap:
    111             self.sr.icon = icon = eveIcon.Icon(parent=self, align=uiconst.TOLEFT, state=uiconst.UI_DISABLED)
    112             icon.LoadIcon(self.iconmap, ignoreSize=True)
    113             icon.SetSize(self.height, self.height)
    114             icon.left = addleft
    115             if self.ghosted:
    116                 icon.opacity = GHOSTALPHA
    117         SPACER = 4
    118         Container(name='push', parent=self, width=SPACER, state=uiconst.UI_DISABLED, align=uiconst.TOLEFT)
    119         indent = self.sr.leftedge.width + (self.height, 0)[not self.iconmap] + SPACER
    120         self.sr.label = eveLabel.Label(text=self.label, parent=self, fontsize=self.fontsize, letterspace=self.hspace, state=uiconst.UI_DISABLED, left=indent)
    121         self.sr.label.top = (self.height - self.sr.label.textheight) / 2 + 1
    122         if self.ghosted:
    123             self.sr.label.opacity = GHOSTALPHA
    124         self.width = indent + self.sr.label.textwidth + SPACER + SPACER + 3
    125         if self.flags & ENTRY_HASSUBMENU:
    126             self.triangle = triangle = self.GetChild('TriangleRight')
    127             triangle.state = uiconst.UI_DISABLED
    128             triangle.top = (self.height - 10) / 2
    129             triangle.left += 2
    130         self.children[1].state = uiconst.UI_HIDDEN
    131         self.sr.selection2 = self.children[2]
    132         if self.hilited == 2:
    133             c = (0.0, 0.0, 0.0, 0.2)
    134         else:
    135             c = (1.0, 1.0, 1.0, 0.25)
    136         self.sr.selection = Fill(parent=self, idx=0, color=c)
    137         self.sr.selection.state = uiconst.UI_HIDDEN
    138         if self.iconmap:
    139             self.sr.iconbg = Fill(parent=self, idx=-1, color=(0, 0, 0, 0.2), left=addleft, top=0, width=self.height, height=self.height, align=uiconst.RELATIVE)
    140         if hasattr(self, 'OnPostCreate'):
    141             self.OnPostCreate(self)
    142         if self.hilited:
    143             self.OnMouseEnter()
    144 
    145     def OnMouseEnter(self, *args):
    146         if self.hilited or not self.disabled:
    147             self.sr.selection.state = uiconst.UI_DISABLED
    148             if self.iconmap:
    149                 self.sr.iconbg.state = uiconst.UI_HIDDEN
    150 
    151     def OnMouseExit(self, *args):
    152         if not self.hilited:
    153             self.sr.selection.state = uiconst.UI_HIDDEN
    154             if self.iconmap:
    155                 self.sr.iconbg.state = uiconst.UI_DISABLED
    156 
    157     def OnMouseUp(self, *args):
    158         if self.disabled:
    159             return
    160         if not self.flags & ENTRY_HASSUBMENU:
    161             uthread.new(ClearMenuLayer)
    162             if self.args:
    163                 uthread.new(self.action, *self.args)
    164             else:
    165                 uthread.new(self.action)
    166 
    167     def GetSubContent(self):
    168         if self.flags & ENTRY_ISDYNAMIC:
    169             try:
    170                 if self.args:
    171                     m = self.action(*self.args)
    172                 else:
    173                     m = self.action()
    174             except Exception as e:
    175                 log.LogException()
    176                 print(str(e))
    177                 m = [{'label': 'ERROR',
    178                   'disabled': True,
    179                   'ghosted': True,
    180                   'action': None,
    181                   'iconmap': '44_8',
    182                   'iconmapscaling': 0.125}]
    183                 sys.exc_clear()
    184 
    185         else:
    186             m = self.action
    187         return m
    188 
    189 
    190 class Menu(Container):
    191     default_name = 'contextualmenu'
    192     default_width = 80
    193     default_height = 64
    194     default_align = uiconst.TOPLEFT
    195     default_state = uiconst.UI_NORMAL
    196 
    197     def ApplyAttributes(self, attributes):
    198         Container.ApplyAttributes(self, attributes)
    199         self.submenu = None
    200         self.hilitedentry = None
    201         entries = Container(parent=self, name='entries', padding=(2, 2, 2, 2), align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN)
    202         underlay = WindowUnderlay(parent=self)
    203 
    204     def Setup(self, menu, entryheight = 16, position = None, origin = 'topleft', caption = None, fromentry = None, reverse = False):
    205         self.reverse = reverse
    206         self.origin = origin
    207         self.entryheight = entryheight
    208         self.fromentry = fromentry
    209         if fromentry:
    210             self.parentmenu = self.fromentry.menuobj
    211         self.state = uiconst.UI_HIDDEN
    212         self.align = uiconst.RELATIVE
    213         container = Container(name='SpiffyEntryList', parent=self, idx=0, pos=(0, 0, 0, 0))
    214         height = 0
    215         width = 0
    216         Container(name='push', parent=container, align=uiconst.TOTOP, height=2)
    217         allflags = 0
    218         wasline = 1
    219         if caption or fromentry:
    220             margin = (0, 1)[not fromentry]
    221         else:
    222             margin = 5
    223         if not menu:
    224             menu = [{'label': 'No items',
    225               'disabled': True,
    226               'ghosted': True,
    227               'action': None,
    228               'iconmap': '44_8',
    229               'iconmapscaling': 0.125}]
    230         while menu[-1] is None:
    231             menu.pop()
    232 
    233         addtop = 0
    234         for entry in menu:
    235             if entry:
    236                 item = MenuEntry(parent=container, height=entryheight)
    237                 item.Setup(entry, addleft=margin, menuobj=self)
    238                 item.OnMouseEnter = (self.OnEntryEnter, item)
    239                 item.OnMouseExit = (self.OnEntryExit, item)
    240                 width = max(width, item.width)
    241                 if item.flags & ENTRY_VADJUST and fromentry and not height:
    242                     addtop = item.height
    243                 allflags |= item.flags
    244                 wasline = 0
    245             else:
    246                 if wasline:
    247                     continue
    248                 item = Line(parent=container, align=uiconst.TOTOP)
    249                 wasline = 1
    250             height += item.height
    251 
    252         if fromentry and item and item.flags & ENTRY_VADJUST:
    253             subbottom = item.height
    254         else:
    255             subbottom = 0
    256         if allflags & ENTRY_HASSUBMENU:
    257             addwidth = 8
    258         else:
    259             addwidth = 0
    260         self.height = ADDTOP + height + ADDTOP
    261         if fromentry and not caption:
    262             addwidth += TRACEWIDTH
    263             edge = Container(name='SpiffyBar', parent=container, align=uiconst.TOLEFT, width=TRACEWIDTH, idx=0)
    264             self.sr.trace = side = Fill(parent=self, align=uiconst.RELATIVE, left=0, top=0, width=TRACEWIDTH, idx=0)
    265         else:
    266             edge = None
    267             if caption:
    268                 raise RuntimeError('SpiffyBar is still broken and needs fixing')
    269                 addwidth += BARWIDTH
    270                 side = uix.GetFill(name='SpiffyBar', parent=container, align=uiconst.TOLEFT, width=BARWIDTH, idx=0)
    271                 t = eveLabel.Label(text=caption, parent=side, width=self.height, height=BARWIDTH, state=uiconst.UI_NORMAL)
    272                 sm.GetService('textmetr').RefreshHeight(t)
    273                 t.left = (BARWIDTH - self.height + t.height) / 2 + 1
    274                 t.height = BARWIDTH
    275                 t.top = (self.height - BARWIDTH) / 2 - 1 - 12
    276                 t.rotation = 90.0
    277                 t.control.model.areas[0].areaMaterials[0].diffuse.a = 0.66
    278             else:
    279                 side = None
    280         if side:
    281             side.SetRGBA(1.0, 1.0, 1.0, HILITEALPHA)
    282         self.width = max(MENUWIDTH, width) + addwidth
    283         if fromentry:
    284             p = self.parentmenu
    285             while True:
    286                 if self.reverse:
    287                     left = p.absoluteLeft - self.width + 3
    288                 else:
    289                     left = p.absoluteRight - 5
    290                 if left < 0 or left + self.width > uicore.desktop.absoluteRight:
    291                     self.reverse = not self.reverse
    292                 else:
    293                     break
    294 
    295             fl, ft, fw, fh = fromentry.GetAbsolute()
    296             top = ft - ADDTOP - addtop
    297             if top + self.height > uicore.desktop.absoluteBottom:
    298                 top = ft + fh + ADDTOP + subbottom - self.height
    299             if self.reverse and side:
    300                 side.width = 10
    301                 side.left = self.width - side.width
    302         else:
    303             if position:
    304                 x, y = position
    305             else:
    306                 x, y = uicore.uilib.x, uicore.uilib.y
    307             if origin == 'topleft':
    308                 left = x
    309                 top = y - addtop
    310             elif origin == 'bottomleft':
    311                 left = x
    312                 top = y - self.height + subbottom
    313             elif origin == 'bottomright':
    314                 left = x - self.width
    315                 top = y - self.height + subbottom
    316             elif origin == 'topright':
    317                 left = x - self.width
    318                 top = y - addtop
    319             else:
    320                 raise ValueError("origin must be one of 'topleft', 'topright', 'bottomleft', 'bottomright'")
    321             if left < 0:
    322                 left = 0
    323             elif left + self.width > uicore.desktop.absoluteRight:
    324                 left = uicore.desktop.absoluteRight - self.width
    325         if top < 0:
    326             top = 0
    327         elif top + self.height > uicore.desktop.absoluteBottom:
    328             top = uicore.desktop.absoluteBottom - self.height
    329         if edge:
    330             if left < p.left:
    331                 edge.width = 4
    332         self.left = left
    333         self.top = top
    334         self.state = uiconst.UI_NORMAL
    335 
    336     def OnEntryEnter(self, entry):
    337         MenuEntry.OnMouseEnter(entry)
    338         PlaySound(uiconst.SOUND_ENTRY_HOVER)
    339         if self.fromentry:
    340             self.DoEntryTrace(entry)
    341         if entry != self.hilitedentry:
    342             self.hilitedentry = entry
    343             if self.submenu:
    344                 self.DoSubmenuCollapse()
    345             if entry.flags & ENTRY_HASSUBMENU:
    346                 self.submenuTimer = timerstuff.AutoTimer(settings.user.ui.Get('menuExpandTime', 10), self.DoSubmenuExpand, entry)
    347 
    348     def OnEntryExit(self, entry):
    349         if not (self.submenu and self.submenu.fromentry == entry):
    350             MenuEntry.OnMouseExit(entry)
    351             if self.fromentry:
    352                 if self.submenu:
    353                     self.DoEntryTrace(entry)
    354                 else:
    355                     self.sr.trace.top = 99999
    356 
    357     def DoSubmenuExpand(self, entry):
    358         self.submenuTimer = None
    359         self.DoSubmenuCollapse()
    360         if entry == self.hilitedentry:
    361             entry.OnMouseEnter()
    362             if self.fromentry:
    363                 self.DoEntryTrace(entry)
    364             self.submenu = Menu(parent=uicore.layer.menu, idx=0)
    365             self.submenu.Setup(entry.GetSubContent(), fromentry=entry, reverse=self.reverse, entryheight=self.entryheight)
    366 
    367     def DoSubmenuCollapse(self):
    368         if self.submenu:
    369             self.submenu.KillMe()
    370             self.submenu = None
    371 
    372     def DoEntryTrace(self, entry):
    373         fl, ft, fw, fh = self.fromentry.GetAbsolute()
    374         el, et, ew, eh = entry.GetAbsolute()
    375         if et + eh / 2 > ft + fh / 2:
    376             top = ft
    377             if self.reverse:
    378                 bottom = et
    379             else:
    380                 bottom = et + eh
    381         else:
    382             bottom = ft + fh
    383             if self.reverse:
    384                 top = et + eh
    385             else:
    386                 top = et
    387         self.sr.trace.top = top - self.absoluteTop
    388         self.sr.trace.height = bottom - top
    389 
    390     def KillMe(self):
    391         self.submenuTimer = None
    392         if self.submenu:
    393             self.submenu.KillMe()
    394             self.submenu = None
    395         if self.fromentry:
    396             self.fromentry.OnMouseExit()
    397         if not self.destroyed:
    398             self.Close()
    399 
    400 
    401 def CreateMenu(menu = None, *args, **kwargs):
    402     if not menu:
    403         return None
    404     ClearMenuLayer()
    405     obj = Menu(parent=uicore.layer.menu)
    406     obj.Setup(menu, *args, **kwargs)
    407     return obj