1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-08 23:44:19 +00:00

Added RGBA color markers to ColorEdit3/ColorEdit4 + opt-in ImGuiSliderFlags_ColorMarkers for Drags/Sliders.

+ Added ImGuiColorEditFlags_NoColorMarkers
+ Added style.ColorMarkerSize.
This commit is contained in:
ocornut 2025-12-05 16:29:15 +01:00
parent a7ecbcdeba
commit fa4b47c5e2
6 changed files with 66 additions and 9 deletions

View file

@ -64,6 +64,14 @@ Other Changes:
between hard minimum window size and table minimum size).
- Fixed an issue where submitting non-integer row heights would eventually
advance table parent layout by +0/+1 depending on its visibility.
- ColorEdit:
- Added R/G/B/A color markers next to each component (enabled by default).
- Added ImGuiColorEditFlags_NoColorMarkers to disable them.
- Added style.ColorMarkerSize to configure width of color component markers.
- Sliders, Drags:
- Added ImGuiSliderFlags_ColorMarkers to opt-in adding R/G/B/A color markers
next to each components, in multi-components functions.
- Added a way to select a specific marker color.
- Text:
- Fixed low-level word-wrapping function reading from *text_end when passed
a string range. (#9107) [@achabense]

View file

@ -1453,6 +1453,7 @@ ImGuiStyle::ImGuiStyle()
DragDropTargetRounding = 0.0f; // Radius of the drag and drop target frame.
DragDropTargetBorderSize = 2.0f; // Thickness of the drag and drop target border.
DragDropTargetPadding = 3.0f; // Size to expand the drag and drop target from actual target item size.
ColorMarkerSize = 3.0f; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers.
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
@ -1520,6 +1521,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
DragDropTargetRounding = ImTrunc(DragDropTargetRounding * scale_factor);
DragDropTargetBorderSize = ImTrunc(DragDropTargetBorderSize * scale_factor);
DragDropTargetPadding = ImTrunc(DragDropTargetPadding * scale_factor);
ColorMarkerSize = ImTrunc(ColorMarkerSize * scale_factor);
SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor);
DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor);
DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor);
@ -3923,6 +3925,18 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
}
}
// FIXME: Might move those to style if there is a real need.
static const ImU32 GColorMarkers[4] = { IM_COL32(240,20,20,255), IM_COL32(20,240,20,255), IM_COL32(20,20,240,255), IM_COL32(140,140,140,255) };
void ImGui::RenderColorComponentMarker(int component_idx, const ImRect& bb, float rounding)
{
if (!(component_idx >= 0 && component_idx < 4) || (bb.Min.x + 1 >= bb.Max.x))
return;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
RenderRectFilledInRangeH(window->DrawList, bb, GetColorU32(GColorMarkers[component_idx]), bb.Min.x, ImMin(bb.Min.x + g.Style.ColorMarkerSize, bb.Max.x), rounding);
}
void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags)
{
ImGuiContext& g = *GImGui;

View file

@ -30,7 +30,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.6 WIP"
#define IMGUI_VERSION_NUM 19252
#define IMGUI_VERSION_NUM 19253
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@ -1873,6 +1873,7 @@ enum ImGuiColorEditFlags_
ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead.
ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source.
ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default)
ImGuiColorEditFlags_NoColorMarkers = 1 << 11, // // ColorEdit: disable rendering R/G/B/A color marker. May also be disabled globally by setting style.ColorMarkerSize = 0.
// Alpha preview
// - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name ImGuiColorEditFlags_AlphaPreview.
@ -1927,6 +1928,11 @@ enum ImGuiSliderFlags_
ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it.
ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.
ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange,
// Color Markers
ImGuiSliderFlags_ColorMarkers = 1 << 12, // DragScalarN(), SliderScalarN(): Draw R/G/B/A color markers on each component.
ImGuiSliderFlags_ColorMarkersIndexShift_ = 13, // [Internal] DragScalar(), SliderScalar(): Pass ([0..3] << ImGuiSliderFlags_ColorMarkersIndexShift_) along with ImGuiSliderFlags_ColorMarkers to select an individual R/G/B/A color.
ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from legacy API (obsoleted 2020-08) that has got miscast to this enum, and will trigger an assert if needed.
};
@ -2314,6 +2320,7 @@ struct ImGuiStyle
float DragDropTargetRounding; // Radius of the drag and drop target frame.
float DragDropTargetBorderSize; // Thickness of the drag and drop target border.
float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size.
float ColorMarkerSize; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers.
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.

View file

@ -1096,8 +1096,9 @@ static void DemoWindowWidgetsColorAndPickers()
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque);
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg);
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop);
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop);
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", &base_flags, ImGuiColorEditFlags_NoColorMarkers);
ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
@ -1710,9 +1711,12 @@ static void DemoWindowWidgetsDragsAndSliders()
ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.");
ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers);
//ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkersG", &flags, 1 << ImGuiSliderFlags_ColorMarkersIndexShift_); // Not explicitly documented but possible.
// Drags
static float drag_f = 0.5f;
static float drag_f4[4];
static int drag_i = 50;
ImGui::Text("Underlying float value: %f", drag_f);
ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
@ -1722,14 +1726,17 @@ static void DemoWindowWidgetsDragsAndSliders()
//ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
//ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
ImGui::DragFloat4("DragFloat4 (0 -> 1)", drag_f4, 0.005f, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
// Sliders
static float slider_f = 0.5f;
static float slider_f4[4];
static int slider_i = 50;
const ImGuiSliderFlags flags_for_sliders = (flags & ~ImGuiSliderFlags_WrapAround);
ImGui::Text("Underlying float value: %f", slider_f);
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
ImGui::SliderFloat4("SliderFloat4 (0 -> 1)", slider_f4, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
ImGui::TreePop();
}
@ -8444,6 +8451,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
SeparatorText("Widgets");
SliderFloat("ColorMarkerSize", &style.ColorMarkerSize, 0.0f, 8.0f, "%.0f");
Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");

View file

@ -3575,6 +3575,7 @@ namespace ImGui
IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known);
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f);
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
IMGUI_API void RenderColorComponentMarker(int component_idx, const ImRect& bb, float rounding);
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0);
IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS

View file

@ -2756,7 +2756,10 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
RenderNavCursor(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, false, style.FrameRounding);
if ((flags & ImGuiSliderFlags_ColorMarkers) && style.ColorMarkerSize > 0.0f)
RenderColorComponentMarker(flags >> ImGuiSliderFlags_ColorMarkersIndexShift_, frame_bb, style.FrameRounding);
RenderFrameBorder(frame_bb.Min, frame_bb.Max, g.Style.FrameRounding);
// Drag behavior
const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags);
@ -2794,7 +2797,12 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags);
ImGuiSliderFlags flags_for_component = flags;
if ((flags & ImGuiSliderFlags_ColorMarkers) && (flags & (0x03 << ImGuiSliderFlags_ColorMarkersIndexShift_)) == 0 && (i < 4))
flags_for_component |= (i << ImGuiSliderFlags_ColorMarkersIndexShift_);
value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags_for_component);
PopID();
PopItemWidth();
p_data = (void*)((char*)p_data + type_size);
@ -3342,7 +3350,10 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
RenderNavCursor(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, false, style.FrameRounding);
if ((flags & ImGuiSliderFlags_ColorMarkers) && style.ColorMarkerSize > 0.0f)
RenderColorComponentMarker(flags >> ImGuiSliderFlags_ColorMarkersIndexShift_, frame_bb, style.FrameRounding);
RenderFrameBorder(frame_bb.Min, frame_bb.Max, g.Style.FrameRounding);
// Slider behavior
ImRect grab_bb;
@ -3386,7 +3397,12 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags);
ImGuiSliderFlags flags_for_component = flags;
if ((flags & ImGuiSliderFlags_ColorMarkers) && (flags & (0x03 << ImGuiSliderFlags_ColorMarkersIndexShift_ )) == 0 && (i < 4))
flags_for_component |= (i << ImGuiSliderFlags_ColorMarkersIndexShift_);
value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags_for_component);
PopID();
PopItemWidth();
v = (void*)((char*)v + type_size);
@ -5784,8 +5800,10 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
{
// RGB/HSV 0..255 Sliders
const float w_items = w_inputs - style.ItemInnerSpacing.x * (components - 1);
const float w_per_component = IM_TRUNC(w_items / components);
const bool draw_color_marker = (flags & (ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_NoColorMarkers)) == 0;
const bool hide_prefix = (IM_TRUNC(w_items / components) <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
const bool hide_prefix = draw_color_marker || (w_per_component <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
static const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
static const char* fmt_table_int[3][4] =
{
@ -5811,14 +5829,15 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
prev_split = next_split;
// FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0.
ImGuiSliderFlags drag_flags = draw_color_marker ? (ImGuiSliderFlags_ColorMarkers | (n << ImGuiSliderFlags_ColorMarkersIndexShift_)) : ImGuiSliderFlags_None;
if (flags & ImGuiColorEditFlags_Float)
{
value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n], drag_flags);
value_changed_as_float |= value_changed;
}
else
{
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n], drag_flags);
}
if (!(flags & ImGuiColorEditFlags_NoOptions))
OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);