Browse Source

Added visible OS mouse cursor mode. When used with an external window, this is the only supported mode, as SDL does not control the cursor visibility of an external window.

Lasse Öörni 13 years ago
parent
commit
481fbfa220

+ 2 - 2
Docs/Reference.dox

@@ -387,7 +387,7 @@ Graphics implements the low-level functionality:
 - Performing primitive rendering operations
 - Performing primitive rendering operations
 - Handling lost device
 - Handling lost device
 
 
-Screen resolution, fullscreen/windowed, vertical sync and hardware multisampling level are all set at once by calling Graphics's \ref Graphics::SetMode "SetMode()" function.
+Screen resolution, fullscreen/windowed, vertical sync and hardware multisampling level are all set at once by calling Graphics's \ref Graphics::SetMode "SetMode()" function.  There is also an experimental option of rendering to an existing window by passing its OS-specific handle to \ref Graphics::SetExternalWindow "SetExternalWindow()" before setting the initial screen mode.
 
 
 When setting the initial screen mode, Graphics does a few checks:
 When setting the initial screen mode, Graphics does a few checks:
 
 
@@ -795,7 +795,7 @@ Rendering detailed auxiliary views can easily have a large performance impact. S
 
 
 \page Input %Input
 \page Input %Input
 
 
-The Input subsystem provides keyboard, mouse, joystick and touch input via both a polled interface and events. It is always instantiated, even in headless mode, but is active only once the application window has been created. Once active, the subsystem takes over the application mouse cursor. It will be hidden, so the UI should be used to render a software cursor if necessary.
+The Input subsystem provides keyboard, mouse, joystick and touch input via both a polled interface and events. It is always instantiated, even in headless mode, but is active only once the application window has been created. Once active, the subsystem takes over the operating system mouse cursor. It will be hidden by default, so the UI should be used to render a software cursor if necessary. For editor-like applications the operating system cursor can be made visible by calling \ref Input::SetMouseVisible "SetMouseVisible()".
 
 
 The input events include:
 The input events include:
 
 

+ 2 - 0
Docs/ScriptAPI.dox

@@ -2559,6 +2559,7 @@ Methods:<br>
 Properties:<br>
 Properties:<br>
 - ShortStringHash type (readonly)
 - ShortStringHash type (readonly)
 - String typeName (readonly)
 - String typeName (readonly)
+- bool mouseVisible
 - bool toggleFullscreen
 - bool toggleFullscreen
 - bool[] keyDown (readonly)
 - bool[] keyDown (readonly)
 - bool[] keyPress (readonly)
 - bool[] keyPress (readonly)
@@ -2567,6 +2568,7 @@ Properties:<br>
 - bool[] qualifierDown (readonly)
 - bool[] qualifierDown (readonly)
 - bool[] qualifierPress (readonly)
 - bool[] qualifierPress (readonly)
 - int qualifiers (readonly)
 - int qualifiers (readonly)
+- IntVector2 mousePosition (readonly)
 - IntVector2 mouseMove (readonly)
 - IntVector2 mouseMove (readonly)
 - int mouseMoveX (readonly)
 - int mouseMoveX (readonly)
 - int mouseMoveY (readonly)
 - int mouseMoveY (readonly)

+ 3 - 0
Engine/Engine/InputAPI.cpp

@@ -142,6 +142,8 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Input", "bool OpenJoystick(uint)", asMETHOD(Input, OpenJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool OpenJoystick(uint)", asMETHOD(Input, OpenJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void CloseJoystick(uint)", asMETHOD(Input, CloseJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void CloseJoystick(uint)", asMETHOD(Input, CloseJoystick), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool DetectJoysticks()", asMETHOD(Input, DetectJoysticks), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool DetectJoysticks()", asMETHOD(Input, DetectJoysticks), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "void set_mouseVisible(bool)", asMETHOD(Input, SetMouseVisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "bool get_mouseVisible() const", asMETHOD(Input, IsMouseVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_toggleFullscreen(bool)", asMETHOD(Input, SetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_toggleFullscreen(bool)", asMETHOD(Input, SetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_toggleFullscreen() const", asMETHOD(Input, GetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_toggleFullscreen() const", asMETHOD(Input, GetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_keyDown(int) const", asMETHOD(Input, GetKeyDown), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_keyDown(int) const", asMETHOD(Input, GetKeyDown), asCALL_THISCALL);
@@ -151,6 +153,7 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Input", "bool get_qualifierDown(int) const", asMETHOD(Input, GetQualifierDown), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_qualifierDown(int) const", asMETHOD(Input, GetQualifierDown), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_qualifierPress(int) const", asMETHOD(Input, GetQualifierPress), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_qualifierPress(int) const", asMETHOD(Input, GetQualifierPress), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_qualifiers() const", asMETHOD(Input, GetQualifiers), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_qualifiers() const", asMETHOD(Input, GetQualifiers), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "IntVector2 get_mousePosition() const", asMETHOD(Input, GetMousePosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "const IntVector2& get_mouseMove() const", asMETHOD(Input, GetMouseMove), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "const IntVector2& get_mouseMove() const", asMETHOD(Input, GetMouseMove), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveX() const", asMETHOD(Input, GetMouseMoveX), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveX() const", asMETHOD(Input, GetMouseMoveX), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveY() const", asMETHOD(Input, GetMouseMoveY), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveY() const", asMETHOD(Input, GetMouseMoveY), asCALL_THISCALL);

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -77,7 +77,7 @@ public:
     /// Destruct. Close the window and release the Direct3D9 device.
     /// Destruct. Close the window and release the Direct3D9 device.
     virtual ~Graphics();
     virtual ~Graphics();
     
     
-    /// %Set external window handle. Call before setting mode for the first time.
+    /// %Set external window handle. Only effective before setting the initial screen mode.
     void SetExternalWindow(void* window);
     void SetExternalWindow(void* window);
     /// %Set window title.
     /// %Set window title.
     void SetWindowTitle(const String& windowTitle);
     void SetWindowTitle(const String& windowTitle);

+ 1 - 1
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -82,7 +82,7 @@ public:
     /// Destruct. Release the OpenGL context and close the window.
     /// Destruct. Release the OpenGL context and close the window.
     virtual ~Graphics();
     virtual ~Graphics();
     
     
-    /// %Set external window handle. Call before setting mode for the first time.
+    /// %Set external window handle. Only effective before setting the initial screen mode. On Windows it is necessary to set up OpenGL pixel format manually for the window.
     void SetExternalWindow(void* window);
     void SetExternalWindow(void* window);
     /// %Set window title.
     /// %Set window title.
     void SetWindowTitle(const String& windowTitle);
     void SetWindowTitle(const String& windowTitle);

+ 66 - 26
Engine/Input/Input.cpp

@@ -67,6 +67,7 @@ Input::Input(Context* context) :
     Object(context),
     Object(context),
     windowID_(0),
     windowID_(0),
     toggleFullscreen_(true),
     toggleFullscreen_(true),
+    mouseVisible_(false),
     active_(false),
     active_(false),
     minimized_(false),
     minimized_(false),
     activated_(false),
     activated_(false),
@@ -145,7 +146,8 @@ void Input::Update()
     if (window)
     if (window)
     {
     {
         unsigned flags = SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS);
         unsigned flags = SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS);
-        if (!active_ && graphics_->GetFullscreen() && flags == (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS))
+        if (!active_ && (graphics_->GetFullscreen() || mouseVisible_) && flags == (SDL_WINDOW_INPUT_FOCUS |
+            SDL_WINDOW_MOUSE_FOCUS))
             activated_ = true;
             activated_ = true;
         else if (active_ && (flags & SDL_WINDOW_INPUT_FOCUS) == 0)
         else if (active_ && (flags & SDL_WINDOW_INPUT_FOCUS) == 0)
             MakeInactive();
             MakeInactive();
@@ -160,13 +162,18 @@ void Input::Update()
     // Check for mouse move
     // Check for mouse move
     if (active_)
     if (active_)
     {
     {
-        IntVector2 mousePos = GetCursorPosition();
-        mouseMove_ = mousePos - lastCursorPosition_;
+        IntVector2 mousePosition = GetMousePosition();
+        mouseMove_ = mousePosition - lastMousePosition_;
         
         
         // Recenter the mouse cursor manually
         // Recenter the mouse cursor manually
-        IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
-        SetCursorPosition(center);
-        lastCursorPosition_ = center;
+        if (!mouseVisible_)
+        {
+            IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
+            SetMousePosition(center);
+            lastMousePosition_ = center;
+        }
+        else
+            lastMousePosition_ = mousePosition;
         
         
         if (mouseMove_ != IntVector2::ZERO && suppressNextMouseMove_)
         if (mouseMove_ != IntVector2::ZERO && suppressNextMouseMove_)
         {
         {
@@ -180,6 +187,11 @@ void Input::Update()
             using namespace MouseMove;
             using namespace MouseMove;
             
             
             VariantMap eventData;
             VariantMap eventData;
+            if (mouseVisible_)
+            {
+                eventData[P_X] = mousePosition.x_;
+                eventData[P_Y] = mousePosition.y_;
+            }
             eventData[P_DX] = mouseMove_.x_;
             eventData[P_DX] = mouseMove_.x_;
             eventData[P_DY] = mouseMove_.y_;
             eventData[P_DY] = mouseMove_.y_;
             eventData[P_BUTTONS] = mouseButtonDown_;
             eventData[P_BUTTONS] = mouseButtonDown_;
@@ -189,6 +201,25 @@ void Input::Update()
     }
     }
 }
 }
 
 
+void Input::SetMouseVisible(bool enable)
+{
+    // External windows can only support visible mouse cursor
+    if (graphics_ && graphics_->GetExternalWindow())
+        enable = true;
+    
+    if (enable != mouseVisible_)
+    {
+        mouseVisible_ = enable;
+        if (initialized_)
+        {
+            if (!mouseVisible_ && active_)
+                SDL_ShowCursor(SDL_FALSE);
+            else
+                SDL_ShowCursor(SDL_TRUE);
+        }
+    }
+}
+
 void Input::SetToggleFullscreen(bool enable)
 void Input::SetToggleFullscreen(bool enable)
 {
 {
     toggleFullscreen_ = enable;
     toggleFullscreen_ = enable;
@@ -318,6 +349,18 @@ int Input::GetQualifiers() const
     return ret;
     return ret;
 }
 }
 
 
+IntVector2 Input::GetMousePosition() const
+{
+    IntVector2 ret = IntVector2::ZERO;
+    
+    if (!graphics_ || !graphics_->IsInitialized())
+        return ret;
+    
+    SDL_GetMouseState(&ret.x_, &ret.y_);
+    
+    return ret;
+}
+
 TouchState* Input::GetTouch(unsigned index) const
 TouchState* Input::GetTouch(unsigned index) const
 {
 {
     unsigned cmpIndex = 0;
     unsigned cmpIndex = 0;
@@ -371,6 +414,10 @@ void Input::Initialize()
     
     
     graphics_ = graphics;
     graphics_ = graphics;
     
     
+    // In external window mode only visible mouse is supported
+    if (graphics_->GetExternalWindow())
+        mouseVisible_ = true;
+    
     // Set the initial activation
     // Set the initial activation
     activated_ = true;
     activated_ = true;
     initialized_ = true;
     initialized_ = true;
@@ -407,8 +454,13 @@ void Input::MakeActive()
     activated_ = false;
     activated_ = false;
     
     
     // Re-establish mouse cursor hiding as necessary
     // Re-establish mouse cursor hiding as necessary
-    SDL_ShowCursor(SDL_FALSE);
-    suppressNextMouseMove_ = true;
+    if (!mouseVisible_)
+    {
+        SDL_ShowCursor(SDL_FALSE);
+        suppressNextMouseMove_ = true;
+    }
+    else
+        lastMousePosition_ = GetMousePosition();
     
     
     SendActivationEvent();
     SendActivationEvent();
 }
 }
@@ -480,8 +532,9 @@ void Input::SendActivationEvent()
 
 
 void Input::SetMouseButton(int button, bool newState)
 void Input::SetMouseButton(int button, bool newState)
 {
 {
-    // After deactivation in windowed mode, activate by a left-click inside the window
-    if (initialized_ && !graphics_->GetFullscreen())
+    // After deactivation in windowed hidden mouse mode, activate only after a left-click inside the window
+    // This allows glitchfree window dragging on all operating systems
+    if (initialized_ && !graphics_->GetFullscreen() && !mouseVisible_)
     {
     {
         if (!active_ && newState && button == MOUSEB_LEFT)
         if (!active_ && newState && button == MOUSEB_LEFT)
             activated_ = true;
             activated_ = true;
@@ -573,7 +626,7 @@ void Input::SetMouseWheel(int delta)
     }
     }
 }
 }
 
 
-void Input::SetCursorPosition(const IntVector2& position)
+void Input::SetMousePosition(const IntVector2& position)
 {
 {
     if (!graphics_)
     if (!graphics_)
         return;
         return;
@@ -581,19 +634,6 @@ void Input::SetCursorPosition(const IntVector2& position)
     SDL_WarpMouseInWindow(graphics_->GetImpl()->GetWindow(), position.x_, position.y_);
     SDL_WarpMouseInWindow(graphics_->GetImpl()->GetWindow(), position.x_, position.y_);
 }
 }
 
 
-
-IntVector2 Input::GetCursorPosition() const
-{
-    IntVector2 ret = lastCursorPosition_;
-    
-    if (!graphics_ || !graphics_->IsInitialized())
-        return ret;
-    
-    SDL_GetMouseState(&ret.x_, &ret.y_);
-    
-    return ret;
-}
-
 void Input::HandleSDLEvent(void* sdlEvent)
 void Input::HandleSDLEvent(void* sdlEvent)
 {
 {
     SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
     SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
@@ -864,8 +904,8 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
         windowID_ = newWindowID;
         windowID_ = newWindowID;
     }
     }
     IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
     IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
-    SetCursorPosition(center);
-    lastCursorPosition_ = center;
+    SetMousePosition(center);
+    lastMousePosition_ = center;
     activated_ = true;
     activated_ = true;
     
     
     // After setting a new screen mode we should not be minimized
     // After setting a new screen mode we should not be minimized

+ 10 - 4
Engine/Input/Input.h

@@ -125,6 +125,8 @@ public:
     void Update();
     void Update();
     /// %Set whether ALT-ENTER fullscreen toggle is enabled.
     /// %Set whether ALT-ENTER fullscreen toggle is enabled.
     void SetToggleFullscreen(bool enable);
     void SetToggleFullscreen(bool enable);
+    /// %Set whether the operating system mouse cursor is visible. When not visible (default), is kept centered to prevent leaving the window.
+    void SetMouseVisible(bool enable);
     /// Open a joystick. Return true if successful.
     /// Open a joystick. Return true if successful.
     bool OpenJoystick(unsigned index);
     bool OpenJoystick(unsigned index);
     /// Close a joystick.
     /// Close a joystick.
@@ -146,6 +148,8 @@ public:
     bool GetQualifierPress(int qualifier) const;
     bool GetQualifierPress(int qualifier) const;
     /// Return the currently held down qualifiers.
     /// Return the currently held down qualifiers.
     int GetQualifiers() const;
     int GetQualifiers() const;
+    /// Return mouse position within window. Should only be used with a visible mouse cursor.
+    IntVector2 GetMousePosition() const;
     /// Return mouse movement since last frame.
     /// Return mouse movement since last frame.
     const IntVector2& GetMouseMove() const { return mouseMove_; }
     const IntVector2& GetMouseMove() const { return mouseMove_; }
     /// Return horizontal mouse movement since last frame.
     /// Return horizontal mouse movement since last frame.
@@ -166,6 +170,8 @@ public:
     JoystickState* GetJoystick(unsigned index);
     JoystickState* GetJoystick(unsigned index);
     /// Return whether fullscreen toggle is enabled.
     /// Return whether fullscreen toggle is enabled.
     bool GetToggleFullscreen() const { return toggleFullscreen_; }
     bool GetToggleFullscreen() const { return toggleFullscreen_; }
+    /// Return whether the operating system mouse cursor is visible.
+    bool IsMouseVisible() const { return mouseVisible_; }
     /// Return whether application window is active.
     /// Return whether application window is active.
     bool IsActive() { return active_; }
     bool IsActive() { return active_; }
     /// Return whether application window is minimized.
     /// Return whether application window is minimized.
@@ -191,9 +197,7 @@ private:
     /// Handle mousewheel change.
     /// Handle mousewheel change.
     void SetMouseWheel(int delta);
     void SetMouseWheel(int delta);
     /// Internal function to set the mouse cursor position.
     /// Internal function to set the mouse cursor position.
-    void SetCursorPosition(const IntVector2& position);
-    /// Internal function to get the mouse cursor position.
-    IntVector2 GetCursorPosition() const;
+    void SetMousePosition(const IntVector2& position);
     /// Handle screen mode event.
     /// Handle screen mode event.
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     /// Handle frame start event.
     /// Handle frame start event.
@@ -216,7 +220,7 @@ private:
     /// Mouse buttons' pressed state.
     /// Mouse buttons' pressed state.
     unsigned mouseButtonPress_;
     unsigned mouseButtonPress_;
     /// Last mouse position for calculating movement.
     /// Last mouse position for calculating movement.
-    IntVector2 lastCursorPosition_;
+    IntVector2 lastMousePosition_;
     /// Mouse movement since last frame.
     /// Mouse movement since last frame.
     IntVector2 mouseMove_;
     IntVector2 mouseMove_;
     /// Mouse wheel movement since last frame.
     /// Mouse wheel movement since last frame.
@@ -225,6 +229,8 @@ private:
     unsigned windowID_;
     unsigned windowID_;
     /// Fullscreen toggle flag.
     /// Fullscreen toggle flag.
     bool toggleFullscreen_;
     bool toggleFullscreen_;
+    /// Operating system mouse cursor visible flag.
+    bool mouseVisible_;
     /// Active flag.
     /// Active flag.
     bool active_;
     bool active_;
     /// Minimized flag.
     /// Minimized flag.

+ 2 - 0
Engine/Input/InputEvents.h

@@ -47,6 +47,8 @@ EVENT(E_MOUSEBUTTONUP, MouseButtonUp)
 /// Mouse moved.
 /// Mouse moved.
 EVENT(E_MOUSEMOVE, MouseMove)
 EVENT(E_MOUSEMOVE, MouseMove)
 {
 {
+    PARAM(P_X, X);                          // int (only when mouse visible)
+    PARAM(P_Y, Y);                          // int (only when mouse visible)
     PARAM(P_DX, DX);                        // int
     PARAM(P_DX, DX);                        // int
     PARAM(P_DY, DY);                        // int
     PARAM(P_DY, DY);                        // int
     PARAM(P_BUTTONS, Buttons);              // int
     PARAM(P_BUTTONS, Buttons);              // int

+ 30 - 8
Engine/UI/UI.cpp

@@ -234,6 +234,15 @@ void UI::RenderUpdate()
     
     
     PROFILE(GetUIBatches);
     PROFILE(GetUIBatches);
     
     
+    // If the OS cursor is visible, do not render the UI's own cursor
+    bool osCursorVisible = GetSubsystem<Input>()->IsMouseVisible();
+    bool uiCursorVisible = false;
+    if (osCursorVisible && cursor_)
+    {
+        uiCursorVisible = cursor_->IsVisible();
+        cursor_->SetTempVisible(false);
+    }
+    
     // Get batches & quads from the UI elements
     // Get batches & quads from the UI elements
     batches_.Clear();
     batches_.Clear();
     quads_.Clear();
     quads_.Clear();
@@ -243,6 +252,10 @@ void UI::RenderUpdate()
     // If no drag, reset cursor shape for next frame
     // If no drag, reset cursor shape for next frame
     if (cursor_ && !dragElement_)
     if (cursor_ && !dragElement_)
         cursor_->SetShape(CS_NORMAL);
         cursor_->SetShape(CS_NORMAL);
+    
+    // Restore UI cursor visibility state
+    if (osCursorVisible && cursor_)
+        cursor_->SetTempVisible(uiCursorVisible);
 }
 }
 
 
 void UI::Render()
 void UI::Render()
@@ -778,17 +791,26 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData)
     
     
     if (cursor_)
     if (cursor_)
     {
     {
+        Input* input = GetSubsystem<Input>();
         const IntVector2& rootSize = rootElement_->GetSize();
         const IntVector2& rootSize = rootElement_->GetSize();
         
         
-        // Move cursor only when visible
-        if (cursor_->IsVisible())
+        if (!input->IsMouseVisible())
         {
         {
-            IntVector2 pos = cursor_->GetPosition();
-            pos.x_ += eventData[P_DX].GetInt();
-            pos.y_ += eventData[P_DY].GetInt();
-            pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
-            pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
-            cursor_->SetPosition(pos);
+            // Relative mouse motion: move cursor only when visible
+            if (cursor_->IsVisible())
+            {
+                IntVector2 pos = cursor_->GetPosition();
+                pos.x_ += eventData[P_DX].GetInt();
+                pos.y_ += eventData[P_DY].GetInt();
+                pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
+                pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
+                cursor_->SetPosition(pos);
+            }
+        }
+        else
+        {
+            // Absolute mouse motion: move always
+            cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt()));
         }
         }
         
         
         if (dragElement_ && mouseButtons_)
         if (dragElement_ && mouseButtons_)

+ 5 - 0
Engine/UI/UIElement.cpp

@@ -1094,6 +1094,11 @@ void UIElement::SetHovering(bool enable)
     hovering_ = enable;
     hovering_ = enable;
 }
 }
 
 
+void UIElement::SetTempVisible(bool enable)
+{
+    visible_ = enable;
+}
+
 void UIElement::AdjustScissor(IntRect& currentScissor)
 void UIElement::AdjustScissor(IntRect& currentScissor)
 {
 {
     if (clipChildren_)
     if (clipChildren_)

+ 2 - 0
Engine/UI/UIElement.h

@@ -360,6 +360,8 @@ public:
     void SetChildOffset(const IntVector2& offset);
     void SetChildOffset(const IntVector2& offset);
     /// %Set hovering state.
     /// %Set hovering state.
     void SetHovering(bool enable);
     void SetHovering(bool enable);
+    /// %Set temporary visibility status without updating layout or sending events. Used internally.
+    void SetTempVisible(bool enable);
     /// Adjust scissor for rendering.
     /// Adjust scissor for rendering.
     void AdjustScissor(IntRect& currentScissor);
     void AdjustScissor(IntRect& currentScissor);
     /// Get UI rendering batches with a specified offset. Also recurses to child elements.
     /// Get UI rendering batches with a specified offset. Also recurses to child elements.