Compare commits

...

17 Commits
v1.06 ... v1.07

Author SHA1 Message Date
efc473df98 Todo list 2014-08-18 19:13:18 +01:00
bbda899801 Removed unused parameter in demo window code 2014-08-18 19:10:00 +01:00
a17885f470 Fixed tooltip size (broken earlier today) + added todo items 2014-08-18 18:43:39 +01:00
7de89e0da3 Removing line from Todo list 2014-08-18 14:31:47 +01:00
7c61822d26 Skip most logic is alpha is 0.0, Begin() also return false to allow user to early out 2014-08-18 14:30:33 +01:00
ca027e1754 Skip rendering if alpha is 0.0 2014-08-18 13:20:57 +01:00
c5dacee3a7 Undo Begin() return false with Alpha==0.0, misleading at the moment 2014-08-18 13:18:32 +01:00
d6f6afabb3 Initialised window->Accessed in constructor. Begin() return false with Alpha==0.0 2014-08-18 13:09:48 +01:00
76a39ad224 Added global Alpha in ImGuiStyle + commented ImGuiStyle fields in .h 2014-08-18 13:03:02 +01:00
926f7bfcc5 Added InputFloat4(), SliderFloat4() helpers. 2014-08-17 14:16:10 +01:00
f6414f2011 Invisible child windows gets clipped earlier in the pipeline. 2014-08-17 14:02:32 +01:00
931a4c5b49 Renamed ImVector<> members. 2014-08-17 13:55:27 +01:00
c32221fa20 Child window with inverted clip rectangles are marked as collapsed. 2014-08-17 11:28:19 +01:00
a165954a69 Reduce inner window clipping to take account for the extend of CollapsingHeader
from arikwestbrook
2014-08-17 10:41:36 +01:00
ddf8b280e9 Allowing the user to call NewFrame() multiple times without calling Render()
Note that this is never a good idea. But, allowing it reduce confusion
in the initial stage of setup.
2014-08-16 18:47:59 +01:00
969b1e0563 Fix clipping of title bar text. 2014-08-16 18:22:52 +01:00
6e15b71663 Minor todo/readme changes 2014-08-16 14:19:19 +01:00
3 changed files with 248 additions and 220 deletions

View File

@ -38,7 +38,7 @@ Developed by [Omar Cornut](http://www.miracleworld.net). The library was develop
Embeds [proggy_clean](http://www.proggyfonts.net/) font by Tristan Grimmer (also MIT license).
Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Matt Willis. Thanks!
Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Thanks!
License
-------

386
imgui.cpp
View File

@ -109,28 +109,28 @@
ISSUES AND TODO-LIST
- misc: allow user to call NewFrame() multiple times without a render.
- misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers
- window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit?
- window: support horizontal scroll
- window: fix resize grip scaling along with Rounding style setting
- window/style: add global alpha modifier (not just "fill_alpha")
- widgets: switching from "widget-label" to "label-widget" would make it more convenient to integrate widgets in trees
- widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay
- main: make IsHovered() 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: make IsHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- scrollbar: use relative mouse movement when first-clicking inside of scroll grab box.
- scrollbar: make the grab visible and a minimum size for long scroll regions
- input number: optional range min/max
- input number: holding [-]/[+] buttons should increase the step non-linearly
- input number: rename Input*() to Input(), Slider*() to Slider() ?
- layout: clean up the InputFloat3/SliderFloat3/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper.
- add input4 helper (once above layout helpers are in they'll be smaller)
- input number: use mouse wheel to step up/down
- layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper.
- columns: declare column set (each column: fixed size, %, fill, distribute default size among fills)
- columns: columns header to act as button (~sort op) and allow resize/reorder
- columns: user specify columns size
- combo: turn child handling code into popup helper
- list selection, concept of a selectable "block" (that can be multiple widgets)
- menubar, menus
- plot: make it easier for user to draw into the graph (e.g: draw basis, highlight certain pointsm, 2d plots, multiple plots)
- plot: "smooth" automatic scale, user give an input 0.0(full user scale) 1.0(full derived from value)
- plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID)
- file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes)
- slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt()
@ -145,8 +145,10 @@
- filters: set a current filter that tree node can automatically query to hide themselves
- 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)
- keyboard: full keyboard navigation and focus
- input: keyboard: full keyboard navigation and focus.
- input: support trackpad style scrolling & slider edit.
- misc: not thread-safe
- misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon?
- optimisation/render: use indexed rendering
- optimisation/render: move clip-rect to vertex data? would allow merging all commands
- optimisation/render: merge command-list of all windows into one command-list?
@ -209,18 +211,19 @@ static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_
ImGuiStyle::ImGuiStyle()
{
Alpha = 1.0f; // Global alpha applies to everything in ImGui
WindowPadding = ImVec2(8,8); // Padding within a window
WindowMinSize = ImVec2(48,48); // Minimum window size
FramePadding = ImVec2(5,4); // Padding within a framed rectangle (used by most widgets)
ItemSpacing = ImVec2(10,5); // Horizontal and vertical spacing between widgets
ItemSpacing = ImVec2(10,5); // Horizontal and vertical spacing between widgets/lines
ItemInnerSpacing = ImVec2(5,5); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
TouchExtraPadding = ImVec2(0,0); // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much!
AutoFitPadding = ImVec2(8,8); // Extra space after auto-fit (double-clicking on resize grip)
WindowFillAlphaDefault = 0.70f;
WindowRounding = 10.0f;
TreeNodeSpacing = 22.0f;
ColumnsMinSpacing = 6.0f; // Minimum space between two columns
ScrollBarWidth = 16.0f;
WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin()
WindowRounding = 10.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
TreeNodeSpacing = 22.0f; // Horizontal spacing when entering a tree node
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
ScrollBarWidth = 16.0f; // Width of the vertical scroll bar
Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
@ -667,9 +670,10 @@ struct ImGuiWindow
float ScrollY;
float NextScrollY;
bool ScrollbarY;
bool Visible;
bool Collapsed;
bool Accessed;
bool Visible; // Set to true on Begin()
bool Accessed; // Set to true when any widget access the current window
bool Collapsed; // Set when collapsing window to become only title-bar
bool SkipItems; // == Visible && !Collapsed
int AutoFitFrames;
ImGuiDrawContext DC;
@ -704,7 +708,8 @@ public:
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : FontSize() + GImGui.Style.FramePadding.y * 2.0f; }
ImGuiAabb TitleBarAabb() const { return ImGuiAabb(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); }
ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(1,1) : GImGui.Style.WindowPadding; }
ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui.Style.Colors[idx]; c.w *= a; return ImConvertColorFloat4ToU32(c); }
ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui.Style.Colors[idx]; c.w *= GImGui.Style.Alpha * a; return ImConvertColorFloat4ToU32(c); }
ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui.Style.Alpha; return ImConvertColorFloat4ToU32(c); }
};
static ImGuiWindow* GetCurrentWindow()
@ -921,7 +926,9 @@ ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_si
NextScrollY = 0.0f;
ScrollbarY = false;
Visible = false;
Accessed = false;
Collapsed = false;
SkipItems = false;
AutoFitFrames = -1;
LastFrameDrawn = -1;
ItemWidthDefault = 0.0f;
@ -1001,8 +1008,8 @@ void ImGuiWindow::AddToRenderList()
for (size_t i = 0; i < DC.ChildWindows.size(); i++)
{
ImGuiWindow* child = DC.ChildWindows[i];
IM_ASSERT(child->Visible); // Shouldn't be in this list if we are not active this frame
child->AddToRenderList();
if (child->Visible) // clipped childs may have been marked not Visible
child->AddToRenderList();
}
}
@ -1246,7 +1253,7 @@ void NewFrame()
float scale = new_font_scale / window->FontScale;
window->FontScale = new_font_scale;
ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
window->Pos += offset;
window->PosFloat += offset;
window->Size *= scale;
@ -1270,11 +1277,17 @@ void NewFrame()
// Mark all windows as not visible
for (size_t i = 0; i != g.Windows.size(); i++)
g.Windows[i]->Visible = false;
{
ImGuiWindow* window = g.Windows[i];
window->Visible = false;
window->Accessed = false;
}
// Create implicit window
// We will only render it if the user has added something to it.
IM_ASSERT(g.CurrentWindowStack.empty()); // No window should be open at the beginning of the frame!
// No window should be open at the beginning of the frame.
// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
g.CurrentWindowStack.clear();
// Create implicit window - we will only render it if the user has added something to it.
ImGui::Begin("Debug", NULL, ImVec2(400,400));
}
@ -1326,7 +1339,8 @@ static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector<ImGuiWindow*>&
for (size_t i = 0; i < window->DC.ChildWindows.size(); i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
AddWindowToSortedBuffer(child, sorted_windows);
if (child->Visible)
AddWindowToSortedBuffer(child, sorted_windows);
}
}
}
@ -1390,34 +1404,39 @@ void Render()
memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
}
// Render tooltip
if (g.Tooltip[0])
// Skip render altogether if alpha is 0.0
// Note that vertex buffers have been created, so it is best practice that you don't call Begin/End in the first place.
if (g.Style.Alpha > 0.0f)
{
// Use a dummy window to render the tooltip
ImGui::BeginTooltip();
ImGui::TextUnformatted(g.Tooltip);
ImGui::EndTooltip();
}
// Render tooltip
if (g.Tooltip[0])
{
// Use a dummy window to render the tooltip
ImGui::BeginTooltip();
ImGui::TextUnformatted(g.Tooltip);
ImGui::EndTooltip();
}
// Gather windows to render
g.RenderDrawLists.resize(0);
for (size_t i = 0; i != g.Windows.size(); i++)
{
ImGuiWindow* window = g.Windows[i];
if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
window->AddToRenderList();
}
for (size_t i = 0; i != g.Windows.size(); i++)
{
ImGuiWindow* window = g.Windows[i];
if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip))
window->AddToRenderList();
}
// Gather windows to render
g.RenderDrawLists.resize(0);
for (size_t i = 0; i != g.Windows.size(); i++)
{
ImGuiWindow* window = g.Windows[i];
if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
window->AddToRenderList();
}
for (size_t i = 0; i != g.Windows.size(); i++)
{
ImGuiWindow* window = g.Windows[i];
if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip))
window->AddToRenderList();
}
// Render
if (!g.RenderDrawLists.empty())
g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size());
g.RenderDrawLists.resize(0);
// Render
if (!g.RenderDrawLists.empty())
g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size());
g.RenderDrawLists.resize(0);
}
}
// Find the optional ## from which we stop displaying text.
@ -1793,6 +1812,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
ImGuiWindow* window = FindWindow(name);
if (!window)
{
// Create window the first time, and load settings
if (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip))
{
window = new ImGuiWindow(name, ImVec2(0,0), size);
@ -1928,7 +1948,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
// Apply and ImClamp scrolling
window->ScrollY = window->NextScrollY;
window->ScrollY = ImMax(window->ScrollY, 0.0f);
if (!window->Collapsed)
if (!window->Collapsed && !window->SkipItems)
window->ScrollY = ImMin(window->ScrollY, ImMax(0.0f, (float)window->SizeContentsFit.y - window->SizeFull.y));
window->NextScrollY = window->ScrollY;
@ -2035,7 +2055,8 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1);
//window->DrawList->AddLine(scrollbar_bb.GetTL(), scrollbar_bb.GetBL(), g.Colors[ImGuiCol_Border]);
window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg));
scrollbar_bb.Expand(ImVec2(-3,-3));
scrollbar_bb.Max.x -= 3;
scrollbar_bb.Expand(ImVec2(0,-3));
const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y));
const float grab_size_y = scrollbar_bb.GetHeight() * grab_size_y_norm;
@ -2113,24 +2134,38 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
{
RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true);
RenderText(window->Pos + style.FramePadding + ImVec2(window->FontSize() + style.ItemInnerSpacing.x, 0), name);
if (open)
ImGui::CloseWindowButton(open);
const ImVec2 text_size = CalcTextSize(name);
const ImVec2 text_min = window->Pos + style.FramePadding + ImVec2(window->FontSize() + style.ItemInnerSpacing.x, 0.0f);
const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (open ? (title_bar_aabb.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y + text_size.y);
const bool clip_title = text_size.x > (text_max.x - text_min.x); // only push a clip rectangle if we need to, because it may turn into a separate draw call
if (clip_title)
ImGui::PushClipRect(ImVec4(text_min.x, text_min.y, text_max.x, text_max.y));
RenderText(text_min, name);
if (clip_title)
ImGui::PopClipRect();
}
}
else
{
// Outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
ImGui::PushClipRect(g.CurrentWindowStack[g.CurrentWindowStack.size()-2]->ClipRectStack.back());
{
ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.size()-2];
ImGui::PushClipRect(parent_window->ClipRectStack.back());
}
else
{
ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
}
// Inner clipping rectangle
// We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
const ImGuiAabb title_bar_aabb = window->TitleBarAabb();
ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x-1.5f, window->Aabb().Max.y-1.5f);
ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f);
if (window->ScrollbarY)
clip_rect.z -= g.Style.ScrollBarWidth;
ImGui::PushClipRect(clip_rect);
@ -2141,8 +2176,25 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
window->Accessed = false;
}
// Return collapsed so that user can perform an early out optimisation
return !window->Collapsed;
// Child window can be out of sight and have "negative" clip windows.
// Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar).
if (flags & ImGuiWindowFlags_ChildWindow)
{
IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
const ImVec4 clip_rect = window->ClipRectStack.back();
window->Collapsed = (clip_rect.x >= clip_rect.z || clip_rect.y >= clip_rect.w);
// We also hide the window from rendering because we've already added its border to the command list.
// (we could perform the check earlier in the function but it is simplier at this point)
if (window->Collapsed)
window->Visible = false;
}
if (g.Style.Alpha <= 0.0f)
window->Visible = false;
// Return false if we don't intend to display anything to allow user to perform an early out optimisation
window->SkipItems = window->Collapsed || (!window->Visible && window->AutoFitFrames == 0);
return !window->SkipItems;
}
void End()
@ -2410,7 +2462,7 @@ ImGuiStorage* GetTreeStateStorage()
void TextV(const char* fmt, va_list args)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
static char buf[1024];
@ -2440,7 +2492,7 @@ void TextUnformatted(const char* text, const char* text_end)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
const char* text_begin = text;
@ -2538,7 +2590,7 @@ void AlignFirstTextHeightToWidgets()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
// Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height.
@ -2550,7 +2602,7 @@ void LabelText(const char* label, const char* fmt, ...)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
const ImGuiStyle& style = g.Style;
const float w = window->DC.ItemWidth.back();
@ -2623,7 +2675,7 @@ bool Button(const char* label, ImVec2 size, bool repeat_when_held)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -2663,7 +2715,7 @@ bool SmallButton(const char* label)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -2691,7 +2743,6 @@ static bool CloseWindowButton(bool* open)
ImGuiWindow* window = GetCurrentWindow();
const ImGuiID id = window->GetID("##CLOSE");
const float title_bar_height = window->TitleBarHeight();
const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-title_bar_height+3.0f,2.0f), window->Aabb().GetTR() + ImVec2(-2.0f,+title_bar_height-2.0f));
@ -2701,7 +2752,6 @@ static bool CloseWindowButton(bool* open)
// Render
const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f,title_bar_height*0.5f-4), col, 16);
//RenderFrame(bb.Min, bb.Max, col, false);
const float cross_padding = 4;
if (hovered && bb.GetWidth() >= (cross_padding+1)*2 && bb.GetHeight() >= (cross_padding+1)*2)
@ -2783,7 +2833,7 @@ bool CollapsingHeader(const char* label, const char* str_id, const bool display_
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -2863,7 +2913,7 @@ void BulletText(const char* fmt, ...)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
static char buf[1024];
@ -3015,7 +3065,7 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -3247,71 +3297,54 @@ bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* disp
return changed;
}
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
static bool SliderFloatN(const char* label, float v[3], int components, float v_min, float v_max, const char* display_format, float power)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)));
bool value_changed = false;
ImGui::PushID(label);
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
for (int i = 0; i < components; i++)
{
ImGui::PushID(i);
if (i + 1 == components)
{
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
}
value_changed |= ImGui::SliderFloat("##v", &v[i], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::PopID();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
{
return SliderFloatN(label, v, 2, v_min, v_max, display_format, power);
}
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
return SliderFloatN(label, v, 3, v_min, v_max, display_format, power);
}
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 3;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderFloat("##Z", &v[2], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format, float power)
{
return SliderFloatN(label, v, 4, v_min, v_max, display_format, power);
}
// Enum for ImGui::Plot()
@ -3331,7 +3364,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
const ImGuiStyle& style = g.Style;
@ -3439,7 +3472,7 @@ void Checkbox(const char* label, bool* v)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
const ImGuiStyle& style = g.Style;
@ -3493,7 +3526,7 @@ bool RadioButton(const char* label, bool active)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -3682,7 +3715,7 @@ bool InputFloat(const char* label, float *v, float step, float step_fast, int de
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -3746,7 +3779,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiIO& io = g.IO;
@ -3966,71 +3999,54 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
return value_changed;
}
bool InputFloat2(const char* label, float v[2], int decimal_precision)
static bool InputFloatN(const char* label, float* v, int components, int decimal_precision)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)));
bool value_changed = false;
ImGui::PushID(label);
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
for (int i = 0; i < components; i++)
{
ImGui::PushID(i);
if (i + 1 == components)
{
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
}
value_changed |= ImGui::InputFloat("##v", &v[i], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::PopID();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool InputFloat2(const char* label, float v[2], int decimal_precision)
{
return InputFloatN(label, v, 2, decimal_precision);
}
bool InputFloat3(const char* label, float v[3], int decimal_precision)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
return InputFloatN(label, v, 3, decimal_precision);
}
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 3;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::InputFloat("##Z", &v[2], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
bool InputFloat4(const char* label, float v[4], int decimal_precision)
{
return InputFloatN(label, v, 4, decimal_precision);
}
static bool Combo_ArrayGetter(void* data, int idx, const char** out_text)
@ -4084,7 +4100,7 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -4199,7 +4215,7 @@ bool ColorButton(const ImVec4& col, bool small_height, bool outline_border)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -4212,9 +4228,7 @@ bool ColorButton(const ImVec4& col, bool small_height, bool outline_border)
const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(bb);
const bool pressed = hovered && g.IO.MouseClicked[0];
const ImU32 col32 = ImConvertColorFloat4ToU32(col);
RenderFrame(bb.Min, bb.Max, col32, outline_border);
RenderFrame(bb.Min, bb.Max, window->Color(col), outline_border);
if (hovered)
{
@ -4248,7 +4262,7 @@ bool ColorEdit4(const char* label, float col[4], bool alpha)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
@ -4384,7 +4398,7 @@ void ColorEditMode(ImGuiColorEditMode mode)
void Separator()
{
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
if (window->DC.ColumnsCount > 1)
@ -4409,7 +4423,7 @@ void Separator()
void Spacing()
{
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
ItemSize(ImVec2(0,0));
@ -4419,7 +4433,7 @@ static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
@ -4445,7 +4459,7 @@ void NextColumn()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
if (window->DC.ColumnsCount > 1)
@ -4499,7 +4513,7 @@ void SameLine(int column_x, int spacing_w)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
if (window->SkipItems)
return;
float x, y;
@ -4572,6 +4586,8 @@ void Columns(int columns_count, const char* id, bool border)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
if (window->DC.ColumnsCount != 1)
{
@ -4799,6 +4815,9 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col)
void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris, const ImVec2& third_point_offset)
{
if ((col >> 24) == 0)
return;
static ImVec2 circle_vtx[12];
static bool circle_vtx_builds = false;
if (!circle_vtx_builds)
@ -5386,6 +5405,7 @@ void ShowStyleEditor(ImGuiStyle* ref)
*ref = g.Style;
}
ImGui::SliderFloat("Alpha", &style.Alpha, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI. But application code could have a toggle to switch between zero and non-zero.
ImGui::SliderFloat("Rounding", &style.WindowRounding, 0.0f, 16.0f, "%.0f");
static ImGuiColorEditMode edit_mode = ImGuiColorEditMode_RGB;
@ -5545,11 +5565,14 @@ void ShowTestWindow(bool* open)
ImGui::InputInt("input int", &i0);
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
//static float vec2b[3] = { 0.10f, 0.20f };
//ImGui::InputFloat2("input float2", vec2b);
//static float vec2a[3] = { 0.10f, 0.20f };
//ImGui::InputFloat2("input float2", vec2a);
static float vec3b[3] = { 0.10f, 0.20f, 0.30f };
ImGui::InputFloat3("input float3", vec3b);
static float vec3a[3] = { 0.10f, 0.20f, 0.30f };
ImGui::InputFloat3("input float3", vec3a);
//static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
//ImGui::InputFloat4("input float4", vec4a);
static int i1=0;
static int i2=42;
@ -5563,15 +5586,18 @@ void ShowTestWindow(bool* open)
ImGui::SliderFloat("float", &f1, 0.0f, 2.0f);
ImGui::SliderFloat("log float", &f2, 0.0f, 10.0f, "%.4f", 2.0f);
ImGui::SliderFloat("signed log float", &f3, -10.0f, 10.0f, "%.4f", 3.0f);
ImGui::SliderFloat("unbound float", &f4, -FLT_MAX, FLT_MAX, "%.4f", 3.0f);
ImGui::SliderFloat("unbound float", &f4, -FLT_MAX, FLT_MAX, "%.4f");
static float angle = 0.0f;
ImGui::SliderAngle("angle", &angle);
//static float vec2a[3] = { 0.10f, 0.20f };
//ImGui::SliderFloat2("slider float2", vec2a, 0.0f, 1.0f);
//static float vec2b[3] = { 0.10f, 0.20f };
//ImGui::SliderFloat2("slider float2", vec2b, 0.0f, 1.0f);
static float vec3a[3] = { 0.10f, 0.20f, 0.30f };
ImGui::SliderFloat3("slider float3", vec3a, 0.0f, 1.0f);
static float vec3b[3] = { 0.10f, 0.20f, 0.30f };
ImGui::SliderFloat3("slider float3", vec3b, 0.0f, 1.0f);
//static float vec4b[4] = { 0.10f, 0.20f, 0.30f, 0.40f };
//ImGui::SliderFloat4("slider float4", vec4b, 0.0f, 1.0f);
static float col1[3] = { 1.0f,0.0f,0.2f };
static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };

80
imgui.h
View File

@ -62,46 +62,46 @@ template<typename T>
class ImVector
{
private:
size_t _size;
size_t _capacity;
T* _data;
size_t Size;
size_t Capacity;
T* Data;
public:
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
ImVector() { _size = _capacity = 0; _data = NULL; }
~ImVector() { if (_data) free(_data); }
ImVector() { Size = Capacity = 0; Data = NULL; }
~ImVector() { if (Data) free(Data); }
inline bool empty() const { return _size == 0; }
inline size_t size() const { return _size; }
inline size_t capacity() const { return _capacity; }
inline bool empty() const { return Size == 0; }
inline size_t size() const { return Size; }
inline size_t capacity() const { return Capacity; }
inline value_type& at(size_t i) { IM_ASSERT(i < _size); return _data[i]; }
inline const value_type& at(size_t i) const { IM_ASSERT(i < _size); return _data[i]; }
inline value_type& operator[](size_t i) { IM_ASSERT(i < _size); return _data[i]; }
inline const value_type& operator[](size_t i) const { IM_ASSERT(i < _size); return _data[i]; }
inline value_type& at(size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& at(size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline value_type& operator[](size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& operator[](size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline void clear() { if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } }
inline iterator begin() { return _data; }
inline const_iterator begin() const { return _data; }
inline iterator end() { return _data + _size; }
inline const_iterator end() const { return _data + _size; }
inline void clear() { if (Data) { Size = Capacity = 0; free(Data); Data = NULL; } }
inline iterator begin() { return Data; }
inline const_iterator begin() const { return Data; }
inline iterator end() { return Data + Size; }
inline const_iterator end() const { return Data + Size; }
inline value_type& front() { return at(0); }
inline const value_type& front() const { return at(0); }
inline value_type& back() { IM_ASSERT(_size > 0); return at(_size-1); }
inline const value_type& back() const { IM_ASSERT(_size > 0); return at(_size-1); }
inline void swap(ImVector<T>& rhs) { const size_t rhs_size = rhs._size; rhs._size = _size; _size = rhs_size; const size_t rhs_cap = rhs._capacity; rhs._capacity = _capacity; _capacity = rhs_cap; value_type* rhs_data = rhs._data; rhs._data = _data; _data = rhs_data; }
inline value_type& back() { IM_ASSERT(Size > 0); return at(Size-1); }
inline const value_type& back() const { IM_ASSERT(Size > 0); return at(Size-1); }
inline void swap(ImVector<T>& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
inline void reserve(size_t new_capacity) { _data = (value_type*)realloc(_data, new_capacity * sizeof(value_type)); _capacity = new_capacity; }
inline void resize(size_t new_size) { if (new_size > _capacity) reserve(new_size); _size = new_size; }
inline void reserve(size_t new_capacity) { Data = (value_type*)realloc(Data, new_capacity * sizeof(value_type)); Capacity = new_capacity; }
inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; }
inline void push_back(const value_type& v) { if (_size == _capacity) reserve(_capacity ? _capacity * 2 : 4); _data[_size++] = v; }
inline void pop_back() { IM_ASSERT(_size > 0); _size--; }
inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; }
inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const int off = it - begin(); memmove(_data + off, _data + off + 1, (_size - off - 1) * sizeof(value_type)); _size--; return _data + off; }
inline void insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const int off = it - begin(); if (_size == _capacity) reserve(_capacity ? _capacity * 2 : 4); if (off < (int)_size) memmove(_data + off + 1, _data + off, (_size - off) * sizeof(value_type)); _data[off] = v; _size++; }
inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const int off = it - begin(); memmove(Data + off, Data + off + 1, (Size - off - 1) * sizeof(value_type)); Size--; return Data + off; }
inline void insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const int off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - off) * sizeof(value_type)); Data[off] = v; Size++; }
};
#endif // #ifndef ImVector
@ -191,6 +191,7 @@ namespace ImGui
bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat4(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians
bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f");
void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float));
@ -202,6 +203,7 @@ namespace ImGui
bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1);
bool InputFloat2(const char* label, float v[2], int decimal_precision = -1);
bool InputFloat3(const char* label, float v[3], int decimal_precision = -1);
bool InputFloat4(const char* label, float v[4], int decimal_precision = -1);
bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100);
bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0);
bool Combo(const char* label, int* current_item, const char** items, int items_count, int popup_height_items = 7);
@ -351,21 +353,21 @@ enum ImGuiColorEditMode_
ImGuiColorEditMode_HEX = 2,
};
// See constructor for comments of individual fields.
struct ImGuiStyle
{
ImVec2 WindowPadding;
ImVec2 WindowMinSize;
ImVec2 FramePadding;
ImVec2 ItemSpacing;
ImVec2 ItemInnerSpacing;
ImVec2 TouchExtraPadding;
ImVec2 AutoFitPadding;
float WindowFillAlphaDefault;
float WindowRounding;
float TreeNodeSpacing;
float ColumnsMinSpacing;
float ScrollBarWidth;
float Alpha; // Global alpha applies to everything in ImGui
ImVec2 WindowPadding; // Padding within a window
ImVec2 WindowMinSize; // Minimum window size
ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets)
ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines
ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
ImVec2 TouchExtraPadding; // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much!
ImVec2 AutoFitPadding; // Extra space after auto-fit (double-clicking on resize grip)
float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin()
float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
float TreeNodeSpacing; // Horizontal spacing when entering a tree node
float ColumnsMinSpacing; // Minimum horizontal spacing between two columns
float ScrollBarWidth; // Width of the vertical scroll bar
ImVec4 Colors[ImGuiCol_COUNT];
ImGuiStyle();