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

baseSingleLineEditNumber.py (14772B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\singlelineedits\baseSingleLineEditNumber.py
      2 import blue
      3 from carbon.client.script.environment.AudioUtil import PlaySound
      4 from carbonui import uiconst
      5 from carbonui.control.singlelineedits.baseSingleLineEdit import BaseSingleLineEdit
      6 from carbonui.primitives.container import Container
      7 from carbonui.uicore import uicore
      8 from carbonui.control.buttonIcon import ButtonIcon
      9 import eveLocalization
     10 from localization import SYSTEM_LANGUAGE
     11 from localization.formatters.numericFormatters import FormatNumeric
     12 from menu import MenuLabel
     13 import platform
     14 import sys
     15 import trinity
     16 from uthread2 import start_tasklet
     17 
     18 class BaseSingleLineEditNumbers(BaseSingleLineEdit):
     19     default_name = 'BaseSingleLineEditNumbers'
     20     default_minValue = None
     21     default_maxValue = None
     22     default_legalCharacters = ''
     23     default_dataType = None
     24     default_arrowIconColor = ButtonIcon.default_iconColor
     25     default_arrowIconClass = None
     26     default_arrowIconBlendMode = trinity.TR2_SBM_ADD
     27     default_arrowIconGlowColor = None
     28     default_arrowUseThemeColor = True
     29     default_showNumericControls = True
     30     HYPHEN = u'-'
     31 
     32     def ApplyAttributes(self, attributes):
     33         self.numericControlsCont = None
     34         minValue = attributes.get('minValue', self.default_minValue)
     35         maxValue = attributes.get('maxValue', self.default_maxValue)
     36         self.dataType = attributes.get('dataType', self.default_dataType)
     37         self.legalCharacters = attributes.get('legalCharacters', self.default_legalCharacters)
     38         self.arrowIconColor = attributes.get('arrowIconColor', self.default_arrowIconColor)
     39         self.arrowIconClass = attributes.get('arrowIconClass', self.default_arrowIconClass)
     40         self.arrowIconBlendMode = attributes.get('arrowIconBlendMode', self.default_arrowIconBlendMode)
     41         self.arrowIconGlowColor = attributes.get('arrowIconGlowColor', self.default_arrowIconGlowColor)
     42         self.arrowUseThemeColor = attributes.get('arrowUseThemeColor', self.default_arrowUseThemeColor)
     43         if minValue is None:
     44             minValue = self.default_minValue
     45         if maxValue is None:
     46             maxValue = self.default_maxValue
     47         self.SetMaxValue(maxValue)
     48         self.SetMinValue(minValue)
     49         super(BaseSingleLineEditNumbers, self).ApplyAttributes(attributes)
     50         showNumericControls = attributes.get('showNumericControls', self.default_showNumericControls)
     51         if showNumericControls:
     52             self.ShowNumericControls()
     53 
     54     def Insert(self, text):
     55         if self.readonly or not text:
     56             return
     57         if not isinstance(text, basestring):
     58             text = unichr(text)
     59         text = text.replace(u'\r', u' ').replace(u'\n', u'')
     60         text = self.FilterIllegalChars(text)
     61         if not text:
     62             return
     63         if text == self.HYPHEN and self.minValue >= 0:
     64             return
     65         if self.GetSelectionBounds() != (None, None):
     66             self.DeleteSelected(inserting=True)
     67         caretIndex = self.caretIndex[0]
     68         numSeparators = self.CountThousandSeparators()
     69         caretIndex -= numSeparators
     70         try:
     71             self.ValidateNegativeInput(text, caretIndex)
     72         except ValueError:
     73             return
     74 
     75         before = self.text[:caretIndex]
     76         after = self.text[caretIndex:]
     77         become = before + text + after
     78         become = self.ValidateNewText(become)
     79         if not become:
     80             return
     81         become, caretIndex = self.CheckForZeroInput(become, caretIndex)
     82         self.autoselect = False
     83         ret = self.CheckBounds(become, allowEmpty=bool(self.hintText), returnNoneIfOK=True)
     84         if ret is not None:
     85             if ret >= self.maxValue:
     86                 become = repr(ret)
     87         self.SetText(become)
     88         newCaretIndex = min(caretIndex + max(len(text), 1), len(become))
     89         newNumSeparators = self.CountThousandSeparators(newCaretIndex + numSeparators)
     90         newCaretIndex += newNumSeparators
     91         if ret is not None:
     92             newCaretIndex = -1
     93         self.caretIndex = self.GetCursorFromIndex(newCaretIndex)
     94         self.OnTextChange()
     95 
     96     def ValidateNewText(self, newText):
     97         return newText
     98 
     99     def CheckBounds(self, quantity, allowEmpty = True, returnNoneIfOK = False):
    100         if allowEmpty and not quantity:
    101             return quantity
    102         if quantity == self.HYPHEN or not quantity:
    103             quantity = 0
    104         quantity = self.FilterIllegalChars(repr(quantity))
    105         minusIndex = repr(quantity).find(self.HYPHEN)
    106         if minusIndex > 1:
    107             return self.minValue
    108         quantity = self.dataType(quantity)
    109         if quantity > self.maxValue:
    110             quantity = self.maxValue
    111         elif quantity < self.minValue:
    112             quantity = self.minValue
    113         elif returnNoneIfOK:
    114             return None
    115         return quantity
    116 
    117     def SetMaxValue(self, newMaxValue):
    118         self.maxValue = self.dataType(min(newMaxValue, sys.maxsize))
    119 
    120     def SetMinValue(self, newMinValue):
    121         self.minValue = self.dataType(max(newMinValue, -sys.maxsize))
    122 
    123     def FilterIllegalChars(self, text):
    124         return filter(lambda x: x in self.legalCharacters, text)
    125 
    126     def Copy(self, selectStart = None, selectEnd = None):
    127         text = self.GetText()
    128         if selectStart is not None and selectEnd is not None:
    129             blue.pyos.SetClipboardData(text[selectStart:selectEnd])
    130         else:
    131             start, end = self.GetSelectionBounds()
    132             if not start and not end:
    133                 blue.pyos.SetClipboardData(text)
    134             else:
    135                 numSeparators = self.CountThousandSeparators(startIndex=start[0], endIndex=end[0])
    136                 blue.pyos.SetClipboardData(text[start[0]:end[0] - numSeparators])
    137 
    138     def CountThousandSeparators(self, endIndex = 0, startIndex = 0):
    139         endIndex = endIndex if endIndex else self.caretIndex[0]
    140         displayText = self.textLabel.GetText()
    141         endIndex = min(endIndex, len(displayText))
    142         displayTextFromStartIndexToEndIndex = displayText[startIndex:endIndex]
    143         return displayTextFromStartIndexToEndIndex.count(self.GetLocalizedThousandSeparator())
    144 
    145     def CheckForZeroInput(self, become, caretIndex):
    146         allLettersAreZero = all((letter == '0' for letter in become))
    147         if allLettersAreZero:
    148             become = '0'
    149             caretIndex = 0
    150         return (become, caretIndex)
    151 
    152     def GetLocalizedThousandSeparator(self):
    153         return eveLocalization.GetThousandSeparator(SYSTEM_LANGUAGE)
    154 
    155     def OnUpKeyPressed(self):
    156         self.ChangeNumericValue(1)
    157 
    158     def OnDownKeyPressed(self):
    159         super(BaseSingleLineEditNumbers, self).OnDownKeyPressed()
    160         self.ChangeNumericValue(-1)
    161 
    162     def Delete(self, direction = True):
    163         if self.readonly:
    164             return
    165         oldCaretIndex = self.caretIndex[0]
    166         indexWithoutSeparators = max(oldCaretIndex - self.CountThousandSeparators(endIndex=oldCaretIndex), 0)
    167         if direction:
    168             begin = indexWithoutSeparators
    169             end = min(indexWithoutSeparators + 1, len(self.textLabel.text))
    170             newIndexWithoutSeparators = indexWithoutSeparators
    171         else:
    172             begin = max(indexWithoutSeparators - 1, 0)
    173             end = indexWithoutSeparators
    174             newIndexWithoutSeparators = max(indexWithoutSeparators - 1, 0)
    175         newText = self.text[:begin] + self.text[end:]
    176         self.SetText(newText)
    177         numSeparators = self.CountThousandSeparators(endIndex=indexWithoutSeparators)
    178         self.caretIndex = self.GetCursorFromIndex(newIndexWithoutSeparators + numSeparators)
    179         self.OnTextChange()
    180 
    181     def StripLeadingZeroesIfNecessary(self, newText):
    182         if not newText or newText.startswith('0.') or newText.startswith('0L') or newText == '0':
    183             return newText
    184         stripped = newText.lstrip('0')
    185         if stripped == 'L' or stripped == '':
    186             return '0'
    187         return stripped
    188 
    189     def DeleteSelected(self, inserting = False):
    190         if self.readonly:
    191             return
    192         start, end = self.GetSelectionBounds()
    193         self.selFrom = self.selTo = None
    194         self.RefreshSelectionDisplay()
    195         separatorsTilStart = 0
    196         if start[0]:
    197             separatorsTilStart = self.CountThousandSeparators(endIndex=start[0])
    198         separatorsBetweenSelection = self.CountThousandSeparators(startIndex=start[0], endIndex=end[0])
    199         deleteFromIndex = max(start[0] - separatorsTilStart, 0)
    200         deleteUntilIndex = min(end[0] - separatorsTilStart - separatorsBetweenSelection, len(self.text))
    201         newText = self.text[:deleteFromIndex] + self.text[deleteUntilIndex:]
    202         self.SetText(newText, format=not inserting)
    203         newSeparatorsTilStart = self.CountThousandSeparators(endIndex=deleteFromIndex)
    204         newCaretIndex = start[0] - separatorsTilStart + newSeparatorsTilStart
    205         self.caretIndex = self.GetCursorFromIndex(newCaretIndex)
    206         self.OnTextChange()
    207 
    208     def SetText(self, newText, format = True):
    209         return super(BaseSingleLineEditNumbers, self).SetText(newText)
    210 
    211     def FormatNumeric(self, otext, useGrouping = True, decimalPlaces = 0, leadingZeroes = 0):
    212         if not otext:
    213             return ''
    214         else:
    215             try:
    216                 number = self.dataType(otext or 0)
    217             except ValueError:
    218                 return otext
    219 
    220             return FormatNumeric(number, useGrouping=useGrouping, decimalPlaces=decimalPlaces, leadingZeroes=leadingZeroes)
    221 
    222     def SetValue(self, text, docallback = 1):
    223         if text == self.HYPHEN:
    224             text = self.minValue
    225         text = self.dataType(text) if text else text
    226         text = self.CheckBounds(text, allowEmpty=bool(self.hintText))
    227         super(BaseSingleLineEditNumbers, self).SetValue(text, docallback)
    228 
    229     def ShowNumericControls(self):
    230         if self.numericControlsCont:
    231             return
    232         self.numericControlsCont = Container(name='numericControlsCont', parent=self, align=uiconst.TORIGHT, idx=0, width=10, padding=(0, 1, 8, 1), opacity=0.75, state=uiconst.UI_HIDDEN if self.readonly else uiconst.UI_NORMAL)
    233         self.upButton = ButtonIcon(name='upButton', parent=self.numericControlsCont, align=uiconst.CENTER, pos=(0, -4, 9, 9), iconSize=7, texturePath='res:/UI/Texture/Shared/up.png', soundClick=uiconst.SOUND_VALUECHANGE_TICK, iconColor=self.arrowIconColor, glowColor=self.arrowIconGlowColor, iconClass=self.arrowIconClass, useThemeColor=self.arrowUseThemeColor, iconBlendMode=self.arrowIconBlendMode)
    234         self.upButton.OnMouseDown = self.OnNumericUpButtonMouseDown
    235         self.upButton.OnMouseUp = self.OnNumericUpButtonMouseUp
    236         self.downButton = ButtonIcon(name='downButton', parent=self.numericControlsCont, align=uiconst.CENTER, pos=(0, 4, 9, 9), iconSize=7, texturePath='res:/UI/Texture/Shared/down.png', soundClick=uiconst.SOUND_VALUECHANGE_TICK, iconColor=self.arrowIconColor, glowColor=self.arrowIconGlowColor, iconClass=self.arrowIconClass, useThemeColor=self.arrowUseThemeColor, iconBlendMode=self.arrowIconBlendMode)
    237         self.downButton.OnMouseDown = self.OnNumericDownButtonMouseDown
    238         self.downButton.OnMouseUp = self.OnNumericDownButtonMouseUp
    239 
    240     def OnNumericUpButtonMouseDown(self, *args):
    241         ButtonIcon.OnMouseDown(self.upButton, *args)
    242         self.updateNumericInputThread = start_tasklet(self.UpdateNumericInputThread, 1)
    243 
    244     def OnNumericDownButtonMouseDown(self, *args):
    245         ButtonIcon.OnMouseDown(self.downButton, *args)
    246         self.updateNumericInputThread = start_tasklet(self.UpdateNumericInputThread, -1)
    247 
    248     def KillNumericInputThread(self):
    249         if self.updateNumericInputThread:
    250             self.updateNumericInputThread.kill()
    251             self.updateNumericInputThread = None
    252 
    253     def OnNumericUpButtonMouseUp(self, *args):
    254         ButtonIcon.OnMouseUp(self.upButton, *args)
    255         self.KillNumericInputThread()
    256 
    257     def OnNumericDownButtonMouseUp(self, *args):
    258         ButtonIcon.OnMouseUp(self.downButton, *args)
    259         self.KillNumericInputThread()
    260 
    261     def UpdateNumericInputThread(self, diff):
    262         sleepTime = 500
    263         while uicore.uilib.leftbtn:
    264             self.ChangeNumericValue(diff)
    265             blue.synchro.SleepWallclock(sleepTime)
    266             sleepTime -= 0.5 * sleepTime
    267             sleepTime = max(10, sleepTime)
    268 
    269     def OnMouseWheel(self, *args):
    270         if self.readonly:
    271             return
    272         PlaySound(uiconst.SOUND_VALUECHANGE_TICK)
    273         if platform.system() == 'Darwin':
    274             self.ChangeNumericValue(uicore.uilib.dz / 120.0)
    275         else:
    276             self.ChangeNumericValue((uicore.uilib.dz / 120) ** 3)
    277 
    278     def ChangeNumericValue(self, val):
    279         self.BlinkButtons(val)
    280         self.ClampMinMaxValue(val)
    281 
    282     def GetValue(self, *args, **kwargs):
    283         if not self.text:
    284             return self.minValue or 0
    285         elif self.text == self.HYPHEN:
    286             return 0
    287         else:
    288             try:
    289                 value = self.dataType(self.text)
    290             except ValueError:
    291                 return 0
    292 
    293             return value
    294 
    295     def ValidateNegativeInput(self, text, caretIndex):
    296         newvalue = self.text[:caretIndex] + text + self.text[caretIndex:]
    297         if text == self.HYPHEN:
    298             if newvalue != self.HYPHEN:
    299                 newvalue = self.FilterIllegalChars(newvalue)
    300                 try:
    301                     self.dataType(newvalue)
    302                 except ValueError:
    303                     sys.exc_clear()
    304                     raise ValueError
    305 
    306         elif abs(self.dataType(newvalue)) >= sys.maxsize:
    307             raise ValueError
    308 
    309     def BlinkButtons(self, val):
    310         if not self.numericControlsCont:
    311             return
    312         if val > 0:
    313             self.upButton.Blink(0.2)
    314         else:
    315             self.downButton.Blink(0.2)
    316 
    317     def ClampMinMaxValue(self, change = 0):
    318         current = 0
    319         try:
    320             current = self.dataType(self.text)
    321         except ValueError:
    322             sys.exc_clear()
    323 
    324         newText = repr(current + change)
    325         text = self.CheckBounds(newText)
    326         self.SetText(text)
    327         self.SendCaretToEnd()
    328         self.ClearSelection()
    329         self.OnTextChange()
    330 
    331     def GetMenu(self):
    332         m = super(BaseSingleLineEditNumbers, self).GetMenu()
    333         if self.displayHistory:
    334             m += [(MenuLabel('/Carbon/UI/Controls/Common/ClearHistory'), self.ClearHistory, (None,))]
    335         return m
    336 
    337     def OnKillFocus(self, *args):
    338         ret = self.CheckBounds(self.text, allowEmpty=bool(self.hintText), returnNoneIfOK=True)
    339         if ret is not None:
    340             if ret <= self.minValue:
    341                 self.SetValue(self.minValue)
    342         super(BaseSingleLineEditNumbers, self).OnKillFocus(*args)