Skip to content

Commit

Permalink
Scrolling: Made it possible for mouse wheel and navigation-triggered …
Browse files Browse the repository at this point in the history
…scrolling to override a call to SetScrollX()/SetScrollY(), making it possible to use a simpler stateless pattern for auto-scrolling.

Demo: Log, Console: Using a simpler stateless pattern for auto-scrolling.
  • Loading branch information
ocornut committed Jul 23, 2019
1 parent 34cf005 commit dcd03f6
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 42 deletions.
6 changes: 6 additions & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ Other Changes:
- InputTextMultiline: Fixed vertical scrolling tracking glitch.
- Word-wrapping: Fixed overzealous word-wrapping when glyph edge lands exactly on the limit. Because
of this, auto-fitting exactly unwrapped text would make it wrap. (fixes initial 1.15 commit, 78645a7d).
- Scrolling: Made it possible for mouse wheel and navigation-triggered scrolling to override a call to
SetScrollX()/SetScrollY(), making it possible to use a simpler stateless pattern for auto-scrolling:
// (Submit items..)
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) // Keep scrolling at the bottom if already
ImGui::SetScrollHereY(1.0f);
- Scrolling: Added SetScrollHereX(), SetScrollFromPosX() for completeness. (#1580) [@kevreco]
- Style: Attenuated default opacity of ImGuiCol_Separator in Classic and Light styles.
- Style: Added style.ColorButtonPosition (left/right, defaults to ImGuiDir_Right) to move the color button
Expand All @@ -86,6 +91,7 @@ Other Changes:
- ImDrawListSplitter: Fixed memory leak when using low-level split api (was not affecting ImDrawList api,
also this type was added in 1.71 and not advertised as a public-facing feature).
- Fonts: binary_to_compressed_c.cpp: Display an error message if failing to open/read the input font file.
- Demo: Log, Console: Using a simpler stateless pattern for auto-scrolling.
- Backends: DX10/DX11: Backup, clear and restore Geometry Shader is any is bound when calling renderer.
- Backends: DX11: Clear Hull Shader, Domain Shader, Compute Shader before rendering. Not backing/restoring them.
- Backends: OSX: Disabled default native Mac clipboard copy/paste implementation in core library (added in 1.71),
Expand Down
38 changes: 20 additions & 18 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3506,7 +3506,7 @@ void ImGui::UpdateMouseWheel()
{
float max_step = window->InnerRect.GetHeight() * 0.67f;
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
SetWindowScrollY(window, window->Scroll.y - wheel_y * scroll_step);
SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
}
}

Expand All @@ -3521,7 +3521,7 @@ void ImGui::UpdateMouseWheel()
{
float max_step = window->InnerRect.GetWidth() * 0.67f;
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
SetWindowScrollX(window, window->Scroll.x - wheel_x * scroll_step);
SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
}
}
}
Expand Down Expand Up @@ -6524,16 +6524,6 @@ ImVec2 ImGui::GetWindowPos()
return window->Pos;
}

void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
{
window->Scroll.x = new_scroll_x;
}

void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
{
window->Scroll.y = new_scroll_y;
}

void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
{
// Test condition (NB: bit 0 is always true) and clear flags for next time
Expand Down Expand Up @@ -6921,6 +6911,18 @@ void ImGui::SetScrollY(float scroll_y)
window->ScrollTargetCenterRatio.y = 0.0f;
}

void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x)
{
window->ScrollTarget.x = new_scroll_x;
window->ScrollTargetCenterRatio.x = 0.0f;
}

void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y)
{
window->ScrollTarget.y = new_scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
}

void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
Expand Down Expand Up @@ -8333,22 +8335,22 @@ static void ImGui::NavUpdate()
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
{
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
}

// *Normal* Manual scroll with NavScrollXXX keys
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
if (scroll_dir.x != 0.0f && window->ScrollbarX)
{
SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
g.NavMoveFromClampedRefRect = true;
}
if (scroll_dir.y != 0.0f)
{
SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
g.NavMoveFromClampedRefRect = true;
}
}
Expand Down Expand Up @@ -8466,9 +8468,9 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
// Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
SetWindowScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
SetWindowScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
}
else
{
Expand Down
30 changes: 10 additions & 20 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3449,7 +3449,7 @@ struct ExampleAppConsole
Commands.push_back("CLEAR");
Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
AutoScroll = true;
ScrollToBottom = true;
ScrollToBottom = false;
AddLog("Welcome to Dear ImGui!");
}
~ExampleAppConsole()
Expand All @@ -3470,7 +3470,6 @@ struct ExampleAppConsole
for (int i = 0; i < Items.Size; i++)
free(Items[i]);
Items.clear();
ScrollToBottom = true;
}

void AddLog(const char* fmt, ...) IM_FMTARGS(2)
Expand All @@ -3483,8 +3482,6 @@ struct ExampleAppConsole
buf[IM_ARRAYSIZE(buf)-1] = 0;
va_end(args);
Items.push_back(Strdup(buf));
if (AutoScroll)
ScrollToBottom = true;
}

void Draw(const char* title, bool* p_open)
Expand Down Expand Up @@ -3513,18 +3510,15 @@ struct ExampleAppConsole
if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine();
bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine();
if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true;
bool copy_to_clipboard = ImGui::SmallButton("Copy");
//static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }

ImGui::Separator();

// Options menu
if (ImGui::BeginPopup("Options"))
{
if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
if (AutoScroll)
ScrollToBottom = true;
ImGui::Checkbox("Auto-scroll", &AutoScroll);
ImGui::EndPopup();
}

Expand Down Expand Up @@ -3573,9 +3567,11 @@ struct ExampleAppConsole
}
if (copy_to_clipboard)
ImGui::LogFinish();
if (ScrollToBottom)

if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
ImGui::SetScrollHereY(1.0f);
ScrollToBottom = false;

ImGui::PopStyleVar();
ImGui::EndChild();
ImGui::Separator();
Expand Down Expand Up @@ -3767,13 +3763,11 @@ struct ExampleAppLog
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines
bool AutoScroll;
bool ScrollToBottom;
bool AutoScroll; // Keep scrolling if already at the bottom

ExampleAppLog()
{
AutoScroll = true;
ScrollToBottom = false;
Clear();
}

Expand All @@ -3794,8 +3788,6 @@ struct ExampleAppLog
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n')
LineOffsets.push_back(old_size + 1);
if (AutoScroll)
ScrollToBottom = true;
}

void Draw(const char* title, bool* p_open = NULL)
Expand All @@ -3809,9 +3801,7 @@ struct ExampleAppLog
// Options menu
if (ImGui::BeginPopup("Options"))
{
if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
if (AutoScroll)
ScrollToBottom = true;
ImGui::Checkbox("Auto-scroll", &AutoScroll);
ImGui::EndPopup();
}

Expand Down Expand Up @@ -3876,9 +3866,9 @@ struct ExampleAppLog
}
ImGui::PopStyleVar();

if (ScrollToBottom)
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);
ScrollToBottom = false;

ImGui::EndChild();
ImGui::End();
}
Expand Down
4 changes: 2 additions & 2 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1460,8 +1460,8 @@ namespace ImGui
IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window);
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
IMGUI_API void SetScrollX(ImGuiWindow* window, float new_scroll_x);
IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y);
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
Expand Down
4 changes: 2 additions & 2 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3637,8 +3637,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_

if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
Expand Down

0 comments on commit dcd03f6

Please sign in to comment.