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

uilib.py (47392B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\uilib.py
      2 import math
      3 import weakref
      4 import blue
      5 import log
      6 import telemetry
      7 import carbonui.const as uiconst
      8 import carbonui.control
      9 import evegraphics.settings as gfxsettings
     10 import trinity
     11 import uthread
     12 from carbon.common.script.sys.serviceConst import ROLE_GML
     13 from carbon.common.script.util.timerstuff import AutoTimer
     14 from carbonui.text.settings import font_shadow_enabled_setting
     15 from carbonui.util.weakrefutil import CallableWeakRef
     16 from eve.client.script.ui.services.uiColorSettings import show_window_bg_blur_setting
     17 from eveexceptions import UserError
     18 from logmodule import LogException
     19 from carbonui.mousesettings import CursorSize, cursor_size_setting
     20 DBLCLICKDELAY = 250.0
     21 CLICKCOUNTRESETTIME = 250
     22 HOVERTIME = 250
     23 
     24 def IsMacOS():
     25     import sys
     26     return sys.platform.startswith('darwin')
     27 
     28 
     29 class Uilib(object):
     30     __notifyevents__ = ['OnUIScalingChange',
     31      'OnSessionChanged',
     32      'OnGraphicSettingsChanged',
     33      'OnUIColorsChanged',
     34      'OnFontSizeChanged']
     35     UTHREADEDEVENTS = (uiconst.UI_CLICK,
     36      uiconst.UI_DBLCLICK,
     37      uiconst.UI_TRIPLECLICK,
     38      uiconst.UI_KEYUP,
     39      uiconst.UI_KEYDOWN,
     40      uiconst.UI_MOUSEMOVE)
     41     EVENTMAP = {uiconst.UI_MOUSEHOVER: 'OnMouseHover',
     42      uiconst.UI_MOUSEMOVE: 'OnMouseMove',
     43      uiconst.UI_MOUSEMOVEDRAG: 'OnMouseMoveDrag',
     44      uiconst.UI_MOUSEENTER: 'OnMouseEnter',
     45      uiconst.UI_MOUSEEXIT: 'OnMouseExit',
     46      uiconst.UI_MOUSEDOWN: 'OnMouseDown',
     47      uiconst.UI_MOUSEDOWNDRAG: 'OnMouseDownDrag',
     48      uiconst.UI_MOUSEUP: 'OnMouseUp',
     49      uiconst.UI_MOUSEWHEEL: 'OnMouseWheel',
     50      uiconst.UI_CLICK: 'OnClick',
     51      uiconst.UI_DBLCLICK: 'OnDblClick',
     52      uiconst.UI_TRIPLECLICK: 'OnTripleClick',
     53      uiconst.UI_KEYDOWN: 'OnKeyDown',
     54      uiconst.UI_KEYUP: 'OnKeyUp',
     55      uiconst.UI_CHAR: 'OnChar'}
     56     tooltipHandler = None
     57     auxiliaryTooltip = None
     58     auxiliaryTooltipPosition = None
     59     cursorPos = (-1, -1)
     60 
     61     def __init__(self, paparazziMode = False):
     62         if not paparazziMode:
     63             sm.RegisterNotify(self)
     64         if len(trinity.textureAtlasMan.atlases) == 0:
     65             trinity.textureAtlasMan.AddAtlas(trinity.PIXEL_FORMAT.B8G8R8A8_UNORM, 2048, 2048)
     66         self.textureAtlas = trinity.textureAtlasMan.atlases[0]
     67         self.textureAtlas.optimizeOnRemoval = False
     68         self.renderObjectToPyObjectDict = weakref.WeakValueDictionary()
     69         self.x = -1
     70         self.y = -1
     71         self.z = 0
     72         self.dx = 0
     73         self.dy = 0
     74         self.dz = 0
     75         self._mouseOver = None
     76         self._auxMouseOverRO = None
     77         self._capturingMouseItem = None
     78         self._clickItem = None
     79         self._mouseTargetObject = None
     80         self.exclusiveMouseFocusActive = False
     81         self.appfocusitem = None
     82         self.selectedCursorType = uiconst.UICURSOR_DEFAULT
     83         self.centerMouse = False
     84         self.ignoreDeadChar = None
     85         self._clickTime = None
     86         self._clickCount = 0
     87         self._clickTimer = None
     88         self._clickPosition = None
     89         self.rootObjects = []
     90         self.rootObjectsByName = {}
     91         self._triuiRegs = {}
     92         self._triuiRegsByMsgID = {}
     93         self._mouseButtonStates = {}
     94         self._mouseDownPosition = {}
     95         self._appfocusitem = None
     96         self._modkeysOff = tuple([ 0 for x in uiconst.MODKEYS ])
     97         self._expandMenu = None
     98         self._keyDownAcceleratorThread = None
     99         self.blurredBackBufferRenderJob = None
    100         self.blurredBackBufferAtlas = None
    101         self.desktopBlurredBg = None
    102         self._pickProjection = trinity.TriProjection()
    103         self._pickView = trinity.TriView()
    104         self._pickViewport = trinity.TriViewport()
    105         self.cursorCache = {}
    106         if not paparazziMode:
    107             if IsMacOS():
    108                 self.cursorSize = CursorSize.NORMAL
    109             else:
    110                 self.cursorSize = cursor_size_setting.get()
    111                 cursor_size_setting.on_change.connect(self.OnCursorSizeChanged)
    112         self.alignIslands = set()
    113         from carbonui.uicore import uicore
    114         uicore.uilib = self
    115         trinity.fontMan.loadFlag = 32
    116         if not paparazziMode:
    117             self._SetupRenderJob()
    118             glowEnabled = gfxsettings.Get(gfxsettings.GFX_SHADER_QUALITY) > gfxsettings.SHADER_MODEL_LOW
    119             self.desktop = self.CreateRootObject('Desktop', renderJob=self.desktopRenderJob, isFullscreen=True, glowEnabled=glowEnabled)
    120             uthread.new(self.EnableEventHandling)
    121             from eve.client.script.ui.tooltips.tooltipHandler import TooltipHandler
    122             self.tooltipHandler = TooltipHandler()
    123         trinity.device.RegisterResource(self)
    124         self._hoverThread = None
    125         self.eventHandlerResolver = None
    126         self.menuHandlerResolver = None
    127         show_window_bg_blur_setting.on_change.connect(self.OnWindowBlurSettingChanged)
    128         font_shadow_enabled_setting.on_change.connect(self._on_font_shadow_enabled_setting_changed)
    129 
    130     def __del__(self, *args):
    131         trinity.mainWindow.onMouseMove = None
    132         trinity.mainWindow.onMouseDown = None
    133         trinity.mainWindow.onMouseUp = None
    134         trinity.mainWindow.onMouseWheel = None
    135         trinity.mainWindow.onKeyDown = None
    136         trinity.mainWindow.onKeyUp = None
    137         trinity.mainWindow.onChar = None
    138         if self.renderJob:
    139             self.renderJob.UnscheduleRecurring()
    140 
    141     def EnableEventHandling(self):
    142         from carbonui.uicore import uicore
    143         while not uicore.IsReady():
    144             blue.synchro.SleepWallclock(1)
    145 
    146         trinity.mainWindow.onMouseMove = self._OnMouseMove
    147         trinity.mainWindow.onMouseDown = self._OnMouseDown
    148         trinity.mainWindow.onMouseUp = self._OnMouseUp
    149         trinity.mainWindow.onMouseWheel = self._OnMouseWheel
    150         trinity.mainWindow.onKeyDown = self._OnKeyDown
    151         trinity.mainWindow.onKeyUp = self._OnKeyUp
    152         trinity.mainWindow.onChar = self._OnChar
    153         trinity.mainWindow.onFocusChange = self._OnFocusChange
    154         trinity.mainWindow.onClose = self._OnClose
    155         log.LogInfo('Uilib event handling enabled')
    156 
    157     def OnInvalidate(self, *args):
    158         self.cursorCache = {}
    159 
    160     def OnCreate(self, *args):
    161         uthread.new(self.PrepareBlurredBackBuffer)
    162 
    163     def OnWindowBlurSettingChanged(self, *args):
    164         self.PrepareBlurredBackBuffer()
    165 
    166     def OnGraphicSettingsChanged(self, *args, **kwargs):
    167         if self.desktop:
    168             self.desktop.glowEnabled = gfxsettings.Get(gfxsettings.GFX_SHADER_QUALITY) > gfxsettings.SHADER_MODEL_LOW
    169 
    170     def OnUIColorsChanged(self):
    171         self.desktop.OnColorThemeChanged()
    172 
    173     def OnFontSizeChanged(self):
    174         self.desktop.OnGlobalFontSizeChanged()
    175 
    176     def OnCursorSizeChanged(self, value):
    177         self.cursorSize = value
    178 
    179     def _on_font_shadow_enabled_setting_changed(self, value):
    180         self.desktop.OnGlobalFontShadowChanged()
    181 
    182     def CreateTexture(self, width, height):
    183         tex = self.textureAtlas.CreateTexture(int(width), int(height))
    184         return tex
    185 
    186     def CreateRootObject(self, name, width = None, height = None, depthMin = None, depthMax = None, isFullscreen = False, renderTarget = None, renderJob = None, **kwargs):
    187         from carbonui.primitives.desktop import UIRoot
    188         desktop = UIRoot(pos=(0,
    189          0,
    190          width or trinity.mainWindow.width,
    191          height or trinity.mainWindow.height), name=name, depthMin=depthMin, depthMax=depthMax, isFullscreen=isFullscreen, renderTarget=renderTarget, renderJob=renderJob, **kwargs)
    192         self.AddRootObject(desktop)
    193         return desktop
    194 
    195     def GetRenderJob(self):
    196         return self.desktopRenderJob
    197 
    198     def GetVideoJob(self):
    199         return self.videoJob
    200 
    201     def OnUIScalingChange(self, *args):
    202         self.PrepareBlurredBackBuffer()
    203 
    204     def PrepareBlurredBackBuffer(self):
    205         if self.blurredBackBufferRenderJob:
    206             renderJob = self.blurredBackBufferRenderJob
    207             renderJob.enabled = True
    208             for step in renderJob.steps[:]:
    209                 renderJob.steps.remove(step)
    210 
    211         else:
    212             renderJob = trinity.CreateRenderJob()
    213             renderJob.name = 'Blurred Back Buffer'
    214             renderJob.ScheduleRecurring(insertFront=True)
    215             self.blurredBackBufferRenderJob = renderJob
    216         gfxShaderSettingSupportsBlur = gfxsettings.Get(gfxsettings.GFX_SHADER_QUALITY) > gfxsettings.SHADER_MODEL_LOW
    217         if not (show_window_bg_blur_setting.is_enabled() and gfxShaderSettingSupportsBlur):
    218             if self.blurredBackBufferRenderJob:
    219                 self.blurredBackBufferRenderJob.enabled = False
    220             return
    221         backbuffer = trinity.device.GetRenderContext().GetDefaultBackBuffer()
    222         self.spaceSceneBackBufferCopy = trinity.Tr2RenderTarget(trinity.mainWindow.width, trinity.mainWindow.height, 1, backbuffer.format)
    223         self.spaceSceneBackBufferDownSizedCopy = trinity.Tr2RenderTarget(trinity.mainWindow.width / 4, trinity.mainWindow.height / 4, 1, trinity.PIXEL_FORMAT.B8G8R8X8_UNORM)
    224         self.spaceSceneBackBufferDownSizedCopy.name = 'spaceSceneBackBufferDownSizedCopy'
    225         step = trinity.TriStepResolve(self.spaceSceneBackBufferCopy, backbuffer)
    226         step.name = 'Resolve back buffer'
    227         renderJob.steps.append(step)
    228         if self.desktopBlurredBg:
    229             self.RemoveRootObject(self.desktopBlurredBg)
    230             self.desktopBlurredBg.Close()
    231         self.desktopBlurredBg = self.CreateRootObject(name='desktopBlurred', renderTarget=self.spaceSceneBackBufferCopy, renderJob=renderJob, isFullscreen=True)
    232         self.desktopBlurredBg.renderObject.clearBackground = False
    233         renderJob.PushDepthStencil().pushCurrent = False
    234         renderJob.SetVariableStore('BlitCurrent', self.spaceSceneBackBufferCopy).name = 'Set BlitCurrent variable'
    235         value = (1.0 / trinity.mainWindow.width,
    236          1.0 / trinity.mainWindow.height,
    237          trinity.mainWindow.width,
    238          trinity.mainWindow.height)
    239         renderJob.SetVariableStore('g_texelSize', value).name = 'Set g_texelSize variable'
    240         renderJob.PushRenderTarget(self.spaceSceneBackBufferDownSizedCopy)
    241         renderJob.Clear((0, 0, 0, 0))
    242         effect = trinity.Tr2Effect()
    243         effect.effectFilePath = 'res:/Graphics/Effect/Managed/Space/PostProcess/ColorDownFilter4.fx'
    244         renderJob.RenderEffect(effect)
    245         renderJob.PopRenderTarget()
    246         renderJob.PopDepthStencil()
    247         textureRes = trinity.TriTextureRes()
    248         textureRes.SetFromRenderTarget(self.spaceSceneBackBufferDownSizedCopy)
    249         atlasTexture = trinity.Tr2AtlasTexture()
    250         atlasTexture.textureRes = textureRes
    251         self.blurredBackBufferAtlas = atlasTexture
    252         sm.ScatterEvent('OnBlurredBufferCreated')
    253 
    254     def _SetupRenderJob(self):
    255         self.renderJob = trinity.CreateRenderJob()
    256         self.renderJob.name = 'UI'
    257         self.PrepareBlurredBackBuffer()
    258         self.sceneViewStep = self.renderJob.SetView()
    259         self.scaledViewportStep = self.renderJob.SetViewport()
    260         self.sceneProjectionStep = self.renderJob.SetProjection()
    261         videoJobStep = self.renderJob.RunJob()
    262         videoJobStep.name = 'Videos'
    263         self.videoJob = trinity.CreateRenderJob()
    264         self.videoJob.name = 'Update videos job'
    265         videoJobStep.job = self.videoJob
    266         self.bracketCurveSet = trinity.TriCurveSet()
    267         self.bracketCurveSet.Play()
    268         self.renderJob.Update(self.bracketCurveSet).name = 'Update brackets'
    269         self.renderJob.SetViewport()
    270         self.renderJob.PythonCB(self.Update).name = 'Update uilib'
    271         self.desktopRenderJob = trinity.CreateRenderJob()
    272         self.desktopRenderJob.name = 'Desktop'
    273         self.renderJob.steps.append(trinity.TriStepRunJob(self.desktopRenderJob))
    274         self.renderJob.ScheduleRecurring()
    275         is_perforce_client = not blue.pyos.packaged
    276         if is_perforce_client:
    277             trinity.SetFpsEnabled(settings.public.ui.Get('isFpsRenderJobEnabled', is_perforce_client))
    278 
    279     def OnSessionChanged(self, isRemote, sess, change):
    280         if 'userid' in change:
    281             has_required_role = session.role & ROLE_GML
    282             is_perforce_client = not blue.pyos.packaged
    283             if has_required_role and settings.public.ui.Get('isFpsRenderJobEnabled', is_perforce_client):
    284                 trinity.SetFpsEnabled(True)
    285             else:
    286                 trinity.SetFpsEnabled(False)
    287 
    288     def _GetMouseTravel(self):
    289         if self._mouseButtonStates.get(uiconst.MOUSELEFT, False):
    290             x, y, z = self._mouseDownPosition[uiconst.MOUSELEFT]
    291             return math.sqrt(abs((x - self.x) * (x - self.x) + (y - self.y) * (y - self.y)))
    292         return 0
    293 
    294     mouseTravel = property(_GetMouseTravel)
    295 
    296     def _GetRightBtn(self):
    297         return self._mouseButtonStates.get(uiconst.MOUSERIGHT, False)
    298 
    299     rightbtn = property(_GetRightBtn)
    300 
    301     def _GetLeftBtn(self):
    302         return self._mouseButtonStates.get(uiconst.MOUSELEFT, False)
    303 
    304     leftbtn = property(_GetLeftBtn)
    305 
    306     def _GetMiddleBtn(self):
    307         return self._mouseButtonStates.get(uiconst.MOUSEMIDDLE, False)
    308 
    309     midbtn = property(_GetMiddleBtn)
    310 
    311     def ReleaseObject(self, object):
    312         try:
    313             del self.renderObjectToPyObjectDict[object.renderObject]
    314         except KeyError:
    315             pass
    316 
    317     def GetMouseOver(self):
    318         if self._mouseOver:
    319             mouseOver = self._mouseOver()
    320             if mouseOver and not mouseOver.destroyed:
    321                 return mouseOver
    322             self._mouseOver = None
    323         from carbonui.uicore import uicore
    324         return uicore.desktop
    325 
    326     mouseOver = property(GetMouseOver)
    327 
    328     def GetAuxMouseOver(self):
    329         if self._auxMouseOverRO:
    330             return self.GetPyObjectFromRenderObject(self._auxMouseOverRO())
    331 
    332     auxMouseOver = property(GetAuxMouseOver)
    333 
    334     def CheckAppFocus(self, hasFocus):
    335         from carbonui.uicore import uicore
    336         if getattr(uicore, 'registry', None) is None:
    337             return
    338         uicore.UpdateCursor(self.GetMouseOver(), 1)
    339         if hasFocus:
    340             modal = uicore.registry.GetModalWindow()
    341             if modal:
    342                 uicore.registry.SetFocus(modal)
    343             else:
    344                 f = uicore.registry.GetFocus()
    345                 if (not f or f.destroyed) and self.appfocusitem and self.appfocusitem():
    346                     f = self.appfocusitem()
    347                 if f is not None and not f.destroyed:
    348                     uicore.registry.SetFocus(f)
    349                 self.appfocusitem = None
    350         else:
    351             focus = uicore.registry.GetFocus()
    352             if focus:
    353                 self.appfocusitem = weakref.ref(focus)
    354                 uicore.registry.SetFocus(None)
    355             mouseCaptureItem = self.GetMouseCapture()
    356             if mouseCaptureItem:
    357                 self.ReleaseCapture()
    358                 self.centerMouse = False
    359                 self._mouseButtonStates = {}
    360                 self._mouseDownPosition = {}
    361                 self._TryExecuteHandler(uiconst.UI_MOUSEUP, mouseCaptureItem, (uiconst.MOUSELEFT,))
    362         return 1
    363 
    364     def CheckAccelerators(self, vkey, flag):
    365         modkeys = self.GetModifierKeyState(vkey)
    366         if self.CheckActiveWindowAccelerators(modkeys, vkey, flag):
    367             return True
    368         if self.CheckMappedAccelerators(modkeys, vkey, flag):
    369             return True
    370         if self.CheckDirectionalAccelerators(vkey):
    371             return True
    372         return False
    373 
    374     def CheckActiveWindowAccelerators(self, modkeys, vkey, flag):
    375         from carbonui.uicore import uicore
    376         wnd = uicore.registry.GetActive()
    377         if wnd and hasattr(wnd, 'OnShortcutKeyDown'):
    378             return wnd.OnShortcutKeyDown(modkeys, vkey, flag)
    379         return False
    380 
    381     def GetModifierKeyState(self, vkey = None):
    382         ret = []
    383         for key in uiconst.MODKEYS:
    384             ret.append(trinity.app.Key(key) and key != vkey)
    385 
    386         return tuple(ret)
    387 
    388     def CheckMappedAccelerators(self, modkeys, vkey, flag):
    389         from carbonui.uicore import uicore
    390         if not uicore.commandHandler:
    391             return False
    392         ctrl = self.Key(uiconst.VK_CONTROL)
    393         if not ctrl and (self._modkeysOff, vkey) in uicore.commandHandler.commandMap.accelerators:
    394             cmd = uicore.commandHandler.commandMap.accelerators[self._modkeysOff, vkey]
    395             if cmd.ignoreModifierKey:
    396                 if not cmd.repeatable and flag & 1073741824:
    397                     return False
    398                 sm.ScatterEvent('OnCommandExecuted', cmd.name)
    399                 ret = uicore.cmd.ExecuteCommand(cmd)
    400                 if ret:
    401                     return ret
    402         if (modkeys, vkey) in uicore.commandHandler.commandMap.accelerators:
    403             cmd = uicore.commandHandler.commandMap.accelerators[modkeys, vkey]
    404             if not cmd.repeatable and flag & 1073741824:
    405                 return False
    406             sm.ScatterEvent('OnCommandExecuted', cmd.name)
    407             return uicore.cmd.ExecuteCommand(cmd)
    408         return False
    409 
    410     def CheckDirectionalAccelerators(self, vkey):
    411         from carbonui.uicore import uicore
    412         active = uicore.registry.GetActive()
    413         focus = uicore.registry.GetFocus()
    414         focusOrActive = focus or active
    415         if vkey == uiconst.VK_UP and hasattr(focusOrActive, 'OnUp'):
    416             uthread.pool('uisvc::CheckDirectionalAccelerators OnUp', focusOrActive.OnUp)
    417             return True
    418         if vkey == uiconst.VK_DOWN and hasattr(focusOrActive, 'OnDown'):
    419             uthread.pool('uisvc::CheckDirectionalAccelerators OnDown', focusOrActive.OnDown)
    420             return True
    421         if vkey == uiconst.VK_LEFT and hasattr(focusOrActive, 'OnLeft'):
    422             uthread.pool('uisvc::CheckDirectionalAccelerators OnLeft', focusOrActive.OnLeft)
    423             return True
    424         if vkey == uiconst.VK_RIGHT and hasattr(focusOrActive, 'OnRight'):
    425             uthread.pool('uisvc::CheckDirectionalAccelerators OnRight', focusOrActive.OnRight)
    426             return True
    427         if vkey == uiconst.VK_HOME and hasattr(focusOrActive, 'OnHome'):
    428             uthread.pool('uisvc::CheckDirectionalAccelerators OnHome', focusOrActive.OnHome)
    429             return True
    430         if vkey == uiconst.VK_END and hasattr(focusOrActive, 'OnEnd'):
    431             uthread.pool('uisvc::CheckDirectionalAccelerators OnEnd', focusOrActive.OnEnd)
    432             return True
    433 
    434     def RegisterForTriuiEvents(self, msgIDlst, function, *args, **kw):
    435         if type(msgIDlst) == int:
    436             msgIDlst = [msgIDlst]
    437         cookie = uthread.uniqueId() or uthread.uniqueId()
    438         self._triuiRegs[cookie] = msgIDlst
    439         ref = CallableWeakRef(function)
    440         for id_ in msgIDlst:
    441             self._triuiRegsByMsgID.setdefault(id_, {})[cookie] = (ref, args, kw)
    442 
    443         log.LogInfo('RegisterForTriuiEvents', cookie, msgIDlst, function, args, kw)
    444         return cookie
    445 
    446     def UnregisterForTriuiEvents(self, cookie):
    447         if cookie not in self._triuiRegs:
    448             return
    449         log.LogInfo('UnregisterForTriuiEvents', cookie)
    450         try:
    451             for msgID_ in self._triuiRegs[cookie]:
    452                 del self._triuiRegsByMsgID[msgID_][cookie]
    453 
    454             del self._triuiRegs[cookie]
    455         except KeyError as what:
    456             log.LogError('UnregisterForTriuiEvents: Tried to kill unexisting registration?', cookie)
    457             log.LogException()
    458 
    459     @telemetry.ZONE_METHOD
    460     def RegisterObject(self, pyObject, renderObject):
    461         self.renderObjectToPyObjectDict[renderObject] = pyObject
    462 
    463     def GetPyObjectFromRenderObject(self, RO):
    464         pyObject = self.renderObjectToPyObjectDict.get(RO, None)
    465         if pyObject and not pyObject.destroyed:
    466             return pyObject
    467 
    468     def AddRootObject(self, obj):
    469         if obj.name in self.rootObjectsByName:
    470             raise AttributeError('Root object already exists with this name (%s)' % obj.name)
    471         self.rootObjectsByName[obj.name] = obj
    472         if obj not in self.rootObjects:
    473             self.rootObjects.append(obj)
    474 
    475     def UpdateRootObjectSizes(self):
    476         for obj in self.rootObjects:
    477             obj.UpdateSize()
    478 
    479     def RemoveRootObject(self, obj):
    480         if obj.name in self.rootObjectsByName:
    481             del self.rootObjectsByName[obj.name]
    482         if obj in self.rootObjects:
    483             self.rootObjects.remove(obj)
    484 
    485     def FindRootObject(self, name):
    486         return self.rootObjectsByName.get(name, None)
    487 
    488     def AddMouseTargetObject(self, mouseTargetObject):
    489         self._mouseTargetObject = mouseTargetObject
    490 
    491     def GetMouseTargetObject(self):
    492         if self._mouseTargetObject:
    493             if self._mouseTargetObject.GetOwner():
    494                 return self._mouseTargetObject
    495             self._mouseTargetObject = None
    496 
    497     @telemetry.ZONE_METHOD
    498     def Update(self, *args):
    499         try:
    500             if getattr(self, 'updatingFromRoot', False):
    501                 return
    502             vp = trinity.TriViewport()
    503             vp.width = trinity.device.width
    504             vp.height = trinity.device.height
    505             self.scaledViewportStep.viewport = vp
    506             self.cursorPos = trinity.mainWindow.GetCursorPos()
    507             self.UpdateMouseOver()
    508             if self.tooltipHandler:
    509                 self.tooltipHandler.RefreshTooltip()
    510             for root in self.rootObjects:
    511                 root.UpdateAlignmentAsRoot('uilib.Update')
    512 
    513             islands = self.alignIslands
    514             self.alignIslands = set()
    515             for island in islands:
    516                 if not island.destroyed:
    517                     island.UpdateAlignmentAsRoot('uilib.Update Islands')
    518 
    519         except:
    520             LogException()
    521             raise
    522 
    523     def SetSceneCamera(self, camera):
    524         from eve.client.script.ui.camera.cameraBase import CameraBase
    525         if isinstance(camera, CameraBase):
    526             self.sceneViewStep.view = None
    527             self.sceneViewStep.camera = camera._camera
    528             self.sceneProjectionStep.projection = camera.projectionMatrix
    529         else:
    530             self.sceneViewStep.view = camera.viewMatrix
    531             self.sceneViewStep.camera = None
    532             self.sceneProjectionStep.projection = camera.projectionMatrix
    533 
    534     def SetSceneView(self, view, projection):
    535         self.sceneViewStep.camera = None
    536         self.sceneViewStep.view = view
    537         self.sceneProjectionStep.projection = projection
    538 
    539     @telemetry.ZONE_METHOD
    540     def UpdateMouseOver(self, *args):
    541         from carbonui.uicore import uicore
    542         pyObject = None
    543         auxRenderObject = None
    544         cursorX, cursorY = self.cursorPos
    545         if 0 <= cursorX <= trinity.mainWindow.width and 0 <= cursorY <= trinity.mainWindow.height:
    546             mouseTargetObject = self.GetMouseTargetObject()
    547             if mouseTargetObject and mouseTargetObject.IsMouseHeadingTowards():
    548                 return
    549             triobj, pyObject = self.PickScreenPosition(int(uicore.ScaleDpi(self.x)), int(uicore.ScaleDpi(self.y)))
    550             if getattr(triobj, 'auxMouseover', None):
    551                 auxRenderObject = triobj.auxMouseover
    552         newMouseOver = pyObject or uicore.desktop
    553         currentMouseOver = self.GetMouseOver()
    554         currentAuxiliaryTooltip = getattr(self, 'auxiliaryTooltip', None)
    555         if auxRenderObject:
    556             self._auxMouseOverRO = weakref.ref(auxRenderObject)
    557             pyAuxObject = self.GetPyObjectFromRenderObject(auxRenderObject)
    558             if pyAuxObject and hasattr(pyAuxObject, 'GetAuxiliaryTooltip'):
    559                 self.auxiliaryTooltip = pyAuxObject.GetAuxiliaryTooltip()
    560                 self.auxiliaryTooltipPosition = pyAuxObject.GetAuxiliaryTooltipPosition()
    561             else:
    562                 self.auxiliaryTooltip = None
    563                 self.auxiliaryTooltipPosition = None
    564         else:
    565             self.auxiliaryTooltip = None
    566             self.auxiliaryTooltipPosition = None
    567             self._auxMouseOverRO = None
    568         mouseCaptureItem = self.GetMouseCapture()
    569         if newMouseOver is not self.mouseOver:
    570             self._mouseOver = weakref.ref(newMouseOver)
    571         if currentMouseOver is not newMouseOver or currentAuxiliaryTooltip != self.auxiliaryTooltip:
    572             self.FlagTooltipsDirty()
    573         if not mouseCaptureItem and currentMouseOver is not newMouseOver:
    574             if self._hoverThread:
    575                 self._hoverThread.kill()
    576             uicore.HideHint()
    577             from carbonui.primitives.dragdrop import DragDropObject
    578             if currentMouseOver:
    579                 if uicore.IsDragging() and isinstance(currentMouseOver, DragDropObject) and uicore.dragObject is not currentMouseOver:
    580                     currentMouseOver.OnDragExit(uicore.dragObject, uicore.dragObject.dragData)
    581                     self.CheckCallbacks(newMouseOver, uiconst.UI_DRAGEXIT, (uicore.dragObject, uicore.dragObject.dragData))
    582                 else:
    583                     self._Propagate(eventId=uiconst.UI_MOUSEEXIT, uiObject=currentMouseOver, stopper=newMouseOver)
    584             if newMouseOver:
    585                 if uicore.IsDragging() and isinstance(newMouseOver, DragDropObject) and uicore.dragObject is not newMouseOver:
    586                     newMouseOver.OnDragEnter(uicore.dragObject, uicore.dragObject.dragData)
    587                     self.CheckCallbacks(newMouseOver, uiconst.UI_DRAGENTER, (uicore.dragObject, uicore.dragObject.dragData))
    588                 else:
    589                     self._Propagate(eventId=uiconst.UI_MOUSEENTER, uiObject=newMouseOver, stopper=currentMouseOver)
    590                 hoverHandlerArgs, hoverHandler = self.FindEventHandler(newMouseOver, self.EVENTMAP[uiconst.UI_MOUSEHOVER])
    591                 if hoverHandler:
    592                     self._hoverThread = uthread.new(self._HoverThread)
    593             uicore.CheckCursor()
    594 
    595     def PickScreenPosition(self, x, y):
    596         triobj = None
    597         pyObject = None
    598         for root in self.rootObjects:
    599             if not root.pickState:
    600                 continue
    601             RO = root.GetRenderObject()
    602             if not RO:
    603                 continue
    604             camera = root.GetCamera()
    605             if root.renderTargetStep:
    606                 pass
    607             elif camera:
    608                 triobj = RO.PickObject(x, y, camera.projectionMatrix, camera.viewMatrix, trinity.device.viewport)
    609             elif hasattr(root, 'PickObject'):
    610                 triobj = root.PickObject(x, y)
    611             else:
    612                 triobj = RO.PickObject(x, y, self._pickProjection, self._pickView, self._pickViewport)
    613             if triobj:
    614                 pyObject = self.GetPyObjectFromRenderObject(triobj)
    615                 if pyObject:
    616                     overridePick = getattr(pyObject, 'OverridePick', None)
    617                     if overridePick:
    618                         overrideObject = overridePick(x, y)
    619                         if overrideObject:
    620                             pyObject = overrideObject
    621                 from carbonui.control.layer import LayerCore
    622                 if pyObject and not isinstance(pyObject, LayerCore):
    623                     break
    624 
    625         return (triobj, pyObject)
    626 
    627     def FlagTooltipsDirty(self, instant = False):
    628         if self.tooltipHandler:
    629             self.tooltipHandler.FlagTooltipsDirty(instant)
    630 
    631     UpdateTooltip = FlagTooltipsDirty
    632 
    633     def RefreshTooltipForOwner(self, owner):
    634         if self.tooltipHandler:
    635             self.tooltipHandler.RefreshTooltipForOwner(owner)
    636 
    637     def _OnMouseMove(self, left, top):
    638         from carbonui.uicore import uicore
    639         with uthread.BlockTrapSection():
    640             currentMouseOver = self.GetMouseOver()
    641             mouseX = uicore.ReverseScaleDpi(left)
    642             mouseY = uicore.ReverseScaleDpi(top)
    643             if self.desktop:
    644                 self.desktop.glowHighlightCoords = (left, top)
    645             if self.x != mouseX or self.y != mouseY:
    646                 self.dx = mouseX - self.x
    647                 self.dy = mouseY - self.y
    648                 self.x = mouseX
    649                 self.y = mouseY
    650                 self.z = 0
    651                 if self.centerMouse:
    652                     self.SetCursorPos(uicore.desktop.width / 2, uicore.desktop.height / 2)
    653                 mouseCaptureItem = self.GetMouseCapture()
    654                 if mouseCaptureItem:
    655                     self._TryExecuteHandler(uiconst.UI_MOUSEMOVE, mouseCaptureItem)
    656                     self._TryExecuteHandler(uiconst.UI_MOUSEMOVEDRAG, mouseCaptureItem)
    657                 elif currentMouseOver:
    658                     self._TryExecuteHandler(uiconst.UI_MOUSEMOVE, currentMouseOver)
    659                     self._TryExecuteHandler(uiconst.UI_MOUSEMOVEDRAG, currentMouseOver)
    660 
    661     def _OnMouseDown(self, button, left, top):
    662         with uthread.BlockTrapSection():
    663             if button == uiconst.MOUSELEFT:
    664                 self._OnLeftMouseDown()
    665             elif button == uiconst.MOUSEMIDDLE:
    666                 self._OnMiddleMouseDown()
    667             elif button == uiconst.MOUSERIGHT:
    668                 self._OnRightMouseDown()
    669             elif button in (uiconst.MOUSEXBUTTON1, uiconst.MOUSEXBUTTON2):
    670                 self._OnOtherMouseDown(button)
    671 
    672     def _OnLeftMouseDown(self):
    673         from carbonui.uicore import uicore
    674         button = uiconst.MOUSELEFT
    675         currentMouseOver = self.GetMouseOver()
    676         self._clickCount += 1
    677         self._clickTimer = AutoTimer(CLICKCOUNTRESETTIME, self.ResetClickCounter)
    678         self._expandMenu = button
    679         self._mouseButtonStates[button] = True
    680         self._mouseDownPosition[button] = (self.x, self.y, self.z)
    681         if self.exclusiveMouseFocusActive:
    682             self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, self.GetMouseCapture(), (button,), param=(button,))
    683             self._TryExecuteHandler(uiconst.UI_MOUSEDOWNDRAG, self.GetMouseCapture(), (button,), param=(button,))
    684         else:
    685             self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, currentMouseOver, (button,), param=(button,))
    686             self._TryExecuteHandler(uiconst.UI_MOUSEDOWNDRAG, currentMouseOver, (button,), param=(button,))
    687             self.SetCapture(currentMouseOver, retainFocus=self.exclusiveMouseFocusActive)
    688             if not currentMouseOver.IsUnder(uicore.layer.menu):
    689                 from carbonui.control.contextMenu.menuUtil import CloseContextMenus
    690                 CloseContextMenus()
    691                 currentFocus = uicore.registry.GetFocus()
    692                 if currentFocus != currentMouseOver:
    693                     uicore.registry.SetFocus(currentMouseOver)
    694 
    695     def _OnMiddleMouseDown(self):
    696         currentMouseOver = self.GetMouseOver()
    697         button = uiconst.MOUSEMIDDLE
    698         self._expandMenu = None
    699         self._mouseButtonStates[button] = True
    700         self._mouseDownPosition[button] = (self.x, self.y, self.z)
    701         self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, currentMouseOver, (button,), param=(button,))
    702         uthread.new(self.CheckAccelerators, uiconst.VK_MBUTTON, 0)
    703 
    704     def _OnRightMouseDown(self):
    705         from carbonui.uicore import uicore
    706         currentMouseOver = self.GetMouseOver()
    707         button = uiconst.MOUSERIGHT
    708         self._expandMenu = button
    709         self._mouseButtonStates[button] = True
    710         self._mouseDownPosition[button] = (self.x, self.y, self.z)
    711         if self.exclusiveMouseFocusActive:
    712             self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, self.GetMouseCapture(), (button,), param=(button,))
    713         else:
    714             self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, currentMouseOver, (button,), param=(button,))
    715         if not currentMouseOver.IsUnder(uicore.layer.menu):
    716             from carbonui.control.contextMenu.menuUtil import CloseContextMenus
    717             CloseContextMenus()
    718             currentFocus = uicore.registry.GetFocus()
    719             if currentFocus is not currentMouseOver:
    720                 uicore.registry.SetFocus(currentMouseOver)
    721 
    722     def _OnOtherMouseDown(self, button):
    723         currentMouseOver = self.GetMouseOver()
    724         self._mouseButtonStates[button] = True
    725         self._TryExecuteHandler(uiconst.UI_MOUSEDOWN, currentMouseOver, (button,), param=(button,))
    726         acc = uiconst.VK_XBUTTON1 if button == uiconst.MOUSEXBUTTON1 else uiconst.VK_XBUTTON2
    727         uthread.new(self.CheckAccelerators, acc, 0)
    728 
    729     def _OnMouseUp(self, button, left, top):
    730         with uthread.BlockTrapSection():
    731             if button == uiconst.MOUSELEFT:
    732                 self._OnLeftMouseUp()
    733             elif button == uiconst.MOUSERIGHT:
    734                 self._OnRightMouseUp()
    735             elif button in (uiconst.MOUSEMIDDLE, uiconst.MOUSEXBUTTON1, uiconst.MOUSEXBUTTON2):
    736                 self._OnOtherMouseUp(button)
    737 
    738     def _OnLeftMouseUp(self):
    739         currentMouseOver = self.GetMouseOver()
    740         button = uiconst.MOUSELEFT
    741         self._mouseButtonStates[button] = False
    742         mouseCaptureItem = self.GetMouseCapture()
    743         if mouseCaptureItem:
    744             if not self.exclusiveMouseFocusActive:
    745                 if getattr(mouseCaptureItem, 'expandOnLeft', 0) and not self.rightbtn and self._expandMenu == button and self.FindMenuHandler(mouseCaptureItem):
    746                     x, y, z = self._mouseDownPosition[button]
    747                     if abs(self.x - x) < 3 and abs(self.y - y) < 3:
    748                         self.FlagTooltipsDirty(True)
    749                         uthread.new(carbonui.control.contextMenu.contextMenu.ShowMenu, mouseCaptureItem, self.GetAuxMouseOver())
    750                 self._expandMenu = False
    751             self._TryExecuteHandler(uiconst.UI_MOUSEUP, mouseCaptureItem, (button,), param=(button, 0))
    752             if not self.exclusiveMouseFocusActive:
    753                 self.ReleaseCapture()
    754             if currentMouseOver is not mouseCaptureItem:
    755                 self._Propagate(eventId=uiconst.UI_MOUSEEXIT, uiObject=mouseCaptureItem, stopper=currentMouseOver)
    756                 self._Propagate(eventId=uiconst.UI_MOUSEENTER, uiObject=currentMouseOver, stopper=mouseCaptureItem)
    757             else:
    758                 self._TryExecuteClickHandler(0, 0)
    759 
    760     def _OnRightMouseUp(self):
    761         currentMouseOver = self.GetMouseOver()
    762         button = uiconst.MOUSERIGHT
    763         self._mouseButtonStates[button] = False
    764         if self.exclusiveMouseFocusActive:
    765             self._TryExecuteHandler(uiconst.UI_MOUSEUP, self.GetMouseCapture(), (button,), param=(button, 0))
    766         else:
    767             if not self.leftbtn and self._expandMenu == button and (self.FindMenuHandler(currentMouseOver) or self._auxMouseOverRO is not None):
    768                 x, y, z = self._mouseDownPosition[button]
    769                 if abs(self.x - x) < 3 and abs(self.y - y) < 3:
    770                     self.FlagTooltipsDirty(True)
    771                     uthread.new(carbonui.control.contextMenu.contextMenu.ShowMenu, currentMouseOver, self.GetAuxMouseOver())
    772             self._expandMenu = None
    773             self._TryExecuteHandler(uiconst.UI_MOUSEUP, currentMouseOver, (button,), param=(button, 0))
    774 
    775     def _OnOtherMouseUp(self, button):
    776         self._mouseButtonStates[button] = False
    777         self._TryExecuteHandler(uiconst.UI_MOUSEUP, self.GetMouseOver(), (button,), param=(button, 0))
    778 
    779     def _OnMouseWheel(self, delta):
    780         from carbonui.uicore import uicore
    781         with uthread.BlockTrapSection():
    782             mouseZ = delta
    783             self.dz = mouseZ
    784             if self.mouseOver:
    785                 mouseOver = self.mouseOver
    786                 wasHandled = False
    787                 while mouseOver.parent and mouseOver != uicore.uilib.desktop:
    788                     mwHandlerArgs, mwHandler = self.FindEventHandler(mouseOver, 'OnMouseWheel')
    789                     if mwHandler:
    790                         args = [mouseZ] + list(mwHandlerArgs[:])
    791                         wasHandled = mwHandler(*args)
    792                         if wasHandled != False:
    793                             break
    794                     mouseOver = mouseOver.parent
    795 
    796                 handlerObject = mouseOver if wasHandled else None
    797                 self.CheckCallbacks(handlerObject, uiconst.UI_MOUSEWHEEL, (mouseZ,))
    798 
    799     def _OnKeyDown(self, key, flags):
    800         from carbonui.uicore import uicore
    801         with uthread.BlockTrapSection():
    802             focus = uicore.registry.GetFocus()
    803             if focus:
    804                 self._TryExecuteHandler(uiconst.UI_KEYDOWN, focus, (key, flags), param=(key, flags))
    805             else:
    806                 self.CheckCallbacks(None, uiconst.UI_KEYDOWN, (key, flags))
    807             self._keyDownAcceleratorThread = uthread.new(self.CheckAccelerators, key, flags)
    808 
    809     def _OnKeyUp(self, key, flags):
    810         from carbonui.uicore import uicore
    811         with uthread.BlockTrapSection():
    812             focus = uicore.registry.GetFocus()
    813             if focus:
    814                 self._TryExecuteHandler(uiconst.UI_KEYUP, focus, (key, flags), param=(key, flags))
    815             else:
    816                 self.CheckCallbacks(None, uiconst.UI_KEYUP, (key, flags))
    817             if key == uiconst.VK_SNAPSHOT and uicore.commandHandler:
    818                 uicore.commandHandler.PrintScreen()
    819 
    820     def _OnChar(self, key, flags, isDead):
    821         from carbonui.uicore import uicore
    822         with uthread.BlockTrapSection():
    823             if isDead:
    824                 focus = uicore.registry.GetFocus()
    825                 if focus and focus.HasEventHandler('OnChar') and focus.IsVisible():
    826                     self.StopKeyDownAcceleratorThread()
    827                 else:
    828                     self.ignoreDeadChar = key
    829             else:
    830                 char = key
    831                 ignoreChar = False
    832                 if char <= 32 or char == self.ignoreDeadChar:
    833                     ctrl = trinity.app.Key(uiconst.VK_CONTROL)
    834                     if char not in (uiconst.VK_RETURN, uiconst.VK_BACK, uiconst.VK_SPACE) or ctrl:
    835                         ignoreChar = True
    836                 if not ignoreChar:
    837                     calledOn = self.ResolveOnChar(key, flags)
    838                     if calledOn:
    839                         self.StopKeyDownAcceleratorThread()
    840                 self.ignoreDeadChar = None
    841 
    842     def _OnFocusChange(self, hasFocus):
    843         from carbonui.uicore import uicore
    844         with uthread.BlockTrapSection():
    845             self.CheckAppFocus(hasFocus=hasFocus)
    846             self.CheckCallbacks(obj=uicore.registry.GetFocus(), msgID=uiconst.UI_ACTIVE, param=(hasFocus,))
    847             sm.ScatterEvent('OnApplicationFocusChanged', hasFocus)
    848 
    849     def _OnClose(self):
    850         from carbonui.uicore import uicore
    851         with uthread.BlockTrapSection():
    852             if uicore.commandHandler:
    853                 uthread.new(uicore.commandHandler.CmdQuitGame)
    854                 return False
    855         return True
    856 
    857     def CheckCallbacks(self, obj, msgID, param):
    858         for cookie, (wr, args, kw) in self._triuiRegsByMsgID.get(msgID, {}).items():
    859             try:
    860                 if not wr() or not wr()(*(args + (obj, msgID, param)), **kw):
    861                     self.UnregisterForTriuiEvents(cookie)
    862             except UserError as what:
    863 
    864                 def f():
    865                     raise what
    866 
    867                 uthread.new(f)
    868             except:
    869                 log.LogError('OnAppEvent (cookie', cookie, '): Exception when trying to process callback!')
    870                 log.LogException()
    871 
    872     def StopKeyDownAcceleratorThread(self):
    873         if self._keyDownAcceleratorThread:
    874             self._keyDownAcceleratorThread.kill()
    875 
    876     def ResetClickCounter(self, *args):
    877         self._clickTimer = None
    878         self._clickCount = 0
    879 
    880     def GetClickCounter(self):
    881         return (self._clickCount - 1) % 3 + 1
    882 
    883     def ResolveOnChar(self, char, flag):
    884         ignore = (uiconst.VK_RETURN, uiconst.VK_BACK)
    885         if char < 32 and char not in ignore:
    886             return False
    887         from carbonui.uicore import uicore
    888         focus = uicore.registry.GetFocus()
    889         if focus and focus.HasEventHandler('OnChar') and focus.IsVisible():
    890             _, handler = self.FindEventHandler(focus, 'OnChar')
    891             handled = handler(char, flag)
    892             if handled:
    893                 return focus
    894 
    895     def _TryExecuteClickHandler(self, wParam, lParam):
    896         currentMouseOver = self.GetMouseOver()
    897         if self._clickCount > 1:
    898             clickObject = self.GetClickObject()
    899             if clickObject is None:
    900                 self.ResetClickCounter()
    901                 return
    902             x, y = self._clickPosition
    903             distanceOK = abs(self.x - x) < 5 and abs(self.y - y) < 5
    904             clickPosOK = clickObject is currentMouseOver and distanceOK
    905             dblHandlerArgs, dblHandler = self.FindEventHandler(clickObject, 'OnDblClick')
    906             tripHandlerArgs, tripleHandler = self.FindEventHandler(clickObject, 'OnTripleClick')
    907             if self._clickCount == 2 and dblHandler and clickPosOK:
    908                 self._TryExecuteHandler(uiconst.UI_DBLCLICK, currentMouseOver)
    909             elif self._clickCount == 3 and tripleHandler and clickPosOK:
    910                 self._TryExecuteHandler(uiconst.UI_TRIPLECLICK, currentMouseOver)
    911             else:
    912                 self._clickCount = 1
    913         if self._clickCount <= 1:
    914             handlerArgs, handler = self.FindEventHandler(currentMouseOver, 'OnClick')
    915             if handler:
    916                 self._TryExecuteHandler(uiconst.UI_CLICK, currentMouseOver)
    917                 self.SetClickObject(currentMouseOver)
    918                 self._clickPosition = (self.x, self.y)
    919 
    920     def _TryExecuteHandler(self, eventID, uiObject, eventArgs = None, param = None):
    921         itemCapturingMouse = self.GetMouseCapture()
    922         if itemCapturingMouse:
    923             uiObject = itemCapturingMouse
    924         handled = self._ExecuteHandlerRaw(eventID, uiObject, eventArgs)
    925         handlerObject = uiObject if handled else None
    926         self.CheckCallbacks(handlerObject, eventID, param)
    927         return handlerObject
    928 
    929     def _ExecuteHandlerRaw(self, eventID, uiObject, arguments = None):
    930         functionName = self.EVENTMAP.get(eventID, None)
    931         if functionName is None:
    932             raise NotImplementedError
    933         handlerArgs, handler = self.FindEventHandler(uiObject, functionName)
    934         if not handler:
    935             return False
    936         args = handlerArgs[:]
    937         if arguments:
    938             args += arguments
    939         if eventID in self.UTHREADEDEVENTS:
    940             uthread.new(handler, *args)
    941         else:
    942             try:
    943                 handler(*args)
    944             except Exception:
    945                 log.LogException()
    946                 raise
    947 
    948         return True
    949 
    950     def SetWindowOrder(self, *args):
    951         return trinity.app.uilib.SetWindowOrder(*args)
    952 
    953     def FindEventHandler(self, uiObject, handlerName):
    954         if getattr(self, 'eventHandlerResolver', None):
    955             return self.eventHandlerResolver(uiObject, handlerName)
    956         else:
    957             return uiObject.FindEventHandler(handlerName)
    958 
    959     def GetEventHandlerResolver(self):
    960         return self.eventHandlerResolver
    961 
    962     def SetEventHandlerResolver(self, resolver):
    963         self.eventHandlerResolver = resolver
    964 
    965     def FindMenuHandler(self, uiObject):
    966         if getattr(self, 'menuHandlerResolver', None):
    967             return self.menuHandlerResolver(uiObject)
    968         else:
    969             return getattr(uiObject, 'GetMenu', None)
    970 
    971     def GetMenuHandlerResolver(self):
    972         return self.menuHandlerResolver
    973 
    974     def SetMenuHandlerResolver(self, resolver):
    975         self.menuHandlerResolver = resolver
    976 
    977     def GetMouseButtonState(self, buttonFlag):
    978         return self._mouseButtonStates.get(buttonFlag, False)
    979 
    980     def Key(self, vkey):
    981         return trinity.app.Key(vkey)
    982 
    983     def SetCursorProperties(self, cursor):
    984         trinity.mainWindow.mouseCursor = cursor
    985 
    986     def SetCursorPos(self, x, y):
    987         self.x = x
    988         self.y = y
    989         from carbonui.uicore import uicore
    990         return trinity.app.SetCursorPos(uicore.ScaleDpi(x), uicore.ScaleDpi(y))
    991 
    992     def GetCursorPath(self):
    993         pass
    994 
    995     def SetCursor(self, cursorResPath):
    996         if self.exclusiveMouseFocusActive:
    997             return
    998         if self.cursorSize != CursorSize.NORMAL:
    999             cursorResPath = uiconst.UICURSOR_REPRESENTATIONS[cursorResPath][self.cursorSize - 1]
   1000         if not blue.paths.exists(cursorResPath):
   1001             raise RuntimeError('Cursor not found: %s' % cursorResPath)
   1002         cursor = self.cursorCache.get(cursorResPath, None)
   1003         if cursor is None:
   1004             cursor = self._ConstructCursor(cursorResPath)
   1005         self.SetCursorProperties(cursor)
   1006 
   1007     def _ConstructCursor(self, cursorResPath):
   1008         representations = []
   1009         for each in uiconst.UICURSOR_REPRESENTATIONS.get(cursorResPath, ()):
   1010             bmp = trinity.Tr2HostBitmap()
   1011             bmp.CreateFromFile(each)
   1012             representations.append(bmp)
   1013 
   1014         bmp = trinity.Tr2HostBitmap()
   1015         bmp.CreateFromFile(cursorResPath)
   1016         center_x = 16
   1017         center_y = 15
   1018         if self.cursorSize == CursorSize.LARGE:
   1019             center_x = 32
   1020             center_y = 31
   1021         elif self.cursorSize == CursorSize.EXTRA_LARGE:
   1022             center_x = 48
   1023             center_y = 47
   1024         cursor = trinity.Tr2MouseCursor(bmp, center_x, center_y, representations)
   1025         self.cursorCache[cursorResPath] = cursor
   1026         return cursor
   1027 
   1028     def FindWindow(self, wndName, fromParent):
   1029         return trinity.app.uilib.FindWindow(wndName, fromParent)
   1030 
   1031     def SetMouseCapture(self, item, retainFocus = False):
   1032         self._capturingMouseItem = weakref.ref(item)
   1033         self.exclusiveMouseFocusActive = retainFocus
   1034         self.FlagTooltipsDirty()
   1035 
   1036     SetCapture = SetMouseCapture
   1037 
   1038     def GetMouseCapture(self):
   1039         if self._capturingMouseItem:
   1040             captureItem = self._capturingMouseItem()
   1041             if captureItem and not captureItem.destroyed:
   1042                 return captureItem
   1043             self._capturingMouseItem = None
   1044             self.exclusiveMouseFocusActive = False
   1045 
   1046     GetCapture = GetMouseCapture
   1047     capture = property(GetMouseCapture)
   1048 
   1049     def SetClickObject(self, item):
   1050         self._clickItem = weakref.ref(item)
   1051 
   1052     def GetClickObject(self):
   1053         if self._clickItem:
   1054             clickObject = self._clickItem()
   1055             if clickObject and not clickObject.destroyed:
   1056                 return clickObject
   1057 
   1058     def ReleaseCapture(self, itemReleasing = None):
   1059         self._capturingMouseItem = None
   1060         self.exclusiveMouseFocusActive = False
   1061         self.FlagTooltipsDirty()
   1062         from carbonui.uicore import uicore
   1063         uicore.UpdateCursor(uicore.uilib.mouseOver)
   1064 
   1065     def ClipCursor(self, *rect):
   1066         from carbonui.uicore import uicore
   1067         self._cursorClip = rect
   1068         l, t, r, b = rect
   1069         trinity.app.ClipCursor(uicore.ScaleDpi(l), uicore.ScaleDpi(t), uicore.ScaleDpi(r), uicore.ScaleDpi(b))
   1070 
   1071     def UnclipCursor(self, *args):
   1072         self._cursorClip = None
   1073         trinity.app.UnclipCursor()
   1074 
   1075     def _HoverThread(self):
   1076         while True:
   1077             if trinity.app.IsHidden():
   1078                 return
   1079             blue.synchro.SleepWallclock(HOVERTIME)
   1080             self._TryExecuteHandler(uiconst.UI_MOUSEHOVER, self.mouseOver)
   1081 
   1082     def _Propagate(self, eventId, uiObject, arguments = None, globalArguments = None, stopper = None):
   1083         firstHandler = None
   1084         while uiObject:
   1085             if uiObject in self.rootObjects:
   1086                 break
   1087             if uiObject is stopper or stopper.IsUnder(uiObject):
   1088                 break
   1089             handled = self._ExecuteHandlerRaw(eventId, uiObject, arguments)
   1090             if handled and firstHandler is None:
   1091                 firstHandler = uiObject
   1092             uiObject = uiObject.parent
   1093 
   1094         self.CheckCallbacks(firstHandler, eventId, globalArguments)