Merge branch 'master' into styles

# Conflicts:
#	TODO.txt
docking
omar 7 years ago
commit 24a78767d2

@ -23,10 +23,13 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic.
- window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd. - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd.
- window: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - window: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon?
- window: expose contents size. (#1045)
- window: GetWindowSize() returns (0,0) when not calculated? (#1045)
!- scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. !- scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet.
- scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y) - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y)
- drawlist: move Font, FontSize, FontTexUvWhitePixel inside ImDrawList and make it self-contained (apart from drawing settings?) - drawlist: move Font, FontSize, FontTexUvWhitePixel inside ImDrawList and make it self-contained (apart from drawing settings?)
- drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally
- drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack.
- drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). - drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command).
- drawlist: avoid passing null (-9999,+9999) rectangle to end-user, instead perhaps pass rectangle based on io.DisplaySize? - drawlist: avoid passing null (-9999,+9999) rectangle to end-user, instead perhaps pass rectangle based on io.DisplaySize?
@ -36,7 +39,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- main: find a way to preserve relative orders of multiple reappearing windows (so an app toggling between "modes" e.g. fullscreen vs all tools) won't lose relative ordering. - main: find a way to preserve relative orders of multiple reappearing windows (so an app toggling between "modes" e.g. fullscreen vs all tools) won't lose relative ordering.
- main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- main: rename the main "Debug" window to avoid ID collision with user who may want to use "Debug" with specific flags - main: rename the main "Debug" window to avoid ID collision with user who may want to use "Debug" with specific flags.
- widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. (#395) - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. (#395)
- widgets: clean up widgets internal toward exposing everything and stabilizing imgui_internals.h. - widgets: clean up widgets internal toward exposing everything and stabilizing imgui_internals.h.
@ -66,11 +69,13 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack. - input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack.
- layout: helper or a way to express ImGui::SameLine(ImGui::GetCursorStartPos().x + ImGui::CalcItemWidth() + ImGui::GetStyle().ItemInnerSpacing.x); in a simpler manner. - layout: helper or a way to express ImGui::SameLine(ImGui::GetCursorStartPos().x + ImGui::CalcItemWidth() + ImGui::GetStyle().ItemInnerSpacing.x); in a simpler manner.
- layout: generalization of the above: a concept equivalent to word processor ruler tab stop ~ mini columns (position in X, no clipping implied) (vaguely relate to #267, #395, also what is used internally for menu items)
- layout: horizontal layout helper (#97) - layout: horizontal layout helper (#97)
- layout: horizontal flow until no space left (#404) - layout: horizontal flow until no space left (#404)
- layout: more generic alignment state (left/right/centered) for single items? - layout: more generic alignment state (left/right/centered) for single items?
- layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding. - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding.
- layout: BeginGroup() needs a border option. - layout: BeginGroup() needs a border option.
- layout: vertical alignement of mixed height items (e.g. buttons) within a same line (#1284)
- columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125) - columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125)
- columns: add a conditional parameter to SetColumnOffset() (#513, #125) - columns: add a conditional parameter to SetColumnOffset() (#513, #125)
@ -161,11 +166,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
!- settings: expose enough to save/load .ini from RAM instead of fopen !- settings: expose enough to save/load .ini from RAM instead of fopen
- settings: write more decent code to allow saving/loading new fields - settings: write more decent code to allow saving/loading new fields
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437)
- stb: add defines to disable stb implementations - stb: add defines to disable stb implementations
!- style: better default styles. !- style: better default styles.
!- style: move border to style structure, remove _ShowBorder flag. !- style: move border to style structure, remove _ShowBorder flag.
- style: border types: out-screen, in-screen, etc.
- style/optimization: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. - style/optimization: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding.
- style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier) - style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier)
- style: color-box not always square? - style: color-box not always square?
@ -174,6 +180,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- style: global scale setting. - style: global scale setting.
- style: WindowPadding needs to be EVEN as the 0.5 multiplier used on this value probably have a subtle effect on clip rectangle - style: WindowPadding needs to be EVEN as the 0.5 multiplier used on this value probably have a subtle effect on clip rectangle
- style: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438, #707, #1223) - style: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438, #707, #1223)
- style: gradients fill (#1223) ~ 2 bg colors for each fill? tricky with rounded shapes and using textures for corners.
- style editor: color child window height expressed in multiple of line height. - style editor: color child window height expressed in multiple of line height.
- log: LogButtons() options for specifying depth and/or hiding depth slider - log: LogButtons() options for specifying depth and/or hiding depth slider
@ -208,12 +215,13 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- keyboard: full keyboard navigation and focus. (#323) - keyboard: full keyboard navigation and focus. (#323)
- focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622) - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622)
- focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame) - focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame)
- input: rework IO system to be able to pass actual ordered/timestamped events. (~#335, #71) - inputs: rework IO system to be able to pass actual ordered/timestamped events. use an event queue? (~#335, #71)
- input: allow to decide and pass explicit double-clicks (e.g. for windows by the CS_DBLCLKS style). - inputs: allow to decide and pass explicit double-clicks (e.g. for windows by the CS_DBLCLKS style).
- input: support track pad style scrolling & slider edit. - inputs: support track pad style scrolling & slider edit.
- misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL)
- misc: provide HoveredTime and ActivatedTime to ease the creation of animations. - misc: provide HoveredTime and ActivatedTime to ease the creation of animations.
- misc: fix for compilation settings where stdcall isn't the default (e.g. vectorcall) (#1230)
- remote: make a system like RemoteImGui first-class citizen/project (#75) - remote: make a system like RemoteImGui first-class citizen/project (#75)
- demo: demo: add a virtual scrolling example? - demo: demo: add a virtual scrolling example?

@ -204,6 +204,8 @@
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
Also read releases logs https://github.com/ocornut/imgui/releases for more details. Also read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
- 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow(), note that most uses relied on default parameters completely.
- 2017/08/13 (1.51) - renamed ImGuiCol_Columns_*** to ImGuiCol_Separator_*** - 2017/08/13 (1.51) - renamed ImGuiCol_Columns_*** to ImGuiCol_Separator_***
- 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
- 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
@ -614,11 +616,10 @@ static void MarkIniSettingsDirty();
static void PushColumnClipRect(int column_index = -1); static void PushColumnClipRect(int column_index = -1);
static ImRect GetVisibleRect(); static ImRect GetVisibleRect();
static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags); static bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
static void CloseInactivePopups(); static void CloseInactivePopups();
static void ClosePopupToLevel(int remaining); static void ClosePopupToLevel(int remaining);
static void ClosePopup(ImGuiID id); static void ClosePopup(ImGuiID id);
static bool IsPopupOpen(ImGuiID id);
static ImGuiWindow* GetFrontMostModalRootWindow(); static ImGuiWindow* GetFrontMostModalRootWindow();
static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid); static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid);
@ -3404,21 +3405,14 @@ void ImGui::EndTooltip()
ImGui::End(); ImGui::End();
} }
static bool IsPopupOpen(ImGuiID id)
{
ImGuiContext& g = *GImGui;
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
}
// Mark popup as open (toggle toward open state). // Mark popup as open (toggle toward open state).
// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing) void ImGui::OpenPopupEx(ImGuiID id, bool reopen_existing)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImGuiID id = window->GetID(str_id);
int current_stack_size = g.CurrentPopupStack.Size; int current_stack_size = g.CurrentPopupStack.Size;
ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here)
if (g.OpenPopupStack.Size < current_stack_size + 1) if (g.OpenPopupStack.Size < current_stack_size + 1)
@ -3432,7 +3426,8 @@ void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing)
void ImGui::OpenPopup(const char* str_id) void ImGui::OpenPopup(const char* str_id)
{ {
ImGui::OpenPopupEx(str_id, false); ImGuiContext& g = *GImGui;
OpenPopupEx(g.CurrentWindow->GetID(str_id), false);
} }
static void CloseInactivePopups() static void CloseInactivePopups()
@ -3488,7 +3483,7 @@ static void ClosePopupToLevel(int remaining)
static void ClosePopup(ImGuiID id) static void ClosePopup(ImGuiID id)
{ {
if (!IsPopupOpen(id)) if (!ImGui::IsPopupOpen(id))
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ClosePopupToLevel(g.OpenPopupStack.Size - 1); ClosePopupToLevel(g.OpenPopupStack.Size - 1);
@ -3508,17 +3503,17 @@ void ImGui::CloseCurrentPopup()
static inline void ClearSetNextWindowData() static inline void ClearSetNextWindowData()
{ {
// FIXME-OPT
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowContentSizeCond = g.SetNextWindowCollapsedCond = 0; g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowContentSizeCond = g.SetNextWindowCollapsedCond = 0;
g.SetNextWindowSizeConstraint = g.SetNextWindowFocus = false; g.SetNextWindowSizeConstraint = g.SetNextWindowFocus = false;
} }
static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) static bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
const ImGuiID id = window->GetID(str_id); if (!ImGui::IsPopupOpen(id))
if (!IsPopupOpen(id))
{ {
ClearSetNextWindowData(); // We behave like Begin() and need to consume those values ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
return false; return false;
@ -3544,12 +3539,26 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
bool ImGui::BeginPopup(const char* str_id) bool ImGui::BeginPopup(const char* str_id)
{ {
if (GImGui->OpenPopupStack.Size <= GImGui->CurrentPopupStack.Size) // Early out for performance ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
{ {
ClearSetNextWindowData(); // We behave like Begin() and need to consume those values ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
return false; return false;
} }
return BeginPopupEx(str_id, ImGuiWindowFlags_ShowBorders); return BeginPopupEx(g.CurrentWindow->GetID(str_id), ImGuiWindowFlags_ShowBorders);
}
// FIXME
bool ImGui::IsPopupOpen(ImGuiID id)
{
ImGuiContext& g = *GImGui;
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
}
bool ImGui::IsPopupOpen(const char* str_id)
{
ImGuiContext& g = *GImGui;
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
} }
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags) bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags)
@ -3592,29 +3601,31 @@ void ImGui::EndPopup()
// 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemHoveredRect() // 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemHoveredRect()
// and passing true to the OpenPopupEx(). // and passing true to the OpenPopupEx().
// Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that // Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that
// the item isn't interactable (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu // the item can be interacted with (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu
// driven by click position. // driven by click position.
bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
{ {
if (IsItemHovered() && IsMouseClicked(mouse_button)) if (IsItemHovered() && IsMouseClicked(mouse_button))
OpenPopupEx(str_id, false); OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), false);
return BeginPopup(str_id); return BeginPopup(str_id);
} }
bool ImGui::BeginPopupContextWindow(bool also_over_items, const char* str_id, int mouse_button) bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
{ {
if (!str_id) str_id = "window_context_menu"; if (!str_id)
str_id = "window_context";
if (IsMouseHoveringWindow() && IsMouseClicked(mouse_button)) if (IsMouseHoveringWindow() && IsMouseClicked(mouse_button))
if (also_over_items || !IsAnyItemHovered()) if (also_over_items || !IsAnyItemHovered())
OpenPopupEx(str_id, true); OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), true);
return BeginPopup(str_id); return BeginPopup(str_id);
} }
bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
{ {
if (!str_id) str_id = "void_context_menu"; if (!str_id)
str_id = "void_context";
if (!IsMouseHoveringAnyWindow() && IsMouseClicked(mouse_button)) if (!IsMouseHoveringAnyWindow() && IsMouseClicked(mouse_button))
OpenPopupEx(str_id, true); OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), true);
return BeginPopup(str_id); return BeginPopup(str_id);
} }
@ -6187,32 +6198,32 @@ void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
void ImGui::PushID(const char* str_id) void ImGui::PushID(const char* str_id)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
window->IDStack.push_back(window->GetID(str_id)); window->IDStack.push_back(window->GetID(str_id));
} }
void ImGui::PushID(const char* str_id_begin, const char* str_id_end) void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
window->IDStack.push_back(window->GetID(str_id_begin, str_id_end)); window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
} }
void ImGui::PushID(const void* ptr_id) void ImGui::PushID(const void* ptr_id)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
window->IDStack.push_back(window->GetID(ptr_id)); window->IDStack.push_back(window->GetID(ptr_id));
} }
void ImGui::PushID(int int_id) void ImGui::PushID(int int_id)
{ {
const void* ptr_id = (void*)(intptr_t)int_id; const void* ptr_id = (void*)(intptr_t)int_id;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
window->IDStack.push_back(window->GetID(ptr_id)); window->IDStack.push_back(window->GetID(ptr_id));
} }
void ImGui::PopID() void ImGui::PopID()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
window->IDStack.pop_back(); window->IDStack.pop_back();
} }
@ -8550,7 +8561,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0);
if (BeginPopupEx(label, flags)) if (BeginPopupEx(id, flags))
{ {
// Display items // Display items
Spacing(); Spacing();
@ -8960,7 +8971,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
{ {
SetNextWindowPos(popup_pos, ImGuiCond_Always); SetNextWindowPos(popup_pos, ImGuiCond_Always);
ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu); ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu);
menu_is_open = BeginPopupEx(label, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
} }
return menu_is_open; return menu_is_open;

@ -381,13 +381,14 @@ namespace ImGui
IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL
// Popups // Popups
IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true!
IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (block interactions behind the modal window, can't close the modal window by clicking outside) IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (block interactions behind the modal window, can't close the modal window by clicking outside)
IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp! IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp!
IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on current window. IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window.
IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (no window). IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (no window).
IMGUI_API void EndPopup(); IMGUI_API void EndPopup();
IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open
IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup.
// Logging: all text output from interface is redirected to tty/file/clipboard. By default, tree nodes are automatically opened during logging. // Logging: all text output from interface is redirected to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
@ -905,7 +906,7 @@ public:
inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; } inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline void swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } inline void swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
inline int _grow_capacity(int new_size) { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > new_size ? new_capacity : new_size; } inline int _grow_capacity(int size) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > size ? new_capacity : size; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) Data[n] = v; Size = new_size; } inline void resize(int new_size, const T& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) Data[n] = v; Size = new_size; }
@ -927,15 +928,11 @@ public:
inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; } inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
}; };
// Helper: execute a block of code at maximum once a frame // Helper: execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: // Usage:
// IMGUI_ONCE_UPON_A_FRAME // static ImGuiOnceUponAFrame oaf;
// { // if (oaf)
// // code block will be executed one per frame // ImGui::Text("This will be called only once per frame");
// }
// Attention! the macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces.
#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf##__LINE__; if (imgui_oaf##__LINE__)
struct ImGuiOnceUponAFrame struct ImGuiOnceUponAFrame
{ {
ImGuiOnceUponAFrame() { RefFrame = -1; } ImGuiOnceUponAFrame() { RefFrame = -1; }
@ -943,6 +940,11 @@ struct ImGuiOnceUponAFrame
operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }
}; };
// Helper macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Will obsolete
#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf)
#endif
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
struct ImGuiTextFilter struct ImGuiTextFilter
{ {
@ -966,11 +968,11 @@ struct ImGuiTextFilter
ImVector<TextRange> Filters; ImVector<TextRange> Filters;
int CountGrep; int CountGrep;
ImGuiTextFilter(const char* default_filter = ""); IMGUI_API ImGuiTextFilter(const char* default_filter = "");
~ImGuiTextFilter() {} ~ImGuiTextFilter() {}
void Clear() { InputBuf[0] = 0; Build(); } void Clear() { InputBuf[0] = 0; Build(); }
bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build
bool PassFilter(const char* text, const char* text_end = NULL) const; IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const;
bool IsActive() const { return !Filters.empty(); } bool IsActive() const { return !Filters.empty(); }
IMGUI_API void Build(); IMGUI_API void Build();
}; };
@ -1386,6 +1388,7 @@ struct ImFontAtlas
int TexWidth; // Texture width calculated during Build(). int TexWidth; // Texture width calculated during Build().
int TexHeight; // Texture height calculated during Build(). int TexHeight; // Texture height calculated during Build().
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1.
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel
ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.

@ -307,14 +307,11 @@ void ImGui::ShowTestWindow(bool* p_open)
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
// Testing IMGUI_ONCE_UPON_A_FRAME macro // Testing ImGuiOnceUponAFrame helper.
//static ImGuiOnceUponAFrame once;
//for (int i = 0; i < 5; i++) //for (int i = 0; i < 5; i++)
//{ // if (once)
// IMGUI_ONCE_UPON_A_FRAME // ImGui::Text("This will be displayed only once.");
// {
// ImGui::Text("This will be displayed only once.");
// }
//}
ImGui::Separator(); ImGui::Separator();
@ -1874,9 +1871,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size)) bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size);
ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions.");
if (fonts_opened)
{ {
ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions.");
ImFontAtlas* atlas = ImGui::GetIO().Fonts; ImFontAtlas* atlas = ImGui::GetIO().Fonts;
if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
{ {
@ -1887,14 +1885,13 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
for (int i = 0; i < atlas->Fonts.Size; i++) for (int i = 0; i < atlas->Fonts.Size; i++)
{ {
ImFont* font = atlas->Fonts[i]; ImFont* font = atlas->Fonts[i];
ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size);
ImGui::TreePush((void*)(intptr_t)i);
ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font;
ImGui::PushFont(font); if (font_details_opened)
ImGui::Text("The quick brown fox jumps over the lazy dog");
ImGui::PopFont();
if (ImGui::TreeNode("Details"))
{ {
ImGui::PushFont(font);
ImGui::Text("The quick brown fox jumps over the lazy dog");
ImGui::PopFont();
ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font
ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
@ -1948,7 +1945,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
} }
ImGui::TreePop(); ImGui::TreePop();
} }
ImGui::TreePop();
} }
static float window_scale = 1.0f; static float window_scale = 1.0f;
ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window

@ -1034,7 +1034,7 @@ void ImDrawData::ScaleClipRects(const ImVec2& scale)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ImFontAtlas // ImFontConfig
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ImFontConfig::ImFontConfig() ImFontConfig::ImFontConfig()
@ -1055,12 +1055,17 @@ ImFontConfig::ImFontConfig()
memset(Name, 0, sizeof(Name)); memset(Name, 0, sizeof(Name));
} }
//-----------------------------------------------------------------------------
// ImFontAtlas
//-----------------------------------------------------------------------------
ImFontAtlas::ImFontAtlas() ImFontAtlas::ImFontAtlas()
{ {
TexID = NULL; TexID = NULL;
TexPixelsAlpha8 = NULL; TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL; TexPixelsRGBA32 = NULL;
TexWidth = TexHeight = TexDesiredWidth = 0; TexWidth = TexHeight = TexDesiredWidth = 0;
TexGlyphPadding = 1;
TexUvWhitePixel = ImVec2(0, 0); TexUvWhitePixel = ImVec2(0, 0);
} }
@ -1281,46 +1286,25 @@ bool ImFontAtlas::Build()
TexUvWhitePixel = ImVec2(0, 0); TexUvWhitePixel = ImVec2(0, 0);
ClearTexData(); ClearTexData();
struct ImFontTempBuildData // Count glyphs/ranges
{ int total_glyphs_count = 0;
stbtt_fontinfo FontInfo; int total_ranges_count = 0;
stbrp_rect* Rects;
stbtt_pack_range* Ranges;
int RangesCount;
};
ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)ConfigData.Size * sizeof(ImFontTempBuildData));
// Initialize font information early (so we can error without any cleanup) + count glyphs
int total_glyph_count = 0;
int total_glyph_range_count = 0;
for (int input_i = 0; input_i < ConfigData.Size; input_i++) for (int input_i = 0; input_i < ConfigData.Size; input_i++)
{ {
ImFontConfig& cfg = ConfigData[input_i]; ImFontConfig& cfg = ConfigData[input_i];
ImFontTempBuildData& tmp = tmp_array[input_i];
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == this));
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
IM_ASSERT(font_offset >= 0);
if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
return false;
// Count glyphs
if (!cfg.GlyphRanges) if (!cfg.GlyphRanges)
cfg.GlyphRanges = GetGlyphRangesDefault(); cfg.GlyphRanges = GetGlyphRangesDefault();
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2) for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
{ total_glyphs_count += (in_range[1] - in_range[0]) + 1;
total_glyph_count += (in_range[1] - in_range[0]) + 1;
total_glyph_range_count++;
}
} }
// Start packing. We need a known width for the skyline algorithm. Using a cheap heuristic here to decide of width. User can override TexDesiredWidth if they wish. // Start packing. We need a known width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
// After packing is done, width shouldn't matter much, but some API/GPU have texture size limitations and increasing width can decrease height. // After packing is done, width shouldn't matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
TexWidth = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyph_count > 4000) ? 4096 : (total_glyph_count > 2000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512; TexWidth = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
TexHeight = 0; TexHeight = 0;
const int max_tex_height = 1024*32; const int max_tex_height = 1024*32;
stbtt_pack_context spc; stbtt_pack_context spc;
stbtt_PackBegin(&spc, NULL, TexWidth, max_tex_height, 0, 1, NULL); stbtt_PackBegin(&spc, NULL, TexWidth, max_tex_height, 0, TexGlyphPadding, NULL);
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
ImVector<stbrp_rect> extra_rects; ImVector<stbrp_rect> extra_rects;
@ -1331,14 +1315,34 @@ bool ImFontAtlas::Build()
if (extra_rects[i].was_packed) if (extra_rects[i].was_packed)
TexHeight = ImMax(TexHeight, extra_rects[i].y + extra_rects[i].h); TexHeight = ImMax(TexHeight, extra_rects[i].y + extra_rects[i].h);
// Initialize font information (so we can error without any cleanup)
struct ImFontTempBuildData
{
stbtt_fontinfo FontInfo;
stbrp_rect* Rects;
stbtt_pack_range* Ranges;
int RangesCount;
};
ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)ConfigData.Size * sizeof(ImFontTempBuildData));
for (int input_i = 0; input_i < ConfigData.Size; input_i++)
{
ImFontConfig& cfg = ConfigData[input_i];
ImFontTempBuildData& tmp = tmp_array[input_i];
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == this));
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
IM_ASSERT(font_offset >= 0);
if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
return false;
}
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyph_count * sizeof(stbtt_packedchar)); stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyph_count * sizeof(stbrp_rect)); stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_glyph_range_count * sizeof(stbtt_pack_range)); stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
memset(buf_packedchars, 0, total_glyph_count * sizeof(stbtt_packedchar)); memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
memset(buf_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity. memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
memset(buf_ranges, 0, total_glyph_range_count * sizeof(stbtt_pack_range)); memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
// First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point) // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
for (int input_i = 0; input_i < ConfigData.Size; input_i++) for (int input_i = 0; input_i < ConfigData.Size; input_i++)
@ -1347,17 +1351,14 @@ bool ImFontAtlas::Build()
ImFontTempBuildData& tmp = tmp_array[input_i]; ImFontTempBuildData& tmp = tmp_array[input_i];
// Setup ranges // Setup ranges
int glyph_count = 0; int font_glyphs_count = 0;
int glyph_ranges_count = 0; int font_ranges_count = 0;
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2) for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
{ font_glyphs_count += (in_range[1] - in_range[0]) + 1;
glyph_count += (in_range[1] - in_range[0]) + 1;
glyph_ranges_count++;
}
tmp.Ranges = buf_ranges + buf_ranges_n; tmp.Ranges = buf_ranges + buf_ranges_n;
tmp.RangesCount = glyph_ranges_count; tmp.RangesCount = font_ranges_count;
buf_ranges_n += glyph_ranges_count; buf_ranges_n += font_ranges_count;
for (int i = 0; i < glyph_ranges_count; i++) for (int i = 0; i < font_ranges_count; i++)
{ {
const ImWchar* in_range = &cfg.GlyphRanges[i * 2]; const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
stbtt_pack_range& range = tmp.Ranges[i]; stbtt_pack_range& range = tmp.Ranges[i];
@ -1370,9 +1371,10 @@ bool ImFontAtlas::Build()
// Pack // Pack
tmp.Rects = buf_rects + buf_rects_n; tmp.Rects = buf_rects + buf_rects_n;
buf_rects_n += glyph_count; buf_rects_n += font_glyphs_count;
stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV); stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects); int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
IM_ASSERT(n == font_glyphs_count);
stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n); stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
// Extend texture height // Extend texture height
@ -1380,9 +1382,9 @@ bool ImFontAtlas::Build()
if (tmp.Rects[i].was_packed) if (tmp.Rects[i].was_packed)
TexHeight = ImMax(TexHeight, tmp.Rects[i].y + tmp.Rects[i].h); TexHeight = ImMax(TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
} }
IM_ASSERT(buf_rects_n == total_glyph_count); IM_ASSERT(buf_rects_n == total_glyphs_count);
IM_ASSERT(buf_packedchars_n == total_glyph_count); IM_ASSERT(buf_packedchars_n == total_glyphs_count);
IM_ASSERT(buf_ranges_n == total_glyph_range_count); IM_ASSERT(buf_ranges_n == total_ranges_count);
// Create texture // Create texture
TexHeight = ImUpperPowerOfTwo(TexHeight); TexHeight = ImUpperPowerOfTwo(TexHeight);
@ -1391,7 +1393,7 @@ bool ImFontAtlas::Build()
spc.pixels = TexPixelsAlpha8; spc.pixels = TexPixelsAlpha8;
spc.height = TexHeight; spc.height = TexHeight;
// Second pass: render characters // Second pass: render font characters
for (int input_i = 0; input_i < ConfigData.Size; input_i++) for (int input_i = 0; input_i < ConfigData.Size; input_i++)
{ {
ImFontConfig& cfg = ConfigData[input_i]; ImFontConfig& cfg = ConfigData[input_i];

@ -4,6 +4,8 @@
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
// Implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) // Implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
// #define IMGUI_DEFINE_MATH_OPERATORS // #define IMGUI_DEFINE_MATH_OPERATORS
// Define IM_PLACEMENT_NEW() macro helper.
// #define IMGUI_DEFINE_PLACEMENT_NEW
#pragma once #pragma once
@ -743,7 +745,8 @@ namespace ImGui
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); IMGUI_API void OpenPopupEx(ImGuiID id, bool reopen_existing);
IMGUI_API bool IsPopupOpen(ImGuiID id);
// NB: All position are in absolute pixels coordinates (never using window coordinates internally) // NB: All position are in absolute pixels coordinates (never using window coordinates internally)
// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.

Loading…
Cancel
Save