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

eveImagePicker.py (18692B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\eveImagePicker.py
      2 import math
      3 import blue
      4 import charactercreator.const as ccConst
      5 import localization
      6 import uthread
      7 from carbon.client.script.environment.AudioUtil import PlaySound
      8 from carbon.common.script.sys import serviceConst
      9 from carbon.common.script.util import logUtil as log, timerstuff
     10 from carbonui import uiconst
     11 from carbonui.primitives.container import Container
     12 from carbonui.primitives.fill import Fill
     13 from carbonui.primitives.frame import Frame
     14 from carbonui.primitives.sprite import Sprite
     15 from carbonui.uicore import uicore
     16 from eve.client.script.ui.login.charcreation.label import CCLabel
     17 from eveprefs import prefs
     18 HILITE = ('ui_105_32_27', 15, -3)
     19 
     20 class ImagePicker(Container):
     21     default_align = uiconst.CENTER
     22     default_left = 0
     23     default_top = 0
     24     default_width = 768
     25     default_height = 128
     26     default_name = 'ImagePicker'
     27     default_state = uiconst.UI_NORMAL
     28 
     29     def ApplyAttributes(self, attributes):
     30         for each in uicore.layer.main.children:
     31             if each.name == self.default_name:
     32                 each.Close()
     33 
     34         Container.ApplyAttributes(self, attributes)
     35         if attributes.parent is None:
     36             uicore.layer.main.children.append(self)
     37         self.onPreSetValueCallback = None
     38         self.onSetValueCallback = None
     39         self.onChangeFocusCallback = None
     40         self._activeData = None
     41         self._lastBrowseDiff = False
     42         self._lastSpringValue = None
     43         self._initMouseDownX = None
     44         self._doBlock = False
     45         self._availableTypeIDs = set()
     46         if session.role & serviceConst.ROLE_CONTENT:
     47             invCache = sm.GetService('invCache')
     48             if session.stationid or session.structureid:
     49                 try:
     50                     inv = invCache.GetInventory(const.containerHangar)
     51                     self._availableTypeIDs.update({i.typeID for i in inv.List(const.flagHangar) if i.categoryID == const.categoryApparel})
     52                 except Exception as e:
     53                     log.LogWarn()
     54 
     55             if session.charid:
     56                 try:
     57                     inv = invCache.GetInventoryFromId(session.charid)
     58                     self._availableTypeIDs.update({i.typeID for i in inv.List() if i.flagID == const.flagWardrobe})
     59                 except Exception as e:
     60                     log.LogWarn()
     61 
     62         self.zoomFactor = attributes.get('zoomFactor', 6.0)
     63         self.imageWidth = attributes.get('imageWidth', 128)
     64         self.imageHeight = attributes.get('imageHeight', 128)
     65         self.browserWidth = attributes.get('browserWidth', 400)
     66         self.numSpecialItems = attributes.get('numSpecialItems', 0)
     67         l, t, w, h = self.parent.GetAbsolute()
     68         self.sr.counterParent = Container(parent=self.parent, align=uiconst.TOPLEFT, name='counterParent', state=uiconst.UI_NORMAL, hint=localization.GetByLabel('UI/CharacterCustomization/ShowActive'), pos=(7, 6, 13, 9), opacity=0.5, idx=0)
     69         self.sr.counterParent.OnMouseEnter = (self.OnGenericMouseEnter, self.sr.counterParent)
     70         self.sr.counterParent.OnMouseExit = (self.OnGenericMouseExit, self.sr.counterParent)
     71         self.sr.counterParent.OnClick = self.ShowActiveSlot
     72         self.sr.counterParent.sr.icon = Frame(frameConst=(ccConst.ICON_FOCUSFRAME, 15, -11), parent=self.sr.counterParent, color=ccConst.COLOR50)
     73         self.sr.counterParent.sr.label = CCLabel(text='', parent=self.sr.counterParent, color=ccConst.COLOR50, align=uiconst.CENTER, left=1)
     74         if self.DebugRoleCheck():
     75             self.sr.debugLabel = CCLabel(text='', parent=self, align=uiconst.CENTER, top=self.imageHeight / 2 + 8, letterspace=0, fontsize=9, color=(1.0, 1.0, 1.0, 0.5), state=uiconst.UI_NORMAL, idx=0)
     76             self.sr.debugLabel.GetMenu = self.GetDebugMenu
     77         self.BuildStrip(attributes.images)
     78         self.UpdateCounter()
     79         self.onSetValueCallback = attributes.get('OnSetValue', None)
     80         self.onChangeFocusCallback = attributes.get('OnChangeFocus', None)
     81         self.onPreSetValueCallback = attributes.get('OnPreSetValue', None)
     82 
     83     def ShowActiveSlot(self, *args):
     84         active = self.GetActiveData()
     85         if active:
     86             self.SetActiveData(active)
     87 
     88     def GetDebugMenu(self):
     89         if self.DebugRoleCheck():
     90             return [('Copy Focus Data', self.CopyFocusData)]
     91 
     92     def CopyFocusData(self):
     93         fd = self.GetFocusData()
     94         if fd:
     95             blue.pyos.SetClipboardData(repr(fd[1]))
     96 
     97     def BuildStrip(self, images, *args):
     98         if self.sr.slots:
     99             self.sr.slots.Close()
    100         self.sr.slots = Container(parent=self, align=uiconst.CENTERLEFT)
    101         self.images = images
    102         self.slots = []
    103         self.height = self.imageHeight + 64
    104         self.width = self.browserWidth
    105         self.focusSlot = None
    106         if len(images) > 0:
    107             for idx, imageData in enumerate(images):
    108                 slot = self.AddSlot(idx, imageData)
    109 
    110         else:
    111             slot = self.AddSlot(0, (None, [None, None], None))
    112             log.LogTraceback('ImagePicker - Building strip without images')
    113         self.sr.slots.width = self.sr.slots.children[-1].left + self.sr.slots.children[-1].width
    114         self.maxSlotLeft = int(self.width / 2.0 - self.imageWidth / 4.0)
    115         self.minSlotLeft = -int(self.sr.slots.width - self.width / 2.0)
    116         self.sr.slots.height = self.imageHeight
    117         self.FixPosition(instant=True)
    118         self.UpdateSlotZoom()
    119 
    120     def AddSlot(self, idx, imageData):
    121         step = int(self.imageWidth * 0.75)
    122         self._slotGap = step
    123         specialItemPadding = 0
    124         if self.numSpecialItems and idx >= self.numSpecialItems:
    125             specialItemPadding = int(step * 0.5)
    126         slotpar = Container(name='slotPar_%s' % idx, parent=self.sr.slots, align=uiconst.TOPLEFT, state=uiconst.UI_PICKCHILDREN, pos=(-self.imageWidth / 2 + (idx + 1) * step + specialItemPadding,
    127          0,
    128          self.imageWidth,
    129          self.imageHeight))
    130         slotpar.idx = idx
    131         slotpar.imageData = imageData
    132         slot = Container(parent=slotpar, align=uiconst.CENTER, state=uiconst.UI_NORMAL, pos=(0,
    133          0,
    134          self.imageWidth / 2,
    135          self.imageHeight / 2))
    136         slot.OnMouseDown = (self.OnSlotMouseDown, slot)
    137         slot.OnMouseEnter = self.OnSlotMouseEnter
    138         slot.OnMouseUp = (self.OnSlotMouseUp, slot)
    139         slot.imageData = imageData
    140         slot.sr.hilite = Frame(parent=slot, align=uiconst.TOALL, frameConst=HILITE, state=uiconst.UI_HIDDEN, color=(1.0, 1.0, 1.0, 1.0))
    141         slot.sr.hilite.padding = -6
    142         slot.sr.thumbnail = Sprite(parent=slot, texturePath=None, align=uiconst.TOALL, padding=(2, 2, 2, 2), state=uiconst.UI_DISABLED)
    143         Fill(parent=slot, padding=(2, 2, 2, 2), color=(0.0, 0.0, 0.0, 0.75))
    144         return slot
    145 
    146     def OnSlotMouseEnter(self):
    147         PlaySound('ui_icc_button_mouse_over_play')
    148 
    149     def GetActiveData(self):
    150         return self._activeData
    151 
    152     def GetOptions(self):
    153         return self.images
    154 
    155     def GetFocusData(self):
    156         if self.focusSlot:
    157             return self.focusSlot.imageData
    158 
    159     def SetActiveDataFromValue(self, toValue, doCallbacks = True, focusOnSlot = True, doYield = True):
    160         toValueSet = set([toValue])
    161         if isinstance(toValue, tuple):
    162             if toValue[1] == '':
    163                 v0TypeData = (toValue[0], 'v0', toValue[2])
    164                 toValueSet.add(v0TypeData)
    165             elif toValue[1] == 'v0':
    166                 emptyStringTypeData = (toValue[0], '', toValue[2])
    167                 toValueSet.add(emptyStringTypeData)
    168         for i, imageData in enumerate(self.images):
    169             resPath, data, hiliteResPath = imageData
    170             if data[1] in toValueSet:
    171                 self.SetActiveData(imageData, focusOnSlot=focusOnSlot, doCallbacks=doCallbacks, doYield=doYield)
    172                 break
    173 
    174     def SetActiveData(self, data, focusOnSlot = True, doCallbacks = True, doYield = True):
    175         newData = self._activeData != data
    176         if doCallbacks and self.onPreSetValueCallback and newData:
    177             self.onPreSetValueCallback(data)
    178         self._activeData = data
    179         self.UpdateCounter()
    180         if focusOnSlot:
    181             uthread.new(self.SetFocusData, data, doYield)
    182         if doCallbacks and self.onSetValueCallback and newData:
    183             self.onSetValueCallback(data)
    184 
    185     def SetFocusData(self, data, doYield = True):
    186         if self.destroyed:
    187             return
    188         slotParent = self.GetSlotParentByData(data)
    189         if slotParent:
    190             l, t, w, h = self.GetAbsolute()
    191             newleft = w / 2 - (slotParent.left + slotParent.width / 2)
    192             if newleft == self.sr.slots.left:
    193                 return
    194             uicore.effect.MorphUIMassSpringDamper(self.sr.slots, 'left', newleft, newthread=not doYield, initVal=self.sr.slots.left, float=False, frequency=15.0, dampRatio=0.75, callback=self.UpdateSlotZoom)
    195             self.state = uiconst.UI_NORMAL
    196 
    197     def UpdateCounter(self):
    198         if self.sr.counterParent:
    199             if self._activeData is not None:
    200                 slotParent = self.GetSlotParentByData(self._activeData)
    201                 self.sr.counterParent.sr.label.text = '%s/%s' % (slotParent.idx + 1, len(self.images))
    202             else:
    203                 self.sr.counterParent.sr.label.text = '-/%s' % len(self.images)
    204             self.sr.counterParent.width = self.sr.counterParent.sr.label.textwidth + 8
    205 
    206     def GetSlotParentByData(self, data):
    207         for slot in self.sr.slots.children:
    208             if getattr(slot, 'imageData', None) == data:
    209                 return slot
    210 
    211     def GetValue(self, *args):
    212         if self.focusSlot:
    213             return self.focusSlot.imageData
    214 
    215     def SpringFeed(self, item, value):
    216         if self.destroyed:
    217             return
    218         lastSpringValue = self._lastSpringValue or 0
    219         self.RotateImages(lastSpringValue - value, clampValue=False)
    220         self._lastSpringValue = value
    221 
    222     def CheckMouseOver(self, slot):
    223         if slot.destroyed:
    224             slot.sr.mouseOverTimer = None
    225             return
    226         if uicore.uilib.leftbtn or uicore.uilib.rightbtn:
    227             return
    228         if self._activeData == slot.imageData:
    229             slot.sr.hilite.state = uiconst.UI_DISABLED
    230             slot.sr.hilite.SetAlpha(1.0)
    231         elif uicore.uilib.mouseOver is slot:
    232             slot.sr.hilite.state = uiconst.UI_DISABLED
    233             slot.sr.hilite.SetAlpha(0.25)
    234         else:
    235             slot.sr.hilite.state = uiconst.UI_HIDDEN
    236 
    237     def OnSlotMouseDown(self, slot, mouseBtn, *args):
    238         self.OnMouseDown(mouseBtn)
    239 
    240     def OnSlotMouseUp(self, slot, mouseBtn, *args):
    241         self.OnMouseUpAlt(slot, mouseBtn)
    242 
    243     def CheckIfSlotLoaded(self, slotParent):
    244         if getattr(slotParent, '_loaded', False):
    245             return
    246         slotParent._loaded = True
    247         slot = slotParent.children[0]
    248         resPath, data, hiliteResPath = slot.imageData
    249         if not resPath or not blue.paths.exists(resPath):
    250             resPath = 'res:/UI/Asset/missingThumbnail.dds'
    251         slot.sr.thumbnail.LoadTexture(resPath)
    252         if len(data) > 2 and data[2] is not None and session.role & serviceConst.ROLE_CONTENT:
    253             flag = Container(parent=slot, align=uiconst.TOPLEFT, padding=(2, 2, 2, 2), pos=(0, 0, 20, 20), state=uiconst.UI_DISABLED, idx=0)
    254             fill = Fill(parent=flag, color=(0, 1.0, 0, 0.5))
    255             if data[2] not in self._availableTypeIDs:
    256                 fill.SetRGB(1.0, 0, 0)
    257                 slot.GetMenu = (self.GetRightClickMenu, data[2])
    258             if getattr(uicore.layer.charactercreation.controller, 'mode', -1) == ccConst.MODE_FULLINITIAL_CUSTOMIZATION:
    259                 Fill(parent=flag, color=(0, 0.0, 0, 1.0), padding=5, idx=0)
    260         if self._activeData == slot.imageData:
    261             slot.sr.hilite.state = uiconst.UI_DISABLED
    262             slot.sr.hilite.SetAlpha(1.0)
    263         elif slot.sr.hilite:
    264             slot.sr.hilite.state = uiconst.UI_HIDDEN
    265         slot.sr.mouseOverTimer = timerstuff.AutoTimer(33, self.CheckMouseOver, slot)
    266 
    267     def OnMouseDown(self, mouseBtn = 0, *args):
    268         if mouseBtn != uiconst.MOUSELEFT:
    269             return
    270         PlaySound('ui_icc_button_mouse_down_play')
    271         self._lastBrowseDiff = None
    272         self._lastMouseX = uicore.uilib.x
    273         self._initMouseDownX = uicore.uilib.x
    274         self._initPosX = self.sr.slots.left
    275         self.sr.scrollTimer = timerstuff.AutoTimer(10, self.UpdateScroll)
    276         uthread.new(self.OnScrollStart)
    277 
    278     def OnMouseUp(self, mouseBtn, *args):
    279         self.OnMouseUpAlt(mouseBtn=mouseBtn)
    280 
    281     def OnMouseUpAlt(self, slot = None, mouseBtn = 0):
    282         if mouseBtn != uiconst.MOUSELEFT:
    283             return
    284         self.sr.scrollTimer = None
    285         if self._lastBrowseDiff:
    286             uthread.new(self.Throw, self._lastBrowseDiff)
    287         elif self.sr.slots.left != getattr(self, '_initPosX', 0):
    288             self._initMouseDownX = None
    289             uthread.new(self.FixPosition)
    290         elif slot:
    291             self.SetActiveData(slot.imageData)
    292 
    293     def OnMouseWheel(self, *args):
    294         uthread.new(self.MouseWheel_thread).context = 'ImagePicker::Throw'
    295         return 1
    296 
    297     def MouseWheel_thread(self, *args):
    298         self.Browse(uicore.uilib.dz / 3)
    299         if self.sr.settleWheelThread:
    300             self.sr.settleWheelThread.kill()
    301             self.sr.settleWheelThread = None
    302         self.sr.settleWheelThread = uthread.new(self.SettleAfterWheel_thread)
    303 
    304     def SettleAfterWheel_thread(self, *args):
    305         blue.pyos.synchro.SleepWallclock(250)
    306         if not self or self.destroyed:
    307             return
    308         self.sr.wheelSettleTimer = None
    309         self.FixPosition()
    310 
    311     def FixPosition(self, instant = False):
    312         l, t, w, h = self.GetAbsolute()
    313         newleft = self.sr.slots.left
    314         rounding = (newleft - w / 2) % self._slotGap
    315         if rounding > self._slotGap / 2:
    316             newleft += self._slotGap - rounding
    317         elif rounding < self._slotGap / 2:
    318             newleft -= rounding
    319         else:
    320             return
    321         newleft = max(-self.sr.slots.width + (w + self.imageWidth) / 2, min(newleft, w / 2 - self._slotGap))
    322         if instant:
    323             self.sr.slots.left = newleft
    324         else:
    325             uicore.effect.MorphUIMassSpringDamper(self.sr.slots, 'left', newleft, newthread=0, initVal=self.sr.slots.left, float=False, frequency=15.0, dampRatio=0.75, callback=self.UpdateSlotZoom)
    326         self.state = uiconst.UI_NORMAL
    327 
    328     def UpdateScroll(self, *args):
    329         newLeft = self._initPosX + (uicore.uilib.x - self._initMouseDownX)
    330         if self.maxSlotLeft > newLeft and newLeft > self.minSlotLeft:
    331             self.sr.slots.left = newLeft
    332         self._lastBrowseDiff = uicore.uilib.x - self._lastMouseX
    333         self._lastMouseX = uicore.uilib.x
    334         self.UpdateSlotZoom()
    335 
    336     def UpdateSlotZoom(self, *args):
    337         if not hasattr(self, 'sr'):
    338             return
    339         l, t, w, h = self.GetAbsolute()
    340         centerX = l + w / 2
    341         slotsInside = []
    342         centerSlot = None
    343         minDistFromCenter = 1000
    344         for slot in self.sr.slots.children:
    345             if not hasattr(slot, 'children'):
    346                 continue
    347             sl, st, sw, sh = slot.GetAbsolute()
    348             slotCenter = sl + sw / 2
    349             if slotCenter >= l and slotCenter <= l + w:
    350                 slotsInside.append((abs(centerX - slotCenter), slotCenter, slot))
    351             else:
    352                 slot.children[0].width = self.imageWidth / 2
    353                 slot.children[0].height = self.imageHeight / 2
    354             distFromCenter = abs(centerX - slotCenter)
    355             if distFromCenter < minDistFromCenter:
    356                 minDistFromCenter = distFromCenter
    357                 centerSlot = slot
    358 
    359         slotsInside.sort()
    360         slotsInside.reverse()
    361         maxDist = w / 2
    362         for diff, slotCenter, slot in slotsInside:
    363             if diff:
    364                 sizeFactor = 1.0 - abs(diff) / float(maxDist)
    365             else:
    366                 sizeFactor = 1.0
    367             slot.children[0].width = self.imageWidth / 2 + int(self.imageWidth / 2 * sizeFactor)
    368             slot.children[0].height = self.imageHeight / 2 + int(self.imageHeight / 2 * sizeFactor)
    369             slot.SetOrder(0)
    370             uthread.new(self.CheckIfSlotLoaded, slot)
    371 
    372         if slotsInside:
    373             self.focusSlot = slotsInside[-1][-1]
    374             if self.onChangeFocusCallback:
    375                 self.onChangeFocusCallback(self.focusSlot.imageData)
    376             if self.DebugRoleCheck():
    377                 resPath, data, hiliteResPath = self.focusSlot.imageData
    378                 self.sr.debugLabel.text = repr(data[1])
    379 
    380     def DebugRoleCheck(self):
    381         mask = serviceConst.ROLE_CONTENT | serviceConst.ROLE_QA | serviceConst.ROLE_PROGRAMMER | serviceConst.ROLE_GML
    382         if session.role & mask and not prefs.GetValue('CCHideAssetDebugText', False):
    383             return True
    384         else:
    385             return False
    386 
    387     def Browse(self, direction):
    388         if not len(self.sr.slots.children):
    389             return
    390         self.sr.slots.left = self.sr.slots.left - direction
    391         self.UpdateSlotZoom()
    392 
    393     def Throw(self, distance):
    394         steps = 20
    395         maxExp = math.exp(steps / 10.0)
    396         l, t, w, h = self.GetAbsolute()
    397         self._initMouseDownX = None
    398         for i in xrange(1, steps + 1):
    399             if self.sr.slots.left > self.maxSlotLeft:
    400                 break
    401             if self.sr.slots.left < self.minSlotLeft:
    402                 break
    403             iExp = math.exp(i / 10.0)
    404             self.Browse(-(distance - int(distance * (iExp / maxExp))))
    405             blue.pyos.synchro.SleepWallclock(10)
    406             if self.destroyed:
    407                 return
    408             if self._initMouseDownX:
    409                 break
    410 
    411         self.FixPosition()
    412 
    413     def OnScrollStart(self, *args):
    414         pass
    415 
    416     def OnGenericMouseEnter(self, btn, *args):
    417         btn.SetOpacity(1.0)
    418 
    419     def OnGenericMouseExit(self, btn, *args):
    420         btn.SetOpacity(0.5)
    421 
    422     def OnGenericMouseDown(self, btn, *args):
    423         btn.sr.icon.top += 1
    424 
    425     def GetRightClickMenu(self, typeID, *args):
    426         if not session.role & serviceConst.ROLE_WORLDMOD:
    427             return []
    428         return [('WM: /create this type', self.GMCreateItem, (typeID,))]
    429 
    430     def GMCreateItem(self, typeID, *args):
    431         try:
    432             sm.RemoteSvc('slash').SlashCmd('/create %s %s %s' % (typeID, 1, session.stationid))
    433             uicore.layer.charactercreation.controller.sr.step.GoToAssetMode(forcedMode=1)
    434             sm.GetService('cc').ClearMyAvailabelTypeIDs()
    435         except Exception as e:
    436             log.LogWarn()