Inputs: Mouse: Amend c8e3a01 for tracking multiple clicks, renaming. (#3229)

This commit is contained in:
ocornut 2021-06-22 15:27:30 +02:00
parent 2318c764cf
commit 9c78fc928a
5 changed files with 37 additions and 33 deletions

View File

@ -38,6 +38,7 @@ Breaking Changes:
Other Changes: Other Changes:
- Added IsMouseTripleClicked() function. Tracking multi-click count in IO structure. (#3229) [@kudaba]
- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce
likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling
vkCmdSetScissor() explicitly every frame. (#4644) vkCmdSetScissor() explicitly every frame. (#4644)

View File

@ -3692,29 +3692,26 @@ static void ImGui::UpdateMouseInputs()
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
{ {
g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
g.IO.MouseClickedCount[i] = 0; // Will be filled below
g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f;
g.IO.MouseMultiClickCount[i] = 0;
if (g.IO.MouseClicked[i]) if (g.IO.MouseClicked[i])
{ {
bool is_repeated_click = false;
if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
{ {
ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
g.IO.MouseMultiClickTracker[i]++; is_repeated_click = true;
else
g.IO.MouseMultiClickTracker[i] = 1;
} }
if (is_repeated_click)
g.IO.MouseClickedLastCount[i]++;
else else
{ g.IO.MouseClickedLastCount[i] = 1;
g.IO.MouseMultiClickTracker[i] = 1;
}
g.IO.MouseClickedTime[i] = g.Time; g.IO.MouseClickedTime[i] = g.Time;
g.IO.MouseClickedPos[i] = g.IO.MousePos; g.IO.MouseClickedPos[i] = g.IO.MousePos;
g.IO.MouseMultiClickCount[i] = g.IO.MouseMultiClickTracker[i]; g.IO.MouseClickedCount[i] = g.IO.MouseClickedLastCount[i];
g.IO.MouseDownMultiClickCount[i] = g.IO.MouseMultiClickTracker[i];
g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
} }
@ -3727,9 +3724,11 @@ static void ImGui::UpdateMouseInputs()
g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y);
} }
if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i]) // We provide io.MouseDoubleClicked[] as a legacy service
g.IO.MouseDownMultiClickCount[i] = 0; g.IO.MouseDoubleClicked[i] = (g.IO.MouseClickedCount[i] == 2);
if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
// Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
if (g.IO.MouseClicked[i])
g.NavDisableMouseHover = false; g.NavDisableMouseHover = false;
} }
} }
@ -4770,14 +4769,14 @@ bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseMultiClickCount[button] == 2; return g.IO.MouseClickedCount[button] == 2;
} }
bool ImGui::IsMouseTripleClicked(ImGuiMouseButton button) bool ImGui::IsMouseTripleClicked(ImGuiMouseButton button)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseMultiClickCount[button] == 3; return g.IO.MouseClickedCount[button] == 3;
} }
// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. // Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
@ -5457,7 +5456,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
if (hovered || held) if (hovered || held)
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
if (held && g.IO.MouseMultiClickCount[0] == 2 && resize_grip_n == 0) if (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0)
{ {
// Manual auto-fit when double-clicking // Manual auto-fit when double-clicking
size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
@ -5992,7 +5991,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{ {
// We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.
ImRect title_bar_rect = window->TitleBarRect(); ImRect title_bar_rect = window->TitleBarRect();
if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseMultiClickCount[0] == 2) if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2)
window->WantCollapseToggle = true; window->WantCollapseToggle = true;
if (window->WantCollapseToggle) if (window->WantCollapseToggle)
{ {

View File

@ -1931,13 +1931,13 @@ struct ImGuiIO
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
ImVec2 MouseClickedPos[5]; // Position at time of clicking ImVec2 MouseClickedPos[5]; // Position at time of clicking
double MouseClickedTime[5]; // Time of last click (used to figure out double-click) double MouseClickedTime[5]; // Time of last click (used to figure out double-click)
bool MouseClicked[5]; // Mouse button went from !Down to Down bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0)
char MouseMultiClickTracker[5]; // Track multiple clicks over multiple frames bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2)
char MouseMultiClickCount[5]; // Has mouse button been clicked multiple times in a row? ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down
ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done.
bool MouseReleased[5]; // Mouse button went from Down to !Down bool MouseReleased[5]; // Mouse button went from Down to !Down
bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
bool MouseDownOwnedUnlessPopupClose[5];//Track if button was clicked inside a dear imgui window. bool MouseDownOwnedUnlessPopupClose[5];//Track if button was clicked inside a dear imgui window.
char MouseDownMultiClickCount[5]; // Track number of mouse down clicks in a row
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point

View File

@ -5518,12 +5518,16 @@ static void ShowDemoWindowMisc()
else else
ImGui::Text("Mouse pos: <INVALID>"); ImGui::Text("Mouse pos: <INVALID>");
ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } int count = IM_ARRAYSIZE(io.MouseDown);
ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)){ ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
ImGui::Text("Mouse tripleclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseTripleClicked(i)){ ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
ImGui::Text("Mouse clickcount:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseMultiClickTracker[i]) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, io.MouseMultiClickTracker[i]); } ImGui::Text(" - clicked double:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text(" - clicked triple:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseTripleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
ImGui::Text(" - clicked count:"); for (int i = 0; i < count; i++) if (io.MouseClickedCount[i]) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, io.MouseClickedCount[i]); }
//ImGui::Text(" - last count:"); for (int i = 0; i < count; i++) if (io.MouseClickedLastCount[i]) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, io.MouseClickedLastCount[i]); }
ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
ImGui::TreePop(); ImGui::TreePop();

View File

@ -564,7 +564,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
SetFocusID(id, window); SetFocusID(id, window);
FocusWindow(window); FocusWindow(window);
} }
if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseMultiClickCount[mouse_button_clicked] == 2)) if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2))
{ {
pressed = true; pressed = true;
if (flags & ImGuiButtonFlags_NoHoldingActiveId) if (flags & ImGuiButtonFlags_NoHoldingActiveId)
@ -641,7 +641,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if ((release_in || release_anywhere) && !g.DragDropActive) if ((release_in || release_anywhere) && !g.DragDropActive)
{ {
// Report as pressed when releasing the mouse (this is the most common path) // Report as pressed when releasing the mouse (this is the most common path)
bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDownMultiClickCount[mouse_button] == 2; bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2;
bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps <on release> bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps <on release>
if (!is_double_click_release && !is_repeating_already) if (!is_double_click_release && !is_repeating_already)
pressed = true; pressed = true;
@ -2409,7 +2409,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
{ {
const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]); const bool clicked = (hovered && g.IO.MouseClicked[0]);
const bool double_clicked = (hovered && g.IO.MouseMultiClickCount[0] == 2); const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2);
if (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id) if (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id)
{ {
SetActiveID(id, window); SetActiveID(id, window);
@ -4176,12 +4176,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f));
const bool is_osx = io.ConfigMacOSXBehaviors; const bool is_osx = io.ConfigMacOSXBehaviors;
if (select_all || (hovered && !is_osx && io.MouseMultiClickCount[0] == 2)) if (select_all || (hovered && !is_osx && io.MouseClickedCount[0] == 2))
{ {
state->SelectAll(); state->SelectAll();
state->SelectedAllMouseLock = true; state->SelectedAllMouseLock = true;
} }
else if (hovered && is_osx && io.MouseMultiClickCount[0] == 2) else if (hovered && is_osx && io.MouseClickedCount[0] == 2)
{ {
// Double-click select a word only, OS X style (by simulating keystrokes) // Double-click select a word only, OS X style (by simulating keystrokes)
state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
@ -5919,7 +5919,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
toggled = true; toggled = true;
if (flags & ImGuiTreeNodeFlags_OpenOnArrow) if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job
if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseMultiClickCount[0] == 2) if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2)
toggled = true; toggled = true;
} }
else if (pressed && g.DragDropHoldJustPressedId == id) else if (pressed && g.DragDropHoldJustPressedId == id)