From c5b8c6303aa9699c7fcc9965636a6eeed5aec507 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:06:14 +0200 Subject: [PATCH 1/8] Refactor PushStyleVar/PopStyleVar so it is constant time + can receive integers (yet unused) (#842) --- imgui.cpp | 105 +++++++++++++++++++++++++++-------------------- imgui.h | 4 +- imgui_internal.h | 17 +++++--- 3 files changed, 74 insertions(+), 52 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ed0c13d6..572c69a5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -563,7 +563,6 @@ - style: color-box not always square? - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc. - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). - - style/opt: PopStyleVar could be optimized by having GetStyleVar returns the type, using a table mapping stylevar enum to data type. - style: global scale setting. - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle - text: simple markup language for color change? @@ -4646,7 +4645,7 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) ImGuiContext& g = *GImGui; ImGuiColMod backup; backup.Col = idx; - backup.PreviousValue = g.Style.Colors[idx]; + backup.BackupValue = g.Style.Colors[idx]; g.ColorModifiers.push_back(backup); g.Style.Colors[idx] = col; } @@ -4657,64 +4656,78 @@ void ImGui::PopStyleColor(int count) while (count > 0) { ImGuiColMod& backup = g.ColorModifiers.back(); - g.Style.Colors[backup.Col] = backup.PreviousValue; + g.Style.Colors[backup.Col] = backup.BackupValue; g.ColorModifiers.pop_back(); count--; } } -static float* GetStyleVarFloatAddr(ImGuiStyleVar idx) +struct ImGuiStyleVarInfo { - ImGuiContext& g = *GImGui; - switch (idx) - { - case ImGuiStyleVar_Alpha: return &g.Style.Alpha; - case ImGuiStyleVar_WindowRounding: return &g.Style.WindowRounding; - case ImGuiStyleVar_ChildWindowRounding: return &g.Style.ChildWindowRounding; - case ImGuiStyleVar_FrameRounding: return &g.Style.FrameRounding; - case ImGuiStyleVar_IndentSpacing: return &g.Style.IndentSpacing; - case ImGuiStyleVar_GrabMinSize: return &g.Style.GrabMinSize; - } - return NULL; + ImGuiDataType Type; + ImU32 Offset; + void* GetVarPtr() const { return (void*)((unsigned char*)&GImGui->Style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = +{ + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildWindowRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, +}; + +static const void* GetStyleVarPtr(ImGuiStyleVar idx, ImGuiDataType type) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_); + const ImGuiStyleVarInfo* info = &GStyleVarInfo[idx]; + return (info->Type == type) ? info->GetVarPtr() : NULL; } -static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx) +void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) { - ImGuiContext& g = *GImGui; - switch (idx) + if (int* pvar = (int*)GetStyleVarPtr(idx, ImGuiDataType_Int)) { - case ImGuiStyleVar_WindowPadding: return &g.Style.WindowPadding; - case ImGuiStyleVar_WindowMinSize: return &g.Style.WindowMinSize; - case ImGuiStyleVar_FramePadding: return &g.Style.FramePadding; - case ImGuiStyleVar_ItemSpacing: return &g.Style.ItemSpacing; - case ImGuiStyleVar_ItemInnerSpacing: return &g.Style.ItemInnerSpacing; + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; } - return NULL; + if (float* pvarf = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvarf)); + *pvarf = (float)val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. } void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - ImGuiContext& g = *GImGui; - float* pvar = GetStyleVarFloatAddr(idx); - IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float. - ImGuiStyleMod backup; - backup.Var = idx; - backup.PreviousValue = ImVec2(*pvar, 0.0f); - g.StyleModifiers.push_back(backup); - *pvar = val; + if (float* pvar = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. } - void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - ImGuiContext& g = *GImGui; - ImVec2* pvar = GetStyleVarVec2Addr(idx); - IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2. - ImGuiStyleMod backup; - backup.Var = idx; - backup.PreviousValue = *pvar; - g.StyleModifiers.push_back(backup); - *pvar = val; + if (ImVec2* pvar = (ImVec2*)GetStyleVarPtr(idx, ImGuiDataType_Float2)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. } void ImGui::PopStyleVar(int count) @@ -4723,10 +4736,12 @@ void ImGui::PopStyleVar(int count) while (count > 0) { ImGuiStyleMod& backup = g.StyleModifiers.back(); - if (float* pvar_f = GetStyleVarFloatAddr(backup.Var)) - *pvar_f = backup.PreviousValue.x; - else if (ImVec2* pvar_v = GetStyleVarVec2Addr(backup.Var)) - *pvar_v = backup.PreviousValue; + IM_ASSERT(backup.VarIdx >= 0 && backup.VarIdx < ImGuiStyleVar_Count_); + const ImGuiStyleVarInfo* info = &GStyleVarInfo[backup.VarIdx]; + void* pvar = info->GetVarPtr(); + if (info->Type == ImGuiDataType_Float) (*(float*)pvar) = backup.BackupFloat[0]; + else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)pvar) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); + else if (info->Type == ImGuiDataType_Int) (*(int*)pvar) = backup.BackupInt[0]; g.StyleModifiers.pop_back(); count--; } diff --git a/imgui.h b/imgui.h index c72e8142..8081f262 100644 --- a/imgui.h +++ b/imgui.h @@ -176,6 +176,7 @@ namespace ImGui IMGUI_API void PopFont(); IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, int val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); @@ -646,7 +647,8 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ItemSpacing, // ImVec2 ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ImGuiStyleVar_IndentSpacing, // float - ImGuiStyleVar_GrabMinSize // float + ImGuiStyleVar_GrabMinSize, // float + ImGuiStyleVar_Count_ }; enum ImGuiAlign_ diff --git a/imgui_internal.h b/imgui_internal.h index 8a0b4824..826fbfbd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -75,6 +75,7 @@ extern IMGUI_API ImGuiContext* GImGui; // current implicit ImGui context po #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) #define IM_PI 3.14159265358979323846f +#define IM_OFFSETOF(_TYPE,_ELM) ((size_t)&(((_TYPE*)0)->_ELM)) // Helpers: UTF-8 <> wchar IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count @@ -192,7 +193,8 @@ enum ImGuiPlotType enum ImGuiDataType { ImGuiDataType_Int, - ImGuiDataType_Float + ImGuiDataType_Float, + ImGuiDataType_Float2, }; // 2D axis aligned bounding-box @@ -241,14 +243,17 @@ struct IMGUI_API ImRect struct ImGuiColMod { ImGuiCol Col; - ImVec4 PreviousValue; + ImVec4 BackupValue; }; -// Stacked style modifier, backup of modified data so we can restore it +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. struct ImGuiStyleMod { - ImGuiStyleVar Var; - ImVec2 PreviousValue; + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } }; // Stacked data for BeginGroup()/EndGroup() @@ -705,7 +710,7 @@ namespace ImGui IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); // NB: All position are in absolute pixels coordinates (not window coordinates) - // FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp! + // FIXME: All those functions are a mess and needs to be refactored into something decent. AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); From 281898e82e880e212453bf5c12139df9add3f535 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:14:10 +0200 Subject: [PATCH 2/8] Tidying up PushStyleVar/PopStyleVar() a little more (#842) --- imgui.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 572c69a5..f5faa159 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4684,25 +4684,27 @@ static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, }; -static const void* GetStyleVarPtr(ImGuiStyleVar idx, ImGuiDataType type) +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) { IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_); - const ImGuiStyleVarInfo* info = &GStyleVarInfo[idx]; - return (info->Type == type) ? info->GetVarPtr() : NULL; + return &GStyleVarInfo[idx]; } void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) { - if (int* pvar = (int*)GetStyleVarPtr(idx, ImGuiDataType_Int)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Int) { + int* pvar = (int*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } - if (float* pvarf = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + if (var_info->Type == ImGuiDataType_Float) { - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvarf)); - *pvarf = (float)val; + float* pvar = (float*)var_info->GetVarPtr(); + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = (float)val; return; } IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. @@ -4710,8 +4712,10 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - if (float* pvar = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float) { + float* pvar = (float*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; @@ -4721,8 +4725,10 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - if (ImVec2* pvar = (ImVec2*)GetStyleVarPtr(idx, ImGuiDataType_Float2)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float2) { + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; @@ -4736,12 +4742,10 @@ void ImGui::PopStyleVar(int count) while (count > 0) { ImGuiStyleMod& backup = g.StyleModifiers.back(); - IM_ASSERT(backup.VarIdx >= 0 && backup.VarIdx < ImGuiStyleVar_Count_); - const ImGuiStyleVarInfo* info = &GStyleVarInfo[backup.VarIdx]; - void* pvar = info->GetVarPtr(); - if (info->Type == ImGuiDataType_Float) (*(float*)pvar) = backup.BackupFloat[0]; - else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)pvar) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); - else if (info->Type == ImGuiDataType_Int) (*(int*)pvar) = backup.BackupInt[0]; + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); + if (info->Type == ImGuiDataType_Float) (*(float*)info->GetVarPtr()) = backup.BackupFloat[0]; + else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)info->GetVarPtr()) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); + else if (info->Type == ImGuiDataType_Int) (*(int*)info->GetVarPtr()) = backup.BackupInt[0]; g.StyleModifiers.pop_back(); count--; } From 02cea0c3c3a7ac245f663e0ceb6f048eb0048405 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:16:19 +0200 Subject: [PATCH 3/8] Comment --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f5faa159..938b6111 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5583,7 +5583,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 pos = window->DC.CursorPos; - if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); From de9f8944ea757d65770411297ab0a4e9ca0ab09f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:38:04 +0200 Subject: [PATCH 4/8] Internal RenderTextClipped() merged optional/rate clip_min* clip_max* into clip_rect* --- imgui.cpp | 20 ++++++++++++-------- imgui_internal.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 938b6111..194ebbca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2866,8 +2866,9 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end } } +// Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max) +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImRect* clip_rect) { // Hide anything after a '##' string const char* text_display_end = FindRenderedTextEnd(text, text_end); @@ -2882,11 +2883,13 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons ImVec2 pos = pos_min; const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); - if (!clip_max) clip_max = &pos_max; + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); - if (!clip_min) clip_min = &pos_min; else need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align + // Align whole block (we should defer that to the better rendering function) if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f); else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x); if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f); @@ -4306,14 +4309,15 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us ImVec2 text_min = window->Pos + style.FramePadding; ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y); - ImVec2 clip_max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() + ImRect clip_rect; + clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0; bool pad_right = (p_open != NULL); if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; - ImVec2 clip_min = ImVec2(text_min.x, window->Pos.y); - RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_min, &clip_max); + clip_rect.Min = ImVec2(text_min.x, window->Pos.y); + RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() @@ -7222,7 +7226,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) - RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb.Min, &bb.Max); + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb); } bool ImGui::Checkbox(const char* label, bool* v) diff --git a/imgui_internal.h b/imgui_internal.h index 826fbfbd..d0dedc47 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From 0f303d363ab03bcc14178ed4aa9b7b6d0dad7e54 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 12:19:15 +0200 Subject: [PATCH 5/8] Refactor text alignment options to use ImVec2, removed ImGuiAlign (#842, #222) --- imgui.cpp | 68 +++++++++++++++++------------------------------- imgui.h | 16 ++---------- imgui_internal.h | 2 +- 3 files changed, 27 insertions(+), 59 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 194ebbca..f9edf25c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -150,6 +150,7 @@ 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. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. @@ -729,7 +730,7 @@ ImGuiStyle::ImGuiStyle() WindowPadding = ImVec2(8,8); // Padding within a window WindowMinSize = ImVec2(32,32); // Minimum window size WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows - WindowTitleAlign = ImGuiAlign_Left; // Alignment for title bar text + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). @@ -2868,7 +2869,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImRect* clip_rect) +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) { // Hide anything after a '##' string const char* text_display_end = FindRenderedTextEnd(text, text_end); @@ -2889,10 +2890,9 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align whole block (we should defer that to the better rendering function) - if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f); - else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x); - if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f); + // Align whole block (we should defer that to the better rendering function + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); // Render if (need_clipping) @@ -4307,15 +4307,15 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (!(flags & ImGuiWindowFlags_NoCollapse)) RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); - ImVec2 text_min = window->Pos + style.FramePadding; - ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y); + ImVec2 text_min = window->Pos; + ImVec2 text_max = window->Pos + ImVec2(window->Size.x, style.FramePadding.y*2 + text_size.y); ImRect clip_rect; clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() - bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0; - bool pad_right = (p_open != NULL); - if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; - if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; - if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; + float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; + if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); + text_min.x += pad_left; + text_max.x -= pad_right; clip_rect.Min = ImVec2(text_min.x, window->Pos.y); RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); } @@ -4694,26 +4694,6 @@ static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) return &GStyleVarInfo[idx]; } -void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) -{ - const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Int) - { - int* pvar = (int*)var_info->GetVarPtr(); - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; - return; - } - if (var_info->Type == ImGuiDataType_Float) - { - float* pvar = (float*)var_info->GetVarPtr(); - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = (float)val; - return; - } - IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. -} - void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); @@ -5470,7 +5450,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) // Render const char* value_text_begin = &g.TempBuffer[0]; const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImGuiAlign_VCenter); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -5603,7 +5583,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, ImGuiAlign_Center | ImGuiAlign_VCenter); + RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, style.ButtonTextAlign); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -5970,12 +5950,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const char log_prefix[] = "\n##"; const char log_suffix[] = "##"; LogRenderedText(text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); LogRenderedText(text_pos, log_suffix+1, log_suffix+3); } else { - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); } } else @@ -6602,7 +6582,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6649,7 +6629,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6899,7 +6879,7 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -7150,7 +7130,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImGuiAlign_Center); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -7226,7 +7206,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) - RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb); + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb); } bool ImGui::Checkbox(const char* label, bool* v) @@ -8440,7 +8420,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi { const char* item_text; if (items_getter(data, *current_item, &item_text)) - RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL); + RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL, ImVec2(0.0f,0.0f)); } if (label_size.x > 0) @@ -8586,7 +8566,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } if (flags & ImGuiSelectableFlags_Disabled) 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, ImVec2(0.0f,0.0f)); if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); // Automatically close popups diff --git a/imgui.h b/imgui.h index 8081f262..48785078 100644 --- a/imgui.h +++ b/imgui.h @@ -70,7 +70,6 @@ typedef void* ImTextureID; // user data to identify a texture (this is typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_ -typedef int ImGuiAlign; // alignment // enum ImGuiAlign_ typedef int ImGuiColorEditMode; // color edit mode for ColorEdit*() // enum ImGuiColorEditMode_ typedef int ImGuiMouseCursor; // a mouse cursor identifier // enum ImGuiMouseCursor_ typedef int ImGuiWindowFlags; // window flags for Begin*() // enum ImGuiWindowFlags_ @@ -176,7 +175,6 @@ namespace ImGui IMGUI_API void PopFont(); IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, int val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); @@ -651,16 +649,6 @@ enum ImGuiStyleVar_ ImGuiStyleVar_Count_ }; -enum ImGuiAlign_ -{ - ImGuiAlign_Left = 1 << 0, - ImGuiAlign_Center = 1 << 1, - ImGuiAlign_Right = 1 << 2, - ImGuiAlign_Top = 1 << 3, - ImGuiAlign_VCenter = 1 << 4, - ImGuiAlign_Default = ImGuiAlign_Left | ImGuiAlign_Top -}; - // Enumeration for ColorEditMode() // FIXME-OBSOLETE: Will be replaced by future color/picker api enum ImGuiColorEditMode_ @@ -701,7 +689,7 @@ struct ImGuiStyle ImVec2 WindowPadding; // Padding within a window ImVec2 WindowMinSize; // Minimum window size float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows - ImGuiAlign WindowTitleAlign; // Alignment for title bar text + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. float ChildWindowRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets) float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). @@ -712,7 +700,7 @@ struct ImGuiStyle float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar float ScrollbarRounding; // Radius of grab corners for scrollbar - float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. diff --git a/imgui_internal.h b/imgui_internal.h index d0dedc47..076ec413 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From 56cdbe434d320e7c7294c77ab786b4ca224d796f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 12:53:13 +0200 Subject: [PATCH 6/8] Style: Added ButtonTextAlign, ImGuiStyleVar_ButtonTextAlign (#842) --- imgui.cpp | 10 ++++++---- imgui.h | 2 ++ imgui_demo.cpp | 7 +++++-- imgui_internal.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f9edf25c..71cc3a42 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -743,6 +743,7 @@ ImGuiStyle::ImGuiStyle() ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. @@ -2890,7 +2891,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align whole block (we should defer that to the better rendering function + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); @@ -4686,6 +4687,7 @@ static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, }; static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) @@ -5583,7 +5585,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, style.ButtonTextAlign); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -5950,12 +5952,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const char log_prefix[] = "\n##"; const char log_suffix[] = "##"; LogRenderedText(text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); LogRenderedText(text_pos, log_suffix+1, log_suffix+3); } else { - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); } } else diff --git a/imgui.h b/imgui.h index 48785078..d6b12b27 100644 --- a/imgui.h +++ b/imgui.h @@ -646,6 +646,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ImGuiStyleVar_IndentSpacing, // float ImGuiStyleVar_GrabMinSize, // float + ImGuiStyleVar_ButtonTextAlign, // flags ImGuiAlign_* ImGuiStyleVar_Count_ }; @@ -702,6 +703,7 @@ struct ImGuiStyle float ScrollbarRounding; // Radius of grab corners for scrollbar float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ae508017..75cd92c5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -790,7 +790,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Separator(); ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); ImGui::SameLine(); - ImGui::SliderInt("Sample count", &display_count, 1, 500); + ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); @@ -1632,7 +1632,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::TreePop(); } - if (ImGui::TreeNode("Sizes")) + if (ImGui::TreeNode("Settings")) { ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 16.0f, "%.0f"); @@ -1647,6 +1647,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 16.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 076ec413..f4a0d688 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From f2699de24241bedad05b18dfe5beba623ba77dcf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 14:18:10 +0200 Subject: [PATCH 7/8] Fix using IsItemActive() after EndGroup() or any widget using groups (#840, #479) --- imgui.cpp | 19 ++++++++++++------- imgui_internal.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 71cc3a42..afd58724 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7609,11 +7609,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn + BeginGroup(); + const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); @@ -7622,7 +7624,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 ImGuiWindow* draw_window = window; if (is_multiline) { - BeginGroup(); if (!BeginChildFrame(id, frame_bb.GetSize())) { EndChildFrame(); @@ -8149,8 +8150,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line EndChildFrame(); EndGroup(); - if (g.ActiveId == id || is_currently_scrolling) // Set LastItemId which was lost by EndChild/EndGroup, so user can use IsItemActive() - window->DC.LastItemId = g.ActiveId; } if (is_password) @@ -8204,7 +8203,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal)) extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; - if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) + if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); // Step buttons @@ -9155,6 +9154,7 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; + group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive; group_data.AdvanceCursor = true; window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; @@ -9166,15 +9166,15 @@ void ImGui::BeginGroup() void ImGui::EndGroup() { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - ImGuiStyle& style = GetStyle(); IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls ImGuiGroupData& group_data = window->DC.GroupStack.back(); ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); - group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. + group_bb.Max.y -= g.Style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. group_bb.Max = ImMax(group_bb.Min, group_bb.Max); window->DC.CursorPos = group_data.BackupCursorPos; @@ -9192,6 +9192,11 @@ void ImGui::EndGroup() ItemAdd(group_bb, NULL); } + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will function on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context. + if (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveId; + window->DC.GroupStack.pop_back(); //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug diff --git a/imgui_internal.h b/imgui_internal.h index f4a0d688..4bfec9dc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -266,6 +266,7 @@ struct ImGuiGroupData float BackupCurrentLineHeight; float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; + bool BackupActiveIdIsAlive; bool AdvanceCursor; }; From 6def01be5df16e17d71f81a8d4083a0f48d04a8d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 14:32:38 +0200 Subject: [PATCH 8/8] Fixed IsItemActive() lagging by one frame on initial widget activation (#840) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index afd58724..c33efc98 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1828,6 +1828,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) g.ActiveId = id; g.ActiveIdAllowOverlap = false; g.ActiveIdIsJustActivated = true; + if (id) + g.ActiveIdIsAlive = true; g.ActiveIdWindow = window; }