@ -380,6 +380,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
// - ArrowButton()
// - CloseButton() [Internal]
// - CollapseButton() [Internal]
// - ScrollbarEx() [Internal]
// - Scrollbar() [Internal]
// - Image()
// - ImageButton()
@ -777,125 +778,133 @@ ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
void ImGui : : Scrollbar ( ImGuiAxis axis )
// Still, the code should probably be made simpler..
bool ImGui : : ScrollbarEx ( const ImRect & bb_frame , ImGuiID id , ImGuiAxis axis , float * p_scroll_v , float size_avail_v , float size_contents_v , ImDrawCornerFlags rounding_corners )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( window - > SkipItems )
return false ;
const bool horizontal = ( axis = = ImGuiAxis_X ) ;
const ImGuiStyle & style = g . Style ;
const ImGuiID id = GetScrollbarID ( window , axis ) ;
KeepAliveID ( id ) ;
// Render background
bool other_scrollbar = ( horizontal ? window - > ScrollbarY : window - > ScrollbarX ) ;
float other_scrollbar_size_w = other_scrollbar ? style . ScrollbarSize : 0.0f ;
const ImRect host_rect = window - > Rect ( ) ;
const float border_size = window - > WindowBorderSize ;
ImRect bb = horizontal
? ImRect ( host_rect . Min . x + border_size , host_rect . Max . y - style . ScrollbarSize , host_rect . Max . x - other_scrollbar_size_w - border_size , host_rect . Max . y - border_size )
: ImRect ( host_rect . Max . x - style . ScrollbarSize , host_rect . Min . y + border_size , host_rect . Max . x - border_size , host_rect . Max . y - other_scrollbar_size_w - border_size ) ;
bb . Min . x = ImMax ( host_rect . Min . x , bb . Min . x ) ; // Handle case where the host rectangle is smaller than the scrollbar
bb . Min . y = ImMax ( host_rect . Min . y , bb . Min . y ) ;
if ( ! horizontal )
bb . Min . y + = window - > TitleBarHeight ( ) + ( ( window - > Flags & ImGuiWindowFlags_MenuBar ) ? window - > MenuBarHeight ( ) : 0.0f ) ; // FIXME: InnerRect?
const float bb_width = bb . GetWidth ( ) ;
const float bb_height = bb . GetHeight ( ) ;
if ( bb_width < = 0.0f | | bb_height < = 0.0f )
return ;
const float bb_frame_width = bb_frame . GetWidth ( ) ;
const float bb_frame_height = bb_frame . GetHeight ( ) ;
if ( bb_frame_width < = 0.0f | | bb_frame_height < = 0.0f )
return false ;
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab)
float alpha = 1.0f ;
if ( ( axis = = ImGuiAxis_Y ) & & bb_ height < g . FontSize + g . Style . FramePadding . y * 2.0f )
{
alpha = ImSaturate ( ( bb_height - g . FontSize ) / ( g . Style . FramePadding . y * 2.0f ) ) ;
if ( alpha < = 0.0f )
return ;
}
if ( ( axis = = ImGuiAxis_Y ) & & bb_frame_height < g . FontSize + g . Style . FramePadding . y * 2.0f )
alpha = ImSaturate ( ( bb_frame_height - g . FontSize ) / ( g . Style . FramePadding . y * 2.0f ) ) ;
if ( alpha < = 0.0f )
return false ;
const ImGuiStyle & style = g . Style ;
const bool allow_interaction = ( alpha > = 1.0f ) ;
const bool horizontal = ( axis = = ImGuiAxis_X ) ;
int window_rounding_corners ;
if ( horizontal )
window_rounding_corners = ImDrawCornerFlags_BotLeft | ( other_scrollbar ? 0 : ImDrawCornerFlags_BotRight ) ;
else
window_rounding_corners = ( ( ( window - > Flags & ImGuiWindowFlags_NoTitleBar ) & & ! ( window - > Flags & ImGuiWindowFlags_MenuBar ) ) ? ImDrawCornerFlags_TopRight : 0 ) | ( other_scrollbar ? 0 : ImDrawCornerFlags_BotRight ) ;
window - > DrawList - > AddRectFilled ( bb . Min , bb . Max , GetColorU32 ( ImGuiCol_ScrollbarBg ) , window - > WindowRounding , window_rounding_corners ) ;
bb . Expand ( ImVec2 ( - ImClamp ( ( float ) ( int ) ( ( bb_width - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) , - ImClamp ( ( float ) ( int ) ( ( bb_height - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) ) ) ;
ImRect bb = bb_frame ;
bb . Expand ( ImVec2 ( - ImClamp ( ( float ) ( int ) ( ( bb_frame_width - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) , - ImClamp ( ( float ) ( int ) ( ( bb_frame_height - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) ) ) ;
// V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
float scrollbar_size_v = horizontal ? bb . GetWidth ( ) : bb . GetHeight ( ) ;
float scroll_v = horizontal ? window - > Scroll . x : window - > Scroll . y ;
float win_size_avail_v = ( horizontal ? window - > SizeFull . x : window - > SizeFull . y ) - other_scrollbar_size_w ;
float win_size_contents_v = horizontal ? window - > SizeContents . x : window - > SizeContents . y ;
const float scrollbar_size_v = horizontal ? bb . GetWidth ( ) : bb . GetHeight ( ) ;
// 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.
IM_ASSERT ( ImMax ( win_ size_contents_v, win_ size_avail_v) > 0.0f ) ; // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
const float win_size_v = ImMax ( ImMax ( win_ size_contents_v, win_ size_avail_v) , 1.0f ) ;
const float grab_h_pixels = ImClamp ( scrollbar_size_v * ( win_ size_avail_v / win_size_v ) , style . GrabMinSize , scrollbar_size_v ) ;
IM_ASSERT ( ImMax ( size_contents_v, size_avail_v) > 0.0f ) ; // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
const float win_size_v = ImMax ( ImMax ( size_contents_v, size_avail_v) , 1.0f ) ;
const float grab_h_pixels = ImClamp ( scrollbar_size_v * ( size_avail_v / win_size_v ) , style . GrabMinSize , scrollbar_size_v ) ;
const float grab_h_norm = grab_h_pixels / scrollbar_size_v ;
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
bool held = false ;
bool hovered = false ;
const bool previously_held = ( g . ActiveId = = id ) ;
ButtonBehavior ( bb , id , & hovered , & held , ImGuiButtonFlags_NoNavFocus ) ;
float scroll_max = ImMax ( 1.0f , win_ size_contents_v - win_ size_avail_v) ;
float scroll_ratio = ImSaturate ( scroll_v / scroll_max ) ;
float scroll_max = ImMax ( 1.0f , size_contents_v - size_avail_v) ;
float scroll_ratio = ImSaturate ( * p_ scroll_v / scroll_max ) ;
float grab_v_norm = scroll_ratio * ( scrollbar_size_v - grab_h_pixels ) / scrollbar_size_v ;
if ( held & & allow_interaction & & grab_h_norm < 1.0f )
{
float scrollbar_pos_v = horizontal ? bb . Min . x : bb . Min . y ;
float mouse_pos_v = horizontal ? g . IO . MousePos . x : g . IO . MousePos . y ;
float * click_delta_to_grab_center_v = horizontal ? & g . ScrollbarClickDeltaToGrabCenter . x : & g . ScrollbarClickDeltaToGrabCenter . y ;
// Click position in scrollbar normalized space (0.0f->1.0f)
const float clicked_v_norm = ImSaturate ( ( mouse_pos_v - scrollbar_pos_v ) / scrollbar_size_v ) ;
SetHoveredID ( id ) ;
bool seek_absolute = false ;
if ( ! previously_hel d)
if ( g . ActiveIdIsJustActivate d)
{
// On initial click calculate the distance between mouse and the center of the grab
if ( clicked_v_norm > = grab_v_norm & & clicked_v_norm < = grab_v_norm + grab_h_norm )
{
* click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f ;
}
seek_absolute = ( clicked_v_norm < grab_v_norm | | clicked_v_norm > grab_v_norm + grab_h_norm ) ;
if ( seek_absolute )
g . ScrollbarClickDeltaToGrabCenter = 0.0f ;
else
{
seek_absolute = true ;
* click_delta_to_grab_center_v = 0.0f ;
}
g . ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f ;
}
// Apply scroll
// It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
const float scroll_v_norm = ImSaturate ( ( clicked_v_norm - * click_delta_to_grab_center_v - grab_h_norm * 0.5f ) / ( 1.0f - grab_h_norm ) ) ;
scroll_v = ( float ) ( int ) ( 0.5f + scroll_v_norm * scroll_max ) ; //(win_size_contents_v - win_size_v));
if ( horizontal )
window - > Scroll . x = scroll_v ;
else
window - > Scroll . y = scroll_v ;
const float scroll_v_norm = ImSaturate ( ( clicked_v_norm - g . ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f ) / ( 1.0f - grab_h_norm ) ) ;
* p_scroll_v = ( float ) ( int ) ( 0.5f + scroll_v_norm * scroll_max ) ; //(win_size_contents_v - win_size_v));
// Update values for rendering
scroll_ratio = ImSaturate ( scroll_v / scroll_max ) ;
scroll_ratio = ImSaturate ( * p_scroll_v / scroll_max ) ;
grab_v_norm = scroll_ratio * ( scrollbar_size_v - grab_h_pixels ) / scrollbar_size_v ;
// Update distance to grab now that we have seeked and saturated
if ( seek_absolute )
* click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f ;
g . ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f ;
}
// Render grab
// Render
window - > DrawList - > AddRectFilled ( bb_frame . Min , bb_frame . Max , GetColorU32 ( ImGuiCol_ScrollbarBg ) , window - > WindowRounding , rounding_corners ) ;
const ImU32 grab_col = GetColorU32 ( held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab , alpha ) ;
ImRect grab_rect ;
if ( horizontal )
grab_rect = ImRect ( ImLerp ( bb . Min . x , bb . Max . x , grab_v_norm ) , bb . Min . y , Im Min( Im Lerp( bb . Min . x , bb . Max . x , grab_v_norm ) + grab_h_pixels , host_rect . Max . x ) , bb . Max . y ) ;
grab_rect = ImRect ( ImLerp ( bb . Min . x , bb . Max . x , grab_v_norm ) , bb . Min . y , Im Lerp( bb . Min . x , bb . Max . x , grab_v_norm ) + grab_h_pixels , bb . Max . y ) ;
else
grab_rect = ImRect ( bb . Min . x , ImLerp ( bb . Min . y , bb . Max . y , grab_v_norm ) , bb . Max . x , Im Min( Im Lerp( bb . Min . y , bb . Max . y , grab_v_norm ) + grab_h_pixels , host_rect . Max . y ) ) ;
grab_rect = ImRect ( bb . Min . x , ImLerp ( bb . Min . y , bb . Max . y , grab_v_norm ) , bb . Max . x , Im Lerp( bb . Min . y , bb . Max . y , grab_v_norm ) + grab_h_pixels ) ;
window - > DrawList - > AddRectFilled ( grab_rect . Min , grab_rect . Max , grab_col , style . ScrollbarRounding ) ;
return held ;
}
void ImGui : : Scrollbar ( ImGuiAxis axis )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
const bool horizontal = ( axis = = ImGuiAxis_X ) ;
const ImGuiStyle & style = g . Style ;
const ImGuiID id = GetScrollbarID ( window , axis ) ;
KeepAliveID ( id ) ;
// Calculate our bounding box (FIXME: This is messy, should be made simpler using e.g. InnerRect/WorkRect data).
const float other_scrollbar_size = window - > ScrollbarSizes [ axis ] ;
const ImRect win_rect = window - > Rect ( ) ;
const float border_size = window - > WindowBorderSize ;
ImRect bb = horizontal
? ImRect ( win_rect . Min . x + border_size , win_rect . Max . y - style . ScrollbarSize , win_rect . Max . x - other_scrollbar_size - border_size , win_rect . Max . y - border_size )
: ImRect ( win_rect . Max . x - style . ScrollbarSize , win_rect . Min . y + border_size , win_rect . Max . x - border_size , win_rect . Max . y - other_scrollbar_size - border_size ) ;
bb . Min . x = ImMax ( win_rect . Min . x , bb . Min . x ) ; // Handle case where the host rectangle is smaller than the scrollbar
bb . Min . y = ImMax ( win_rect . Min . y , bb . Min . y ) ;
if ( ! horizontal )
bb . Min . y + = window - > TitleBarHeight ( ) + ( ( window - > Flags & ImGuiWindowFlags_MenuBar ) ? window - > MenuBarHeight ( ) : 0.0f ) ; // FIXME: InnerRect?
// Select rounding
ImDrawCornerFlags rounding_corners ;
if ( horizontal )
rounding_corners = ImDrawCornerFlags_BotLeft ;
else
rounding_corners = ( ( window - > Flags & ImGuiWindowFlags_NoTitleBar ) & & ! ( window - > Flags & ImGuiWindowFlags_MenuBar ) ) ? ImDrawCornerFlags_TopRight : 0 ;
if ( other_scrollbar_size < = 0.0f )
rounding_corners | = ImDrawCornerFlags_BotRight ;
if ( horizontal )
ScrollbarEx ( bb , id , axis , & window - > Scroll . x , window - > SizeFull . x - other_scrollbar_size , window - > SizeContents . x , rounding_corners ) ;
else
ScrollbarEx ( bb , id , axis , & window - > Scroll . y , window - > SizeFull . y - other_scrollbar_size , window - > SizeContents . y , rounding_corners ) ;
}
void ImGui : : Image ( ImTextureID user_texture_id , const ImVec2 & size , const ImVec2 & uv0 , const ImVec2 & uv1 , const ImVec4 & tint_col , const ImVec4 & border_col )