UI utilities - "User" scrollbar
A scrollbar that can be used at will rather than on windows only.
This commit is contained in:
parent
99264594f6
commit
8d2aac85b3
2 changed files with 153 additions and 0 deletions
124
ui-utilities.cc
124
ui-utilities.cc
|
@ -3,6 +3,7 @@
|
||||||
#include "c-utilities.hh"
|
#include "c-utilities.hh"
|
||||||
#include "ui-utilities.hh"
|
#include "ui-utilities.hh"
|
||||||
|
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +75,129 @@ uint32_t ImGui::ColorHSVAToU32(
|
||||||
return GetColorU32( out );
|
return GetColorU32( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Code stolen and modified from ImGui itself
|
||||||
|
bool ImGui::UserScrollbar(
|
||||||
|
const bool horizontal ,
|
||||||
|
const float total ,
|
||||||
|
const float display ,
|
||||||
|
float* const scrollPos ,
|
||||||
|
const ImVec2 topLeft ,
|
||||||
|
const float length ,
|
||||||
|
char const* const name ) noexcept
|
||||||
|
{
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
ImGuiWindow* const window = g.CurrentWindow;
|
||||||
|
ImDrawList* const dl = window->DrawList;
|
||||||
|
|
||||||
|
const ImGuiStyle& style = g.Style;
|
||||||
|
const ImGuiID id = window->GetID( name ? name :
|
||||||
|
( horizontal ? "#UserScrollX" : "#UserScrollY" ) );
|
||||||
|
|
||||||
|
// Render background
|
||||||
|
ImRect bb = horizontal
|
||||||
|
? ImRect( topLeft , topLeft + ImVec2( length , style.ScrollbarSize ) )
|
||||||
|
: ImRect( topLeft , topLeft + ImVec2( style.ScrollbarSize , length ) );
|
||||||
|
ImRect contentArea = window->ContentsRegionRect;
|
||||||
|
contentArea.Translate( window->Pos );
|
||||||
|
if ( !bb.Overlaps( contentArea ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dl->AddRectFilled( bb.Min , bb.Max , GetColorU32( ImGuiCol_ScrollbarBg ) );
|
||||||
|
bb.Expand( ImVec2(
|
||||||
|
-ImClamp( (float)(int)( ( bb.Max.x - bb.Min.x - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) ,
|
||||||
|
-ImClamp( (float)(int)( ( bb.Max.y - bb.Min.y - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) ) );
|
||||||
|
|
||||||
|
// V denote the main, longer axis of the scrollbar (= height for a
|
||||||
|
// vertical scrollbar)
|
||||||
|
const float scrollbarSizeV = horizontal ? bb.GetWidth( ) : bb.GetHeight( );
|
||||||
|
float scrollV = *scrollPos;
|
||||||
|
|
||||||
|
// Calculate the height of our grabbable box. It generally represent
|
||||||
|
// the amount visible (vs the total scrollable amount) But we maintain
|
||||||
|
// a minimum size in pixel to allow for the user to still aim inside.
|
||||||
|
const float maxSize = ImMax( ImMax( total , display ) , 1.0f );
|
||||||
|
const float grabSizePx = ImClamp( scrollbarSizeV * ( display / maxSize ) ,
|
||||||
|
style.GrabMinSize , scrollbarSizeV );
|
||||||
|
const float grabSizeNorm = grabSizePx / scrollbarSizeV;
|
||||||
|
|
||||||
|
// Handle input right away.
|
||||||
|
bool held = false;
|
||||||
|
bool hovered = false;
|
||||||
|
const bool previouslyHeld = ( g.ActiveId == id );
|
||||||
|
ButtonBehavior( bb , id , &hovered , &held );
|
||||||
|
|
||||||
|
const float scrollMax = ImMax( 1.0f , total - display );
|
||||||
|
float scrollRatio = ImSaturate( scrollV / scrollMax );
|
||||||
|
float grabNorm = scrollRatio * ( scrollbarSizeV - grabSizePx ) / scrollbarSizeV;
|
||||||
|
if ( held && grabSizeNorm < 1.0f ) {
|
||||||
|
ImGuiStorage* const storage = window->DC.StateStorage;
|
||||||
|
const float scrollbarPosV = horizontal ? bb.Min.x : bb.Min.y;
|
||||||
|
const float mousePos = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
|
||||||
|
float clickDeltaToGrabCenter = storage->GetFloat( id );
|
||||||
|
|
||||||
|
// Click position in scrollbar normalized space (0.0f->1.0f)
|
||||||
|
const float clickedVNorm = ImSaturate(
|
||||||
|
( mousePos - scrollbarPosV ) / scrollbarSizeV );
|
||||||
|
SetHoveredID( id );
|
||||||
|
|
||||||
|
bool seekAbsolute = false;
|
||||||
|
if ( !previouslyHeld ) {
|
||||||
|
// On initial click calculate the distance between mouse
|
||||||
|
// and the center of the grab
|
||||||
|
if ( clickedVNorm >= grabNorm && clickedVNorm <= grabNorm + grabSizeNorm ) {
|
||||||
|
clickDeltaToGrabCenter = clickedVNorm - grabNorm - grabSizeNorm * 0.5f;
|
||||||
|
} else {
|
||||||
|
seekAbsolute = true;
|
||||||
|
clickDeltaToGrabCenter = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply scroll
|
||||||
|
const float scrollVNorm = ImSaturate(
|
||||||
|
( clickedVNorm - clickDeltaToGrabCenter - grabSizeNorm * 0.5f )
|
||||||
|
/ ( 1.0f - grabSizeNorm ) );
|
||||||
|
scrollV = (float)(int)( 0.5f + scrollVNorm * scrollMax );
|
||||||
|
|
||||||
|
// Update values for rendering
|
||||||
|
scrollRatio = ImSaturate( scrollV / scrollMax );
|
||||||
|
grabNorm = scrollRatio * ( scrollbarSizeV - grabSizePx ) / scrollbarSizeV;
|
||||||
|
|
||||||
|
// Update distance to grab now that we have seeked and saturated
|
||||||
|
if ( seekAbsolute ) {
|
||||||
|
clickDeltaToGrabCenter = clickedVNorm - grabNorm - grabSizeNorm * 0.5f;
|
||||||
|
}
|
||||||
|
storage->SetFloat( id , clickDeltaToGrabCenter );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render
|
||||||
|
const ImU32 grabCol = GetColorU32(
|
||||||
|
held ? ImGuiCol_ScrollbarGrabActive
|
||||||
|
: hovered ? ImGuiCol_ScrollbarGrabHovered
|
||||||
|
: ImGuiCol_ScrollbarGrab);
|
||||||
|
ImRect grabRect;
|
||||||
|
if ( horizontal ) {
|
||||||
|
grabRect = ImRect(
|
||||||
|
ImLerp( bb.Min.x , bb.Max.x , grabNorm ) , bb.Min.y,
|
||||||
|
ImMin( ImLerp( bb.Min.x , bb.Max.x , grabNorm ) + grabSizePx ,
|
||||||
|
contentArea.Max.x ) , bb.Max.y );
|
||||||
|
} else {
|
||||||
|
grabRect = ImRect(
|
||||||
|
bb.Min.x, ImLerp( bb.Min.y , bb.Max.y , grabNorm ) ,
|
||||||
|
bb.Max.x , ImMin(
|
||||||
|
ImLerp( bb.Min.y , bb.Max.y , grabNorm ) + grabSizePx ,
|
||||||
|
contentArea.Max.y ) );
|
||||||
|
}
|
||||||
|
dl->AddRectFilled( grabRect.Min , grabRect.Max , grabCol , style.ScrollbarRounding );
|
||||||
|
|
||||||
|
if ( scrollV != *scrollPos ) {
|
||||||
|
*scrollPos = scrollV;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*= T_CameraMouseControl =======================================================*/
|
/*= T_CameraMouseControl =======================================================*/
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,35 @@ namespace ImGui {
|
||||||
float value ,
|
float value ,
|
||||||
float alpha ) noexcept;
|
float alpha ) noexcept;
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* "User" scrollbar
|
||||||
|
*
|
||||||
|
* Code ripped from ImGui and modified so it can be used in other
|
||||||
|
* circumstances.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* horizontal Horizontal bar if true, vertical bar if false
|
||||||
|
* total Total size of the scrolled area
|
||||||
|
* display Size of the displayed area
|
||||||
|
* pos Pointer to the position, will be updated when
|
||||||
|
* scrolled
|
||||||
|
* topLeft Top-left corner of the scroll bar
|
||||||
|
* length Width of the scrollbar (if horizontal)
|
||||||
|
* Height of the scrollbar (if vertical)
|
||||||
|
* name Name of the widget; if NULL, #UserScrollX will
|
||||||
|
* be used by default for horizontal scrollbars,
|
||||||
|
* or #UserScrollY for vertical scrollbars
|
||||||
|
*/
|
||||||
|
bool UserScrollbar(
|
||||||
|
bool horizontal ,
|
||||||
|
float total ,
|
||||||
|
float display ,
|
||||||
|
float* pos ,
|
||||||
|
ImVec2 topLeft ,
|
||||||
|
float length ,
|
||||||
|
char const* name = nullptr ) noexcept;
|
||||||
|
|
||||||
} // namespace ImGui
|
} // namespace ImGui
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in a new issue