LumixEngine/external/imgui/imgui_user.inl
2017-08-20 00:16:51 +02:00

831 lines
24 KiB
C++

#include "imgui.h"
#include "imgui_internal.h"
#include <math.h>
static const float NODE_SLOT_RADIUS = 4.0f;
namespace ImGui
{
bool ToolbarButton(ImTextureID texture, const ImVec4& bg_color, const char* tooltip)
{
auto frame_padding = ImGui::GetStyle().FramePadding;
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, frame_padding);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
bool ret = false;
ImGui::SameLine();
ImVec4 tint_color = ImGui::GetStyle().Colors[ImGuiCol_Text];
if (ImGui::ImageButton(texture, ImVec2(24, 24), ImVec2(0, 0), ImVec2(1, 1), -1, bg_color, tint_color))
{
ret = true;
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("%s", tooltip);
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(3);
return ret;
}
bool BeginToolbar(const char* str_id, ImVec2 screen_pos, ImVec2 size)
{
bool is_global = GImGui->CurrentWindowStack.Size == 1;
SetNextWindowPos(screen_pos);
ImVec2 frame_padding = GetStyle().FramePadding;
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
PushStyleVar(ImGuiStyleVar_WindowPadding, frame_padding);
PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
float padding = frame_padding.y * 2;
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings;
if (size.x == 0) size.x = GetContentRegionAvailWidth();
SetNextWindowSize(size);
bool ret = is_global ? Begin(str_id, nullptr, size, -1, flags) : BeginChild(str_id, size, false, flags);
PopStyleVar(3);
return ret;
}
void EndToolbar()
{
auto frame_padding = ImGui::GetStyle().FramePadding;
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
PushStyleVar(ImGuiStyleVar_WindowPadding, frame_padding);
PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
ImVec2 pos = GetWindowPos();
ImVec2 size = GetWindowSize();
if (GImGui->CurrentWindowStack.Size == 2) End(); else EndChild();
PopStyleVar(3);
ImGuiWindow* win = GetCurrentWindowRead();
if (GImGui->CurrentWindowStack.Size > 1) SetCursorScreenPos(pos + ImVec2(0, size.y + GetStyle().FramePadding.y * 2));
}
ImVec2 GetOsImePosRequest()
{
return ImGui::GetCurrentContext()->OsImePosRequest;
}
void ResetActiveID()
{
SetActiveID(0, nullptr);
}
int PlotHistogramEx(const char* label,
float(*values_getter)(void* data, int idx),
void* data,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max,
ImVec2 graph_size,
int selected_index)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) return -1;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (graph_size.x == 0.0f) graph_size.x = CalcItemWidth() + (style.FramePadding.x * 2);
if (graph_size.y == 0.0f) graph_size.y = label_size.y + (style.FramePadding.y * 2);
const ImRect frame_bb(
window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
const ImRect total_bb(frame_bb.Min,
frame_bb.Max +
ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, NULL)) return -1;
// Determine scale from values if not specified
if (scale_min == FLT_MAX || scale_max == FLT_MAX)
{
float v_min = FLT_MAX;
float v_max = -FLT_MAX;
for (int i = 0; i < values_count; i++)
{
const float v = values_getter(data, i);
v_min = ImMin(v_min, v);
v_max = ImMax(v_max, v);
}
if (scale_min == FLT_MAX) scale_min = v_min;
if (scale_max == FLT_MAX) scale_max = v_max;
}
RenderFrame(
frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
int res_w = ImMin((int)graph_size.x, values_count);
// Tooltip on hover
int v_hovered = -1;
if (IsHovered(inner_bb, 0))
{
const float t = ImClamp(
(g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
const int v_idx = (int)(t * (values_count + 0));
IM_ASSERT(v_idx >= 0 && v_idx < values_count);
const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
SetTooltip("%d: %8.4g", v_idx, v0);
v_hovered = v_idx;
}
const float t_step = 1.0f / (float)res_w;
float v0 = values_getter(data, (0 + values_offset) % values_count);
float t0 = 0.0f;
ImVec2 p0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)));
const ImU32 col_base = GetColorU32(ImGuiCol_PlotHistogram);
const ImU32 col_hovered = GetColorU32(ImGuiCol_PlotHistogramHovered);
for (int n = 0; n < res_w; n++)
{
const float t1 = t0 + t_step;
const int v_idx = (int)(t0 * values_count + 0.5f);
IM_ASSERT(v_idx >= 0 && v_idx < values_count);
const float v1 = values_getter(data, (v_idx + values_offset + 1) % values_count);
const ImVec2 p1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)));
window->DrawList->AddRectFilled(ImLerp(inner_bb.Min, inner_bb.Max, p0),
ImLerp(inner_bb.Min, inner_bb.Max, ImVec2(p1.x, 1.0f)) + ImVec2(-1, 0),
selected_index == v_idx ? col_hovered : col_base);
t0 = t1;
p0 = p1;
}
if (overlay_text)
{
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y),
frame_bb.Max,
overlay_text,
NULL,
NULL,
ImVec2(0.5f, 0.5f));
}
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
if (v_hovered >= 0 && IsMouseClicked(0))
{
return v_hovered;
}
return -1;
}
bool ListBox(const char* label,
int* current_item,
int scroll_to_item,
bool(*items_getter)(void*, int, const char**),
void* data,
int items_count,
int height_in_items)
{
if (!ListBoxHeader(label, items_count, height_in_items)) return false;
// Assume all items have even height (= 1 line of text). If you need items of different or
// variable sizes you can create a custom version of ListBox() in your code without using the
// clipper.
bool value_changed = false;
if (scroll_to_item != -1)
{
SetScrollY(scroll_to_item * GetTextLineHeightWithSpacing());
}
ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing());
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
{
const bool item_selected = (i == *current_item);
const char* item_text;
if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*";
PushID(i);
if (Selectable(item_text, item_selected))
{
*current_item = i;
value_changed = true;
}
PopID();
}
clipper.End();
ListBoxFooter();
return value_changed;
}
static bool isThisOrParentFocused(ImGuiWindow* win)
{
if (!win) return false;
ImGuiContext& g = *GImGui;
return g.FocusedWindow && g.FocusedWindow == win || isThisOrParentFocused(win->ParentWindow);
}
bool IsWindowOrChildWindowFocused()
{
ImGuiContext& g = *GImGui;
return isThisOrParentFocused(g.CurrentWindow);
}
void BringToFront()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GImGui->CurrentWindow;
if ((window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) || g.Windows.back() == window)
{
return;
}
for (int i = 0; i < g.Windows.Size; i++)
{
if (g.Windows[i] == window)
{
g.Windows.erase(g.Windows.begin() + i);
break;
}
}
g.Windows.push_back(window);
}
static ImVec2 node_pos;
static ImGuiID last_node_id;
void BeginNode(ImGuiID id, ImVec2 screen_pos)
{
PushID(id);
last_node_id = id;
node_pos = screen_pos;
SetCursorScreenPos(screen_pos + GetStyle().WindowPadding);
PushItemWidth(150);
ImDrawList* draw_list = GetWindowDrawList();
draw_list->ChannelsSplit(2);
draw_list->ChannelsSetCurrent(1);
BeginGroup();
}
void EndNode(ImVec2& pos)
{
ImDrawList* draw_list = GetWindowDrawList();
ImGui::SameLine();
float width = GetCursorScreenPos().x - node_pos.x;
EndGroup();
PopItemWidth();
float height = GetCursorScreenPos().y - node_pos.y;
ImVec2 size(width + GetStyle().WindowPadding.x, height + GetStyle().WindowPadding.y);
SetCursorScreenPos(node_pos);
SetNextWindowPos(node_pos);
SetNextWindowSize(size);
BeginChild((ImGuiID)last_node_id, size, false, ImGuiWindowFlags_NoInputs);
EndChild();
SetCursorScreenPos(node_pos);
InvisibleButton("bg", size);
if (IsItemActive() && IsMouseDragging(0))
{
pos += GetIO().MouseDelta;
}
draw_list->ChannelsSetCurrent(0);
draw_list->AddRectFilled(node_pos, node_pos + size, ImColor(230, 230, 230), 4.0f);
draw_list->AddRect(node_pos, node_pos + size, ImColor(150, 150, 150), 4.0f);
PopID();
draw_list->ChannelsMerge();
}
ImVec2 GetNodeInputPos(ImGuiID id, int input)
{
PushID(id);
ImGuiWindow* parent_win = GetCurrentWindow();
char title[256];
ImFormatString(title, IM_ARRAYSIZE(title), "%s.child_%08x", parent_win->Name, id);
ImGuiWindow* win = FindWindowByName(title);
if (!win)
{
PopID();
return ImVec2(0, 0);
}
ImVec2 pos = win->Pos;
pos.x -= NODE_SLOT_RADIUS;
ImGuiStyle& style = GetStyle();
pos.y += (GetTextLineHeight() + style.ItemSpacing.y) * input;
pos.y += style.WindowPadding.y + GetTextLineHeight() * 0.5f;
PopID();
return pos;
}
ImVec2 GetNodeOutputPos(ImGuiID id, int output)
{
PushID(id);
ImGuiWindow* parent_win = GetCurrentWindow();
char title[256];
ImFormatString(title, IM_ARRAYSIZE(title), "%s.child_%08x", parent_win->Name, id);
ImGuiWindow* win = FindWindowByName(title);
if (!win)
{
PopID();
return ImVec2(0, 0);
}
ImVec2 pos = win->Pos;
pos.x += win->Size.x + NODE_SLOT_RADIUS;
ImGuiStyle& style = GetStyle();
pos.y += (GetTextLineHeight() + style.ItemSpacing.y) * output;
pos.y += style.WindowPadding.y + GetTextLineHeight() * 0.5f;
PopID();
return pos;
}
bool NodePin(ImGuiID id, ImVec2 screen_pos)
{
ImDrawList* draw_list = GetWindowDrawList();
SetCursorScreenPos(screen_pos - ImVec2(NODE_SLOT_RADIUS, NODE_SLOT_RADIUS));
PushID(id);
InvisibleButton("", ImVec2(2 * NODE_SLOT_RADIUS, 2 * NODE_SLOT_RADIUS));
bool hovered = IsItemHovered();
PopID();
draw_list->AddCircleFilled(screen_pos,
NODE_SLOT_RADIUS,
hovered ? ImColor(0, 150, 0, 150) : ImColor(150, 150, 150, 150));
return hovered;
}
void NodeLink(ImVec2 from, ImVec2 to)
{
ImVec2 p1 = from;
ImVec2 t1 = ImVec2(+80.0f, 0.0f);
ImVec2 p2 = to;
ImVec2 t2 = ImVec2(+80.0f, 0.0f);
const int STEPS = 12;
ImDrawList* draw_list = GetWindowDrawList();
for (int step = 0; step <= STEPS; step++)
{
float t = (float)step / (float)STEPS;
float h1 = +2 * t * t * t - 3 * t * t + 1.0f;
float h2 = -2 * t * t * t + 3 * t * t;
float h3 = t * t * t - 2 * t * t + t;
float h4 = t * t * t - t * t;
draw_list->PathLineTo(ImVec2(h1 * p1.x + h2 * p2.x + h3 * t1.x + h4 * t2.x,
h1 * p1.y + h2 * p2.y + h3 * t1.y + h4 * t2.y));
}
draw_list->PathStroke(ImColor(200, 200, 100), false, 3.0f);
}
ImVec2 operator*(float f, const ImVec2& v)
{
return ImVec2(f * v.x, f * v.y);
}
const float CurveEditor::GRAPH_MARGIN = 14;
const float CurveEditor::HEIGHT = 100;
CurveEditor BeginCurveEditor(const char* label)
{
CurveEditor editor;
editor.valid = false;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) return editor;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
editor.beg_pos = GetCursorScreenPos();
ImVec2 cursor_pos = editor.beg_pos + ImVec2(CurveEditor::GRAPH_MARGIN, CurveEditor::GRAPH_MARGIN);
SetCursorScreenPos(cursor_pos);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
editor.graph_size.x = CalcItemWidth() + (style.FramePadding.x * 2);
editor.graph_size.y = CurveEditor::HEIGHT;
const ImRect frame_bb(cursor_pos, cursor_pos + editor.graph_size);
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
editor.inner_bb_min = inner_bb.Min;
editor.inner_bb_max = inner_bb.Max;
const ImRect total_bb(frame_bb.Min,
frame_bb.Max +
ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, nullptr)) return editor;
editor.valid = true;
PushID(label);
RenderFrame(
frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
SetCursorScreenPos(cursor_pos);
editor.point_idx = -1;
return editor;
}
void EndCurveEditor(const CurveEditor& editor)
{
SetCursorScreenPos(editor.inner_bb_min);
PopID();
InvisibleButton("bg", editor.inner_bb_max - editor.inner_bb_min);
SetCursorScreenPos(editor.beg_pos + ImVec2(0, editor.graph_size.y + 2 * CurveEditor::GRAPH_MARGIN + 4));
}
bool CurveSegment(ImVec2* points, CurveEditor& editor)
{
ImGuiWindow* window = GetCurrentWindow();
const ImRect inner_bb(editor.inner_bb_min, editor.inner_bb_max);
ImVec2 p_last = points[0];
ImVec2 tangent_last = points[1];
ImVec2 tangent = points[2];
ImVec2 p = points[3];
auto transform = [inner_bb](const ImVec2& p) -> ImVec2
{
return ImVec2(inner_bb.Min.x * (1 - p.x) + inner_bb.Max.x * p.x,
inner_bb.Min.y * p.y + inner_bb.Max.y * (1 - p.y));
};
auto handlePoint = [&window, &editor, transform, inner_bb](ImVec2& p) -> bool
{
static const float SIZE = 3;
ImVec2 cursor_pos = GetCursorScreenPos();
ImVec2 pos = transform(p);
SetCursorScreenPos(pos - ImVec2(SIZE, SIZE));
PushID(editor.point_idx);
++editor.point_idx;
InvisibleButton("", ImVec2(2 * NODE_SLOT_RADIUS, 2 * NODE_SLOT_RADIUS));
ImU32 col = IsItemHovered() ? GetColorU32(ImGuiCol_PlotLinesHovered) : GetColorU32(ImGuiCol_PlotLines);
window->DrawList->AddLine(pos + ImVec2(-SIZE, 0), pos + ImVec2(0, SIZE), col);
window->DrawList->AddLine(pos + ImVec2(SIZE, 0), pos + ImVec2(0, SIZE), col);
window->DrawList->AddLine(pos + ImVec2(SIZE, 0), pos + ImVec2(0, -SIZE), col);
window->DrawList->AddLine(pos + ImVec2(-SIZE, 0), pos + ImVec2(0, -SIZE), col);
bool changed = false;
if (IsItemActive() && IsMouseDragging(0))
{
pos += GetIO().MouseDelta;
ImVec2 v;
v.x = (pos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x);
v.y = (inner_bb.Max.y - pos.y) / (inner_bb.Max.y - inner_bb.Min.y);
v = ImClamp(v, ImVec2(0, 0), ImVec2(1, 1));
p = v;
changed = true;
}
PopID();
SetCursorScreenPos(cursor_pos);
return changed;
};
auto handleTangent = [&window, &editor, transform, inner_bb](ImVec2& t, const ImVec2& p) -> bool
{
static const float SIZE = 2;
static const float LENGTH = 18;
auto normalized = [](const ImVec2& v) -> ImVec2
{
float len = 1.0f / sqrtf(v.x *v.x + v.y * v.y);
return ImVec2(v.x * len, v.y * len);
};
ImVec2 cursor_pos = GetCursorScreenPos();
ImVec2 pos = transform(p);
ImVec2 tang = pos + normalized(ImVec2(t.x, -t.y)) * LENGTH;
SetCursorScreenPos(tang - ImVec2(SIZE, SIZE));
PushID(editor.point_idx);
++editor.point_idx;
InvisibleButton("", ImVec2(2 * NODE_SLOT_RADIUS, 2 * NODE_SLOT_RADIUS));
window->DrawList->AddLine(pos, tang, GetColorU32(ImGuiCol_PlotLines));
ImU32 col = IsItemHovered() ? GetColorU32(ImGuiCol_PlotLinesHovered) : GetColorU32(ImGuiCol_PlotLines);
window->DrawList->AddLine(tang + ImVec2(-SIZE, SIZE), tang + ImVec2(SIZE, SIZE), col);
window->DrawList->AddLine(tang + ImVec2(SIZE, SIZE), tang + ImVec2(SIZE, -SIZE), col);
window->DrawList->AddLine(tang + ImVec2(SIZE, -SIZE), tang + ImVec2(-SIZE, -SIZE), col);
window->DrawList->AddLine(tang + ImVec2(-SIZE, -SIZE), tang + ImVec2(-SIZE, SIZE), col);
bool changed = false;
if (IsItemActive() && IsMouseDragging(0))
{
tang = GetIO().MousePos - pos;
tang = normalized(tang);
tang.y *= -1;
t = tang;
changed = true;
}
PopID();
SetCursorScreenPos(cursor_pos);
return changed;
};
bool changed = false;
if (editor.point_idx < 0)
{
if (handlePoint(p_last))
{
p_last.x = 0;
points[0] = p_last;
changed = true;
}
}
else
{
window->DrawList->AddBezierCurve(
transform(p_last),
transform(p_last + tangent_last),
transform(p + tangent),
transform(p),
GetColorU32(ImGuiCol_PlotLines),
1.0f,
20);
if (handleTangent(tangent_last, p_last))
{
points[1] = ImClamp(tangent_last, ImVec2(0, -1), ImVec2(1, 1));
changed = true;
}
if (handleTangent(tangent, p))
{
points[2] = ImClamp(tangent, ImVec2(-1, -1), ImVec2(0, 1));
changed = true;
}
if (handlePoint(p))
{
points[3] = p;
changed = true;
}
}
return changed;
}
bool BeginResizablePopup(const char* str_id, const ImVec2& size_on_first_use)
{
if (GImGui->OpenPopupStack.Size <= GImGui->CurrentPopupStack.Size)
{
ClearSetNextWindowData();
return false;
}
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiID id = window->GetID(str_id);
if (!IsPopupOpen(id))
{
ClearSetNextWindowData();
return false;
}
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
char name[32];
ImFormatString(name, 20, "##popup_%08x", id);
float alpha = 1.0f;
bool opened = ImGui::Begin(name, NULL, size_on_first_use, alpha, flags);
if (!(window->Flags & ImGuiWindowFlags_ShowBorders))
g.CurrentWindow->Flags &= ~ImGuiWindowFlags_ShowBorders;
if (!opened)
ImGui::EndPopup();
return opened;
}
void IntervalGraph(const unsigned long long* value_pairs,
int value_pairs_count,
unsigned long long scale_min,
unsigned long long scele_max)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) return;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
ImVec2 graph_size(CalcItemWidth() + (style.FramePadding.x * 2), ImGui::GetTextLineHeight());
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
const ImRect total_bb(frame_bb.Min, frame_bb.Max);
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, NULL)) return;
double graph_length = double(scele_max - scale_min);
const ImU32 col_base = GetColorU32(ImGuiCol_PlotHistogram);
for (int i = 0; i < value_pairs_count; ++i)
{
ImVec2 tmp = frame_bb.Min + ImVec2(float((value_pairs[i * 2] - scale_min) / graph_length * graph_size.x), 0);
window->DrawList->AddRectFilled(
tmp, tmp + ImVec2(ImMax(1.0f, float(value_pairs[i * 2 + 1] / graph_length * graph_size.x)), graph_size.y), col_base);
}
}
bool FilterInput(const char* label, char* buf, size_t buf_size, float width)
{
auto pos = GetCursorPos();
PushItemWidth(width < 0 ? GetContentRegionAvail().x : width);
char tmp[32];
strcpy(tmp, "##");
strcat(tmp, label);
bool ret = InputText(tmp, buf, buf_size);
if (buf[0] == 0 && !IsItemActive())
{
pos.x += GetStyle().FramePadding.x;
SetCursorPos(pos);
AlignFirstTextHeightToWidgets();
TextColored(GetStyle().Colors[ImGuiCol_TextDisabled], "Filter");
}
PopItemWidth();
return ret;
}
void Rect(float w, float h, ImU32 color)
{
ImGuiWindow* win = GetCurrentWindow();
ImVec2 screen_pos = GetCursorScreenPos();
ImVec2 end_pos = screen_pos + ImVec2(w, h);
ImRect total_bb(screen_pos, end_pos);
ItemSize(total_bb);
if (!ItemAdd(total_bb, NULL)) return;
win->DrawList->AddRectFilled(screen_pos, end_pos, color);
}
void HSplitter(const char* str_id, ImVec2* size)
{
ImVec2 screen_pos = GetCursorScreenPos();
InvisibleButton(str_id, ImVec2(-1, 3));
ImVec2 end_pos = screen_pos + GetItemRectSize();
ImGuiWindow* win = GetCurrentWindow();
ImVec4* colors = GetStyle().Colors;
ImU32 color = GetColorU32(IsItemActive() || IsItemHovered() ? colors[ImGuiCol_ButtonActive] : colors[ImGuiCol_Button]);
win->DrawList->AddRectFilled(screen_pos, end_pos, color);
if (ImGui::IsItemActive())
{
size->y = ImMax(1.0f, ImGui::GetIO().MouseDelta.y + size->y);
}
}
void VSplitter(const char* str_id, ImVec2* size)
{
ImVec2 screen_pos = GetCursorScreenPos();
InvisibleButton(str_id, ImVec2(3, -1));
ImVec2 end_pos = screen_pos + GetItemRectSize();
ImGuiWindow* win = GetCurrentWindow();
ImVec4* colors = GetStyle().Colors;
ImU32 color = GetColorU32(IsItemActive() || IsItemHovered() ? colors[ImGuiCol_ButtonActive] : colors[ImGuiCol_Button]);
win->DrawList->AddRectFilled(screen_pos, end_pos, color);
if (ImGui::IsItemActive())
{
size->x = ImMax(1.0f, ImGui::GetIO().MouseDelta.x + size->x);
}
}
static float s_max_timeline_value;
bool BeginTimeline(const char* str_id, float max_value)
{
s_max_timeline_value = max_value;
return BeginChild(str_id);
}
static const float TIMELINE_RADIUS = 6;
bool TimelineEvent(const char* str_id, float* value)
{
ImGuiWindow* win = GetCurrentWindow();
const ImU32 inactive_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
const ImU32 active_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ButtonHovered]);
const ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Text]);
bool changed = false;
ImVec2 cursor_pos = win->DC.CursorPos;
ImVec2 pos = cursor_pos;
pos.x += win->Size.x * *value / s_max_timeline_value + TIMELINE_RADIUS;
pos.y += TIMELINE_RADIUS;
SetCursorScreenPos(pos - ImVec2(TIMELINE_RADIUS, TIMELINE_RADIUS));
InvisibleButton(str_id, ImVec2(2 * TIMELINE_RADIUS, 2 * TIMELINE_RADIUS));
if (IsItemActive() || IsItemHovered())
{
ImGui::SetTooltip("%f", *value);
ImVec2 a(pos.x, GetWindowContentRegionMin().y + win->Pos.y);
ImVec2 b(pos.x, GetWindowContentRegionMax().y + win->Pos.y);
win->DrawList->AddLine(a, b, line_color);
}
if (IsItemActive() && IsMouseDragging(0))
{
*value += GetIO().MouseDelta.x / win->Size.x * s_max_timeline_value;
changed = true;
}
win->DrawList->AddCircleFilled(
pos, TIMELINE_RADIUS, IsItemActive() || IsItemHovered() ? active_color : inactive_color);
ImGui::SetCursorScreenPos(cursor_pos);
return changed;
}
void EndTimeline()
{
ImGuiWindow* win = GetCurrentWindow();
ImU32 color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Border]);
ImU32 text_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Text]);
float rounding = GImGui->Style.ScrollbarRounding;
ImVec2 start(GetWindowContentRegionMin().x + win->Pos.x,
GetWindowContentRegionMax().y - GetTextLineHeightWithSpacing() + win->Pos.y);
ImVec2 end = GetWindowContentRegionMax() + win->Pos;
win->DrawList->AddRectFilled(start, end, color, rounding);
const int LINE_COUNT = 5;
const ImVec2 text_offset(0, GetTextLineHeightWithSpacing());
for (int i = 0; i < LINE_COUNT; ++i)
{
ImVec2 a = GetWindowContentRegionMin() + win->Pos + ImVec2(TIMELINE_RADIUS, 0);
a.x += i * GetWindowContentRegionWidth() / LINE_COUNT;
ImVec2 b = a;
b.y = start.y;
win->DrawList->AddLine(a, b, line_color);
char tmp[256];
ImFormatString(tmp, sizeof(tmp), "%.2f", i * s_max_timeline_value / LINE_COUNT);
win->DrawList->AddText(b, text_color, tmp);
}
EndChild();
}
} // namespace ImGui
#include "imgui_dock.inl"