ocornut/imgui

Inertial scrolling [help needed]

Open

#2,675 建立於 2019年7月18日

在 GitHub 查看
 (1 留言) (0 反應) (0 負責人)C++ (73,213 star) (11,765 fork)batch import
help wantedscrolling

描述

Version: 1.72WIP Branch: master

Back-ends: imgui_impl_directX11.cpp + imgui_impl_win32.cpp Compiler: VS2017 Operating System: Windows 7 SP1 x64

I started an attempt to add inertial (kinetic/ballistic) scrolling to ImGui for a touch based application.

For now, I just started implementing the related gesture detection and the realtime speed computation.

This part of the code is added inside the ImGui::UpdateMouseInputs() function in ImGui.ccp

The code is very small for now, just some lines.

// Moving mouse less than this duration and distance (pixels) does not launch an inertial scroll.
const float InertialScrollThresholdTime = 0.25f;
const float InertialScrollThresholdDistance = 10.0f;

// SpeedDecay for each frame once scroll is launched, 0.95 means 95% of the preceding speed
const float InertialScrollSpeedDecay = 0.95f;
bool InertialScrollOngoing = false;
float CurrentInertialScrollSpeed =  0.0f;

static void ImGui::UpdateMouseInputs()
{
  ImGuiContext& g = *GImGui;

...
  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.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
    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.MouseDoubleClicked[i] = false;

    // New code for inertial scroll
    if (InertialScrollOngoing == true)
    {
      //TODO: Use deltatime instead of update on each frame.
      CurrentInertialScrollSpeed *= InertialScrollSpeedDecay;
      if (CurrentInertialScrollSpeed < 0.001f)
        InertialScrollOngoing = false;
    }

    if (g.IO.MouseReleased[i] &&
       (g.IO.MouseDownDurationPrev[i] >= InertialScrollThresholdTime) &&
       (g.IO.MouseDragMaxDistanceAbs[i].y > InertialScrollThresholdDistance))
    {
      // launch inertial scroll
      InertialScrollOngoing = true;
      CurrentInertialScrollSpeed = g.IO.MouseDragMaxDistanceAbs[i].y;
    }
    // end of new code for inertial scroll
...

In the following example, the red text is the actual speed of the scroll (CurrentInertialScrollSpeed ) we would apply on a scrolling area inertial

The detection of the movement to launch the scroll is not always working correctly. I do not know why so I just wanted to share and maybe someone has already worked on the subject. Do not consider this as an issue it is just some discussion.

Once detection and speed handling is working I have to do the actual scroll. And to be touch friendly it would be good to have the possibility to initiate the scroll from other areas than the scrollbar itself. I have no idea to handle this for now neither.

貢獻者指南