Merge remote-tracking branch 'origin' into 2015-04-indexed-rendering

This commit is contained in:
ocornut 2015-06-14 20:29:10 -06:00
commit b360c83e92
3 changed files with 221 additions and 144 deletions

View File

@ -44,7 +44,10 @@ Gallery
![screenshot 4](/web/test_window_04.png?raw=true) ![screenshot 4](/web/test_window_04.png?raw=true)
![screenshot 5](/web/test_window_05_menus.png?raw=true) ![screenshot 5](/web/test_window_05_menus.png?raw=true)
![screenshot 6](/web/examples_03.png?raw=true) ![screenshot 6](/web/examples_03.png?raw=true)
![screenshot 7](/web/examples_02.png?raw=true)
![screenshot 7](https://cloud.githubusercontent.com/assets/8225057/7903336/96f0fb7c-07d0-11e5-95d6-41c6a1595e5a.png)
![screenshot 8](/web/examples_02.png?raw=true)
ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with: ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with:
``` ```

334
imgui.cpp
View File

@ -1,4 +1,4 @@
// ImGui library v1.40 WIP // ImGui library v1.41 WIP
// See ImGui::ShowTestWindow() for sample code. // See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui // Get latest version at https://github.com/ocornut/imgui
@ -136,11 +136,13 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
- 2015/05/31 (1.39) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
- 2015/05/31 (1.39) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
- 2015/05/27 (1.39) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
- 2015/05/11 (1.39) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "opened" state of a popup. BeginPopup() returns true if the popup is opened. - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
- 2015/05/03 (1.39) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
- 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "opened" state of a popup. BeginPopup() returns true if the popup is opened.
- 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
- 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete). - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
- 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
- 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
@ -326,19 +328,22 @@
================== ==================
- misc: merge or clarify ImVec4 vs ImRect? - misc: merge or clarify ImVec4 vs ImRect?
- window: add horizontal scroll
- window: fix resize grip rendering scaling along with Rounding style setting - window: fix resize grip rendering scaling along with Rounding style setting
- window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit? - window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit?
- window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list.
- window: allow resizing of child windows (possibly given min/max for each axis?) - window: allow resizing of child windows (possibly given min/max for each axis?)
- window: background options for child windows, border option (disable rounding) - window: background options for child windows, border option (disable rounding)
- window: resizing from any sides? + mouse cursor directives for app. - window: resizing from any sides? + mouse cursor directives for app.
- scrolling: add horizontal scroll
!- scrolling: set scrolling given a position.
!- scrolling: allow immediately effective change of scroll if we haven't appended items yet
- widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc.
- widgets: clean up widgets internal toward exposing everything. - widgets: clean up widgets internal toward exposing everything.
- main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them. - main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them.
- main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- input text: add ImGuiInputTextFlags_EnterToApply? (off github issue #218) - input text: add ImGuiInputTextFlags_EnterToApply? (off github issue #218)
!- input text: multiple lines inputs (#200)
!- input number: large int not reliably supported because of int<>float conversions. !- input number: large int not reliably supported because of int<>float conversions.
- input number: optional range min/max for Input*() functions - input number: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
@ -359,8 +364,12 @@
- combo/listbox: keyboard control. need inputtext like non-active focus + key handling. considering keybord for custom listbox (see github pr #203) - combo/listbox: keyboard control. need inputtext like non-active focus + key handling. considering keybord for custom listbox (see github pr #203)
- listbox: multiple selection - listbox: multiple selection
- listbox: user may want to initial scroll to focus on the one selected value? - listbox: user may want to initial scroll to focus on the one selected value?
- listbox: keyboard navigation.
- listbox: scrolling should track modified selection.
- menus: local shortcuts, global shortcuts (github issue #126) - menus: local shortcuts, global shortcuts (github issue #126)
- menus: icons - menus: icons
- menus: see we can allow for click-menu-hold-release-on-item to work (like Windows does)
- menus: menubars: some sort of priority / effect of main menu-bar on desktop size?
- tabs - tabs
- separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y) - separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y)
- gauge: various forms of gauge/loading bars widgets - gauge: various forms of gauge/loading bars widgets
@ -381,7 +390,7 @@
- tooltip: figure out a way to use TextWrapped() in a tooltip. - tooltip: figure out a way to use TextWrapped() in a tooltip.
- settings: write more decent code to allow saving/loading new fields - settings: write more decent code to allow saving/loading new fields
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file
! style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost. - style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost.
- style: checkbox: padding for "active" color should be a multiplier of the - style: checkbox: padding for "active" color should be a multiplier of the
- style: colorbox not always square? - style: colorbox not always square?
- text: simple markup language for color change? - text: simple markup language for color change?
@ -392,7 +401,7 @@
- filters: set a current filter that tree node can automatically query to hide themselves - filters: set a current filter that tree node can automatically query to hide themselves
- filters: handle wildcards (with implicit leading/trailing *), regexps - filters: handle wildcards (with implicit leading/trailing *), regexps
- shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus)
! keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing !- keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing
- keyboard: full keyboard navigation and focus. - keyboard: full keyboard navigation and focus.
- input: rework IO to be able to pass actual events to fix temporal aliasing issues. - input: rework IO to be able to pass actual events to fix temporal aliasing issues.
- input: support track pad style scrolling & slider edit. - input: support track pad style scrolling & slider edit.
@ -511,7 +520,6 @@ struct ImGuiState;
struct ImGuiWindow; struct ImGuiWindow;
typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ typedef int ImGuiLayoutType; // enum ImGuiLayoutType_
typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_
typedef int ImGuiSelectableFlags; // enum ImGuiSelectableFlags_
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0); static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0);
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
@ -972,18 +980,19 @@ enum ImGuiLayoutType_
enum ImGuiButtonFlags_ enum ImGuiButtonFlags_
{ {
ImGuiButtonFlags_Repeat = (1 << 0), ImGuiButtonFlags_Repeat = 1 << 0,
ImGuiButtonFlags_PressedOnClick = (1 << 1), ImGuiButtonFlags_PressedOnClick = 1 << 1,
ImGuiButtonFlags_FlattenChilds = (1 << 2), ImGuiButtonFlags_FlattenChilds = 1 << 2,
ImGuiButtonFlags_DontClosePopups = (1 << 3), ImGuiButtonFlags_DontClosePopups = 1 << 3,
ImGuiButtonFlags_Disabled = (1 << 4) ImGuiButtonFlags_Disabled = 1 << 4
}; };
enum ImGuiSelectableFlags_ enum ImGuiSelectableFlagsPrivate_
{ {
ImGuiSelectableFlags_MenuItem = (1 << 0), // NB: need to be in sync with last value of ImGuiSelectableFlags_
ImGuiSelectableFlags_DontClosePopups = (1 << 1), ImGuiSelectableFlags_MenuItem = 1 << 2,
ImGuiSelectableFlags_Disabled = (1 << 2) ImGuiSelectableFlags_Disabled = 1 << 3,
ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 4
}; };
@ -1294,7 +1303,6 @@ struct ImGuiState
ImGuiTextEditState InputTextState; ImGuiTextEditState InputTextState;
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode
ImGuiID ActiveComboID;
ImVec2 ActiveClickDeltaToCenter; ImVec2 ActiveClickDeltaToCenter;
float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings
ImVec2 DragLastMouseDelta; ImVec2 DragLastMouseDelta;
@ -1355,7 +1363,6 @@ struct ImGuiState
SetNextTreeNodeOpenedCond = 0; SetNextTreeNodeOpenedCond = 0;
ScalarAsInputTextId = 0; ScalarAsInputTextId = 0;
ActiveComboID = 0;
ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f); ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f);
DragCurrentValue = 0.0f; DragCurrentValue = 0.0f;
DragLastMouseDelta = ImVec2(0.0f, 0.0f); DragLastMouseDelta = ImVec2(0.0f, 0.0f);
@ -1395,7 +1402,7 @@ struct ImGuiWindow
ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame
ImGuiID MoveID; // == window->GetID("#MOVE") ImGuiID MoveID; // == window->GetID("#MOVE")
float ScrollY; float ScrollY;
float NextScrollY; float ScrollTargetCenterY; // position which we aim to center on
bool ScrollbarY; bool ScrollbarY;
bool Active; // Set to true on Begin() bool Active; // Set to true on Begin()
bool WasActive; bool WasActive;
@ -1761,7 +1768,7 @@ ImGuiWindow::ImGuiWindow(const char* name)
Size = SizeFull = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f);
SizeContents = ImVec2(0.0f, 0.0f); SizeContents = ImVec2(0.0f, 0.0f);
ScrollY = 0.0f; ScrollY = 0.0f;
NextScrollY = 0.0f; ScrollTargetCenterY = -1.0f;
ScrollbarY = false; ScrollbarY = false;
Active = WasActive = false; Active = WasActive = false;
Accessed = false; Accessed = false;
@ -2188,7 +2195,7 @@ void ImGui::NewFrame()
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
{ {
const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
window->NextScrollY -= g.IO.MouseWheel * window->CalcFontSize() * scroll_lines; window->ScrollY -= g.IO.MouseWheel * window->CalcFontSize() * scroll_lines;
} }
} }
} }
@ -2696,7 +2703,7 @@ static void RenderCheckMark(ImVec2 pos, ImU32 col)
a.x = pos.x + start_x; a.x = pos.x + start_x;
b.x = a.x + rem_third; b.x = a.x + rem_third;
c.x = a.x + rem_third * 3.0f; c.x = a.x + rem_third * 3.0f;
b.y = pos.y + (float)(int)(g.Font->BaseLine * (g.FontSize / g.Font->FontSize) + 0.5f) + (float)(int)(g.Font->DisplayOffset.y); b.y = pos.y + (float)(int)(g.Font->Ascent * (g.FontSize / g.Font->FontSize) + 0.5f) + (float)(int)(g.Font->DisplayOffset.y);
a.y = b.y - rem_third; a.y = b.y - rem_third;
c.y = b.y - rem_third * 2.0f; c.y = b.y - rem_third * 2.0f;
@ -3119,6 +3126,14 @@ static void ClosePopupToLevel(int remaining)
g.OpenedPopupStack.resize(remaining); g.OpenedPopupStack.resize(remaining);
} }
static void ClosePopup(ImGuiID id)
{
if (!IsPopupOpen(id))
return;
ImGuiState& g = *GImGui;
ClosePopupToLevel(g.OpenedPopupStack.size() - 1);
}
// Close the popup we have begin-ed into. // Close the popup we have begin-ed into.
void ImGui::CloseCurrentPopup() void ImGui::CloseCurrentPopup()
{ {
@ -3149,7 +3164,7 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
} }
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize;
char name[32]; char name[32];
if (flags & ImGuiWindowFlags_ChildMenu) if (flags & ImGuiWindowFlags_ChildMenu)
@ -3169,7 +3184,7 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
bool ImGui::BeginPopup(const char* str_id) bool ImGui::BeginPopup(const char* str_id)
{ {
return BeginPopupEx(str_id, 0); return BeginPopupEx(str_id, ImGuiWindowFlags_ShowBorders);
} }
void ImGui::EndPopup() void ImGui::EndPopup()
@ -3461,7 +3476,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
} }
// Process SetNextWindow***() calls // Process SetNextWindow***() calls
bool window_pos_set_by_api = false; bool window_pos_set_by_api = false, window_size_set_by_api = false;
if (g.SetNextWindowPosCond) if (g.SetNextWindowPosCond)
{ {
const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this anymore :( need to look into that. const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this anymore :( need to look into that.
@ -3474,6 +3489,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
if (g.SetNextWindowSizeCond) if (g.SetNextWindowSizeCond)
{ {
if (!window_was_visible) window->SetWindowSizeAllowFlags |= ImGuiSetCond_Appearing; if (!window_was_visible) window->SetWindowSizeAllowFlags |= ImGuiSetCond_Appearing;
window_size_set_by_api = (window->SetWindowSizeAllowFlags & g.SetNextWindowSizeCond) != 0;
ImGui::SetWindowSize(g.SetNextWindowSizeVal, g.SetNextWindowSizeCond); ImGui::SetWindowSize(g.SetNextWindowSizeVal, g.SetNextWindowSizeCond);
g.SetNextWindowSizeCond = 0; g.SetNextWindowSizeCond = 0;
} }
@ -3565,7 +3581,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_visible) if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_visible)
{ {
window->HiddenFrames = 1; window->HiddenFrames = 1;
window->Size = window->SizeFull = window->SizeContents = ImVec2(0.f, 0.f); // TODO: We don't support SetNextWindowSize() for tooltips or popups yet if (!window_size_set_by_api)
window->Size = window->SizeFull = ImVec2(0.f, 0.f);
window->SizeContents = ImVec2(0.f, 0.f);
} }
// Calculate auto-fit size // Calculate auto-fit size
@ -3595,11 +3613,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
} }
else else
{ {
if (flags & ImGuiWindowFlags_AlwaysAutoResize) if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window_size_set_by_api)
{ {
window->SizeFull = size_auto_fit; window->SizeFull = size_auto_fit;
} }
else if (window->AutoFitFrames > 0) else if (window->AutoFitFrames > 0 && !window_size_set_by_api)
{ {
// Auto-fit only grows during the first few frames // Auto-fit only grows during the first few frames
window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit;
@ -3699,11 +3717,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX;
// Apply scrolling // Apply scrolling
window->ScrollY = window->NextScrollY; if (window->ScrollTargetCenterY >= 0.0f)
{
window->ScrollY = window->ScrollTargetCenterY - (window->Pos.y + (window->SizeFull.y + window->TitleBarHeight() + window->WindowPadding().y) * 0.5f);
window->ScrollTargetCenterY = -1.0f;
}
window->ScrollY = ImMax(window->ScrollY, 0.0f); window->ScrollY = ImMax(window->ScrollY, 0.0f);
if (!window->Collapsed && !window->SkipItems) if (!window->Collapsed && !window->SkipItems)
window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y)); window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y));
window->NextScrollY = window->ScrollY;
// Draw window + handle manual resize // Draw window + handle manual resize
ImRect title_bar_rect = window->TitleBarRect(); ImRect title_bar_rect = window->TitleBarRect();
@ -3998,7 +4019,6 @@ static void Scrollbar(ImGuiWindow* window)
// Apply scroll // Apply scroll
const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm*0.5f) / (1.0f - grab_h_norm)); const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y)); window->ScrollY = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y));
window->NextScrollY = window->ScrollY;
// Update values for rendering // Update values for rendering
scroll_ratio = ImSaturate(window->ScrollY / scroll_max); scroll_ratio = ImSaturate(window->ScrollY / scroll_max);
@ -4303,36 +4323,43 @@ const char* ImGui::GetStyleColName(ImGuiCol idx)
return "Unknown"; return "Unknown";
} }
bool ImGui::IsWindowHovered()
{
ImGuiState& g = *GImGui;
return g.HoveredWindow == g.CurrentWindow;
}
bool ImGui::IsWindowFocused() bool ImGui::IsWindowFocused()
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); return g.FocusedWindow == g.CurrentWindow;
return g.FocusedWindow == window;
} }
bool ImGui::IsRootWindowFocused() bool ImGui::IsRootWindowFocused()
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* root_window = GetCurrentWindow()->RootWindow; ImGuiWindow* root_window = g.CurrentWindow->RootWindow;
return g.FocusedWindow == root_window; return g.FocusedWindow == root_window;
} }
bool ImGui::IsRootWindowOrAnyChildFocused() bool ImGui::IsRootWindowOrAnyChildFocused()
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* root_window = GetCurrentWindow()->RootWindow; ImGuiWindow* root_window = g.CurrentWindow->RootWindow;
return g.FocusedWindow && g.FocusedWindow->RootWindow == root_window; return g.FocusedWindow && g.FocusedWindow->RootWindow == root_window;
} }
float ImGui::GetWindowWidth() float ImGui::GetWindowWidth()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiState& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
return window->Size.x; return window->Size.x;
} }
ImVec2 ImGui::GetWindowPos() ImVec2 ImGui::GetWindowPos()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiState& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
return window->Pos; return window->Pos;
} }
@ -4621,7 +4648,7 @@ float ImGui::GetScrollMaxY()
void ImGui::SetScrollPosHere() void ImGui::SetScrollPosHere()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->NextScrollY = (window->DC.CursorPos.y + window->ScrollY) - (window->Pos.y + window->SizeFull.y * 0.5f) - (window->TitleBarHeight() + window->WindowPadding().y); window->ScrollTargetCenterY = (float)(int)(window->DC.CursorPos.y + window->ScrollY - window->DC.PrevLineHeight * 0.5f);
} }
void ImGui::SetKeyboardFocusHere(int offset) void ImGui::SetKeyboardFocusHere(int offset)
@ -5083,7 +5110,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
// Default to using texture ID as ID. User can still push string/integer prefixes. // Default to using texture ID as ID. User can still push string/integer prefixes.
// We could hash the size/uv to create a unique ID but that would prevent the user from animating buttons. // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
ImGui::PushID((void *)user_texture_id); ImGui::PushID((void *)user_texture_id);
const ImGuiID id = window->GetID("#image"); const ImGuiID id = window->GetID("#image");
ImGui::PopID(); ImGui::PopID();
@ -5100,8 +5127,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I
// Render // Render
const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
if (padding.x > 0.0f || padding.y > 0.0f) RenderFrame(bb.Min, bb.Max, col);
RenderFrame(bb.Min, bb.Max, col);
if (bg_col.w > 0.0f) if (bg_col.w > 0.0f)
window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, window->Color(bg_col)); window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, window->Color(bg_col));
window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, window->Color(tint_col)); window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, window->Color(tint_col));
@ -5615,13 +5641,15 @@ static inline float RoundScalar(float value, int decimal_precision)
// 0: 1, 1: 0.1, 2: 0.01, etc. // 0: 1, 1: 0.1, 2: 0.01, etc.
// So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0 // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
// FIXME: Investigate better rounding methods // FIXME: Investigate better rounding methods
const float min_step = 1.0f / powf(10.0f, (float)decimal_precision); float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
const float remainder = fmodf(value, min_step); bool negative = value < 0.0f;
value = fabsf(value);
float remainder = fmodf(value, min_step);
if (remainder <= min_step*0.5f) if (remainder <= min_step*0.5f)
value -= remainder; value -= remainder;
else else
value += (min_step - remainder); value += (min_step - remainder);
return value; return negative ? -value : value;
} }
static bool SliderScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal) static bool SliderScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal)
@ -5704,7 +5732,6 @@ static bool SliderScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, f
// Round past decimal precision // Round past decimal precision
new_value = RoundScalar(new_value, decimal_precision); new_value = RoundScalar(new_value, decimal_precision);
if (*v != new_value) if (*v != new_value)
{ {
*v = new_value; *v = new_value;
@ -7270,7 +7297,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char** items, int
bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
{ {
int items_count = 0; int items_count = 0;
const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
while (*p) while (*p)
{ {
p += strlen(p) + 1; p += strlen(p) + 1;
@ -7302,7 +7329,6 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
const float arrow_size = (g.FontSize + style.FramePadding.x * 2.0f); const float arrow_size = (g.FontSize + style.FramePadding.x * 2.0f);
const bool hovered = IsHovered(frame_bb, id); const bool hovered = IsHovered(frame_bb, id);
bool value_changed = false;
const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding);
RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING
@ -7318,80 +7344,81 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
if (label_size.x > 0) if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
ImGui::PushID((int)id);
bool menu_toggled = false; bool menu_toggled = false;
if (hovered) if (hovered)
{ {
g.HoveredId = id; g.HoveredId = id;
if (g.IO.MouseClicked[0]) if (g.IO.MouseClicked[0])
{ {
menu_toggled = true; SetActiveId(0);
g.ActiveComboID = (g.ActiveComboID == id) ? 0 : id; if (IsPopupOpen(id))
if (g.ActiveComboID) {
FocusWindow(window); ClosePopup(id);
}
else
{
FocusWindow(window);
ImGui::OpenPopup(label);
menu_toggled = true;
}
} }
} }
if (g.ActiveComboID == id) bool value_changed = false;
if (IsPopupOpen(id))
{ {
// Size default to hold ~7 items // Size default to hold ~7 items
if (height_in_items < 0) if (height_in_items < 0)
height_in_items = 7; height_in_items = 7;
const ImVec2 backup_pos = ImGui::GetCursorPos(); const ImVec2 backup_pos = ImGui::GetCursorPos();
const float popup_off_x = 0.0f;//style.ItemInnerSpacing.x;
const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3); const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3);
const ImRect popup_rect(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height)); const ImRect popup_rect(ImVec2(frame_bb.Min.x, frame_bb.Max.y), ImVec2(frame_bb.Max.x, frame_bb.Max.y + popup_height));
ImGui::SetCursorPos(popup_rect.Min - window->Pos); ImGui::SetNextWindowPos(popup_rect.Min);
ImGui::SetNextWindowSize(popup_rect.GetSize());
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); if (BeginPopupEx(label, flags))
ImGui::BeginChild("#ComboBox", popup_rect.GetSize(), false, flags);
ImGui::Spacing();
bool combo_item_active = false;
combo_item_active |= (g.ActiveId == GetCurrentWindow()->GetID("#SCROLLY"));
// Display items
for (int i = 0; i < items_count; i++)
{ {
ImGui::PushID((void*)(intptr_t)i); // Display items
const bool item_selected = (i == *current_item); ImGui::Spacing();
const char* item_text; for (int i = 0; i < items_count; i++)
if (!items_getter(data, i, &item_text))
item_text = "*Unknown item*";
if (ImGui::Selectable(item_text, item_selected))
{ {
SetActiveId(0); ImGui::PushID((void*)(intptr_t)i);
g.ActiveComboID = 0; const bool item_selected = (i == *current_item);
value_changed = true; const char* item_text;
*current_item = i; if (!items_getter(data, i, &item_text))
item_text = "*Unknown item*";
if (ImGui::Selectable(item_text, item_selected))
{
SetActiveId(0);
value_changed = true;
*current_item = i;
}
if (item_selected && menu_toggled)
ImGui::SetScrollPosHere();
ImGui::PopID();
} }
if (item_selected && menu_toggled) ImGui::EndPopup();
ImGui::SetScrollPosHere();
combo_item_active |= ImGui::IsItemActive();
ImGui::PopID();
} }
ImGui::EndChild();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::SetCursorPos(backup_pos);
if (!combo_item_active && g.ActiveId != 0)
g.ActiveComboID = 0;
} }
ImGui::PopID();
return value_changed; return value_changed;
} }
static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, ImGuiSelectableFlags flags) // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
return false; return false;
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
PopClipRect();
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
ImGuiID id = window->GetID(label); ImGuiID id = window->GetID(label);
ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
@ -7403,10 +7430,11 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar
// Fill horizontal space. // Fill horizontal space.
ImVec2 window_padding = window->WindowPadding(); ImVec2 window_padding = window->WindowPadding();
float w_draw = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? ImGui::GetWindowContentRegionMax().x : ImGui::GetContentRegionMax().x;
ImVec2 size_draw(size_draw_arg.x != 0.0f ? size_draw_arg.x : w_draw, size_draw_arg.y != 0.0f ? size_draw_arg.y : size.y); float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
ImRect bb_with_spacing(pos, pos + size_draw); ImRect bb_with_spacing(pos, pos + size_draw);
if (size_draw_arg.x == 0.0f) if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
bb_with_spacing.Max.x += window_padding.x; bb_with_spacing.Max.x += window_padding.x;
// Selectables are tightly packed together, we extend the box to cover spacing between selectable. // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
@ -7419,7 +7447,11 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar
bb_with_spacing.Max.x += spacing_R; bb_with_spacing.Max.x += spacing_R;
bb_with_spacing.Max.y += spacing_D; bb_with_spacing.Max.y += spacing_D;
if (!ItemAdd(bb_with_spacing, &id)) if (!ItemAdd(bb_with_spacing, &id))
{
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
PushColumnClipRect();
return false; return false;
}
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, ((flags & ImGuiSelectableFlags_MenuItem) ? ImGuiButtonFlags_PressedOnClick : 0) | ((flags & ImGuiSelectableFlags_Disabled) ? ImGuiButtonFlags_Disabled : 0)); bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, ((flags & ImGuiSelectableFlags_MenuItem) ? ImGuiButtonFlags_PressedOnClick : 0) | ((flags & ImGuiSelectableFlags_Disabled) ? ImGuiButtonFlags_Disabled : 0));
@ -7430,8 +7462,15 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar
if (hovered || selected) if (hovered || selected)
{ {
const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, style.FrameRounding); RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
} }
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
{
PushColumnClipRect();
bb_with_spacing.Max.x -= (ImGui::GetContentRegionMax().x - max_x);
}
if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size); RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size);
if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor(); if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor();
@ -7442,16 +7481,9 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar
return pressed; return pressed;
} }
// Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image. bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
{ {
return SelectableEx(label, selected, size_arg, size_arg, 0); if (ImGui::Selectable(label, *p_selected, flags, size_arg))
}
bool ImGui::Selectable(const char* label, bool* p_selected, const ImVec2& size_arg)
{
if (SelectableEx(label, *p_selected, size_arg, size_arg, 0))
{ {
*p_selected = !*p_selected; *p_selected = !*p_selected;
return true; return true;
@ -7567,7 +7599,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo
float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w);
bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); bool pressed = ImGui::Selectable(label, false, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
if (shortcut_size.x > 0.0f) if (shortcut_size.x > 0.0f)
{ {
ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
@ -7680,7 +7712,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f);
float w = label_size.x; float w = label_size.x;
pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); pressed = ImGui::Selectable(label, opened, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::SameLine(); ImGui::SameLine();
window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
@ -7690,7 +7722,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w);
pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); pressed = ImGui::Selectable(label, opened, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false);
if (!enabled) ImGui::PopStyleColor(); if (!enabled) ImGui::PopStyleColor();
@ -7750,7 +7782,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (opened) if (opened)
{ {
ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always);
ImGuiWindowFlags flags = (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu; ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu);
opened = BeginPopupEx(label, flags); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) opened = BeginPopupEx(label, flags); // opened can be 'false' when the popup is completely clipped (e.g. zero size display)
} }
@ -7773,7 +7805,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID("#colorbutton"); const ImGuiID id = window->GetID("#colorbutton");
const float square_size = g.FontSize; const float square_size = g.FontSize;
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.y*2, square_size + (small_height ? 0 : style.FramePadding.y*2)));
ItemSize(bb, small_height ? 0.0f : style.FramePadding.y); ItemSize(bb, small_height ? 0.0f : style.FramePadding.y);
if (!ItemAdd(bb, &id)) if (!ItemAdd(bb, &id))
return false; return false;
@ -7820,7 +7852,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const float w_full = ImGui::CalcItemWidth(); const float w_full = ImGui::CalcItemWidth();
const float square_sz = (g.FontSize + style.FramePadding.x * 2.0f); const float square_sz = (g.FontSize + style.FramePadding.y * 2.0f);
ImGuiColorEditMode edit_mode = window->DC.ColorEditMode; ImGuiColorEditMode edit_mode = window->DC.ColorEditMode;
if (edit_mode == ImGuiColorEditMode_UserSelect || edit_mode == ImGuiColorEditMode_UserSelectShowButton) if (edit_mode == ImGuiColorEditMode_UserSelect || edit_mode == ImGuiColorEditMode_UserSelectShowButton)
@ -9219,7 +9251,8 @@ bool ImFontAtlas::Build()
const float font_scale = stbtt_ScaleForPixelHeight(&data.FontInfo, data.SizePixels); const float font_scale = stbtt_ScaleForPixelHeight(&data.FontInfo, data.SizePixels);
int font_ascent, font_descent, font_line_gap; int font_ascent, font_descent, font_line_gap;
stbtt_GetFontVMetrics(&data.FontInfo, &font_ascent, &font_descent, &font_line_gap); stbtt_GetFontVMetrics(&data.FontInfo, &font_ascent, &font_descent, &font_line_gap);
data.OutFont->BaseLine = (font_ascent * font_scale); data.OutFont->Ascent = (font_ascent * font_scale);
data.OutFont->Descent = (font_descent * font_scale);
data.OutFont->Glyphs.resize(0); data.OutFont->Glyphs.resize(0);
const float uv_scale_x = 1.0f / TexWidth; const float uv_scale_x = 1.0f / TexWidth;
@ -9378,7 +9411,7 @@ void ImFont::Clear()
{ {
FontSize = 0.0f; FontSize = 0.0f;
DisplayOffset = ImVec2(-0.5f, 0.5f); DisplayOffset = ImVec2(-0.5f, 0.5f);
BaseLine = 0.0f; Ascent = Descent = 0.0f;
ContainerAtlas = NULL; ContainerAtlas = NULL;
Glyphs.clear(); Glyphs.clear();
FallbackGlyph = NULL; FallbackGlyph = NULL;
@ -9735,12 +9768,20 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
if (c == 0) if (c == 0)
break; break;
if (c == '\n') if (c < 32)
{ {
line_width = word_width = blank_width = 0.0f; if (c == '\n')
inside_word = true; {
s = next_s; line_width = word_width = blank_width = 0.0f;
continue; inside_word = true;
s = next_s;
continue;
}
if (c == '\r')
{
s = next_s;
continue;
}
} }
const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance;
@ -9846,12 +9887,17 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
break; break;
} }
if (c == '\n') if (c < 32)
{ {
text_size.x = ImMax(text_size.x, line_width); if (c == '\n')
text_size.y += line_height; {
line_width = 0.0f; text_size.x = ImMax(text_size.x, line_width);
continue; text_size.y += line_height;
line_width = 0.0f;
continue;
}
if (c == '\r')
continue;
} }
const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance;
@ -9893,12 +9939,17 @@ ImVec2 ImFont::CalcTextSizeW(float size, float max_width, const ImWchar* text_be
{ {
const unsigned int c = (unsigned int)(*s++); const unsigned int c = (unsigned int)(*s++);
if (c == '\n') if (c < 32)
{ {
text_size.x = ImMax(text_size.x, line_width); if (c == '\n')
text_size.y += line_height; {
line_width = 0.0f; text_size.x = ImMax(text_size.x, line_width);
continue; text_size.y += line_height;
line_width = 0.0f;
continue;
}
if (c == '\r')
continue;
} }
const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance;
@ -9994,11 +10045,16 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
break; break;
} }
if (c == '\n') if (c < 32)
{ {
x = pos.x; if (c == '\n')
y += line_height; {
continue; x = pos.x;
y += line_height;
continue;
}
if (c == '\r')
continue;
} }
float char_width = 0.0f; float char_width = 0.0f;
@ -10593,7 +10649,7 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushID(i); ImGui::PushID(i);
int frame_padding = -1 + i; // -1 = uses default padding int frame_padding = -1 + i; // -1 = uses default padding
if (ImGui::ImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding)) if (ImGui::ImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding, ImColor(0,0,0,255)))
pressed_count += 1; pressed_count += 1;
ImGui::PopID(); ImGui::PopID();
} }
@ -10626,7 +10682,7 @@ void ImGui::ShowTestWindow(bool* opened)
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
ImGui::PushID(i); ImGui::PushID(i);
if (ImGui::Selectable("Me", &selected[i], ImVec2(50,50))) if (ImGui::Selectable("Me", &selected[i], 0, ImVec2(50,50)))
{ {
int x = i % 4, y = i / 4; int x = i % 4, y = i / 4;
if (x > 0) selected[i - 1] ^= 1; if (x > 0) selected[i - 1] ^= 1;
@ -10828,13 +10884,13 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%");
static float f1=1.00f, f2=0.0067f; static float f1=1.00f, f2=0.0067f;
ImGui::DragFloat("drag float", &f1, 1.0f); ImGui::DragFloat("drag float", &f1, 0.005f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
} }
{ {
static int i1=0; static int i1=0;
ImGui::SliderInt("slider int", &i1, 0, 3); ImGui::SliderInt("slider int", &i1, -1, 3);
ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value."); ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value.");
static float f1=0.123f, f2=0.0f; static float f1=0.123f, f2=0.0f;
@ -11213,9 +11269,14 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::Separator(); ImGui::Separator();
const char* names[3] = { "One", "Two", "Three" }; const char* names[3] = { "One", "Two", "Three" };
const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
static int selected = -1;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
ImGui::Text("%04d", i); ImGui::NextColumn(); char label[32];
sprintf(label, "%04d", i);
if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
selected = i;
ImGui::NextColumn();
ImGui::Text(names[i]); ImGui::NextColumn(); ImGui::Text(names[i]); ImGui::NextColumn();
ImGui::Text(paths[i]); ImGui::NextColumn(); ImGui::Text(paths[i]); ImGui::NextColumn();
ImGui::Text("...."); ImGui::NextColumn(); ImGui::Text("...."); ImGui::NextColumn();
@ -11465,6 +11526,7 @@ void ImGui::ShowMetricsWindow(bool* opened)
NodeDrawList(window->DrawList, "DrawList"); NodeDrawList(window->DrawList, "DrawList");
if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
if (window->DC.ChildWindows.size() > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); if (window->DC.ChildWindows.size() > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
ImGui::BulletText("Storage: %d bytes", (int)window->StateStorage.Data.size() * sizeof(ImGuiStorage::Pair));
ImGui::TreePop(); ImGui::TreePop();
} }
}; };

26
imgui.h
View File

@ -1,4 +1,4 @@
// ImGui library v1.40 WIP // ImGui library v1.41 WIP
// See .cpp file for documentation. // See .cpp file for documentation.
// See ImGui::ShowTestWindow() for sample code. // See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.
@ -13,7 +13,7 @@
#include <stdlib.h> // NULL, malloc, free, qsort, atoi #include <stdlib.h> // NULL, malloc, free, qsort, atoi
#include <string.h> // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp #include <string.h> // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp
#define IMGUI_VERSION "1.40 WIP" #define IMGUI_VERSION "1.41 WIP"
// Define assertion handler. // Define assertion handler.
#ifndef IM_ASSERT #ifndef IM_ASSERT
@ -48,6 +48,7 @@ typedef int ImGuiMouseCursor; // enum ImGuiMouseCursor_
typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_ typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_
typedef int ImGuiSetCond; // enum ImGuiSetCond_ typedef int ImGuiSetCond; // enum ImGuiSetCond_
typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_ typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_
typedef int ImGuiSelectableFlags; // enum ImGuiSelectableFlags_
struct ImGuiTextEditCallbackData; // for advanced uses of InputText() struct ImGuiTextEditCallbackData; // for advanced uses of InputText()
typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
@ -236,7 +237,7 @@ namespace ImGui
IMGUI_API bool SmallButton(const char* label); IMGUI_API bool SmallButton(const char* label);
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size);
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding
IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false); IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false);
IMGUI_API bool Checkbox(const char* label, bool* v); IMGUI_API bool Checkbox(const char* label, bool* v);
IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
@ -300,8 +301,8 @@ namespace ImGui
IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened. IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened.
// Widgets: Selectable / Lists // Widgets: Selectable / Lists
IMGUI_API bool Selectable(const char* label, bool selected = false, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
IMGUI_API bool Selectable(const char* label, bool* p_selected, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0));
IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1);
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. make sure to call ListBoxFooter() afterwards. IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. make sure to call ListBoxFooter() afterwards.
@ -344,6 +345,7 @@ namespace ImGui
IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item in screen space IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item in screen space
IMGUI_API ImVec2 GetItemRectMax(); // " IMGUI_API ImVec2 GetItemRectMax(); // "
IMGUI_API ImVec2 GetItemRectSize(); // " IMGUI_API ImVec2 GetItemRectSize(); // "
IMGUI_API bool IsWindowHovered();
IMGUI_API bool IsWindowFocused(); // is current window focused (differentiate child windows from each others) IMGUI_API bool IsWindowFocused(); // is current window focused (differentiate child windows from each others)
IMGUI_API bool IsRootWindowFocused(); // is current root window focused (top parent window in case of child windows) IMGUI_API bool IsRootWindowFocused(); // is current root window focused (top parent window in case of child windows)
IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused
@ -442,6 +444,14 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CallbackCharFilter = 1 << 9 // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character. ImGuiInputTextFlags_CallbackCharFilter = 1 << 9 // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character.
}; };
// Flags for ImGui::Selectable()
enum ImGuiSelectableFlags_
{
// Default: 0
ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window
ImGuiSelectableFlags_SpanAllColumns = 1 << 1 // Selectable frame can span all columns (text will still fit in current column)
};
// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array
enum ImGuiKey_ enum ImGuiKey_
{ {
@ -1112,7 +1122,8 @@ struct ImFont
signed short XOffset, YOffset; signed short XOffset, YOffset;
float U0, V0, U1, V1; // Texture coordinates float U0, V0, U1, V1; // Texture coordinates
}; };
float BaseLine; // Distance from top to bottom of e.g. 'A' [0..FontSize] float Ascent; // Distance from top to bottom of e.g. 'A' [0..FontSize]
float Descent; //
ImFontAtlas* ContainerAtlas; // What we has been loaded into ImFontAtlas* ContainerAtlas; // What we has been loaded into
ImVector<Glyph> Glyphs; ImVector<Glyph> Glyphs;
const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar)
@ -1125,9 +1136,10 @@ struct ImFont
IMGUI_API ~ImFont(); IMGUI_API ~ImFont();
IMGUI_API void Clear(); IMGUI_API void Clear();
IMGUI_API void BuildLookupTable(); IMGUI_API void BuildLookupTable();
IMGUI_API float GetCharAdvance(unsigned short c) const { return ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] : FallbackXAdvance; }
IMGUI_API const Glyph* FindGlyph(unsigned short c) const; IMGUI_API const Glyph* FindGlyph(unsigned short c) const;
IMGUI_API void SetFallbackChar(ImWchar c); IMGUI_API void SetFallbackChar(ImWchar c);
IMGUI_API bool IsLoaded() const { return ContainerAtlas != NULL; } IMGUI_API bool IsLoaded() const { return ContainerAtlas != NULL; }
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.