tooltips.py (22573B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\tooltips.py 2 import blue 3 from carbon.common.script.util.timerstuff import AutoTimer 4 from carbonui import TextColor, uiconst 5 from carbonui.text.styles import TextHeader, TextBody, TextDetail 6 from carbonui.control.contextMenu.menuUtil import GetContextMenuOwner 7 from carbonui.primitives.container import Container 8 from carbonui.primitives.containerAutoSize import ContainerAutoSize 9 from carbonui.primitives.fill import Fill 10 from carbonui.primitives.sprite import Sprite 11 from carbonui.uicore import uicore 12 from eve.client.script.ui import eveColor 13 from carbonui.control.buttonIcon import ButtonIcon 14 from eve.client.script.ui.control.infoIcon import InfoIcon 15 from eve.client.script.ui.control.eveLabel import EveCaptionSmall, EveLabelLarge, EveLabelMedium, EveLabelSmall, EveCaptionMedium, EveCaptionLarge 16 from eve.client.script.ui.control.pointerPanel import PointerPanel, FrameWithPointer, FadeOutPanelAndClose, RefreshPanelPosition 17 COLOR_NUMBERVALUE = TextColor.SECONDARY 18 COLOR_NUMBERVALUE_NEGATIVE = eveColor.HOT_RED 19 COLOR_NUMBERVALUE_POSITIVE = eveColor.SUCCESS_GREEN 20 SLEEPTIME_EXTEND = 1000 21 SLEEPTIME_EXTENDFAST = 10 22 SLEEPTIME_TIMETOLIVE = 50 23 SLEEPTIME_TIMETOLIVE_EDITABLE = 300 24 25 class ShortcutHint(Container): 26 default_align = uiconst.TOPRIGHT 27 28 def ApplyAttributes(self, attributes): 29 Container.ApplyAttributes(self, attributes) 30 bgColor = attributes.get('bgColor', (1, 1, 1, 0.1)) 31 Fill(bgParent=self, color=bgColor) 32 textColor = attributes.get('textColor', TextColor.SECONDARY) 33 self.textLabel = EveLabelMedium(align=uiconst.CENTER, parent=self, text=attributes.text, bold=True, color=textColor) 34 self.AdjustSize() 35 36 def AdjustSize(self): 37 width = self.textLabel.width + 8 38 self.width = width - width % 16 + 16 39 self.height = self.textLabel.height 40 41 42 class TooltipGeneric(Container): 43 pointerSize = 9 44 beingDestroyed = None 45 scaleTransform = None 46 default_pointerDirection = uiconst.POINT_BOTTOM_2 47 horizontal_padding = 16 48 vertical_padding = 16 49 50 def ApplyAttributes(self, attributes): 51 attributes.align = uiconst.NOALIGN 52 Container.ApplyAttributes(self, attributes) 53 self.pointerDirection = attributes.get('pointerDirection', self.default_pointerDirection) 54 self.backgroundFrame = FrameWithPointer(bgParent=self) 55 self.textLabel = EveLabelMedium(align=uiconst.TOPLEFT, width=200, autoFitToText=True, parent=self, left=self.horizontal_padding, top=self.vertical_padding) 56 57 def SetTooltipString(self, tooltipString, owner): 58 if not tooltipString and self.opacity: 59 self.display = False 60 return 61 self.textLabel.text = tooltipString 62 self.owner = owner 63 self.pos = (0, 64 0, 65 uicore.ReverseScaleDpi(self.textLabel.actualTextWidth) + 2 * self.horizontal_padding, 66 uicore.ReverseScaleDpi(self.textLabel.actualTextHeight) + 2 * self.vertical_padding) 67 RefreshPanelPosition(self) 68 69 @apply 70 def left(): 71 doc = 'x-coordinate of UI element' 72 73 def fget(self): 74 return self._left 75 76 def fset(self, value): 77 self._left = value 78 self.displayX = uicore.ScaleDpiF(self._left) 79 ro = self.renderObject 80 if ro: 81 ro.displayX = self._displayX 82 83 return property(**locals()) 84 85 @apply 86 def top(): 87 doc = 'y-coordinate of UI element' 88 89 def fget(self): 90 return self._top 91 92 def fset(self, value): 93 self._top = value 94 self.displayY = uicore.ScaleDpiF(self._top) 95 ro = self.renderObject 96 if ro: 97 ro.displayY = self._displayY 98 99 return property(**locals()) 100 101 @apply 102 def pos(): 103 doc = 'Position of UI element' 104 105 def fget(self): 106 return (self._left, 107 self._top, 108 self._width, 109 self._height) 110 111 def fset(self, value): 112 left, top, width, height = value 113 doFlag = self._width != width or self._height != height 114 self._left = left 115 self._top = top 116 self._width = width 117 self._height = height 118 self.displayX = uicore.ScaleDpiF(self._left) 119 self.displayY = uicore.ScaleDpiF(self._top) 120 self.displayWidth = uicore.ScaleDpiF(self._width) 121 self.displayHeight = uicore.ScaleDpiF(self._height) 122 ro = self.renderObject 123 if ro: 124 ro.displayX = self._displayX 125 ro.displayY = self._displayY 126 ro.displayWidth = self._displayWidth 127 ro.displayHeight = self._displayHeight 128 if not self._constructingBase and doFlag: 129 self.FlagAlignmentDirty() 130 131 return property(**locals()) 132 133 def _SetDisplay(self, value): 134 if value != self._display: 135 self._display = value 136 ro = self.renderObject 137 if ro: 138 ro.display = value 139 140 def Close(self, *args): 141 if getattr(uicore.uilib, 'tooltipHandler', None): 142 now = blue.os.GetWallclockTime() 143 uicore.uilib.tooltipHandler.lastCloseTime = now 144 Container.Close(self, *args) 145 if getattr(self, 'debugFrame', None): 146 self.debugFrame.Close() 147 if self.scaleTransform: 148 self.scaleTransform.Close() 149 self.scaleTransform = None 150 151 152 class TooltipPanel(PointerPanel): 153 default_state = uiconst.UI_PICKCHILDREN 154 default_align = uiconst.TOPLEFT 155 default_opacity = 0.0 156 default_cellClipChildren = False 157 158 def Close(self, *args): 159 if getattr(uicore.uilib, 'tooltipHandler', None) and len(self.children): 160 now = blue.os.GetWallclockTime() 161 uicore.uilib.tooltipHandler.lastCloseTime = now 162 if self.owner and getattr(self.owner, 'OnTooltipPanelClosed', None): 163 self.owner.OnTooltipPanelClosed() 164 PointerPanel.Close(self, *args) 165 166 def CloseWithFade(self, *args): 167 if getattr(uicore.uilib, 'tooltipHandler', None) and len(self.children): 168 now = blue.os.GetWallclockTime() 169 uicore.uilib.tooltipHandler.lastCloseTime = now 170 FadeOutPanelAndClose(self) 171 172 def ShowPanel(self, owner): 173 PointerPanel.ShowPanel(self, owner) 174 if hasattr(owner, 'LoadExtendedTooltipPanel'): 175 alt = uicore.uilib.Key(uiconst.VK_MENU) 176 if alt: 177 expandSleeptime = SLEEPTIME_EXTENDFAST 178 else: 179 expandSleeptime = SLEEPTIME_EXTEND 180 self.expandTimer = AutoTimer(expandSleeptime, self.ExpandTooltipPanel, owner) 181 if self.pickState == uiconst.TR2_SPS_ON: 182 timeToLive = SLEEPTIME_TIMETOLIVE_EDITABLE 183 else: 184 timeToLive = SLEEPTIME_TIMETOLIVE 185 if self.owner and getattr(self.owner, 'OnTooltipPanelOpened', None): 186 self.owner.OnTooltipPanelOpened() 187 self.HoldTillMouseOutside(timeToLive) 188 if self.destroyed or self.beingDestroyed: 189 return 190 if self.opacity: 191 FadeOutPanelAndClose(self) 192 else: 193 self.Close() 194 195 def ExpandTooltipPanel(self, owner): 196 self.expandTimer = None 197 if self.destroyed or self.beingDestroyed: 198 return 199 if owner.destroyed: 200 return 201 owner.LoadExtendedTooltipPanel(self) 202 203 def HoldTillMouseOutside(self, graceTime): 204 lastOnTime = blue.os.GetWallclockTime() 205 radialMenuSvc = sm.GetService('radialmenu') 206 while not self.destroyed: 207 now = blue.os.GetWallclockTime() 208 if self.pickState == uiconst.TR2_SPS_ON: 209 contextMenuOwner = GetContextMenuOwner() 210 if contextMenuOwner and contextMenuOwner.IsUnder(self): 211 lastOnTime = now 212 blue.synchro.SleepWallclock(5) 213 continue 214 radialMenuOwner = radialMenuSvc.GetRadialMenuOwner() 215 if radialMenuOwner and radialMenuOwner.IsUnder(self): 216 lastOnTime = now 217 blue.synchro.SleepWallclock(5) 218 continue 219 mouseCapture = uicore.uilib.GetMouseCapture() 220 if mouseCapture and mouseCapture.IsUnder(self): 221 lastOnTime = now 222 blue.synchro.SleepWallclock(5) 223 continue 224 ownerPickable = self.IsOwnerPickable() 225 if not ownerPickable: 226 return False 227 mouseInside = self.IsMouseInside() 228 if mouseInside: 229 lastOnTime = now 230 blue.synchro.SleepWallclock(5) 231 continue 232 blue.synchro.SleepWallclock(1) 233 if self.destroyed: 234 return False 235 if lastOnTime and blue.os.TimeDiffInMs(lastOnTime, now) > graceTime: 236 return False 237 238 def IsOwnerPickable(self): 239 owner = self.owner 240 if not owner: 241 return False 242 prestate = owner.state 243 owner.state = uiconst.UI_NORMAL 244 try: 245 ol, ot, ow, oh = owner.GetAbsolute() 246 ol = uicore.ScaleDpiF(ol) 247 ot = uicore.ScaleDpiF(ot) 248 ow = uicore.ScaleDpiF(ow) 249 oh = uicore.ScaleDpiF(oh) 250 renderObject, pyObject = uicore.uilib.PickScreenPosition(int(ol + ow / 2), int(ot + oh / 2)) 251 if pyObject and pyObject.IsUnder(uicore.layer.menu): 252 return True 253 if pyObject is not owner: 254 pickRadius = uicore.ScaleDpiF(getattr(owner, 'pickRadius', 0.0)) 255 if pickRadius < 0.0: 256 pickRadius = min(ow, oh) / 2.0 257 if pickRadius > 0.0: 258 x_center = ol + ow / 2.0 259 y_center = ot + oh / 2.0 260 tryPick = ((x_center - pickRadius + 1, y_center), 261 (x_center + pickRadius - 1, y_center), 262 (x_center, y_center - pickRadius + 1), 263 (x_center, y_center + pickRadius - 1)) 264 else: 265 tryPick = ((ol + 1, ot + oh / 2), 266 (ol + ow - 1, ot + oh / 2), 267 (ol + ow / 2, ot + 1), 268 (ol + ow / 2, ot + oh - 1)) 269 hits = 0 270 for x, y in tryPick: 271 renderObject, pyObject = uicore.uilib.PickScreenPosition(int(x), int(y)) 272 if pyObject is owner: 273 hits += 1 274 if hits == 2: 275 return True 276 if pyObject and pyObject.IsUnder(uicore.layer.menu): 277 return True 278 279 finally: 280 owner.state = prestate 281 282 return pyObject is owner 283 284 def IsMouseInside(self): 285 if self.destroyed: 286 return False 287 owner = self.owner 288 if not owner: 289 return False 290 mouseOver = uicore.uilib.mouseOver 291 if mouseOver is owner: 292 return True 293 if mouseOver is self or mouseOver.IsUnder(self): 294 return True 295 focus = uicore.registry.GetFocus() 296 if focus and focus.IsUnder(self): 297 return True 298 return False 299 300 def LoadTooltip(self, *args): 301 pass 302 303 def ExpandTooltip(self, owner): 304 self.expandTimer = None 305 if self.destroyed or self.beingDestroyed: 306 return 307 if owner.destroyed: 308 return 309 if hasattr(owner, 'LoadExtendedTooltipPanel'): 310 owner.LoadExtendedTooltipPanel(self) 311 312 def AddCommandTooltip(self, command): 313 label = command.GetName() 314 shortcutStr = command.GetShortcutAsString() 315 l = self.AddLabelShortcut(label, shortcutStr) 316 detailedDescription = command.GetDetailedDescription() 317 d = None 318 if detailedDescription: 319 d = self.AddLabelMedium(text=detailedDescription, align=uiconst.TOPLEFT, wrapWidth=200, colSpan=self.columns, color=TextColor.SECONDARY) 320 return (l, d) 321 322 def AddShortcutCell(self, shortcut): 323 shortcutObj = ShortcutHint(text=shortcut) 324 self.AddCell(shortcutObj) 325 return shortcutObj 326 327 def AddLabelShortcut(self, label, shortcut, bold = True): 328 self.FillRow() 329 labelObj = self.AddLabelMedium(text=label, bold=bold, colSpan=self.columns - 1) 330 if shortcut: 331 shortcutObj = self.AddShortcutCell(shortcut) 332 else: 333 self.AddCell() 334 shortcutObj = None 335 return (labelObj, shortcutObj) 336 337 def AddLabelValue(self, label, value, valueColor = COLOR_NUMBERVALUE, wrapWidth = None, opacity = 1.0): 338 self.FillRow() 339 labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=True, cellPadding=(0, 0, 16, 0), opacity=opacity) 340 valueObj = self.AddLabelMedium(text=value, align=uiconst.CENTERRIGHT, color=valueColor, colSpan=self.columns - 1, wrapWidth=wrapWidth, opacity=opacity) 341 return (labelObj, valueObj) 342 343 def AddSpriteLabel(self, texturePath, label, labelColor = TextColor.NORMAL, bold = False, iconSize = 32, iconColor = Sprite.default_color, iconOffset = -5, labelOffset = 5, mainAlign = uiconst.CENTERLEFT, align = uiconst.TOLEFT, textAlign = uiconst.CENTERLEFT, **keywords): 344 mainContainer = ContainerAutoSize(align=mainAlign, height=iconSize, width=iconSize) 345 sprite = Sprite(parent=mainContainer, align=align, width=iconSize, height=iconSize, texturePath=texturePath, left=iconOffset, color=iconColor) 346 labelCont = ContainerAutoSize(parent=mainContainer, align=align, height=iconSize) 347 label = EveLabelMedium(parent=labelCont, text=label, color=labelColor, bold=bold, align=textAlign, left=labelOffset, **keywords) 348 self.AddCell(mainContainer, **keywords) 349 return (sprite, label) 350 351 def AddIconLabel(self, icon, label, iconSize = 32, padBottom = 0, bold = True, iconColor = Sprite.default_color): 352 self.FillRow() 353 iconObj = Sprite(pos=(0, 354 0, 355 iconSize, 356 iconSize), align=uiconst.CENTERLEFT, color=iconColor) 357 iconObj.LoadIcon(icon, ignoreSize=True) 358 self.AddCell(iconObj, cellPadding=(-3, 359 0, 360 7, 361 padBottom)) 362 labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=bold, cellPadding=(0, 363 0, 364 7, 365 padBottom)) 366 return (iconObj, labelObj) 367 368 def AddIconLabelValue(self, icon, label, value, valueColor = COLOR_NUMBERVALUE, iconSize = 32): 369 self.FillRow() 370 iconObj = Sprite(pos=(0, 371 0, 372 iconSize, 373 iconSize), align=uiconst.CENTERLEFT) 374 iconObj.LoadIcon(icon, ignoreSize=True) 375 self.AddCell(iconObj, cellPadding=(-3, 0, 3, 0)) 376 labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=True, cellPadding=(0, 0, 7, 0)) 377 valueObj = self.AddLabelMedium(align=uiconst.CENTERRIGHT, bold=True, color=valueColor, top=1, colSpan=self.columns - 2, cellPadding=(7, 0, 0, 0)) 378 return (iconObj, labelObj, valueObj) 379 380 def AddButtonLabelValue(self, name, buttonTexturePath, buttonFunc = None, buttonArgs = None, buttonSize = 32, buttonOpacity = 1.0, label = '', valueColor = COLOR_NUMBERVALUE): 381 self.FillRow() 382 buttonObj = ButtonIcon(name='%s_icon' % name, texturePath=buttonTexturePath, align=uiconst.CENTERLEFT, pos=(0, 383 0, 384 buttonSize, 385 buttonSize), state=uiconst.UI_NORMAL, func=buttonFunc, args=buttonArgs, iconSize=buttonSize, colorType=uiconst.COLORTYPE_UIHILIGHT) 386 cell = self.AddCell(buttonObj, cellPadding=(0, 0, 0, 0)) 387 labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=False, cellPadding=(4, 0, 7, 0)) 388 valueObj = self.AddLabelMedium(align=uiconst.CENTERRIGHT, bold=True, color=valueColor, top=0, colSpan=self.columns - 2, cellPadding=(7, 0, 0, 0)) 389 return (cell, 390 buttonObj, 391 labelObj, 392 valueObj) 393 394 def AddDivider(self, color = TextColor.DISABLED, cellPadding = None): 395 self.FillRow() 396 divider = Fill(align=uiconst.TOTOP, state=uiconst.UI_DISABLED, color=color, height=1, padding=(0, 3, 0, 3)) 397 self.AddCell(divider, colSpan=self.columns, cellPadding=cellPadding) 398 return divider 399 400 def AddSpacer(self, width = 0, height = 0, colSpan = 1, rowSpan = 1): 401 spacer = Fill(align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, width=width, height=height, opacity=0.0) 402 self.AddCell(spacer, colSpan=colSpan, rowSpan=rowSpan) 403 return spacer 404 405 def AddLabelSmall(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 406 if wrapWidth: 407 keywords['width'] = wrapWidth 408 keywords['autoFitToText'] = True 409 label = EveLabelSmall(state=state, **keywords) 410 self.AddCell(label, **keywords) 411 return label 412 413 def AddLabelMedium(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 414 if wrapWidth: 415 keywords['width'] = wrapWidth 416 keywords['autoFitToText'] = True 417 label = EveLabelMedium(state=state, **keywords) 418 self.AddCell(label, **keywords) 419 return label 420 421 def AddLabelLarge(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 422 if wrapWidth: 423 keywords['width'] = wrapWidth 424 keywords['autoFitToText'] = True 425 label = EveLabelLarge(state=state, **keywords) 426 self.AddCell(label, **keywords) 427 return label 428 429 def AddCaptionSmall(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 430 if wrapWidth: 431 keywords['width'] = wrapWidth 432 keywords['autoFitToText'] = True 433 label = EveCaptionSmall(state=state, **keywords) 434 self.AddCell(label, **keywords) 435 return label 436 437 def AddCaptionMedium(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 438 if wrapWidth: 439 keywords['width'] = wrapWidth 440 keywords['autoFitToText'] = True 441 label = EveCaptionMedium(state=state, **keywords) 442 self.AddCell(label, **keywords) 443 return label 444 445 def AddCaptionLarge(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 446 if wrapWidth: 447 keywords['width'] = wrapWidth 448 keywords['autoFitToText'] = True 449 label = EveCaptionLarge(state=state, **keywords) 450 self.AddCell(label, **keywords) 451 return label 452 453 def AddInfoIcon(self, typeID = None, itemID = None, align = uiconst.TOPRIGHT, **keywords): 454 infoIcon = InfoIcon(typeID=typeID, itemID=itemID, align=align, left=0, top=0) 455 self.AddCell(infoIcon, **keywords) 456 return infoIcon 457 458 def AddMediumHeader(self, labelColSpan = None, **keywords): 459 row = self.AddHeaderRow() 460 label = EveLabelMedium(**keywords) 461 row.AddCell(label, colSpan=(labelColSpan or self.columns), **keywords) 462 self.FillRow() 463 return (row, label) 464 465 def AddTextDetailsLabel(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 466 if wrapWidth: 467 keywords['width'] = wrapWidth 468 keywords['autoFitToText'] = True 469 label = TextDetail(state=state, **keywords) 470 self.AddCell(label, **keywords) 471 return label 472 473 def AddTextBodyLabel(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 474 if wrapWidth: 475 keywords['width'] = wrapWidth 476 keywords['autoFitToText'] = True 477 label = TextBody(state=state, **keywords) 478 self.AddCell(label, **keywords) 479 return label 480 481 def AddTextHeaderLabel(self, state = uiconst.UI_DISABLED, wrapWidth = None, **keywords): 482 if wrapWidth: 483 keywords['width'] = wrapWidth 484 keywords['autoFitToText'] = True 485 label = TextHeader(state=state, **keywords) 486 self.AddCell(label, **keywords) 487 return label 488 489 def AddTextBodyHeading(self, state = uiconst.UI_DISABLED, wrapWidth = None, labelColSpan = None, **keywords): 490 if wrapWidth: 491 keywords['width'] = wrapWidth 492 keywords['autoFitToText'] = True 493 row = self.AddHeaderRow() 494 label = TextBody(state=state, **keywords) 495 row.AddCell(label, colSpan=(labelColSpan or self.columns), **keywords) 496 self.FillRow() 497 return (row, label) 498 499 def AddHeaderRow(self): 500 self.FillRow() 501 row = self.AddRow(cellPadding=(11, 9)) 502 Fill(bgParent=row, color=(1, 1, 1, 0.1)) 503 return row 504 505 def LoadGeneric1ColumnTemplate(self): 506 self.columns = 1 507 self.LoadStandardSpacingOld() 508 509 def LoadGeneric2ColumnTemplate(self): 510 self.columns = 2 511 self.LoadStandardSpacingOld() 512 513 def LoadGeneric3ColumnTemplate(self): 514 self.columns = 3 515 self.LoadStandardSpacingOld() 516 517 def LoadGeneric4ColumnTemplate(self): 518 self.columns = 4 519 self.LoadStandardSpacingOld() 520 521 def LoadGeneric5ColumnTemplate(self): 522 self.columns = 5 523 self.LoadStandardSpacingOld() 524 525 def LoadStandardSpacingOld(self): 526 self.margin = (16, 16, 16, 16) 527 self.cellPadding = 0 528 self.cellSpacing = (8, 8) 529 530 def LoadStandardSpacing(self): 531 self.margin = (16, 16, 16, 16) 532 self.cellPadding = (8, 0) 533 self.cellSpacing = (0, 8) 534 535 def SetSpacing(self, margin = (16, 16, 16, 16), cellPadding = (8, 0), cellSpacing = (0, 8)): 536 self.margin = margin 537 self.cellPadding = cellPadding 538 self.cellSpacing = cellSpacing 539 540 541 class TooltipPersistentPanel(TooltipPanel): 542 picktestEnabled = True 543 checkIfBlocked = False 544 545 def ApplyAttributes(self, attributes): 546 TooltipPanel.ApplyAttributes(self, attributes) 547 548 def DisablePickTest(self): 549 self.picktestEnabled = False 550 551 def HoldTillMouseOutside(self, graceTime): 552 while not self.destroyed and self.owner and not self.owner.destroyed: 553 if self.picktestEnabled: 554 ownerPickable = self.IsOwnerPickable() 555 if not ownerPickable: 556 self.opacity = 0.0 557 else: 558 self.opacity = 1.0 559 blue.synchro.SleepWallclock(5) 560 561 def IsMouseInside(self): 562 return True 563 564 def Close(self, *args): 565 PointerPanel.Close(self, *args)