Updated ImGui.

This commit is contained in:
Branimir Karadžić 2016-05-07 00:37:02 -07:00
parent 3b61978c7a
commit 7dddab9f1c
2 changed files with 71 additions and 52 deletions

View File

@ -20,12 +20,14 @@
- How can I help?
- How do I update to a newer version of ImGui?
- What is ImTextureID and how do I display an image?
- Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) / A primer on the use of labels/IDs in ImGui.
- I integrated ImGui in my engine and the text or lines are blurry..
- I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around..
- How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs.
- How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
- How can I load a different font than the default?
- How can I load multiple fonts?
- How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
- How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
- ISSUES & TODO-LIST
- CODE
@ -140,9 +142,8 @@
SwapBuffers();
}
- after calling ImGui::NewFrame() you can read back flags from the IO structure to tell how ImGui intends to use your inputs.
When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available.
- You can read back 'io.WantCaptureMouse', 'io.WantCaptureKeybord' etc. flags from the IO structure to tell how ImGui intends to use your
inputs and to know if you should share them or hide them from the rest of your application. Read the FAQ below for more information.
API BREAKING CHANGES
@ -278,6 +279,13 @@
ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
It is your responsibility to get textures uploaded to your GPU.
Q: I integrated ImGui in my engine and the text or lines are blurry..
A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around..
A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height).
Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes)
A: Yes. A primer on the use of labels/IDs in ImGui..
@ -371,12 +379,11 @@
e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
Q: I integrated ImGui in my engine and the text or lines are blurry..
A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around..
A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height).
Q: How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame.
When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available.
ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow().
Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
A: Use the font atlas to load the TTF file you want:
@ -414,7 +421,7 @@
Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
All strings passed need to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work.
All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will not work.
In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code.
@ -424,6 +431,10 @@
As for text input, depends on you passing the right character code to io.AddInputCharacter(). The example applications do that.
Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, zero background alpha,
then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
- tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code.
- tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings)
@ -565,6 +576,7 @@
- style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438)
- style editor: color child window height expressed in multiple of line height.
- remote: make a system like RemoteImGui first-class citizen/project (#75)
- drawlist: move Font, FontSize, FontTexUvWhitePixel inside ImDrawList and make it self-contained (apart from drawing settings?)
- drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack.
- examples: directx9: save/restore device state more thoroughly.
- examples: window minimize, maximize (#583)
@ -597,7 +609,6 @@
#pragma warning (disable: 4127) // condition expression is constant
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#define snprintf _snprintf
#endif
// Clang warnings with -Weverything
@ -616,6 +627,7 @@
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
#endif
//-------------------------------------------------------------------------
@ -1999,8 +2011,35 @@ void ImGui::NewFrame()
g.ActiveIdPreviousFrame = g.ActiveId;
g.ActiveIdIsAlive = false;
g.ActiveIdIsJustActivated = false;
if (!g.ActiveId)
// Handle user moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows.
if (g.MovedWindowMoveId && g.MovedWindowMoveId == g.ActiveId)
{
KeepAliveID(g.MovedWindowMoveId);
IM_ASSERT(g.MovedWindow && g.MovedWindow->RootWindow);
IM_ASSERT(g.MovedWindow->RootWindow->MoveID == g.MovedWindowMoveId);
if (g.IO.MouseDown[0])
{
if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoMove))
{
g.MovedWindow->PosFloat += g.IO.MouseDelta;
if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings))
MarkSettingsDirty();
}
FocusWindow(g.MovedWindow);
}
else
{
SetActiveID(0);
g.MovedWindow = NULL;
g.MovedWindowMoveId = 0;
}
}
else
{
g.MovedWindow = NULL;
g.MovedWindowMoveId = 0;
}
// Delay saving settings so we don't spam disk too much
if (g.SettingsDirtyTimer > 0.0f)
@ -2011,11 +2050,11 @@ void ImGui::NewFrame()
}
// Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow
g.HoveredWindow = FindHoveredWindow(g.IO.MousePos, false);
g.HoveredWindow = g.MovedWindow ? g.MovedWindow : FindHoveredWindow(g.IO.MousePos, false);
if (g.HoveredWindow && (g.HoveredWindow->Flags & ImGuiWindowFlags_ChildWindow))
g.HoveredRootWindow = g.HoveredWindow->RootWindow;
else
g.HoveredRootWindow = FindHoveredWindow(g.IO.MousePos, true);
g.HoveredRootWindow = g.MovedWindow ? g.MovedWindow->RootWindow : FindHoveredWindow(g.IO.MousePos, true);
if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow())
{
@ -2412,8 +2451,6 @@ void ImGui::EndFrame()
ImGui::End();
// Click to focus window and start moving (after we're done with all our widgets)
if (!g.ActiveId)
g.MovedWindow = NULL;
if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0])
{
if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear
@ -2424,7 +2461,8 @@ void ImGui::EndFrame()
if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove))
{
g.MovedWindow = g.HoveredWindow;
SetActiveID(g.HoveredRootWindow->MoveID, g.HoveredRootWindow);
g.MovedWindowMoveId = g.HoveredRootWindow->MoveID;
SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow);
}
}
else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL)
@ -2834,6 +2872,7 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
}
// Find window given position, search front-to-back
// FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected.
static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs)
{
ImGuiState& g = *GImGui;
@ -2848,7 +2887,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs)
continue;
// Using the clipped AABB so a child window will typically be clipped by its parent.
ImRect bb(window->ClippedWindowRect.Min - g.Style.TouchExtraPadding, window->ClippedWindowRect.Max + g.Style.TouchExtraPadding);
ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding);
if (bb.Contains(pos))
return window;
}
@ -3876,28 +3915,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
window->PosFloat = g.IO.MousePos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
}
// User moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows.
KeepAliveID(window->MoveID);
if (g.ActiveId == window->MoveID)
{
if (g.IO.MouseDown[0])
{
if (!(flags & ImGuiWindowFlags_NoMove))
{
window->PosFloat += g.IO.MouseDelta;
if (!(flags & ImGuiWindowFlags_NoSavedSettings))
MarkSettingsDirty();
}
IM_ASSERT(g.MovedWindow != NULL);
FocusWindow(g.MovedWindow);
}
else
{
SetActiveID(0);
g.MovedWindow = NULL; // Not strictly necessary but doing it for sanity.
}
}
// Clamp position so it stays visible
if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
{
@ -4112,8 +4129,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
}
// Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
window->ClippedWindowRect = window->Rect();
window->ClippedWindowRect.Clip(window->ClipRect);
window->WindowRectClipped = window->Rect();
window->WindowRectClipped.Clip(window->ClipRect);
// Pressing CTRL+C while holding on a window copy its content to the clipboard
// This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
@ -4150,7 +4167,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
window->Collapsed = parent_window && parent_window->Collapsed;
if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
window->Collapsed |= (window->ClippedWindowRect.Min.x >= window->ClippedWindowRect.Max.x || window->ClippedWindowRect.Min.y >= window->ClippedWindowRect.Max.y);
window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y);
// We also hide the window from rendering because we've already added its border to the command list.
// (we could perform the check earlier in the function but it is simpler at this point)
@ -4812,7 +4829,7 @@ void ImGui::SetNextWindowFocus()
ImVec2 ImGui::GetContentRegionMax()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y);
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y);
ImVec2 mx = content_region_size - window->Scroll - window->WindowPadding;
if (window->DC.ColumnsCount != 1)
mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x;
@ -4840,7 +4857,7 @@ ImVec2 ImGui::GetWindowContentRegionMin()
ImVec2 ImGui::GetWindowContentRegionMax()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y);
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y);
ImVec2 m = content_region_size - window->Scroll - window->WindowPadding - window->ScrollbarSizes;
return m;
}
@ -8914,7 +8931,7 @@ void ImGui::BeginGroup()
group_data.BackupLogLinePosY = window->DC.LogLinePosY;
group_data.AdvanceCursor = true;
window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x;
window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
window->DC.CursorMaxPos = window->DC.CursorPos;
window->DC.CurrentLineHeight = 0.0f;
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
@ -9160,7 +9177,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
window->DC.ColumnsCount = columns_count;
window->DC.ColumnsShowBorders = border;
const float content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x;
const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->Size.x;
window->DC.ColumnsMinX = window->DC.IndentX; // Lock our horizontal range
window->DC.ColumnsMaxX = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
@ -9440,7 +9457,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
continue;
}
bool node_open2 = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
if (show_clip_rects && ImGui::IsItemHovered())
{
ImRect clip_rect = pcmd->ClipRect;
@ -9451,7 +9468,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
}
if (!node_open2)
if (!pcmd_node_open)
continue;
for (int i = elem_offset; i+2 < elem_offset + (int)pcmd->ElemCount; i += 3)
{

View File

@ -375,7 +375,8 @@ struct ImGuiState
bool ActiveIdIsJustActivated; // Set at the time of activation for one frame
bool ActiveIdAllowOverlap; // Set only by active widget
ImGuiWindow* ActiveIdWindow;
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window.
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window.
ImGuiID MovedWindowMoveId; // == MovedWindow->RootWindow->MoveId
ImVector<ImGuiIniData> Settings; // .ini Settings
float SettingsDirtyTimer; // Save .ini settinngs on disk when time reaches zero
ImVector<ImGuiColMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
@ -460,6 +461,7 @@ struct ImGuiState
ActiveIdAllowOverlap = false;
ActiveIdWindow = NULL;
MovedWindow = NULL;
MovedWindowMoveId = 0;
SettingsDirtyTimer = 0.0f;
SetNextWindowPosVal = ImVec2(0.0f, 0.0f);
@ -627,7 +629,7 @@ struct IMGUI_API ImGuiWindow
ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame
ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack
ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2.
ImRect ClippedWindowRect; // = ClipRect just after setup in Begin()
ImRect WindowRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window.
int LastFrameActive;
float ItemWidthDefault;
ImGuiSimpleColumns MenuColumns; // Simplified columns storage for menu items