mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-16 22:16:53 +07:00
update modules
This commit is contained in:
575
sources/3rdparty/imgui/imgui_widgets.cpp
vendored
575
sources/3rdparty/imgui/imgui_widgets.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.72 WIP
|
||||
// dear imgui, v1.73 WIP
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -24,6 +24,7 @@ Index of this file:
|
||||
// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc.
|
||||
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
|
||||
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
|
||||
// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
|
||||
|
||||
*/
|
||||
|
||||
@@ -625,8 +626,6 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
|
||||
flags |= ImGuiButtonFlags_Repeat;
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
|
||||
if (pressed)
|
||||
MarkItemEdited(id);
|
||||
|
||||
// Render
|
||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
@@ -1089,6 +1088,7 @@ bool ImGui::RadioButton(const char* label, bool active)
|
||||
return pressed;
|
||||
}
|
||||
|
||||
// FIXME: This would work nicely if it was a public template, e.g. 'template<T> RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it..
|
||||
bool ImGui::RadioButton(const char* label, int* v, int v_button)
|
||||
{
|
||||
const bool pressed = RadioButton(label, *v == v_button);
|
||||
@@ -3123,7 +3123,7 @@ namespace ImStb
|
||||
|
||||
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
|
||||
static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; }
|
||||
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx+char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); }
|
||||
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }
|
||||
static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
|
||||
static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
|
||||
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
|
||||
@@ -3638,8 +3638,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
|
||||
@@ -3654,7 +3654,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
|
||||
}
|
||||
else if (IsKeyPressedMap(ImGuiKey_Enter))
|
||||
else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter))
|
||||
{
|
||||
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
|
||||
if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
|
||||
@@ -3994,9 +3994,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
|
||||
else if (cursor_offset.y - size.y >= scroll_y)
|
||||
scroll_y = cursor_offset.y - size.y;
|
||||
draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
|
||||
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
|
||||
draw_window->Scroll.y = scroll_y;
|
||||
draw_pos.y = draw_window->DC.CursorPos.y;
|
||||
}
|
||||
|
||||
state->CursorFollow = false;
|
||||
@@ -4137,8 +4136,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const float square_sz = GetFrameHeight();
|
||||
const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
|
||||
const float w_items_all = CalcItemWidth() - w_extra;
|
||||
const float w_full = CalcItemWidth();
|
||||
const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
|
||||
const float w_inputs = w_full - w_button;
|
||||
const char* label_display_end = FindRenderedTextEnd(label);
|
||||
g.NextItemData.ClearFlags();
|
||||
|
||||
@@ -4182,11 +4182,15 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
bool value_changed = false;
|
||||
bool value_changed_as_float = false;
|
||||
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f;
|
||||
window->DC.CursorPos.x = pos.x + inputs_offset_x;
|
||||
|
||||
if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
|
||||
{
|
||||
// RGB/HSV 0..255 Sliders
|
||||
const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
|
||||
const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
|
||||
const float w_item_one = ImMax(1.0f, (float)(int)((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
|
||||
const float w_item_last = ImMax(1.0f, (float)(int)(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
|
||||
|
||||
const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
|
||||
static const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
|
||||
@@ -4230,7 +4234,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255));
|
||||
else
|
||||
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255));
|
||||
SetNextItemWidth(w_items_all);
|
||||
SetNextItemWidth(w_inputs);
|
||||
if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
|
||||
{
|
||||
value_changed = true;
|
||||
@@ -4250,8 +4254,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
ImGuiWindow* picker_active_window = NULL;
|
||||
if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
|
||||
{
|
||||
if (!(flags & ImGuiColorEditFlags_NoInputs))
|
||||
SameLine(0, style.ItemInnerSpacing.x);
|
||||
const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x;
|
||||
window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y);
|
||||
|
||||
const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
|
||||
if (ColorButton("##ColorButton", col_v4, flags))
|
||||
@@ -4285,7 +4289,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
|
||||
if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
|
||||
{
|
||||
SameLine(0, style.ItemInnerSpacing.x);
|
||||
window->DC.CursorPos = ImVec2(pos.x + w_full + style.ItemInnerSpacing.x, pos.y + style.FramePadding.y);
|
||||
TextEx(label, label_display_end);
|
||||
}
|
||||
|
||||
@@ -4398,17 +4402,19 @@ void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU
|
||||
}
|
||||
|
||||
// Helper for ColorPicker4()
|
||||
static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
|
||||
static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha)
|
||||
{
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK);
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK);
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
|
||||
ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha);
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8));
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8));
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8));
|
||||
ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8));
|
||||
}
|
||||
|
||||
// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
|
||||
// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.)
|
||||
// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)
|
||||
// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0)
|
||||
bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -4658,17 +4664,22 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
}
|
||||
}
|
||||
|
||||
ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
|
||||
ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
|
||||
ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, 1.0f));
|
||||
const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha);
|
||||
const ImU32 col_black = IM_COL32(0,0,0,style_alpha8);
|
||||
const ImU32 col_white = IM_COL32(255,255,255,style_alpha8);
|
||||
const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8);
|
||||
const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) };
|
||||
|
||||
ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
|
||||
ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
|
||||
ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!!
|
||||
|
||||
const ImU32 hue_colors[6+1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) };
|
||||
ImVec2 sv_cursor_pos;
|
||||
|
||||
if (flags & ImGuiColorEditFlags_PickerHueWheel)
|
||||
{
|
||||
// Render Hue Wheel
|
||||
const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
|
||||
const float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
|
||||
const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
|
||||
for (int n = 0; n < 6; n++)
|
||||
{
|
||||
@@ -4676,13 +4687,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
|
||||
const int vert_start_idx = draw_list->VtxBuffer.Size;
|
||||
draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
|
||||
draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
|
||||
draw_list->PathStroke(col_white, false, wheel_thickness);
|
||||
const int vert_end_idx = draw_list->VtxBuffer.Size;
|
||||
|
||||
// Paint colors over existing vertices
|
||||
ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner);
|
||||
ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner);
|
||||
ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]);
|
||||
ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n+1]);
|
||||
}
|
||||
|
||||
// Render Cursor + preview on Hue Wheel
|
||||
@@ -4692,8 +4703,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
|
||||
int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
|
||||
draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
|
||||
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments);
|
||||
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
|
||||
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, col_midgrey, hue_cursor_segments);
|
||||
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments);
|
||||
|
||||
// Render SV triangle (rotated according to hue)
|
||||
ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
|
||||
@@ -4703,46 +4714,46 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
draw_list->PrimReserve(6, 6);
|
||||
draw_list->PrimVtx(tra, uv_white, hue_color32);
|
||||
draw_list->PrimVtx(trb, uv_white, hue_color32);
|
||||
draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
|
||||
draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
|
||||
draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
|
||||
draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
|
||||
draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f);
|
||||
draw_list->PrimVtx(trc, uv_white, col_white);
|
||||
draw_list->PrimVtx(tra, uv_white, 0);
|
||||
draw_list->PrimVtx(trb, uv_white, col_white);
|
||||
draw_list->PrimVtx(trc, uv_white, 0);
|
||||
draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);
|
||||
sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
|
||||
}
|
||||
else if (flags & ImGuiColorEditFlags_PickerHueBar)
|
||||
{
|
||||
// Render SV Square
|
||||
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
|
||||
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK);
|
||||
RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f);
|
||||
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white);
|
||||
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black);
|
||||
RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);
|
||||
sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
|
||||
sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
|
||||
|
||||
// Render Hue Bar
|
||||
for (int i = 0; i < 6; ++i)
|
||||
draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]);
|
||||
draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]);
|
||||
float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
|
||||
RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
|
||||
RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
|
||||
RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
|
||||
}
|
||||
|
||||
// Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
|
||||
float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
|
||||
draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
|
||||
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12);
|
||||
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
|
||||
draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12);
|
||||
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, col_midgrey, 12);
|
||||
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12);
|
||||
|
||||
// Render alpha bar
|
||||
if (alpha_bar)
|
||||
{
|
||||
float alpha = ImSaturate(col[3]);
|
||||
ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
|
||||
RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
|
||||
draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK);
|
||||
RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
|
||||
draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK);
|
||||
float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
|
||||
RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
|
||||
RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
|
||||
RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
|
||||
}
|
||||
|
||||
EndGroup();
|
||||
@@ -4834,9 +4845,6 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
|
||||
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
|
||||
|
||||
if (pressed)
|
||||
MarkItemEdited(id);
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@@ -4990,7 +4998,6 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
|
||||
// - TreeNodeBehavior() [Internal]
|
||||
// - TreePush()
|
||||
// - TreePop()
|
||||
// - TreeAdvanceToLabelPos()
|
||||
// - GetTreeNodeToLabelSpacing()
|
||||
// - SetNextItemOpen()
|
||||
// - CollapsingHeader()
|
||||
@@ -5238,13 +5245,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
|
||||
|
||||
// Render
|
||||
const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
const ImU32 text_col = GetColorU32(ImGuiCol_Text);
|
||||
const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
|
||||
ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin;
|
||||
if (display_frame)
|
||||
{
|
||||
// Framed type
|
||||
const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding);
|
||||
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
|
||||
RenderArrow(window->DrawList, frame_bb.Min + ImVec2(padding.x, text_base_offset_y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
|
||||
@@ -5269,6 +5276,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
// Unframed typed for tree nodes
|
||||
if (hovered || selected)
|
||||
{
|
||||
const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
|
||||
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
|
||||
}
|
||||
@@ -5331,12 +5339,6 @@ void ImGui::TreePop()
|
||||
PopID();
|
||||
}
|
||||
|
||||
void ImGui::TreeAdvanceToLabelPos()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing();
|
||||
}
|
||||
|
||||
// Horizontal distance preceding label when using TreeNode() or Bullet()
|
||||
float ImGui::GetTreeNodeToLabelSpacing()
|
||||
{
|
||||
@@ -5477,13 +5479,16 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
const bool was_selected = selected;
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
|
||||
// Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets)
|
||||
if (pressed || hovered)
|
||||
|
||||
// Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
|
||||
if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover)))
|
||||
{
|
||||
if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
|
||||
{
|
||||
g.NavDisableHighlight = true;
|
||||
SetNavID(id, window->DC.NavLayerCurrent);
|
||||
}
|
||||
}
|
||||
if (pressed)
|
||||
MarkItemEdited(id);
|
||||
|
||||
@@ -5495,6 +5500,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
|
||||
|
||||
// Render
|
||||
if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld))
|
||||
hovered = true;
|
||||
if (hovered || selected)
|
||||
{
|
||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
@@ -5938,6 +5945,10 @@ void ImGui::EndMainMenuBar()
|
||||
End();
|
||||
}
|
||||
|
||||
// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere..
|
||||
// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer.
|
||||
// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary.
|
||||
// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars.
|
||||
bool ImGui::BeginMenuBar()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
@@ -5947,7 +5958,7 @@ bool ImGui::BeginMenuBar()
|
||||
return false;
|
||||
|
||||
IM_ASSERT(!window->DC.MenuBarAppending);
|
||||
BeginGroup(); // Backup position on layer 0
|
||||
BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore
|
||||
PushID("##menubar");
|
||||
|
||||
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
|
||||
@@ -6177,7 +6188,9 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
|
||||
ImGuiSelectableFlags flags = ImGuiSelectableFlags_PressedOnRelease | (enabled ? 0 : ImGuiSelectableFlags_Disabled);
|
||||
// We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73),
|
||||
// but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only.
|
||||
ImGuiSelectableFlags flags = ImGuiSelectableFlags_PressedOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled);
|
||||
bool pressed;
|
||||
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
|
||||
{
|
||||
@@ -6276,18 +6289,18 @@ static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const voi
|
||||
return (int)(a->Offset - b->Offset);
|
||||
}
|
||||
|
||||
static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref)
|
||||
static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return ref.Ptr ? ref.Ptr : g.TabBars.GetByIndex(ref.IndexInMainPool);
|
||||
return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index);
|
||||
}
|
||||
|
||||
static ImGuiTabBarRef GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
|
||||
static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.TabBars.Contains(tab_bar))
|
||||
return ImGuiTabBarRef(g.TabBars.GetIndex(tab_bar));
|
||||
return ImGuiTabBarRef(tab_bar);
|
||||
return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar));
|
||||
return ImGuiPtrOrIndex(tab_bar);
|
||||
}
|
||||
|
||||
bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
|
||||
@@ -6346,7 +6359,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
|
||||
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
|
||||
|
||||
// Draw separator
|
||||
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
|
||||
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);
|
||||
const float y = tab_bar->BarRect.Max.y - 1.0f;
|
||||
{
|
||||
const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f);
|
||||
@@ -6625,7 +6638,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f);
|
||||
float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f);
|
||||
tab_bar->ScrollingTargetDistToVisibility = 0.0f;
|
||||
if (tab_bar->ScrollingTarget > tab_x1)
|
||||
if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth()))
|
||||
{
|
||||
tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f);
|
||||
tab_bar->ScrollingTarget = tab_x1;
|
||||
@@ -6642,7 +6655,7 @@ void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem*
|
||||
IM_ASSERT(dir == -1 || dir == +1);
|
||||
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
|
||||
tab_bar->ReorderRequestTabId = tab->ID;
|
||||
tab_bar->ReorderRequestDir = dir;
|
||||
tab_bar->ReorderRequestDir = (ImS8)dir;
|
||||
}
|
||||
|
||||
static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
|
||||
@@ -7089,3 +7102,425 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
|
||||
return close_button_pressed;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
|
||||
// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
|
||||
//-------------------------------------------------------------------------
|
||||
// - GetColumnIndex()
|
||||
// - GetColumnCount()
|
||||
// - GetColumnOffset()
|
||||
// - GetColumnWidth()
|
||||
// - SetColumnOffset()
|
||||
// - SetColumnWidth()
|
||||
// - PushColumnClipRect() [Internal]
|
||||
// - PushColumnsBackground() [Internal]
|
||||
// - PopColumnsBackground() [Internal]
|
||||
// - FindOrCreateColumns() [Internal]
|
||||
// - GetColumnsID() [Internal]
|
||||
// - BeginColumns()
|
||||
// - NextColumn()
|
||||
// - EndColumns()
|
||||
// - Columns()
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
int ImGui::GetColumnIndex()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;
|
||||
}
|
||||
|
||||
int ImGui::GetColumnsCount()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;
|
||||
}
|
||||
|
||||
float ImGui::GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm)
|
||||
{
|
||||
return offset_norm * (columns->OffMaxX - columns->OffMinX);
|
||||
}
|
||||
|
||||
float ImGui::GetColumnNormFromOffset(const ImGuiColumns* columns, float offset)
|
||||
{
|
||||
return offset / (columns->OffMaxX - columns->OffMinX);
|
||||
}
|
||||
|
||||
static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
|
||||
|
||||
static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index)
|
||||
{
|
||||
// Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
|
||||
// window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
|
||||
IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
|
||||
|
||||
float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;
|
||||
x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
|
||||
if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
|
||||
x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
float ImGui::GetColumnOffset(int column_index)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns == NULL)
|
||||
return 0.0f;
|
||||
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
IM_ASSERT(column_index < columns->Columns.Size);
|
||||
|
||||
const float t = columns->Columns[column_index].OffsetNorm;
|
||||
const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
|
||||
return x_offset;
|
||||
}
|
||||
|
||||
static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false)
|
||||
{
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
|
||||
float offset_norm;
|
||||
if (before_resize)
|
||||
offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
|
||||
else
|
||||
offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
|
||||
return ImGui::GetColumnOffsetFromNorm(columns, offset_norm);
|
||||
}
|
||||
|
||||
float ImGui::GetColumnWidth(int column_index)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns == NULL)
|
||||
return GetContentRegionAvail().x;
|
||||
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
|
||||
}
|
||||
|
||||
void ImGui::SetColumnOffset(int column_index, float offset)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
IM_ASSERT(columns != NULL);
|
||||
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
IM_ASSERT(column_index < columns->Columns.Size);
|
||||
|
||||
const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
|
||||
const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
|
||||
|
||||
if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
|
||||
offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
|
||||
columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX);
|
||||
|
||||
if (preserve_width)
|
||||
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
|
||||
}
|
||||
|
||||
void ImGui::SetColumnWidth(int column_index, float width)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
IM_ASSERT(columns != NULL);
|
||||
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
|
||||
}
|
||||
|
||||
void ImGui::PushColumnClipRect(int column_index)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (column_index < 0)
|
||||
column_index = columns->Current;
|
||||
|
||||
ImGuiColumnData* column = &columns->Columns[column_index];
|
||||
PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);
|
||||
}
|
||||
|
||||
// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)
|
||||
void ImGui::PushColumnsBackground()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns->Count == 1)
|
||||
return;
|
||||
window->DrawList->ChannelsSetCurrent(0);
|
||||
int cmd_size = window->DrawList->CmdBuffer.Size;
|
||||
PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
|
||||
IM_UNUSED(cmd_size);
|
||||
IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd
|
||||
}
|
||||
|
||||
void ImGui::PopColumnsBackground()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindowRead();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns->Count == 1)
|
||||
return;
|
||||
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
|
||||
PopClipRect();
|
||||
}
|
||||
|
||||
ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)
|
||||
{
|
||||
// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.
|
||||
for (int n = 0; n < window->ColumnsStorage.Size; n++)
|
||||
if (window->ColumnsStorage[n].ID == id)
|
||||
return &window->ColumnsStorage[n];
|
||||
|
||||
window->ColumnsStorage.push_back(ImGuiColumns());
|
||||
ImGuiColumns* columns = &window->ColumnsStorage.back();
|
||||
columns->ID = id;
|
||||
return columns;
|
||||
}
|
||||
|
||||
ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
// Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
|
||||
// In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
|
||||
PushID(0x11223347 + (str_id ? 0 : columns_count));
|
||||
ImGuiID id = window->GetID(str_id ? str_id : "columns");
|
||||
PopID();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
||||
IM_ASSERT(columns_count >= 1);
|
||||
IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
|
||||
|
||||
// Acquire storage for the columns set
|
||||
ImGuiID id = GetColumnsID(str_id, columns_count);
|
||||
ImGuiColumns* columns = FindOrCreateColumns(window, id);
|
||||
IM_ASSERT(columns->ID == id);
|
||||
columns->Current = 0;
|
||||
columns->Count = columns_count;
|
||||
columns->Flags = flags;
|
||||
window->DC.CurrentColumns = columns;
|
||||
|
||||
columns->HostCursorPosY = window->DC.CursorPos.y;
|
||||
columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
|
||||
columns->HostClipRect = window->ClipRect;
|
||||
columns->HostWorkRect = window->WorkRect;
|
||||
|
||||
// Set state for first column
|
||||
// We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect
|
||||
const float column_padding = g.Style.ItemSpacing.x;
|
||||
const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize));
|
||||
const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
||||
const float max_2 = window->WorkRect.Max.x + half_clip_extend_x;
|
||||
columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
||||
columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f);
|
||||
columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
|
||||
|
||||
// Clear data if columns count changed
|
||||
if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
|
||||
columns->Columns.resize(0);
|
||||
|
||||
// Initialize default widths
|
||||
columns->IsFirstFrame = (columns->Columns.Size == 0);
|
||||
if (columns->Columns.Size == 0)
|
||||
{
|
||||
columns->Columns.reserve(columns_count + 1);
|
||||
for (int n = 0; n < columns_count + 1; n++)
|
||||
{
|
||||
ImGuiColumnData column;
|
||||
column.OffsetNorm = n / (float)columns_count;
|
||||
columns->Columns.push_back(column);
|
||||
}
|
||||
}
|
||||
|
||||
for (int n = 0; n < columns_count; n++)
|
||||
{
|
||||
// Compute clipping rectangle
|
||||
ImGuiColumnData* column = &columns->Columns[n];
|
||||
float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
|
||||
float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
|
||||
column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
|
||||
column->ClipRect.ClipWith(window->ClipRect);
|
||||
}
|
||||
|
||||
if (columns->Count > 1)
|
||||
{
|
||||
window->DrawList->ChannelsSplit(1 + columns->Count);
|
||||
window->DrawList->ChannelsSetCurrent(1);
|
||||
PushColumnClipRect(0);
|
||||
}
|
||||
|
||||
// We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user.
|
||||
float offset_0 = GetColumnOffset(columns->Current);
|
||||
float offset_1 = GetColumnOffset(columns->Current + 1);
|
||||
float width = offset_1 - offset_0;
|
||||
PushItemWidth(width * 0.65f);
|
||||
window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
||||
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
||||
window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
|
||||
}
|
||||
|
||||
void ImGui::NextColumn()
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems || window->DC.CurrentColumns == NULL)
|
||||
return;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
|
||||
if (columns->Count == 1)
|
||||
{
|
||||
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
||||
IM_ASSERT(columns->Current == 0);
|
||||
return;
|
||||
}
|
||||
PopItemWidth();
|
||||
PopClipRect();
|
||||
|
||||
const float column_padding = g.Style.ItemSpacing.x;
|
||||
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
|
||||
if (++columns->Current < columns->Count)
|
||||
{
|
||||
// Columns 1+ ignore IndentX (by canceling it out)
|
||||
// FIXME-COLUMNS: Unnecessary, could be locked?
|
||||
window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding;
|
||||
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// New row/line
|
||||
// Column 0 honor IndentX
|
||||
window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
|
||||
window->DrawList->ChannelsSetCurrent(1);
|
||||
columns->Current = 0;
|
||||
columns->LineMinY = columns->LineMaxY;
|
||||
}
|
||||
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
||||
window->DC.CursorPos.y = columns->LineMinY;
|
||||
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
||||
window->DC.CurrLineTextBaseOffset = 0.0f;
|
||||
|
||||
PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
|
||||
|
||||
// FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup.
|
||||
float offset_0 = GetColumnOffset(columns->Current);
|
||||
float offset_1 = GetColumnOffset(columns->Current + 1);
|
||||
float width = offset_1 - offset_0;
|
||||
PushItemWidth(width * 0.65f);
|
||||
window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
|
||||
}
|
||||
|
||||
void ImGui::EndColumns()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
IM_ASSERT(columns != NULL);
|
||||
|
||||
PopItemWidth();
|
||||
if (columns->Count > 1)
|
||||
{
|
||||
PopClipRect();
|
||||
window->DrawList->ChannelsMerge();
|
||||
}
|
||||
|
||||
const ImGuiColumnsFlags flags = columns->Flags;
|
||||
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
|
||||
window->DC.CursorPos.y = columns->LineMaxY;
|
||||
if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize))
|
||||
window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
|
||||
|
||||
// Draw columns borders and handle resize
|
||||
// The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy
|
||||
bool is_being_resized = false;
|
||||
if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
|
||||
{
|
||||
// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
|
||||
const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);
|
||||
const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);
|
||||
int dragging_column = -1;
|
||||
for (int n = 1; n < columns->Count; n++)
|
||||
{
|
||||
ImGuiColumnData* column = &columns->Columns[n];
|
||||
float x = window->Pos.x + GetColumnOffset(n);
|
||||
const ImGuiID column_id = columns->ID + ImGuiID(n);
|
||||
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
|
||||
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
|
||||
KeepAliveID(column_id);
|
||||
if (IsClippedEx(column_hit_rect, column_id, false))
|
||||
continue;
|
||||
|
||||
bool hovered = false, held = false;
|
||||
if (!(flags & ImGuiColumnsFlags_NoResize))
|
||||
{
|
||||
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
|
||||
if (hovered || held)
|
||||
g.MouseCursor = ImGuiMouseCursor_ResizeEW;
|
||||
if (held && !(column->Flags & ImGuiColumnsFlags_NoResize))
|
||||
dragging_column = n;
|
||||
}
|
||||
|
||||
// Draw column
|
||||
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
|
||||
const float xi = (float)(int)x;
|
||||
window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
|
||||
}
|
||||
|
||||
// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
|
||||
if (dragging_column != -1)
|
||||
{
|
||||
if (!columns->IsBeingResized)
|
||||
for (int n = 0; n < columns->Count + 1; n++)
|
||||
columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
|
||||
columns->IsBeingResized = is_being_resized = true;
|
||||
float x = GetDraggedColumnOffset(columns, dragging_column);
|
||||
SetColumnOffset(dragging_column, x);
|
||||
}
|
||||
}
|
||||
columns->IsBeingResized = is_being_resized;
|
||||
|
||||
window->WorkRect = columns->HostWorkRect;
|
||||
window->DC.CurrentColumns = NULL;
|
||||
window->DC.ColumnsOffset.x = 0.0f;
|
||||
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
||||
}
|
||||
|
||||
// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
|
||||
void ImGui::Columns(int columns_count, const char* id, bool border)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
IM_ASSERT(columns_count >= 1);
|
||||
|
||||
ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
|
||||
//flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
|
||||
ImGuiColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
|
||||
return;
|
||||
|
||||
if (columns != NULL)
|
||||
EndColumns();
|
||||
|
||||
if (columns_count != 1)
|
||||
BeginColumns(id, columns_count, flags);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user