2018-08-29 03:59:14 +08:00
// dear imgui, v1.64 WIP
// (widgets code)
# if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif
# include "imgui.h"
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif
# include "imgui_internal.h"
2018-08-29 21:15:36 +08:00
# include <ctype.h> // toupper, isprint
// Visual Studio warnings
# ifdef _MSC_VER
# pragma warning (disable: 4127) // condition expression is constant
# pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
# endif
// Clang/GCC warnings with -Weverything
# ifdef __clang__
# pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
# pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
# elif defined(__GNUC__)
# pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
# if __GNUC__ >= 8
# pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
# endif
# endif
2018-08-29 03:59:14 +08:00
//-------------------------------------------------------------------------
// Forward Declarations
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
2018-08-29 21:15:36 +08:00
// SHARED UTILITIES
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Text
// - TextUnformatted()
// - Text()
// - TextV()
// - TextColored()
// - TextColoredV()
// - TextDisabled()
// - TextDisabledV()
// - TextWrapped()
// - TextWrappedV()
// - LabelText()
// - LabelTextV()
// - BulletText()
// - BulletTextV()
//-------------------------------------------------------------------------
2018-08-30 20:38:44 +08:00
void ImGui : : TextUnformatted ( const char * text , const char * text_end )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
IM_ASSERT ( text ! = NULL ) ;
const char * text_begin = text ;
if ( text_end = = NULL )
text_end = text + strlen ( text ) ; // FIXME-OPT
const ImVec2 text_pos ( window - > DC . CursorPos . x , window - > DC . CursorPos . y + window - > DC . CurrentLineTextBaseOffset ) ;
const float wrap_pos_x = window - > DC . TextWrapPos ;
const bool wrap_enabled = wrap_pos_x > = 0.0f ;
if ( text_end - text > 2000 & & ! wrap_enabled )
{
// Long text!
// Perform manual coarse clipping to optimize for long multi-line text
// From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
// We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
const char * line = text ;
const float line_height = GetTextLineHeight ( ) ;
const ImRect clip_rect = window - > ClipRect ;
ImVec2 text_size ( 0 , 0 ) ;
if ( text_pos . y < = clip_rect . Max . y )
{
ImVec2 pos = text_pos ;
// Lines to skip (can't skip when logging text)
if ( ! g . LogEnabled )
{
int lines_skippable = ( int ) ( ( clip_rect . Min . y - text_pos . y ) / line_height ) ;
if ( lines_skippable > 0 )
{
int lines_skipped = 0 ;
while ( line < text_end & & lines_skipped < lines_skippable )
{
const char * line_end = strchr ( line , ' \n ' ) ;
if ( ! line_end )
line_end = text_end ;
line = line_end + 1 ;
lines_skipped + + ;
}
pos . y + = lines_skipped * line_height ;
}
}
// Lines to render
if ( line < text_end )
{
ImRect line_rect ( pos , pos + ImVec2 ( FLT_MAX , line_height ) ) ;
while ( line < text_end )
{
const char * line_end = strchr ( line , ' \n ' ) ;
if ( IsClippedEx ( line_rect , 0 , false ) )
break ;
const ImVec2 line_size = CalcTextSize ( line , line_end , false ) ;
text_size . x = ImMax ( text_size . x , line_size . x ) ;
RenderText ( pos , line , line_end , false ) ;
if ( ! line_end )
line_end = text_end ;
line = line_end + 1 ;
line_rect . Min . y + = line_height ;
line_rect . Max . y + = line_height ;
pos . y + = line_height ;
}
// Count remaining lines
int lines_skipped = 0 ;
while ( line < text_end )
{
const char * line_end = strchr ( line , ' \n ' ) ;
if ( ! line_end )
line_end = text_end ;
line = line_end + 1 ;
lines_skipped + + ;
}
pos . y + = lines_skipped * line_height ;
}
text_size . y + = ( pos - text_pos ) . y ;
}
ImRect bb ( text_pos , text_pos + text_size ) ;
ItemSize ( bb ) ;
ItemAdd ( bb , 0 ) ;
}
else
{
const float wrap_width = wrap_enabled ? CalcWrapWidthForPos ( window - > DC . CursorPos , wrap_pos_x ) : 0.0f ;
const ImVec2 text_size = CalcTextSize ( text_begin , text_end , false , wrap_width ) ;
// Account of baseline offset
ImRect bb ( text_pos , text_pos + text_size ) ;
ItemSize ( text_size ) ;
if ( ! ItemAdd ( bb , 0 ) )
return ;
// Render (we don't hide text after ## in this end-user function)
RenderTextWrapped ( bb . Min , text_begin , text_end , wrap_width ) ;
}
}
void ImGui : : Text ( const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
TextV ( fmt , args ) ;
va_end ( args ) ;
}
void ImGui : : TextV ( const char * fmt , va_list args )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
const char * text_end = g . TempBuffer + ImFormatStringV ( g . TempBuffer , IM_ARRAYSIZE ( g . TempBuffer ) , fmt , args ) ;
TextUnformatted ( g . TempBuffer , text_end ) ;
}
void ImGui : : TextColored ( const ImVec4 & col , const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
TextColoredV ( col , fmt , args ) ;
va_end ( args ) ;
}
void ImGui : : TextColoredV ( const ImVec4 & col , const char * fmt , va_list args )
{
PushStyleColor ( ImGuiCol_Text , col ) ;
TextV ( fmt , args ) ;
PopStyleColor ( ) ;
}
void ImGui : : TextDisabled ( const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
TextDisabledV ( fmt , args ) ;
va_end ( args ) ;
}
void ImGui : : TextDisabledV ( const char * fmt , va_list args )
{
PushStyleColor ( ImGuiCol_Text , GImGui - > Style . Colors [ ImGuiCol_TextDisabled ] ) ;
TextV ( fmt , args ) ;
PopStyleColor ( ) ;
}
void ImGui : : TextWrapped ( const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
TextWrappedV ( fmt , args ) ;
va_end ( args ) ;
}
void ImGui : : TextWrappedV ( const char * fmt , va_list args )
{
bool need_wrap = ( GImGui - > CurrentWindow - > DC . TextWrapPos < 0.0f ) ; // Keep existing wrap position is one ia already set
if ( need_wrap ) PushTextWrapPos ( 0.0f ) ;
TextV ( fmt , args ) ;
if ( need_wrap ) PopTextWrapPos ( ) ;
}
void ImGui : : LabelText ( const char * label , const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
LabelTextV ( label , fmt , args ) ;
va_end ( args ) ;
}
// Add a label+text combo aligned to other label+value widgets
void ImGui : : LabelTextV ( const char * label , const char * fmt , va_list args )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
const ImGuiStyle & style = g . Style ;
const float w = CalcItemWidth ( ) ;
const ImVec2 label_size = CalcTextSize ( label , NULL , true ) ;
const ImRect value_bb ( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( w , label_size . y + style . FramePadding . y * 2 ) ) ;
const ImRect total_bb ( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( w + ( label_size . x > 0.0f ? style . ItemInnerSpacing . x : 0.0f ) , style . FramePadding . y * 2 ) + label_size ) ;
ItemSize ( total_bb , style . FramePadding . y ) ;
if ( ! ItemAdd ( total_bb , 0 ) )
return ;
// Render
const char * value_text_begin = & g . TempBuffer [ 0 ] ;
const char * value_text_end = value_text_begin + ImFormatStringV ( g . TempBuffer , IM_ARRAYSIZE ( g . TempBuffer ) , fmt , args ) ;
RenderTextClipped ( value_bb . Min , value_bb . Max , value_text_begin , value_text_end , NULL , ImVec2 ( 0.0f , 0.5f ) ) ;
if ( label_size . x > 0.0f )
RenderText ( ImVec2 ( value_bb . Max . x + style . ItemInnerSpacing . x , value_bb . Min . y + style . FramePadding . y ) , label ) ;
}
void ImGui : : BulletText ( const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
BulletTextV ( fmt , args ) ;
va_end ( args ) ;
}
// Text with a little bullet aligned to the typical tree node.
void ImGui : : BulletTextV ( const char * fmt , va_list args )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
const ImGuiStyle & style = g . Style ;
const char * text_begin = g . TempBuffer ;
const char * text_end = text_begin + ImFormatStringV ( g . TempBuffer , IM_ARRAYSIZE ( g . TempBuffer ) , fmt , args ) ;
const ImVec2 label_size = CalcTextSize ( text_begin , text_end , false ) ;
const float text_base_offset_y = ImMax ( 0.0f , window - > DC . CurrentLineTextBaseOffset ) ; // Latch before ItemSize changes it
const float line_height = ImMax ( ImMin ( window - > DC . CurrentLineSize . y , g . FontSize + g . Style . FramePadding . y * 2 ) , g . FontSize ) ;
const ImRect bb ( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( g . FontSize + ( label_size . x > 0.0f ? ( label_size . x + style . FramePadding . x * 2 ) : 0.0f ) , ImMax ( line_height , label_size . y ) ) ) ; // Empty text doesn't add padding
ItemSize ( bb ) ;
if ( ! ItemAdd ( bb , 0 ) )
return ;
// Render
RenderBullet ( bb . Min + ImVec2 ( style . FramePadding . x + g . FontSize * 0.5f , line_height * 0.5f ) ) ;
RenderText ( bb . Min + ImVec2 ( g . FontSize + style . FramePadding . x * 2 , text_base_offset_y ) , text_begin , text_end , false ) ;
}
2018-08-29 21:15:36 +08:00
//-------------------------------------------------------------------------
// WIDGETS: Main
// - ButtonBehavior() [Internal]
// - Button()
// - SmallButton()
// - InvisibleButton()
// - ArrowButton()
// - CloseButton() [Internal]
// - CollapseButton() [Internal]
// - Image()
// - ImageButton()
// - Checkbox()
// - CheckboxFlags()
// - RadioButton()
// - ProgressBar()
// - Bullet()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Combo Box
// - BeginCombo()
// - EndCombo()
// - Combo()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Data Type and Data Formatting Helpers [Internal]
// - PatchFormatStringFloatToInt()
// - DataTypeFormatString()
// - DataTypeApplyOp()
// - DataTypeApplyOpFromText()
// - GetMinimumStepAtDecimalPrecision
// - RoundScalarWithFormat<>()
//-------------------------------------------------------------------------
2018-08-29 03:59:14 +08:00
//-------------------------------------------------------------------------
2018-08-29 21:15:36 +08:00
// WIDGETS: Drags
// - DragBehaviorT<>() [Internal]
// - DragBehavior() [Internal]
// - DragScalar()
// - DragScalarN()
// - DragFloat()
// - DragFloat2()
// - DragFloat3()
// - DragFloat4()
// - DragFloatRange2()
// - DragInt()
// - DragInt2()
// - DragInt3()
// - DragInt4()
// - DragIntRange2()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Sliders
// - SliderBehaviorT<>() [Internal]
// - SliderBehavior() [Internal]
// - SliderScalar()
// - SliderScalarN()
// - SliderFloat()
// - SliderFloat2()
// - SliderFloat3()
// - SliderFloat4()
// - SliderAngle()
// - SliderInt()
// - SliderInt2()
// - SliderInt3()
// - SliderInt4()
// - VSliderScalar()
// - VSliderFloat()
// - VSliderInt()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Inputs (_excepted InputText_)
// - ImParseFormatFindStart()
// - ImParseFormatFindEnd()
// - ImParseFormatTrimDecorations()
// - ImParseFormatPrecision()
// - InputScalarAsWidgetReplacement() [Internal]
// - InputScalar()
// - InputScalarN()
// - InputFloat()
// - InputFloat2()
// - InputFloat3()
// - InputFloat4()
// - InputInt()
// - InputInt2()
// - InputInt3()
// - InputInt4()
// - InputDouble()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: InputText
// - InputText()
// - InputTextMultiline()
// - InputTextEx() [Internal]
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Color Editor / Picker
// - ColorEdit3()
// - ColorEdit4()
// - ColorPicker3()
// - RenderColorRectWithAlphaCheckerboard() [Internal]
// - ColorPicker4()
// - ColorButton()
// - SetColorEditOptions()
// - ColorTooltip() [Internal]
// - ColorEditOptionsPopup() [Internal]
// - ColorPickerOptionsPopup() [Internal]
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Trees
// - TreeNode()
// - TreeNodeV()
// - TreeNodeEx()
// - TreeNodeExV()
// - TreeNodeBehavior() [Internal]
// - TreePush()
// - TreePop()
// - TreeAdvanceToLabelPos()
// - GetTreeNodeToLabelSpacing()
// - SetNextTreeNodeOpen()
// - CollapsingHeader()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Selectables
// - Selectable()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: List Box
// - ListBox()
// - ListBoxHeader()
// - ListBoxFooter()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Data Plotting
// - PlotEx() [Internal]
// - PlotLines()
// - PlotHistogram()
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// WIDGETS: Value() helpers
// - Value()
//-------------------------------------------------------------------------
2018-08-29 03:59:14 +08:00
//-------------------------------------------------------------------------
2018-08-29 21:15:36 +08:00
// WIDGETS: Menus
// - BeginMainMenuBar()
// - EndMainMenuBar()
// - BeginMenuBar()
// - EndMenuBar()
// - BeginMenu()
// - EndMenu()
// - MenuItem()
2018-08-29 03:59:14 +08:00
//-------------------------------------------------------------------------