baseSingleLineEdit.py (41652B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\singlelineedits\baseSingleLineEdit.py 2 import weakref 3 import logging 4 import sys 5 import blue 6 import evetypes 7 import mathext 8 import trinity 9 import uthread 10 from brennivin.itertoolsext import Bundle 11 from carbonui.button import styling 12 from carbonui.button.const import HEIGHT_NORMAL 13 from carbonui.control.combo import Combo 14 from carbonui.control.singlelineedits.caret import Caret 15 from carbonui.control.singlelineedits.singleLineEditHistory import SingleLineEditHistory, HistoryData 16 from carbonui.fontconst import DEFAULT_FONTSIZE 17 from carbonui.primitives.containerAutoSize import ContainerAutoSize 18 from carbonui.primitives.sprite import Sprite 19 from carbonui.text.settings import check_convert_font_size 20 from eve.client.script.ui import eveThemeColor 21 from carbon.common.script.util.commonutils import StripTags 22 from carbon.common.script.util.timerstuff import AutoTimer 23 from carbonui import Density, uiconst, Align 24 from carbonui.control.label import LabelOverride as Label 25 from carbonui.primitives.container import Container 26 from carbonui.primitives.fill import Fill 27 from carbonui.text.color import TextColor 28 from carbonui.uianimations import animations 29 from carbonui.uicore import uicore 30 from carbonui.util.various_unsorted import GetBrowser, GetWindowAbove, GetClipboardData 31 from carbonui.control.buttonIcon import ButtonIcon 32 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveLabelSmall 33 from carbonui.control.window import Window 34 from carbonui.decorative.inputUnderlay import InputUnderlay 35 from eve.client.script.ui.shared.market import GetTypeIDFromDragItem 36 from eve.client.script.ui.tooltips.tooltipUtil import RefreshTooltipForOwner 37 from eve.client.script.ui.util.linkUtil import GetItemIDFromTextLink 38 from menu import MenuLabel 39 from qtyTooltip.tooltip import LoadTooltipForNumber 40 from carbonui.control.singlelineedits.util import GetDroppedCharCorpOrAllianceName, GetDroppedCharInfo 41 logger = logging.getLogger(__name__) 42 CARET_SCROLL_MARGIN = 16 43 44 class BaseSingleLineEdit(Container): 45 default_name = 'BaseSingleLineEdit' 46 default_align = uiconst.TOPLEFT 47 default_width = 160 48 default_height = HEIGHT_NORMAL 49 default_state = uiconst.UI_NORMAL 50 default_density = Density.NORMAL 51 default_readonly = False 52 default_autoselect = False 53 default_dynamicHistoryWidth = False 54 default_caretcolor = eveThemeColor.THEME_ACCENT 55 default_selectioncolor = tuple(eveThemeColor.THEME_FOCUSDARK[:3]) + (0.4,) 56 default_fontcolor = TextColor.NORMAL 57 default_textLeftMargin = 0 58 default_textRightMargin = 0 59 default_bold = False 60 default_inputType = None 61 default_adjustWidth = False 62 default_label = '' 63 default_setvalue = '' 64 default_icon = None 65 default_OnChange = None 66 default_OnSetFocus = None 67 default_OnFocusLost = None 68 default_OnReturn = None 69 default_OnInsert = None 70 default_fontsize = DEFAULT_FONTSIZE 71 default_fontStyle = None 72 default_fontFamily = None 73 default_fontPath = None 74 default_fadeOutContent = True 75 default_displayHistory = True 76 registerHistory = True 77 78 def ApplyAttributes(self, attributes): 79 super(BaseSingleLineEdit, self).ApplyAttributes(attributes) 80 self.rightAlignedButtons = weakref.WeakSet() 81 self._clearButton = None 82 self.caretIndex = (0, 0) 83 self.isTabStop = 1 84 self.selFrom = None 85 self.selTo = None 86 self.historyMenu = None 87 self.displayHistory = attributes.get('displayHistory', self.default_displayHistory) 88 self.caret = None 89 self.selectionTimer = None 90 self.underlay = None 91 self.textLabel = None 92 self.hintLabel = None 93 self.selectionFill = None 94 self.draggedValue = None 95 self._textClipperInner = None 96 self.iconSprite = None 97 self.OnChange = None 98 self.OnFocusLost = None 99 self.OnReturn = None 100 self.OnInsert = None 101 self.text = attributes.get('text', '') 102 self.hintText = attributes.get('hintText', '') 103 self.readonly = attributes.get('readonly', self.default_readonly) 104 self.fontStyle = attributes.get('fontStyle', self.default_fontStyle) 105 self.fontFamily = attributes.get('fontFamily', self.default_fontFamily) 106 self.fontPath = attributes.get('fontPath', self.default_fontPath) 107 self.fontsize = attributes.get('fontsize', self.default_fontsize) 108 self.bold = attributes.get('bold', self.default_bold) 109 self.textLeftMargin = attributes.get('textLeftMargin', self.default_textLeftMargin) 110 self.textRightMargin = attributes.get('textRightMargin', self.default_textRightMargin) 111 self.icon = attributes.get('icon', self.default_icon) 112 self.CaretColor = attributes.get('caretColor', self.default_caretcolor) 113 self.SelectColor = attributes.get('selectColor', self.default_selectioncolor) 114 self.fontcolor = attributes.get('fontcolor', self.default_fontcolor) 115 self.autoselect = attributes.get('autoselect', self.default_autoselect) 116 self.dynamicHistoryWidth = attributes.get('dynamicHistoryWidth', self.default_dynamicHistoryWidth) 117 self.inputType = attributes.get('inputType', self.default_inputType) 118 self.isTypeField = attributes.get('isTypeField', False) 119 self.isCharacterField = attributes.get('isCharacterField', False) 120 self.isCharCorpOrAllianceField = attributes.get('isCharCorpOrAllianceField', False) 121 self.isLocationField = attributes.get('isLocationField', False) 122 self.OnAnyChar = attributes.get('OnAnyChar', self.OnAnyChar) 123 self.adjustWidth = attributes.get('adjustWidth', self.default_adjustWidth) 124 self.fadeOutContent = attributes.get('fadeOutContent', self.default_fadeOutContent) 125 self.ConstructIcon() 126 self.ConstructTextClipper() 127 self.ConstructBackground() 128 self.ConstructLabels() 129 self.SetTextColor(self.fontcolor) 130 self.SetLabel(attributes.get('label', self.default_label)) 131 self.SetValue(attributes.get('setvalue', self.default_setvalue)) 132 self.CheckHintText() 133 self.OnChange = attributes.get('OnChange', self.default_OnChange) 134 self.__OnSetFocus = attributes.get('OnSetFocus', self.default_OnSetFocus) 135 self.OnFocusLost = attributes.get('OnFocusLost', self.default_OnFocusLost) 136 self.OnReturn = attributes.get('OnReturn', self.default_OnReturn) 137 self.OnInsert = attributes.get('OnInsert', self.default_OnInsert) 138 self.sendSelfAsArgument = attributes.get('sendSelfAsArgument', False) 139 self.density = attributes.get('density', self.default_density) 140 if self.GetAlign() == uiconst.TOALL: 141 self.height = self.width = 0 142 else: 143 self.height = styling.get_height(self.density) 144 uicore.event.RegisterForTriuiEvents(uiconst.UI_MOUSEDOWN, self.OnGlobalMouseDownCallback) 145 146 def ConstructIcon(self): 147 if self.icon: 148 if not self.iconSprite: 149 iconCont = ContainerAutoSize(name='iconCont', parent=self, align=uiconst.TOLEFT, padLeft=8) 150 self.iconSprite = Sprite(name='iconSprite', parent=iconCont, align=Align.CENTERLEFT, color=TextColor.SECONDARY, pos=(0, 0, 16, 16)) 151 self.iconSprite.SetTexturePath(self.icon) 152 else: 153 self.iconSprite = None 154 155 def ConstructTextClipper(self): 156 self._textClipper = Container(name='_textClipper', parent=self, clipChildren=False, padding=(8, 0, 8, 0)) 157 self._textClipperInner = Container(parent=self._textClipper, align=uiconst.TOALL, clipChildren=True) 158 self._textClipper._OnSizeChange_NoBlock = self.OnClipperSizeChange 159 160 def ConstructBackground(self): 161 if self.underlay: 162 return 163 self.underlay = InputUnderlay(bgParent=self) 164 165 def ConstructLabels(self): 166 self.textLabel = EveLabelMedium(name='textLabel', parent=self._textClipperInner, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, left=self.textLeftMargin, text='', maxLines=1) 167 self.hintLabel = Label(name='hintTextLabel', parent=self._textClipperInner, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, left=self.textLeftMargin, text='', maxLines=1, color=TextColor.SECONDARY) 168 169 def ConstructCaret(self): 170 if self.caret or not hasattr(self, 'caret'): 171 return 172 self.caret = Caret(name='caret', parent=self._textClipper, align=uiconst.CENTERLEFT, idx=0, state=uiconst.UI_HIDDEN, left=self.textLeftMargin, height=1) 173 174 def ConstructSelectionFill(self): 175 _, h = self.GetAbsoluteSize() 176 order = self.textLabel.GetOrder() 177 if self.selectionFill: 178 return 179 self.selectionFill = Fill(name='selectionFill', parent=self._textClipperInner, align=uiconst.CENTERLEFT, idx=order + 1, color=self.SelectColor) 180 181 def SetLabel(self, text): 182 self.label = EveLabelSmall(parent=self, name='__caption', text=text, state=uiconst.UI_DISABLED, align=uiconst.TOPLEFT, idx=0) 183 self.label.top = -self.label.textheight 184 if self.adjustWidth: 185 self.width = max(self.width, self.label.textwidth) 186 187 def SetHistoryVisibility(self, status): 188 self.displayHistory = status 189 190 def SetTextColor(self, color): 191 if not color: 192 return 193 self.textLabel.SetRGBA(*color) 194 195 def SetHintText(self, hint): 196 self.hintText = hint 197 self.CheckHintText() 198 199 def OnClipperSizeChange(self, newWidth, newHeight): 200 if newWidth: 201 self.RefreshCaretPosition() 202 self.RefreshSelectionDisplay() 203 self.RefreshTextClipper() 204 205 def RefreshCaretPosition(self): 206 if self.destroyed: 207 return 208 self.ConstructCaret() 209 w, h = self._textClipper.GetAbsoluteSize() 210 self.caret.left = self.textLabel.left + self.caretIndex[1] 211 if self.textLabel.textwidth < w - self.textLeftMargin - self.textRightMargin: 212 self.textLabel.left = self.textLeftMargin 213 else: 214 if self.textLabel.left + self.textLabel.textwidth < w - self.textLeftMargin - self.textRightMargin: 215 self.textLabel.left = w - self.textLeftMargin - self.textRightMargin - self.textLabel.textwidth 216 if self.caret.left > w - self.textRightMargin - CARET_SCROLL_MARGIN: 217 diff = self.caret.left - w + self.textRightMargin + CARET_SCROLL_MARGIN 218 self.textLabel.left = max(self.textLabel.left - diff, w - self.textLabel.textwidth) 219 elif self.caret.left < self.textLeftMargin + CARET_SCROLL_MARGIN: 220 diff = -self.caret.left + self.textLeftMargin + CARET_SCROLL_MARGIN 221 self.textLabel.left = min(self.textLabel.left + diff, 0) 222 self.caret.left = mathext.clamp(value=self.textLabel.left + self.caretIndex[1], low=0, high=w - self.caret.width) 223 224 def RefreshSelectionDisplay(self): 225 selection = self.GetSelectionBounds() 226 if selection != (None, None): 227 self.ConstructSelectionFill() 228 f, t = selection 229 self.selectionFill.left = self.textLabel.left + f[1] 230 self.selectionFill.width = t[1] - f[1] 231 self.selectionFill.state = uiconst.UI_DISABLED 232 fontSize = check_convert_font_size(self.fontsize) 233 self.selectionFill.height = fontSize + 4 234 elif self.selectionFill: 235 self.selectionFill.state = uiconst.UI_HIDDEN 236 237 def GetSelectionBounds(self): 238 if self.selFrom and self.selTo and self.selFrom[0] != self.selTo[0]: 239 return (min(self.selFrom, self.selTo), max(self.selFrom, self.selTo)) 240 return (None, None) 241 242 def RefreshTextClipper(self): 243 if self._clearButton: 244 if len(self.text) >= self._clearButton.showOnLetterCount: 245 self._clearButton.Show() 246 else: 247 self._clearButton.Hide() 248 visible_button_count = 0 249 left = 5 250 for each in self.rightAlignedButtons: 251 if not each.destroyed and each.display: 252 visible_button_count += 1 253 each.left = left 254 left += each.width 255 256 if visible_button_count > 0: 257 left += 4 258 left = max(left, 8) 259 self._textClipper.padRight = left 260 if self.fadeOutContent: 261 w, h = self._textClipper.GetAbsoluteSize() 262 if self.textLabel.left + self.textLabel.textwidth > w: 263 self.textLabel.SetRightAlphaFade(-self.textLabel.left + w, 8) 264 else: 265 self.textLabel.SetRightAlphaFade(0, 0) 266 if self.textLabel.left < self.textLeftMargin: 267 self.textLabel.SetLeftAlphaFade(-self.textLabel.left + self.textLeftMargin, 8) 268 else: 269 self.textLabel.SetLeftAlphaFade(0, 0) 270 271 def ShowClearButton(self, icon = None, hint = None, showOnLetterCount = True): 272 if self._clearButton: 273 self._clearButton.Close() 274 icon = icon or 'res:/UI/Texture/Icons/73_16_210.png' 275 clearButton = self.AddIconButton(icon, hint) 276 clearButton.OnClick = self.OnClearButtonClick 277 clearButton.Hide() 278 clearButton.showOnLetterCount = showOnLetterCount 279 self._clearButton = clearButton 280 return clearButton 281 282 def OnGlobalMouseDownCallback(self, uiObject, *args, **kwds): 283 if self.destroyed: 284 return False 285 if uiObject is not self and self.historyMenu: 286 historyMenu = self.historyMenu() 287 if historyMenu and not historyMenu.destroyed: 288 if not uiObject.IsUnder(historyMenu): 289 self.CloseHistoryMenu() 290 return True 291 292 def AutoFitToText(self, text = None, minWidth = None): 293 if self.align in (uiconst.TOTOP, uiconst.TOBOTTOM, uiconst.TOALL): 294 raise RuntimeError('Incorrect alignment for SingleLine.AutoFitToText') 295 if text is not None: 296 textwidth, textheight = self.textLabel.MeasureTextSize(text) 297 autoWidth = textwidth + self.textLeftMargin * 2 + 2 298 else: 299 autoWidth = self.textLabel.textwidth + self.textLeftMargin * 2 + 2 300 if minWidth: 301 autoWidth = max(minWidth, autoWidth) 302 self.width = autoWidth 303 self.textLabel.left = self.textLeftMargin 304 305 def CloseHistoryMenu(self): 306 if self.historyMenu: 307 historyMenu = self.historyMenu() 308 if historyMenu and not historyMenu.destroyed: 309 self.active = None 310 historyMenu.Close() 311 self.historyMenu = None 312 313 def GetValid(self): 314 current = self.GetValue(registerHistory=False) 315 id, mine = self.GetHistory() 316 valid = [ HistoryData(each, each) for each in mine if each.lower().startswith(unicode(current).lower()) and each != current ] 317 valid.sort(key=lambda x: len(x.displayText)) 318 return valid 319 320 def ClearHistory(self, *args): 321 id, mine, all = self.GetHistory(getAll=True) 322 if id in all: 323 del all[id] 324 settings.user.ui.Set('editHistory', all) 325 326 def RegisterHistory(self, value = None): 327 if not self.registerHistory: 328 return 329 id, mine, all = self.GetHistory(getAll=True) 330 current = (value or self.text).rstrip() 331 if current not in mine: 332 mine.append(current) 333 all[id] = mine 334 settings.user.ui.Set('editHistory', all) 335 336 def AddIconButton(self, texturePath, hint = None): 337 rightAlignedButton = self._ConstructIconButton(hint, texturePath) 338 self.rightAlignedButtons.add(rightAlignedButton) 339 return rightAlignedButton 340 341 def _ConstructIconButton(self, hint, texturePath): 342 return ButtonIcon(texturePath=texturePath, pos=(0, 0, 16, 16), align=uiconst.CENTERRIGHT, parent=self, hint=hint, idx=0) 343 344 def OnChar(self, char, flag): 345 if self.OnAnyChar(char): 346 fontFamily = uicore.font.GetFontFamilyBasedOnClientLanguageID() 347 if fontFamily != self.textLabel.fontFamily: 348 self.textLabel.fontFamily = fontFamily 349 self.hintLabel.fontFamily = fontFamily 350 if char in [127, uiconst.VK_BACK]: 351 if self.GetSelectionBounds() != (None, None): 352 self.DeleteSelected() 353 else: 354 self.Delete(direction=False) 355 self.CheckHistory() 356 if self.OnInsert: 357 self.OnInsert(char, flag) 358 return True 359 if char != uiconst.VK_RETURN: 360 self.Insert(char) 361 self.CheckHistory() 362 if self.OnInsert: 363 self.OnInsert(char, flag) 364 return True 365 return False 366 367 def Confirm(self, *args): 368 if self.OnReturn: 369 self.CloseHistoryMenu() 370 if self.sendSelfAsArgument: 371 return uthread.new(self.OnReturn, self) 372 else: 373 return uthread.new(self.OnReturn) 374 searchFrom = GetWindowAbove(self) 375 if searchFrom: 376 wnds = [ w for w in searchFrom.Find('trinity.Tr2Sprite2dContainer') + searchFrom.Find('trinity.Tr2Sprite2d') if getattr(w, 'btn_default', 0) == 1 ] 377 if len(wnds): 378 for wnd in wnds: 379 if self == wnd: 380 continue 381 if wnd.IsVisible(): 382 if hasattr(wnd, 'OnClick'): 383 uthread.new(wnd.OnClick, wnd) 384 return True 385 386 return False 387 388 def OnKeyDown(self, vkey, flag): 389 isMac = sys.platform.startswith('darwin') 390 391 def k(win, mac): 392 if isMac: 393 return mac 394 return win 395 396 HOME = uiconst.VK_HOME 397 END = uiconst.VK_END 398 CTRL = uicore.uilib.Key(uiconst.VK_CONTROL) 399 ALT = uicore.uilib.Key(uiconst.VK_MENU) 400 CMD = uicore.uilib.Key(uiconst.VK_LWIN) 401 SHIFT = uicore.uilib.Key(uiconst.VK_SHIFT) 402 if self.destroyed: 403 return 404 oldCaretIndex = self.caretIndex 405 selection = self.GetSelectionBounds() 406 index = oldCaretIndex[0] 407 if SHIFT and vkey == uiconst.VK_DELETE: 408 wasDeleted = self.TryDeleteFromHistory() 409 if wasDeleted: 410 return 411 if vkey == uiconst.VK_LEFT and (not isMac or not CMD): 412 if k(win=CTRL, mac=ALT): 413 index = self.text.rfind(' ', 0, max(index - 1, 0)) + 1 or 0 414 else: 415 index = self.MoveIndexToLeft(index) 416 elif vkey == uiconst.VK_RIGHT and (not isMac or not CMD): 417 if k(win=CTRL, mac=ALT): 418 index = self.text.find(' ', index) + 1 or len(self.textLabel.text) 419 else: 420 index = self.MoveIndexToRight(index) 421 index = min(index, len(self.textLabel.text)) 422 elif vkey == HOME or isMac and vkey == uiconst.VK_LEFT and CMD: 423 index = 0 424 elif vkey == END or isMac and vkey == uiconst.VK_RIGHT and CMD: 425 index = len(self.textLabel.text) 426 elif vkey == uiconst.VK_DELETE: 427 if self.GetSelectionBounds() != (None, None): 428 self.DeleteSelected() 429 return 430 else: 431 self.Delete(direction=True) 432 return 433 else: 434 if vkey == uiconst.VK_UP: 435 self.OnUpKeyPressed() 436 elif vkey == uiconst.VK_DOWN: 437 self.OnDownKeyPressed() 438 else: 439 self.OnUnusedKeyDown(self, vkey, flag) 440 return 441 self.caretIndex = self.GetCursorFromIndex(index) 442 if vkey in (uiconst.VK_LEFT, 443 uiconst.VK_RIGHT, 444 HOME, 445 END): 446 if SHIFT: 447 if self.selTo is not None: 448 self.selTo = self.caretIndex 449 elif self.selTo is None: 450 self.selFrom = oldCaretIndex 451 self.selTo = self.caretIndex 452 elif selection != (None, None): 453 if vkey == uiconst.VK_LEFT: 454 index = selection[0][0] 455 elif vkey == uiconst.VK_RIGHT: 456 index = selection[1][0] 457 self.caretIndex = self.GetCursorFromIndex(index) 458 if not SHIFT or self.selFrom == self.selTo: 459 self.selFrom = self.selTo = None 460 self.CloseHistoryMenu() 461 self.RefreshCaretPosition() 462 self.RefreshSelectionDisplay() 463 self.RefreshTextClipper() 464 465 def TryDeleteFromHistory(self): 466 if not self.historyMenu: 467 return False 468 historyMenu = self.historyMenu() 469 if not historyMenu: 470 return False 471 selectedEntry = historyMenu.GetSelectedEntry() 472 return self.DeleteEntryFromHistory(selectedEntry) 473 474 def DeleteEntryFromHistory(self, selectedEntry): 475 historyMenu = self.historyMenu() 476 if not historyMenu: 477 return False 478 if not selectedEntry: 479 return False 480 currentText = historyMenu.GetTextEntered() 481 return self.DeleteFromHistory(currentText, selectedEntry.string) 482 483 def OnDownKeyPressed(self): 484 self.BrowseHistory(down=True) 485 486 def OnUpKeyPressed(self): 487 self.BrowseHistory(down=False) 488 489 def OnUnusedKeyDown(self, *args): 490 pass 491 492 def MoveIndexToRight(self, index): 493 index += 1 494 return index 495 496 def MoveIndexToLeft(self, index): 497 index = max(index - 1, 0) 498 return index 499 500 def _GetSizeForHistoryMenu(self): 501 return self.GetAbsolute() 502 503 def OnSetFocus(self, *args): 504 if self.pickState != uiconst.TR2_SPS_ON: 505 return 506 if not self.readonly and uicore.imeHandler: 507 uicore.imeHandler.SetFocus(self) 508 if self and not self.destroyed and self.parent and self.parent.name == 'inlines': 509 if self.parent.parent and getattr(self.parent.parent.sr, 'node', None): 510 browser = GetBrowser(self) 511 if browser: 512 uthread.new(browser.ShowObject, self) 513 self._OnSetFocus() 514 self.ShowCaret() 515 self.CheckHintText() 516 if self.autoselect: 517 self.SelectAll() 518 else: 519 self.RefreshSelectionDisplay() 520 if hasattr(self, '__OnSetFocus') and self.__OnSetFocus: 521 self.__OnSetFocus(*args) 522 523 def _OnSetFocus(self): 524 pass 525 526 def Cut(self, *args): 527 if self.GetSelectionBounds() != (None, None): 528 self.Copy() 529 self.DeleteSelected() 530 531 def Copy(self, selectStart = None, selectEnd = None): 532 if selectStart is not None and selectEnd is not None: 533 blue.pyos.SetClipboardData(self.text[selectStart:selectEnd]) 534 else: 535 start, end = self.GetSelectionBounds() 536 if not start and not end: 537 blue.pyos.SetClipboardData(self.text) 538 else: 539 blue.pyos.SetClipboardData(self.text[start[0]:end[0]]) 540 541 def Paste(self, paste, deleteStart = None, deleteEnd = None, forceFocus = False): 542 if deleteStart is None or deleteEnd is None: 543 start, end = self.GetSelectionBounds() 544 if start is not None and end is not None: 545 self.DeleteSelected() 546 else: 547 text = self.text 548 self.SetText(text[:deleteStart] + text[deleteEnd:]) 549 self.caretIndex = self.GetCursorFromIndex(deleteStart) 550 self.OnTextChange() 551 self.Insert(paste) 552 hadFocus = uicore.registry.GetFocus() is self 553 if (hadFocus or forceFocus) and not uicore.registry.GetFocus() == self: 554 uicore.registry.SetFocus(self) 555 556 def SelectAll(self): 557 self.selFrom = self.GetCursorFromIndex(0) 558 self.selTo = self.GetCursorFromIndex(-1) 559 self.RefreshSelectionDisplay() 560 561 def ShowCaret(self): 562 self.ConstructCaret() 563 self.RefreshCaretPosition() 564 fontSize = check_convert_font_size(self.fontsize) 565 self.caret.height = fontSize + 4 566 self.caret.state = uiconst.UI_DISABLED 567 self.caretTimer = AutoTimer(interval=uiconst.CARET_BLINK_INTERVAL_MS, method=self.BlinkCaret) 568 self.caret.SetRGBA(*self.CaretColor) 569 570 def HideCaret(self): 571 self.caretTimer = None 572 if self.caret: 573 self.caret.state = uiconst.UI_HIDDEN 574 575 def BlinkCaret(self): 576 if self.destroyed: 577 self.caretTimer = None 578 return 579 if self.caret: 580 if not trinity.app.IsActive(): 581 self.caret.state = uiconst.UI_HIDDEN 582 return 583 self.caret.state = [uiconst.UI_HIDDEN, uiconst.UI_DISABLED][self.caret.state == uiconst.UI_HIDDEN] 584 585 def SelectNone(self): 586 self.selFrom = (None, None) 587 self.selTo = (None, None) 588 self.RefreshSelectionDisplay() 589 590 def OnAnyChar(self, char, *args): 591 return True 592 593 def OnKillFocus(self, *args): 594 if not self.readonly and uicore.imeHandler: 595 uicore.imeHandler.KillFocus(self) 596 if self.autoselect: 597 self.SelectNone() 598 self.HideCaret() 599 self.CheckHintText() 600 self.CloseHistoryMenu() 601 self.ClearSelection() 602 if self.OnFocusLost: 603 uthread.new(self.OnFocusLost, self) 604 605 def Insert(self, text): 606 if self.readonly or text is None: 607 return 608 if not isinstance(text, basestring): 609 text = unichr(text) 610 text = text.replace(u'\r', u' ').replace(u'\n', u'') 611 if self.GetSelectionBounds() != (None, None): 612 self.DeleteSelected() 613 caretIndex = self.caretIndex[0] if self.caretIndex else 0 614 before = self.text[:caretIndex] 615 after = self.text[caretIndex:] 616 become = before + text + after 617 become = self._ValidateInsert(become) 618 self.autoselect = False 619 self.SetText(become) 620 if become != before: 621 newCaretIndex = caretIndex + max(len(text), 1) 622 self.caretIndex = self.GetCursorFromIndex(newCaretIndex) 623 self.OnTextChange() 624 625 def _ValidateInsert(self, insert): 626 return insert 627 628 def ShowHistoryMenu(self, history): 629 hadMenu = 0 630 if self.historyMenu and self.historyMenu(): 631 hadMenu = 1 632 self.CloseHistoryMenu() 633 if not history: 634 return 635 currentText = self.GetValue(registerHistory=False) 636 l, t, w, h = self._GetSizeForHistoryMenu() 637 mp = SingleLineEditHistory(parent=uicore.layer.menu, pos=(l, 638 t + h + 2, 639 w, 640 0), dynamicHistoryWidth=self.dynamicHistoryWidth, mouseDownFunc=self.HEMouseDown, mouseUpFunc=self.HEMouseUp, currentText=currentText, deleteHistoryEntryFunc=self.DeleteEntryFromHistory) 641 if not hadMenu: 642 mp.opacity = 0.0 643 self.PopulateHistoryMenu(mp, history) 644 self.historyMenu = weakref.ref(mp) 645 if not hadMenu: 646 animations.FadeIn(mp, duration=0.25) 647 648 def OnDblClick(self, *args): 649 self.caretIndex = self.GetIndexUnderCursor() 650 self.selFrom = self.GetCursorFromIndex(0) 651 self.selTo = self.caretIndex = self.GetCursorFromIndex(-1) 652 self.RefreshCaretPosition() 653 self.RefreshSelectionDisplay() 654 self.RefreshTextClipper() 655 656 def GetIndexUnderCursor(self): 657 l, t = self.textLabel.GetAbsolutePosition() 658 cursorXpos = uicore.uilib.x - l 659 return self.textLabel.GetIndexUnderPos(cursorXpos) 660 661 def PopulateHistoryMenu(self, menuParent, history): 662 historyFormatted = [] 663 for historyEntry in history: 664 removeable = True 665 if isinstance(historyEntry, tuple): 666 displayText = historyEntry[0] 667 editText = historyEntry[1] 668 elif isinstance(historyEntry, HistoryData): 669 displayText = historyEntry.displayText 670 editText = historyEntry.editText 671 removeable = historyEntry.removeable 672 else: 673 displayText = editText = historyEntry 674 b = Bundle(displayText=displayText, editText=editText, info=None, historyEntry=historyEntry, removeable=removeable) 675 historyFormatted.append(b) 676 677 menuParent.PopulateHistoryMenu(historyFormatted) 678 679 def BrowseHistory(self, down): 680 justopened = 0 681 if not (self.historyMenu and self.historyMenu()): 682 if not self.CheckHistory(): 683 return 684 justopened = 1 685 hm = self.historyMenu() 686 currentIdx = None 687 i = 0 688 for entry in hm.sr.entries.children: 689 if entry.selected: 690 currentIdx = i 691 entry.sr.hilite.state = uiconst.UI_HIDDEN 692 entry.selected = 0 693 i += 1 694 695 if justopened: 696 return 697 if currentIdx is None: 698 if down: 699 currentIdx = 0 700 else: 701 currentIdx = len(hm.sr.entries.children) - 1 702 elif down: 703 currentIdx += 1 704 if currentIdx >= len(hm.sr.entries.children): 705 currentIdx = 0 706 else: 707 currentIdx -= 1 708 if currentIdx < 0: 709 currentIdx = len(hm.sr.entries.children) - 1 710 self.active = active = hm.sr.entries.children[currentIdx] 711 active.sr.hilite.state = uiconst.UI_DISABLED 712 active.selected = 1 713 if not getattr(self, 'blockSetValue', 0): 714 self.SetValue(active.string) 715 716 def HEMouseDown(self, entry, mouseButton, *args): 717 if mouseButton == uiconst.MOUSELEFT: 718 self.SetValue(entry.string) 719 self.OnHistoryClick(entry.string) 720 721 def HEMouseUp(self, entry, mouseButton, *args): 722 if mouseButton == uiconst.MOUSELEFT: 723 self.CloseHistoryMenu() 724 725 def OnHistoryClick(self, clickedString, *args): 726 pass 727 728 def OnMouseUp(self, *args): 729 self.mouseDownCaretIndex = None 730 self.selectionTimer = None 731 732 def OnMouseDown(self, button, *etc): 733 if uicore.uilib.mouseTravel > 10: 734 return 735 gettingFocus = uicore.registry.GetFocus() != self 736 if gettingFocus: 737 uicore.registry.SetFocus(self) 738 leftClick = button == uiconst.MOUSELEFT 739 if uicore.uilib.Key(uiconst.VK_SHIFT): 740 if self.selFrom is None: 741 self.selFrom = self.caretIndex 742 self.selTo = self.caretIndex = self.GetIndexUnderCursor() 743 self.RefreshCaretPosition() 744 self.RefreshSelectionDisplay() 745 self.RefreshTextClipper() 746 elif leftClick: 747 self.caretIndex = self.mouseDownCaretIndex = self.GetIndexUnderCursor() 748 self.selFrom = None 749 self.selTo = None 750 self.RefreshCaretPosition() 751 self.RefreshSelectionDisplay() 752 self.RefreshTextClipper() 753 if self.autoselect and gettingFocus: 754 self.SelectAll() 755 else: 756 self.selectionTimer = AutoTimer(50, self.UpdateSelection) 757 758 def UpdateSelection(self): 759 oldCaretIndex = self.mouseDownCaretIndex 760 newCaretIndex = self.GetIndexUnderCursor() 761 self.selFrom = oldCaretIndex 762 self.selTo = newCaretIndex 763 self.caretIndex = newCaretIndex 764 self.RefreshCaretPosition() 765 self.RefreshSelectionDisplay() 766 self.RefreshTextClipper() 767 768 def CheckHistory(self): 769 if not self.displayHistory: 770 return 771 if self.readonly: 772 return 773 validHistoryEntries = self.GetValid() 774 if validHistoryEntries: 775 self.ShowHistoryMenu(validHistoryEntries[:5]) 776 return 1 777 self.CloseHistoryMenu() 778 return 0 779 780 def GetHistory(self, getAll = False): 781 historyID = self.GetHistoryID() 782 editHistory = settings.user.ui.Get('editHistory', {}) 783 suggestions = self.GetSuggestions() 784 if suggestions is None: 785 suggestions = editHistory.get(historyID, []) 786 if getAll: 787 return (historyID, suggestions, editHistory) 788 return (historyID, suggestions) 789 790 def GetHistoryID(self): 791 id = '' 792 item = self 793 while item.parent: 794 id = '/' + item.name + id 795 if isinstance(item, Window): 796 break 797 item = item.parent 798 799 return id 800 801 def GetSuggestions(self): 802 return None 803 804 def DeleteFromHistory(self, currentText, historyEntry): 805 _, history = self.GetHistory() 806 if historyEntry in history: 807 history.remove(historyEntry) 808 self.CloseHistoryMenu() 809 if not getattr(self, 'blockSetValue', 0): 810 self.SetValue(currentText) 811 self.CheckHistory() 812 return True 813 return False 814 815 def SetReadOnly(self, state): 816 self.readonly = state 817 818 def Delete(self, direction = True): 819 if self.readonly or self.text is None: 820 return 821 if not self.caretIndex: 822 logger.exception('BaseSingleLineEdit::Delete failed, caretIndex is None') 823 return 824 caretIndex = self.caretIndex[0] if self.caretIndex else 0 825 if direction: 826 begin = caretIndex 827 end = min(caretIndex + 1, len(self.textLabel.text)) 828 else: 829 begin = max(caretIndex - 1, 0) 830 end = caretIndex 831 newText = self.text[:begin] + self.text[end:] 832 self.SetText(newText) 833 newCaretIndex = begin 834 self.caretIndex = self.GetCursorFromIndex(newCaretIndex) 835 self.OnTextChange() 836 837 def DeleteSelected(self, inserting = False): 838 if self.readonly: 839 return 840 start, end = self.GetSelectionBounds() 841 self.ClearSelection() 842 text = self.text 843 newText = text[:start[0]] + text[end[0]:] 844 self.SetText(newText) 845 self.caretIndex = self.GetCursorFromIndex(start[0]) 846 self.OnTextChange() 847 848 def OnClearButtonClick(self): 849 self.Clear() 850 851 def OnClear(self): 852 pass 853 854 def SetValue(self, text, docallback = True): 855 self.draggedValue = None 856 if text is None: 857 return 858 text = self.SanitizeText(text) 859 self.SetText(text) 860 self.SendCaretToEnd() 861 self.ClearSelection() 862 self.OnTextChange(docallback) 863 864 def Clear(self, docallback = True): 865 self.SetText('') 866 self.SendCaretToEnd() 867 self.ClearSelection() 868 self.OnTextChange(docallback) 869 self.OnClear() 870 871 def SanitizeText(self, text): 872 isString = isinstance(text, basestring) 873 if isString: 874 text = StripTags(text, stripOnly=['localized']) 875 return text 876 877 def ClearSelection(self): 878 self.selFrom = self.selTo = None 879 self.RefreshSelectionDisplay() 880 881 def GetCursorFromIndex(self, index): 882 return self.textLabel.GetWidthToIndex(index) 883 884 def SendCaretToEnd(self): 885 self.caretIndex = self.GetCursorFromIndex(-1) 886 887 def SetText(self, text): 888 if not isinstance(text, basestring): 889 text = str(text) 890 text = StripTags(text, stripOnly=['localized']) 891 self.SetDisplayText(text.replace('<', '<').replace('>', '>')) 892 self.text = text 893 self.CheckHintText() 894 895 def SetDisplayText(self, text): 896 self.textLabel.SetText(text) 897 898 def OnTextChange(self, docallback = True): 899 self.CheckHintText() 900 self.RefreshCaretPosition() 901 self.RefreshTextClipper() 902 if docallback and self.OnChange: 903 self.OnChange(self.GetText()) 904 RefreshTooltipForOwner(self) 905 906 def CheckHintText(self): 907 if self.text: 908 self.hintLabel.display = False 909 elif uicore.registry.GetFocus() is self: 910 self.hintLabel.color = TextColor.DISABLED 911 self.hintLabel.display = True 912 else: 913 self.hintLabel.color = TextColor.SECONDARY 914 self.hintLabel.display = True 915 self.hintLabel.SetText(self.hintText) 916 917 def GetText(self): 918 return self.text 919 920 def GetValue(self, registerHistory = True): 921 if registerHistory: 922 self.RegisterHistory() 923 return self.text 924 925 def GetMenu(self): 926 m = [] 927 start, end = self.GetSelectionBounds() 928 if start is not None: 929 start = start[0] 930 if end is not None: 931 end = end[0] 932 m += [(MenuLabel('/Carbon/UI/Controls/Common/Copy'), self.Copy, (start, end))] 933 if not self.readonly: 934 paste = GetClipboardData() 935 if paste: 936 m += [(MenuLabel('/Carbon/UI/Controls/Common/Paste'), self.Paste, (paste, 937 start, 938 end, 939 True))] 940 return m 941 942 def OnDropData(self, dragObj, nodes): 943 if self.isTypeField: 944 self.OnDropType(dragObj, nodes) 945 elif self.isLocationField: 946 self.OnDropLocation(dragObj, nodes) 947 elif self.isCharCorpOrAllianceField: 948 self.OndDropCharCorpOrAlliance(dragObj, nodes) 949 elif self.isCharacterField: 950 self.OnDropCharacter(dragObj, nodes) 951 else: 952 super(BaseSingleLineEdit, self).OnDropData(dragObj, nodes) 953 954 def OnDropType(self, dragObj, nodes): 955 node = nodes[0] 956 guid = getattr(node, '__guid__', None) 957 if guid in ('xtriui.ShipUIModule', 'xtriui.InvItem', 'listentry.InvItem', 'listentry.InvAssetItem'): 958 typeID = getattr(node.item, 'typeID', None) 959 elif guid in ('listentry.GenericMarketItem', 'listentry.QuickbarItem', 'listentry.Item'): 960 typeID = getattr(node, 'typeID', None) 961 else: 962 typeID = GetTypeIDFromDragItem(node) 963 if typeID and evetypes.IsPublished(typeID): 964 typeName = evetypes.GetName(typeID) 965 self.SetValueAfterDragging(typeName, draggedValue=typeID) 966 967 def OnDropLocation(self, dragObj, nodes): 968 node = nodes[0] 969 guid = node.Get('__guid__', None) 970 locationItemID = None 971 itemID = GetItemIDFromTextLink(node, None) 972 if self._IsLocation(itemID): 973 locationItemID = itemID 974 elif guid in ('xtriui.ListSurroundingsBtn', 'listentry.LocationTextEntry', 'listentry.LabelLocationTextTop', 'listentry.LocationGroup', 'listentry.LocationSearchItem'): 975 if self._IsLocation(node.itemID): 976 locationItemID = node.itemID 977 if locationItemID: 978 self.SetValueAfterDragging(cfg.evelocations.Get(locationItemID).name, locationItemID) 979 980 def _IsLocation(self, itemID): 981 if not itemID: 982 return False 983 try: 984 cfg.evelocations.Get(itemID) 985 return True 986 except KeyError: 987 return False 988 989 def OnDropCharacter(self, dragObj, nodes): 990 charInfo = GetDroppedCharInfo(nodes[0]) 991 if charInfo is not None: 992 self.SetValueAfterDragging(charInfo.charName, charInfo.charID) 993 994 def OndDropCharCorpOrAlliance(self, dragObj, nodes): 995 itemInfo = GetDroppedCharCorpOrAllianceName(nodes[0]) 996 if itemInfo is not None: 997 self.SetValueAfterDragging(itemInfo.itemName, itemInfo.itemID) 998 999 def SetValueAfterDragging(self, name, draggedValue): 1000 self.SetValue(name) 1001 self.draggedValue = draggedValue 1002 1003 def LoadTooltipPanel(self, tooltipPanel, *args): 1004 normalHint = self.hint 1005 if self.inputType: 1006 return LoadTooltipForNumber(tooltipPanel, normalHint, self.text, self.inputType) 1007 1008 def Disable(self): 1009 super(BaseSingleLineEdit, self).Disable() 1010 self.opacity = 0.3 1011 1012 def Enable(self): 1013 super(BaseSingleLineEdit, self).Enable() 1014 self.opacity = 1.0 1015 1016 def SetMaxLength(self, newMaxLength): 1017 pass 1018 1019 def LoadCombo(self, id, options, callback = None, setvalue = None, comboIsTabStop = True): 1020 for each in self.children[:]: 1021 if each.name == 'combo': 1022 each.Close() 1023 1024 combo = Combo(parent=self, label='', options=options, name=id, select=setvalue, callback=self.OnComboChange, pos=(0, 0, 16, 16), align=uiconst.BOTTOMRIGHT) 1025 combo.sr.inputCallback = callback 1026 combo.isTabStop = comboIsTabStop 1027 combo.name = 'combo' 1028 combo.Confirm = self.ComboConfirm 1029 combo.Hide() 1030 self.sr.combo = combo 1031 comboButton = self.AddIconButton('res:/UI/Texture/Icons/38_16_229.png') 1032 comboButton.name = 'combo' 1033 comboButton.OnMouseDown = (self.ExpandCombo, combo) 1034 1035 def ExpandCombo(self, combo, *args, **kwds): 1036 if not combo._Expanded(): 1037 uthread.new(combo.Expand, self.GetAbsolute()) 1038 1039 def ComboConfirm(self, *args, **kwargs): 1040 if self.sr.combo and not self.sr.combo.destroyed: 1041 self.OnComboChange(self.sr.combo, self.sr.combo.GetKey(), self.sr.combo.GetValue()) 1042 self.sr.combo.Cleanup(setfocus=False) 1043 1044 def GetComboValue(self): 1045 if self.sr.combo: 1046 return self.sr.combo.GetValue() 1047 1048 def OnComboChange(self, combo, label, value, *args): 1049 self.SetValue(label) 1050 if combo.sr.inputCallback: 1051 combo.sr.inputCallback(combo, label, value) 1052 1053 def Close(self): 1054 self.CloseHistoryMenu() 1055 super(BaseSingleLineEdit, self).Close() 1056 1057 def get_absolute_caret_position(self): 1058 y = self.absoluteTop + 2 1059 x = self.absoluteLeft + self.caretIndex[1] - 1 + self.textLabel.left 1060 return (x, y)