From c5b8c6303aa9699c7fcc9965636a6eeed5aec507 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:06:14 +0200 Subject: [PATCH] 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 ed0c13d6b..572c69a57 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 c72e81429..8081f2620 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 8a0b4824a..826fbfbd5 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);