mirror of
https://github.com/ocornut/imgui.git
synced 2025-12-28 00:54:34 +00:00
Merge remote-tracking branch 'origin' into 2015-04-indexed-rendering
Conflicts: examples/directx11_example/imgui_impl_dx11.cpp
This commit is contained in:
98
imgui.cpp
98
imgui.cpp
@@ -13,7 +13,7 @@
|
||||
- API BREAKING CHANGES (read me when you update!)
|
||||
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
|
||||
- How do I update to a newer version of ImGui?
|
||||
- Can I have multiple widgets with the same label? (Yes)
|
||||
- Can I have multiple widgets with the same label? Can I have widget without a label? (Yes)
|
||||
- Why is my text output blurry?
|
||||
- How can I load a different font than the default?
|
||||
- How can I load multiple fonts?
|
||||
@@ -196,38 +196,42 @@
|
||||
Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name
|
||||
in the code, there will likely be a comment about it. Please report any issue to the GitHub page!
|
||||
|
||||
Q: Can I have multiple widgets with the same label?
|
||||
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..
|
||||
|
||||
- Elements that are not clickable, such as Text() items don't need an ID.
|
||||
|
||||
- Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget).
|
||||
to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
|
||||
|
||||
Button("OK"); // Label = "OK", ID = hash of "OK"
|
||||
Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
|
||||
|
||||
- Elements that are not clickable, such as Text() items don't need an ID.
|
||||
|
||||
- ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows
|
||||
or in two different locations of a tree.
|
||||
|
||||
- if you have a same ID twice in the same location, you'll have a conflict:
|
||||
|
||||
Button("OK");
|
||||
Button("OK"); // ID collision! Both buttons will be treated as the same.
|
||||
Button("OK"); // ID collision! Both buttons will be treated as the same.
|
||||
|
||||
Fear not! this is easy to solve and there are many ways to solve it!
|
||||
|
||||
- when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
|
||||
use "##" to pass a complement to the ID that won't be visible to the end-user:
|
||||
|
||||
Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
|
||||
Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
|
||||
Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
|
||||
Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
|
||||
|
||||
- so if you want to hide the label but need an ID:
|
||||
|
||||
Checkbox("##On", &b); // Label = "", ID = hash of "##On"
|
||||
|
||||
- occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels.
|
||||
use "###" to pass a label that isn't part of ID:
|
||||
|
||||
Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
|
||||
Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
|
||||
Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
|
||||
Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
|
||||
|
||||
- use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
|
||||
this is the most convenient way of distinguish ID if you are iterating and creating many UI elements.
|
||||
@@ -495,8 +499,9 @@ struct ImGuiTextEditState;
|
||||
struct ImGuiIniData;
|
||||
struct ImGuiState;
|
||||
struct ImGuiWindow;
|
||||
typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_
|
||||
|
||||
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false);
|
||||
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0);
|
||||
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
|
||||
|
||||
static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
|
||||
@@ -700,6 +705,7 @@ static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs)
|
||||
static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
|
||||
static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
|
||||
//static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
|
||||
static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-lhs.w); }
|
||||
|
||||
static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; }
|
||||
static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; }
|
||||
@@ -714,6 +720,7 @@ static inline float ImSaturate(float f)
|
||||
static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; }
|
||||
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
|
||||
static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
|
||||
static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; }
|
||||
|
||||
static int ImStricmp(const char* str1, const char* str2)
|
||||
{
|
||||
@@ -932,6 +939,13 @@ static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode,
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum ImGuiButtonFlags_
|
||||
{
|
||||
ImGuiButtonFlags_Repeat = (1 << 0),
|
||||
ImGuiButtonFlags_PressedOnClick = (1 << 1),
|
||||
ImGuiButtonFlags_FlattenChilds = (1 << 2)
|
||||
};
|
||||
|
||||
struct ImGuiColMod // Color modifier, backup of modified data so we can restore it
|
||||
{
|
||||
ImGuiCol Col;
|
||||
@@ -1277,6 +1291,7 @@ struct ImGuiWindow
|
||||
bool Accessed; // Set to true when any widget access the current window
|
||||
bool Collapsed; // Set when collapsing window to become only title-bar
|
||||
bool SkipItems; // == Visible && !Collapsed
|
||||
int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
|
||||
int AutoFitFrames;
|
||||
bool AutoFitOnlyGrows;
|
||||
int AutoPosLastDirection;
|
||||
@@ -1636,6 +1651,7 @@ ImGuiWindow::ImGuiWindow(const char* name)
|
||||
Accessed = false;
|
||||
Collapsed = false;
|
||||
SkipItems = false;
|
||||
BeginCount = 0;
|
||||
AutoFitFrames = -1;
|
||||
AutoFitOnlyGrows = false;
|
||||
AutoPosLastDirection = -1;
|
||||
@@ -1868,7 +1884,6 @@ static void SaveSettings()
|
||||
static void MarkSettingsDirty()
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
if (g.SettingsDirtyTimer <= 0.0f)
|
||||
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
||||
}
|
||||
@@ -2981,7 +2996,7 @@ void ImGui::EndChild()
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);
|
||||
if (window->Flags & ImGuiWindowFlags_ComboBox)
|
||||
if ((window->Flags & ImGuiWindowFlags_ComboBox) || window->BeginCount > 1)
|
||||
{
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -3218,21 +3233,19 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
if (first_begin_of_the_frame)
|
||||
{
|
||||
window->Active = true;
|
||||
window->BeginCount = 0;
|
||||
window->DrawList->Clear();
|
||||
window->ClipRectStack.resize(0);
|
||||
window->LastFrameDrawn = current_frame;
|
||||
window->IDStack.resize(1);
|
||||
}
|
||||
|
||||
// Setup texture, outer clipping rectangle
|
||||
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
|
||||
PushClipRect(parent_window->ClipRectStack.back());
|
||||
else
|
||||
PushClipRect(GetVisibleRect());
|
||||
// Setup texture, outer clipping rectangle
|
||||
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
|
||||
PushClipRect(parent_window->ClipRectStack.back());
|
||||
else
|
||||
PushClipRect(GetVisibleRect());
|
||||
|
||||
if (first_begin_of_the_frame)
|
||||
{
|
||||
// New windows appears in front
|
||||
if (!window_was_visible)
|
||||
{
|
||||
@@ -3431,7 +3444,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR());
|
||||
const ImGuiID resize_id = window->GetID("#RESIZE");
|
||||
bool hovered, held;
|
||||
ButtonBehavior(resize_rect, resize_id, &hovered, &held, true);
|
||||
ButtonBehavior(resize_rect, resize_id, &hovered, &held, true, ImGuiButtonFlags_FlattenChilds);
|
||||
resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
|
||||
|
||||
if (hovered || held)
|
||||
@@ -3584,6 +3597,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
ImGui::LogToClipboard();
|
||||
*/
|
||||
}
|
||||
window->BeginCount++;
|
||||
|
||||
// Inner clipping rectangle
|
||||
// We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
|
||||
@@ -3628,8 +3642,6 @@ void ImGui::End()
|
||||
|
||||
ImGui::Columns(1, "#CloseColumns");
|
||||
PopClipRect(); // inner window clip rectangle
|
||||
PopClipRect(); // outer window clip rectangle
|
||||
window->DrawList->PopTextureID();
|
||||
|
||||
// Stop logging
|
||||
if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
|
||||
@@ -3782,7 +3794,6 @@ float ImGui::CalcItemWidth()
|
||||
static void SetFont(ImFont* font)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
IM_ASSERT(font && font->IsLoaded());
|
||||
IM_ASSERT(font->Scale > 0.0f);
|
||||
g.Font = font;
|
||||
@@ -3794,10 +3805,8 @@ static void SetFont(ImFont* font)
|
||||
void ImGui::PushFont(ImFont* font)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
if (!font)
|
||||
font = g.IO.Fonts->Fonts[0];
|
||||
|
||||
SetFont(font);
|
||||
g.FontStack.push_back(font);
|
||||
g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
|
||||
@@ -3806,7 +3815,6 @@ void ImGui::PushFont(ImFont* font)
|
||||
void ImGui::PopFont()
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
g.CurrentWindow->DrawList->PopTextureID();
|
||||
g.FontStack.pop_back();
|
||||
SetFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back());
|
||||
@@ -3839,7 +3847,6 @@ void ImGui::PopTextWrapPos()
|
||||
void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
ImGuiColMod backup;
|
||||
backup.Col = idx;
|
||||
backup.PreviousValue = g.Style.Colors[idx];
|
||||
@@ -3850,7 +3857,6 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
|
||||
void ImGui::PopStyleColor(int count)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
ImGuiColMod& backup = g.ColorModifiers.back();
|
||||
@@ -3891,7 +3897,6 @@ static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx)
|
||||
void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
float* pvar = GetStyleVarFloatAddr(idx);
|
||||
IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float.
|
||||
ImGuiStyleMod backup;
|
||||
@@ -3905,7 +3910,6 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
|
||||
void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
ImVec2* pvar = GetStyleVarVec2Addr(idx);
|
||||
IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2.
|
||||
ImGuiStyleMod backup;
|
||||
@@ -3918,7 +3922,6 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
|
||||
void ImGui::PopStyleVar(int count)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
ImGuiStyleMod& backup = g.StyleModifiers.back();
|
||||
@@ -4521,10 +4524,9 @@ void ImGui::LabelText(const char* label, const char* fmt, ...)
|
||||
|
||||
static inline bool IsWindowContentHoverable(ImGuiWindow* window)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
|
||||
// An active popup disable hovering on other windows (apart from its own children)
|
||||
if (ImGuiWindow* focused_window = g.FocusedWindow)
|
||||
ImGuiState& g = *GImGui;
|
||||
if (ImGuiWindow* focused_window = g.FocusedWindow)
|
||||
if (ImGuiWindow* focused_root_window = focused_window->RootWindow)
|
||||
if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow)
|
||||
return false;
|
||||
@@ -4532,13 +4534,13 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsHovered(const ImRect& bb, ImGuiID id)
|
||||
static bool IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs = false)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
if (g.HoveredId == 0)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (g.HoveredRootWindow == window->RootWindow)
|
||||
if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow))
|
||||
if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb))
|
||||
if (IsWindowContentHoverable(g.HoveredRootWindow))
|
||||
return true;
|
||||
@@ -4546,13 +4548,13 @@ static bool IsHovered(const ImRect& bb, ImGuiID id)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click)
|
||||
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
const bool hovered = IsHovered(bb, id);
|
||||
bool pressed = false;
|
||||
const bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0);
|
||||
if (hovered)
|
||||
{
|
||||
g.HoveredId = id;
|
||||
@@ -4560,7 +4562,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
{
|
||||
if (g.IO.MouseClicked[0])
|
||||
{
|
||||
if (pressed_on_click)
|
||||
if (flags & ImGuiButtonFlags_PressedOnClick)
|
||||
{
|
||||
pressed = true;
|
||||
SetActiveId(0);
|
||||
@@ -4571,7 +4573,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
}
|
||||
FocusWindow(window);
|
||||
}
|
||||
else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true))
|
||||
else if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && ImGui::IsMouseClicked(0, true))
|
||||
{
|
||||
pressed = true;
|
||||
}
|
||||
@@ -4617,7 +4619,7 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h
|
||||
return false;
|
||||
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held);
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held ? ImGuiButtonFlags_Repeat : 0);
|
||||
|
||||
// Render
|
||||
const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
@@ -6801,7 +6803,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
|
||||
|
||||
// Draw blinking cursor
|
||||
if (g.InputTextState.CursorIsVisible())
|
||||
window->DrawList->AddRect(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text));
|
||||
window->DrawList->AddLine(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text));
|
||||
|
||||
// Notify OS of text input position for advanced IME
|
||||
if (io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_pos) > 0.0001f)
|
||||
@@ -7093,7 +7095,7 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
|
||||
return false;
|
||||
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, false, false);
|
||||
bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true);
|
||||
|
||||
// Render
|
||||
if (hovered || selected)
|
||||
@@ -8005,7 +8007,11 @@ void ImDrawList::UpdateClipRect()
|
||||
}
|
||||
else
|
||||
{
|
||||
current_cmd->clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
|
||||
ImVec4 current_clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
|
||||
if (commands.size() > 2 && ImLengthSqr(commands[commands.size()-2].clip_rect - current_clip_rect) < 0.00001f)
|
||||
commands.pop_back();
|
||||
else
|
||||
current_cmd->clip_rect = current_clip_rect;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user