feat: refine editor color picker UI

This commit is contained in:
2026-03-28 17:24:48 +08:00
parent 2b255751b6
commit 3c45a051a2
2 changed files with 920 additions and 38 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include "ColorPicker.h"
#include "Core.h"
#include "PropertyLayout.h"
@@ -26,8 +27,9 @@ inline void DrawComboPreviewFrame(
const char* id,
const char* previewValue,
float width,
float height,
bool popupOpen) {
const float frameHeight = ImGui::GetFrameHeight();
const float frameHeight = (std::max)(height, 1.0f);
ImGui::InvisibleButton(id, ImVec2(width, frameHeight));
const bool hovered = ImGui::IsItemHovered();
@@ -86,28 +88,42 @@ inline void DrawComboPreviewFrame(
textColor);
}
inline void DrawControlFrameChrome(
ImDrawList* drawList,
const ImVec2& min,
const ImVec2& max,
bool hovered,
bool active = false) {
if (!drawList) {
return;
inline bool DrawCompactCheckboxControl(const char* id, bool& value) {
const float size = CompactIndicatorSize();
ImGui::InvisibleButton(id, ImVec2(size, size));
const bool hovered = ImGui::IsItemHovered();
const bool held = ImGui::IsItemActive();
const bool pressed = ImGui::IsItemClicked(ImGuiMouseButton_Left);
if (pressed) {
value = !value;
}
const ImGuiStyle& style = ImGui::GetStyle();
const ImU32 frameColor = ImGui::GetColorU32(
active ? ImGuiCol_FrameBgActive : (hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg));
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const float rounding = ImGui::GetStyle().FrameRounding;
const ImU32 fillColor = ImGui::GetColorU32(
(held && hovered) ? ImGuiCol_FrameBgActive :
hovered ? ImGuiCol_FrameBgHovered :
ImGuiCol_FrameBg);
const ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border);
drawList->AddRectFilled(min, max, frameColor, style.FrameRounding);
drawList->AddRect(
ImVec2(min.x + 0.5f, min.y + 0.5f),
ImVec2(max.x - 0.5f, max.y - 0.5f),
borderColor,
style.FrameRounding,
0,
style.FrameBorderSize);
const ImU32 checkColor = ImGui::GetColorU32(ImGuiCol_CheckMark);
ImDrawList* drawList = ImGui::GetWindowDrawList();
drawList->AddRectFilled(min, max, fillColor, rounding);
drawList->AddRect(min, max, borderColor, rounding);
if (value) {
const float pad = (std::max)(size * 0.22f, 2.0f);
const ImVec2 points[3] = {
ImVec2(min.x + pad, min.y + size * 0.56f),
ImVec2(min.x + size * 0.44f, max.y - pad),
ImVec2(max.x - pad, min.y + pad)
};
drawList->AddPolyline(points, 3, checkColor, ImDrawFlags_None, 2.0f);
}
return pressed;
}
inline bool DrawFloat(
@@ -119,9 +135,16 @@ inline bool DrawFloat(
float max = 0.0f,
const char* format = "%.2f"
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics& layout) {
const ImVec2 framePadding = ScalarControlFramePadding();
const PropertyLayoutSpec adjustedLayout =
WithMinimumRowHeight(layoutSpec, CalcPropertyRowHeightForFramePadding(framePadding));
return DrawPropertyRow(label, adjustedLayout, [&](const PropertyLayoutMetrics& layout) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
AlignPropertyControlVertically(layout, ImGui::GetFrameHeight());
SetNextPropertyControlWidth(layout);
return ImGui::DragFloat("##value", &value, dragSpeed, min, max, format);
const bool changed = ImGui::DragFloat("##value", &value, dragSpeed, min, max, format);
ImGui::PopStyleVar();
return changed;
});
}
@@ -137,8 +160,7 @@ inline bool DrawLinearSlider(
const bool active = ImGui::IsItemActive();
const ImVec2 min = ImGui::GetItemRectMin();
const ImVec2 max = ImGui::GetItemRectMax();
const ImGuiStyle& style = ImGui::GetStyle();
const float trackPadding = (std::max)(LinearSliderHorizontalPadding(), style.FramePadding.x);
const float trackPadding = LinearSliderHorizontalPadding();
const float trackMinX = min.x + trackPadding;
const float trackMaxX = max.x - trackPadding;
const float centerY = (min.y + max.y) * 0.5f;
@@ -146,7 +168,6 @@ inline bool DrawLinearSlider(
const float trackHalfThickness = LinearSliderTrackThickness() * 0.5f;
ImDrawList* drawList = ImGui::GetWindowDrawList();
DrawControlFrameChrome(drawList, min, max, hovered, active);
drawList->AddRectFilled(
ImVec2(trackMinX, centerY - trackHalfThickness),
ImVec2(trackMaxX, centerY + trackHalfThickness),
@@ -184,9 +205,16 @@ inline bool DrawInt(
int min = 0,
int max = 0
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics& layout) {
const ImVec2 framePadding = ScalarControlFramePadding();
const PropertyLayoutSpec adjustedLayout =
WithMinimumRowHeight(layoutSpec, CalcPropertyRowHeightForFramePadding(framePadding));
return DrawPropertyRow(label, adjustedLayout, [&](const PropertyLayoutMetrics& layout) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
AlignPropertyControlVertically(layout, ImGui::GetFrameHeight());
SetNextPropertyControlWidth(layout);
return ImGui::DragInt("##value", &value, static_cast<float>(step), min, max);
const bool changed = ImGui::DragInt("##value", &value, static_cast<float>(step), min, max);
ImGui::PopStyleVar();
return changed;
});
}
@@ -195,8 +223,9 @@ inline bool DrawBool(
bool& value,
const PropertyLayoutSpec& layoutSpec = MakePropertyLayout()
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics&) {
return ImGui::Checkbox("##value", &value);
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics& layout) {
AlignPropertyControlVertically(layout, CompactIndicatorSize());
return DrawCompactCheckboxControl("##value", value);
});
}
@@ -205,9 +234,7 @@ inline bool DrawColor3(
float color[3],
const PropertyLayoutSpec& layoutSpec = MakePropertyLayout()
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics&) {
return ImGui::ColorEdit3("##value", color, ImGuiColorEditFlags_NoInputs);
});
return DrawUnityColor3(label, color, layoutSpec);
}
inline bool DrawColor4(
@@ -215,9 +242,7 @@ inline bool DrawColor4(
float color[4],
const PropertyLayoutSpec& layoutSpec = MakePropertyLayout()
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics&) {
return ImGui::ColorEdit4("##value", color, ImGuiColorEditFlags_NoInputs);
});
return DrawUnityColor4(label, color, layoutSpec);
}
inline bool DrawSliderFloat(
@@ -228,13 +253,18 @@ inline bool DrawSliderFloat(
const PropertyLayoutSpec& layoutSpec = MakePropertyLayout(),
const char* format = "%.2f"
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics& layout) {
const ImVec2 framePadding = ScalarControlFramePadding();
const PropertyLayoutSpec adjustedLayout =
WithMinimumRowHeight(layoutSpec, CalcPropertyRowHeightForFramePadding(framePadding));
return DrawPropertyRow(label, adjustedLayout, [&](const PropertyLayoutMetrics& layout) {
const float totalWidth = layout.controlWidth;
const float inputWidth = SliderValueFieldWidth();
const float spacing = CompoundControlSpacing();
const float sliderWidth = ImMax(totalWidth - inputWidth - spacing, 1.0f);
const float range = max - min;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
AlignPropertyControlVertically(layout, ImGui::GetFrameHeight());
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, 0.0f));
float normalizedValue = range > 0.0f ? (value - min) / range : 0.0f;
bool changed = DrawLinearSlider("##slider", sliderWidth, normalizedValue);
@@ -251,6 +281,7 @@ inline bool DrawSliderFloat(
changed = ImGui::InputFloat("##value", &value, 0.0f, 0.0f, format) || changed;
value = std::clamp(value, min, max);
ImGui::PopStyleVar();
ImGui::PopStyleVar();
return changed;
});
}
@@ -262,13 +293,18 @@ inline bool DrawSliderInt(
int max,
const PropertyLayoutSpec& layoutSpec = MakePropertyLayout()
) {
return DrawPropertyRow(label, layoutSpec, [&](const PropertyLayoutMetrics& layout) {
const ImVec2 framePadding = ScalarControlFramePadding();
const PropertyLayoutSpec adjustedLayout =
WithMinimumRowHeight(layoutSpec, CalcPropertyRowHeightForFramePadding(framePadding));
return DrawPropertyRow(label, adjustedLayout, [&](const PropertyLayoutMetrics& layout) {
const float totalWidth = layout.controlWidth;
const float inputWidth = SliderValueFieldWidth();
const float spacing = CompoundControlSpacing();
const float sliderWidth = ImMax(totalWidth - inputWidth - spacing, 1.0f);
const int range = max - min;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
AlignPropertyControlVertically(layout, ImGui::GetFrameHeight());
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, 0.0f));
const float normalizedValue = range > 0 ? static_cast<float>(value - min) / static_cast<float>(range) : 0.0f;
bool changed = DrawLinearSlider("##slider", sliderWidth, normalizedValue);
@@ -285,6 +321,7 @@ inline bool DrawSliderInt(
changed = ImGui::InputInt("##value", &value, 0, 0) || changed;
value = std::clamp(value, min, max);
ImGui::PopStyleVar();
ImGui::PopStyleVar();
return changed;
});
}
@@ -306,7 +343,9 @@ inline int DrawCombo(
: "";
const float comboWidth = layout.controlWidth;
const float popupWidth = comboWidth;
DrawComboPreviewFrame("##value", previewValue, comboWidth, ImGui::IsPopupOpen(popupId));
const float comboHeight = (std::max)(ImGui::GetFrameHeight() + ComboPreviewHeightOffset(), 1.0f);
AlignPropertyControlVertically(layout, comboHeight);
DrawComboPreviewFrame("##value", previewValue, comboWidth, comboHeight, ImGui::IsPopupOpen(popupId));
const ImVec2 comboMin = ImGui::GetItemRectMin();
const ImVec2 comboMax = ImGui::GetItemRectMax();