Browse Source

Merge remote-tracking branch 'hdunderscore/UIDrag_Bugfix'

Lasse Öörni 11 years ago
parent
commit
0821dd482f

+ 6 - 6
Bin/Data/LuaScripts/37_UIDrag.lua

@@ -1,8 +1,8 @@
--- Urho2D tile map example.
+-- Urho3D UI Drag Example:
 -- This sample demonstrates:
 -- This sample demonstrates:
---     - Creating a 2D scene with tile map
---     - Displaying the scene using the Renderer subsystem
---     - Handling keyboard to move and zoom 2D camera
+--     - Creating GUI elements from AngelScript
+--     - Loading GUI Style from xml
+--     - Subscribing to GUI drag events and handling them.
 
 
 require "LuaScripts/Utilities/Sample"
 require "LuaScripts/Utilities/Sample"
 VAR_BUTTONS = StringHash("BUTTONS")
 VAR_BUTTONS = StringHash("BUTTONS")
@@ -130,7 +130,7 @@ function HandleDragBegin(eventType, eventData)
     local lx = eventData:GetInt("X")
     local lx = eventData:GetInt("X")
     local ly = eventData:GetInt("Y")
     local ly = eventData:GetInt("Y")
 
 
-    local p = element:GetPosition()
+    local p = element.position
     element:SetVar(VAR_START, Variant(p))
     element:SetVar(VAR_START, Variant(p))
     element:SetVar(VAR_DELTA, Variant(Vector2(p.x - lx, p.y - ly)))
     element:SetVar(VAR_DELTA, Variant(Vector2(p.x - lx, p.y - ly)))
 
 
@@ -171,7 +171,7 @@ function HandleUpdate(eventType, eventData)
         local t = tolua.cast(ui.root:GetChild("Touch " .. i), 'Text')
         local t = tolua.cast(ui.root:GetChild("Touch " .. i), 'Text')
         local ts = input:GetTouch(i)
         local ts = input:GetTouch(i)
 
 
-        local pos = ts:GetPosition()
+        local pos = ts.position
         pos.y = pos.y - 30
         pos.y = pos.y - 30
 
 
         t:SetPosition(pos)
         t:SetPosition(pos)

+ 4 - 4
Bin/Data/Scripts/37_UIDrag.as

@@ -1,8 +1,8 @@
-// Urho2D tile map example.
+// Urho3D UI Drag Example:
 // This sample demonstrates:
 // This sample demonstrates:
-//     - Creating a 2D scene with tile map
-//     - Displaying the scene using the Renderer subsystem
-//     - Handling keyboard to move and zoom 2D camera
+//     - Creating GUI elements from AngelScript
+//     - Loading GUI Style from xml
+//     - Subscribing to GUI drag events and handling them.
 
 
 #include "Scripts/Utilities/Sample.as"
 #include "Scripts/Utilities/Sample.as"
 StringHash VAR_BUTTONS("BUTTONS");
 StringHash VAR_BUTTONS("BUTTONS");

+ 67 - 3
Source/Engine/Input/Input.cpp

@@ -61,6 +61,8 @@ const StringHash VAR_BUTTON_MOUSE_BUTTON_BINDING("VAR_BUTTON_MOUSE_BUTTON_BINDIN
 const StringHash VAR_LAST_KEYSYM("VAR_LAST_KEYSYM");
 const StringHash VAR_LAST_KEYSYM("VAR_LAST_KEYSYM");
 const StringHash VAR_SCREEN_JOYSTICK_ID("VAR_SCREEN_JOYSTICK_ID");
 const StringHash VAR_SCREEN_JOYSTICK_ID("VAR_SCREEN_JOYSTICK_ID");
 
 
+const unsigned TOUCHID_MAX = 32;
+
 /// Convert SDL keycode if necessary.
 /// Convert SDL keycode if necessary.
 int ConvertSDLKeyCode(int keySym, int scanCode)
 int ConvertSDLKeyCode(int keySym, int scanCode)
 {
 {
@@ -114,6 +116,9 @@ Input::Input(Context* context) :
     suppressNextMouseMove_(false),
     suppressNextMouseMove_(false),
     initialized_(false)
     initialized_(false)
 {
 {
+    for (int i = 0; i < TOUCHID_MAX; i++)
+        availableTouchIDs_.Push(i);
+
     SubscribeToEvent(E_SCREENMODE, HANDLER(Input, HandleScreenMode));
     SubscribeToEvent(E_SCREENMODE, HANDLER(Input, HandleScreenMode));
 
 
     // Try to initialize right now, but skip if screen mode is not yet set
     // Try to initialize right now, but skip if screen mode is not yet set
@@ -928,6 +933,62 @@ void Input::ResetTouches()
     touches_.Clear();
     touches_.Clear();
 }
 }
 
 
+unsigned Input::GetTouchIndexFromID(int touchID)
+{
+    HashMap<int, int>::ConstIterator i = touchIDMap_.Find(touchID);
+    if (i != touchIDMap_.End())
+    {
+        return i->second_;
+    }
+
+    int index = PopTouchIndex();
+    touchIDMap_[touchID] = index;
+    return index;
+}
+
+unsigned Input::PopTouchIndex()
+{
+    if (availableTouchIDs_.Empty())
+        return 0;
+
+    unsigned index = availableTouchIDs_.Front();
+    availableTouchIDs_.PopFront();
+    return index;
+}
+
+void Input::PushTouchIndex(int touchID)
+{
+    HashMap<int, int>::ConstIterator ci = touchIDMap_.Find(touchID);
+    if (ci == touchIDMap_.End())
+        return;
+
+    int index = touchIDMap_[touchID];
+    touchIDMap_.Erase(touchID);
+
+    // Sorted insertion
+    bool inserted = false;
+    for (List<int>::Iterator i = availableTouchIDs_.Begin(); i != availableTouchIDs_.End(); ++i)
+    {
+        if (*i == index)
+        {
+            // This condition can occur when TOUCHID_MAX is reached.
+            inserted = true;
+            break;
+        }
+
+        if (*i > index)
+        {
+            availableTouchIDs_.Insert(i, index);
+            inserted = true;
+            break;
+        }
+    }
+
+    // If empty, or the lowest value then insert at end.
+    if (!inserted)
+        availableTouchIDs_.Push(index);
+}
+
 void Input::SendInputFocusEvent()
 void Input::SendInputFocusEvent()
 {
 {
     using namespace InputFocus;
     using namespace InputFocus;
@@ -1172,7 +1233,7 @@ void Input::HandleSDLEvent(void* sdlEvent)
     case SDL_FINGERDOWN:
     case SDL_FINGERDOWN:
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         {
         {
-            int touchID = evt.tfinger.fingerId & 0x7ffffff;
+            int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
             TouchState& state = touches_[touchID];
             TouchState& state = touches_[touchID];
             state.touchID_ = touchID;
             state.touchID_ = touchID;
             state.lastPosition_ = state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
             state.lastPosition_ = state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
@@ -1194,7 +1255,7 @@ void Input::HandleSDLEvent(void* sdlEvent)
     case SDL_FINGERUP:
     case SDL_FINGERUP:
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         {
         {
-            int touchID = evt.tfinger.fingerId & 0x7ffffff;
+            int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
             TouchState& state = touches_[touchID];
             TouchState& state = touches_[touchID];
 
 
             using namespace TouchEnd;
             using namespace TouchEnd;
@@ -1207,6 +1268,9 @@ void Input::HandleSDLEvent(void* sdlEvent)
             eventData[P_Y] = state.position_.y_;
             eventData[P_Y] = state.position_.y_;
             SendEvent(E_TOUCHEND, eventData);
             SendEvent(E_TOUCHEND, eventData);
 
 
+            // Add touch index back to list of available touch Ids
+            PushTouchIndex(touchID);
+
             touches_.Erase(touchID);
             touches_.Erase(touchID);
         }
         }
         break;
         break;
@@ -1214,7 +1278,7 @@ void Input::HandleSDLEvent(void* sdlEvent)
     case SDL_FINGERMOTION:
     case SDL_FINGERMOTION:
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
         {
         {
-            int touchID = evt.tfinger.fingerId & 0x7ffffff;
+            int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
             // We don't want this event to create a new touches_ event if it doesn't exist (touchEmulation)
             // We don't want this event to create a new touches_ event if it doesn't exist (touchEmulation)
             if (touchEmulation_ && !touches_.Contains(touchID))
             if (touchEmulation_ && !touches_.Contains(touchID))
                 break;
                 break;

+ 11 - 0
Source/Engine/Input/Input.h

@@ -26,6 +26,7 @@
 #include "InputEvents.h"
 #include "InputEvents.h"
 #include "Mutex.h"
 #include "Mutex.h"
 #include "Object.h"
 #include "Object.h"
+#include "List.h"
 
 
 namespace Urho3D
 namespace Urho3D
 {
 {
@@ -243,6 +244,12 @@ private:
     void ResetState();
     void ResetState();
     /// Clear touch states and send touch end events.
     /// Clear touch states and send touch end events.
     void ResetTouches();
     void ResetTouches();
+    /// Get the index of a touch based on the touch ID.
+    unsigned GetTouchIndexFromID(int touchID);
+    /// Used internally to return and remove the next available touch index.
+    unsigned PopTouchIndex();
+    /// Push a touch index back into the list of available when finished with it.
+    void PushTouchIndex(int touchID);
     /// Send an input focus or window minimization change event.
     /// Send an input focus or window minimization change event.
     void SendInputFocusEvent();
     void SendInputFocusEvent();
     /// Handle a mouse button change.
     /// Handle a mouse button change.
@@ -274,6 +281,10 @@ private:
     HashSet<int> scancodePress_;
     HashSet<int> scancodePress_;
     /// Active finger touches.
     /// Active finger touches.
     HashMap<int, TouchState> touches_;
     HashMap<int, TouchState> touches_;
+    /// List that maps between event touch IDs and normalised touch IDs
+    List<int> availableTouchIDs_;
+    /// Mapping of touch indicies
+    HashMap<int, int> touchIDMap_;
     /// String for text input.
     /// String for text input.
     String textInput_;
     String textInput_;
     /// Opened joysticks.
     /// Opened joysticks.

+ 6 - 16
Source/Engine/UI/UI.cpp

@@ -1481,7 +1481,7 @@ void UI::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
     IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
     IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
     usingTouchInput_ = true;
     usingTouchInput_ = true;
 
 
-    int touchId = TOUCHID_MASK(GetTouchIndexFromID(eventData[P_TOUCHID].GetInt()));
+    int touchId = TOUCHID_MASK(eventData[P_TOUCHID].GetInt());
     WeakPtr<UIElement> element(GetElementAt(pos));
     WeakPtr<UIElement> element(GetElementAt(pos));
 
 
     if (element)
     if (element)
@@ -1498,7 +1498,10 @@ void UI::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
     using namespace TouchEnd;
     using namespace TouchEnd;
 
 
     IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
     IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
-    int touchId = TOUCHID_MASK(GetTouchIndexFromID(eventData[P_TOUCHID].GetInt()));
+
+    // Get the touch index
+    int eventTouchId = eventData[P_TOUCHID].GetInt();
+    int touchId = TOUCHID_MASK(eventTouchId);
 
 
     // Transmit hover end to the position where the finger was lifted
     // Transmit hover end to the position where the finger was lifted
     WeakPtr<UIElement> element(GetElementAt(pos));
     WeakPtr<UIElement> element(GetElementAt(pos));
@@ -1527,7 +1530,7 @@ void UI::HandleTouchMove(StringHash eventType, VariantMap& eventData)
     IntVector2 deltaPos(eventData[P_DX].GetInt(), eventData[P_DY].GetInt());
     IntVector2 deltaPos(eventData[P_DX].GetInt(), eventData[P_DY].GetInt());
     usingTouchInput_ = true;
     usingTouchInput_ = true;
 
 
-    int touchId = TOUCHID_MASK(GetTouchIndexFromID(eventData[P_TOUCHID].GetInt()));
+    int touchId = TOUCHID_MASK(eventData[P_TOUCHID].GetInt());
 
 
     ProcessMove(pos, deltaPos, touchId, 0, 0, true);
     ProcessMove(pos, deltaPos, touchId, 0, 0, true);
 }
 }
@@ -1736,19 +1739,6 @@ IntVector2 UI::SumTouchPositions(UI::DragData* dragData, const IntVector2& oldSe
     return sendPos;
     return sendPos;
 }
 }
 
 
-unsigned UI::GetTouchIndexFromID(int touchID)
-{
-    Input* input = GetSubsystem<Input>();
-    unsigned numTouches = input->GetNumTouches();
-    for (unsigned i = 0; i < numTouches; ++i)
-    {
-        TouchState* touch = input->GetTouch(i);
-        if (touch->touchID_ == touchID)
-            return i;
-    }
-    return 0; // Should not happen
-}
-
 void RegisterUILibrary(Context* context)
 void RegisterUILibrary(Context* context)
 {
 {
     Font::RegisterObject(context);
     Font::RegisterObject(context);

+ 0 - 2
Source/Engine/UI/UI.h

@@ -229,8 +229,6 @@ private:
     void ProcessDragCancel();
     void ProcessDragCancel();
     /// Sum touch positions and return the begin position ready to send.
     /// Sum touch positions and return the begin position ready to send.
     IntVector2 SumTouchPositions(UI::DragData* dragData, const IntVector2& oldSendPos);
     IntVector2 SumTouchPositions(UI::DragData* dragData, const IntVector2& oldSendPos);
-    /// Get the index of a touch based on the touch ID.
-    unsigned GetTouchIndexFromID(int touchID);
 
 
     /// Graphics subsystem.
     /// Graphics subsystem.
     WeakPtr<Graphics> graphics_;
     WeakPtr<Graphics> graphics_;

+ 2 - 2
Source/Engine/UI/UIElement.h

@@ -158,9 +158,9 @@ public:
     /// React to mouse drag motion.
     /// React to mouse drag motion.
     virtual void OnDragMove(const IntVector2& position, const IntVector2& screenPosition, const IntVector2& deltaPos, int buttons, int qualifiers, Cursor* cursor);
     virtual void OnDragMove(const IntVector2& position, const IntVector2& screenPosition, const IntVector2& deltaPos, int buttons, int qualifiers, Cursor* cursor);
     /// React to mouse drag end.
     /// React to mouse drag end.
-    virtual void OnDragEnd(const IntVector2& position, const IntVector2& screenPosition, int dragButtons, int buttons, Cursor* cursor);
+    virtual void OnDragEnd(const IntVector2& position, const IntVector2& screenPosition, int dragButtons, int releaseButton, Cursor* cursor);
     /// React to a mouse drag cancel event (ie, when an extra button is pressed)
     /// React to a mouse drag cancel event (ie, when an extra button is pressed)
-    virtual void OnDragCancel(const IntVector2& position, const IntVector2& screenPosition, int dragButtons, int buttons, Cursor* cursor);
+    virtual void OnDragCancel(const IntVector2& position, const IntVector2& screenPosition, int dragButtons, int cancelButton, Cursor* cursor);
     /// React to drag and drop test. Return true to signal that the drop is acceptable.
     /// React to drag and drop test. Return true to signal that the drop is acceptable.
     virtual bool OnDragDropTest(UIElement* source);
     virtual bool OnDragDropTest(UIElement* source);
     /// React to drag and drop finish. Return true to signal that the drop was accepted.
     /// React to drag and drop finish. Return true to signal that the drop was accepted.

+ 1 - 2
Source/Samples/37_UIDrag/UIDrag.h

@@ -34,8 +34,7 @@ namespace Urho3D
 /// This sample demonstrates:
 /// This sample demonstrates:
 ///     - Creating GUI elements from C++
 ///     - Creating GUI elements from C++
 ///     - Loading GUI Style from xml
 ///     - Loading GUI Style from xml
-///     - Subscribing to GUI events and handling them.
-///     - Using the drag edit of a LineEdit.
+///     - Subscribing to GUI drag events and handling them.
 class UIDrag : public Sample
 class UIDrag : public Sample
 {
 {
     OBJECT(UIDrag);
     OBJECT(UIDrag);