关键节点
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
enum class UIEditorCollectionPrimitiveKind : std::uint8_t {
|
||||
None = 0,
|
||||
ScrollView,
|
||||
TreeView,
|
||||
TreeItem,
|
||||
ListView,
|
||||
ListItem,
|
||||
PropertySection,
|
||||
FieldRow
|
||||
};
|
||||
|
||||
UIEditorCollectionPrimitiveKind ClassifyUIEditorCollectionPrimitive(std::string_view tagName);
|
||||
bool IsUIEditorCollectionPrimitiveContainer(UIEditorCollectionPrimitiveKind kind);
|
||||
bool UsesUIEditorCollectionPrimitiveColumnLayout(UIEditorCollectionPrimitiveKind kind);
|
||||
bool IsUIEditorCollectionPrimitiveHoverable(UIEditorCollectionPrimitiveKind kind);
|
||||
bool DoesUIEditorCollectionPrimitiveClipChildren(UIEditorCollectionPrimitiveKind kind);
|
||||
float ResolveUIEditorCollectionPrimitivePadding(
|
||||
UIEditorCollectionPrimitiveKind kind);
|
||||
float ResolveUIEditorCollectionPrimitiveDefaultHeight(
|
||||
UIEditorCollectionPrimitiveKind kind);
|
||||
float ResolveUIEditorCollectionPrimitiveIndent(
|
||||
UIEditorCollectionPrimitiveKind kind,
|
||||
float indentLevel);
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
33
editor/include/XCEditor/Widgets/UIEditorColorUtils.h
Normal file
33
editor/include/XCEditor/Widgets/UIEditorColorUtils.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
struct UIEditorHsvColor {
|
||||
float hue = 0.0f;
|
||||
float saturation = 0.0f;
|
||||
float value = 0.0f;
|
||||
float alpha = 1.0f;
|
||||
};
|
||||
|
||||
float ClampUIEditorColorUnit(float value);
|
||||
int ToUIEditorColorByte(float value);
|
||||
UIEditorHsvColor ConvertUIEditorColorToHsv(
|
||||
const ::XCEngine::UI::UIColor& color,
|
||||
float fallbackHue = 0.0f);
|
||||
::XCEngine::UI::UIColor ConvertUIEditorHsvToColor(const UIEditorHsvColor& hsv);
|
||||
UIEditorHsvColor ResolveUIEditorDisplayHsv(
|
||||
const ::XCEngine::UI::UIColor& color,
|
||||
float rememberedHue,
|
||||
bool hueValid);
|
||||
std::string FormatUIEditorColorHex(
|
||||
const ::XCEngine::UI::UIColor& color,
|
||||
bool includeAlpha = true);
|
||||
std::string FormatUIEditorColorChannelsText(
|
||||
const ::XCEngine::UI::UIColor& color,
|
||||
bool includeAlpha = true);
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
125
editor/include/XCEditor/Widgets/UIEditorFieldRowLayout.h
Normal file
125
editor/include/XCEditor/Widgets/UIEditorFieldRowLayout.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
struct UIEditorInspectorFieldStyleTokens {
|
||||
::XCEngine::UI::UIColor rowHoverColor =
|
||||
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||
::XCEngine::UI::UIColor rowActiveColor =
|
||||
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
||||
::XCEngine::UI::UIColor labelColor =
|
||||
::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
|
||||
::XCEngine::UI::UIColor valueColor =
|
||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||
::XCEngine::UI::UIColor readOnlyValueColor =
|
||||
::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlColor =
|
||||
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlHoverColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlEditingColor =
|
||||
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlReadOnlyColor =
|
||||
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor controlFocusedBorderColor =
|
||||
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
||||
::XCEngine::UI::UIColor prefixColor =
|
||||
::XCEngine::UI::UIColor(0.13f, 0.13f, 0.13f, 1.0f);
|
||||
::XCEngine::UI::UIColor prefixBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor axisXColor =
|
||||
::XCEngine::UI::UIColor(0.78f, 0.42f, 0.42f, 1.0f);
|
||||
::XCEngine::UI::UIColor axisYColor =
|
||||
::XCEngine::UI::UIColor(0.56f, 0.72f, 0.46f, 1.0f);
|
||||
::XCEngine::UI::UIColor axisZColor =
|
||||
::XCEngine::UI::UIColor(0.45f, 0.62f, 0.82f, 1.0f);
|
||||
::XCEngine::UI::UIColor axisWColor =
|
||||
::XCEngine::UI::UIColor(0.76f, 0.66f, 0.42f, 1.0f);
|
||||
::XCEngine::UI::UIColor arrowColor =
|
||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||
::XCEngine::UI::UIColor swatchBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor swatchHoverBorderColor =
|
||||
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
|
||||
::XCEngine::UI::UIColor swatchReadOnlyOverlayColor =
|
||||
::XCEngine::UI::UIColor(0.08f, 0.08f, 0.08f, 0.18f);
|
||||
::XCEngine::UI::UIColor popupColor =
|
||||
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
|
||||
::XCEngine::UI::UIColor popupBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor popupHeaderColor =
|
||||
::XCEngine::UI::UIColor(0.11f, 0.11f, 0.11f, 1.0f);
|
||||
::XCEngine::UI::UIColor popupTitleColor =
|
||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||
::XCEngine::UI::UIColor popupTextColor =
|
||||
::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f);
|
||||
::XCEngine::UI::UIColor popupTextMutedColor =
|
||||
::XCEngine::UI::UIColor(0.66f, 0.66f, 0.66f, 1.0f);
|
||||
::XCEngine::UI::UIColor previewBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor previewBaseColor =
|
||||
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||
::XCEngine::UI::UIColor checkerLightColor =
|
||||
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
|
||||
::XCEngine::UI::UIColor checkerDarkColor =
|
||||
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||
::XCEngine::UI::UIColor sliderBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor numericBoxColor =
|
||||
::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
|
||||
::XCEngine::UI::UIColor numericBoxBorderColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor numericBoxTextColor =
|
||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||
::XCEngine::UI::UIColor closeButtonColor =
|
||||
::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
::XCEngine::UI::UIColor closeButtonHoverColor =
|
||||
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
::XCEngine::UI::UIColor closeGlyphColor =
|
||||
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
|
||||
::XCEngine::UI::UIColor handleFillColor =
|
||||
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
::XCEngine::UI::UIColor handleStrokeColor =
|
||||
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 0.5f);
|
||||
float controlTrailingInset = 9.0f;
|
||||
float controlMinWidth = 88.0f;
|
||||
float dropdownArrowWidth = 14.0f;
|
||||
float vectorComponentMinWidth = 74.0f;
|
||||
float vectorPrefixWidth = 18.0f;
|
||||
float vectorPrefixGap = 5.0f;
|
||||
};
|
||||
|
||||
struct UIEditorFieldRowLayoutMetrics {
|
||||
float rowHeight = 22.0f;
|
||||
float horizontalPadding = 12.0f;
|
||||
float labelControlGap = 20.0f;
|
||||
float controlColumnStart = 236.0f;
|
||||
float controlMinWidth = 0.0f;
|
||||
float controlTrailingInset = 8.0f;
|
||||
float controlInsetY = 1.0f;
|
||||
};
|
||||
|
||||
struct UIEditorFieldRowLayout {
|
||||
::XCEngine::UI::UIRect bounds = {};
|
||||
::XCEngine::UI::UIRect labelRect = {};
|
||||
::XCEngine::UI::UIRect controlRect = {};
|
||||
};
|
||||
|
||||
const UIEditorInspectorFieldStyleTokens& GetUIEditorInspectorFieldStyleTokens();
|
||||
|
||||
bool AreUIEditorFieldMetricsEqual(float lhs, float rhs);
|
||||
|
||||
bool AreUIEditorFieldColorsEqual(
|
||||
const ::XCEngine::UI::UIColor& lhs,
|
||||
const ::XCEngine::UI::UIColor& rhs);
|
||||
|
||||
UIEditorFieldRowLayout BuildUIEditorFieldRowLayout(
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
float minimumControlWidth,
|
||||
const UIEditorFieldRowLayoutMetrics& metrics = {});
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
154
editor/include/XCEditor/Widgets/UIEditorTextLayout.h
Normal file
154
editor/include/XCEditor/Widgets/UIEditorTextLayout.h
Normal file
@@ -0,0 +1,154 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
|
||||
#include <XCEngine/UI/Text/UITextEditing.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
inline float MeasureUIEditorTextLayoutHeight(float fontSize) {
|
||||
return (std::max)(0.0f, fontSize * 1.35f);
|
||||
}
|
||||
|
||||
inline float ResolveUIEditorTextTop(
|
||||
const ::XCEngine::UI::UIRect& rect,
|
||||
float fontSize,
|
||||
float offsetY = 0.0f) {
|
||||
const float textHeight = MeasureUIEditorTextLayoutHeight(fontSize);
|
||||
const float centeredTop =
|
||||
rect.y + (std::max)(0.0f, std::floor((rect.height - textHeight) * 0.5f));
|
||||
return centeredTop - 1.0f + offsetY;
|
||||
}
|
||||
|
||||
inline float ResolveUIEditorControlTextTop(
|
||||
const ::XCEngine::UI::UIRect& rect,
|
||||
float fontSize,
|
||||
float offsetY = 0.0f) {
|
||||
const float textHeight = MeasureUIEditorTextLayoutHeight(fontSize);
|
||||
const float centeredTop =
|
||||
rect.y + (std::max)(0.0f, std::floor((rect.height - textHeight) * 0.5f));
|
||||
return centeredTop + offsetY;
|
||||
}
|
||||
|
||||
inline ::XCEngine::UI::UIRect ResolveUIEditorTextClipRect(
|
||||
const ::XCEngine::UI::UIRect& rect,
|
||||
float fontSize) {
|
||||
const float extraPadding = (std::max)(2.0f, std::ceil(fontSize * 0.35f));
|
||||
return ::XCEngine::UI::UIRect(
|
||||
rect.x,
|
||||
rect.y - 1.0f,
|
||||
rect.width,
|
||||
rect.height + extraPadding + 1.0f);
|
||||
}
|
||||
|
||||
inline float MeasureUIEditorTextWidth(
|
||||
const std::string& text,
|
||||
float fontSize,
|
||||
const ::XCEngine::UI::Editor::UIEditorTextMeasurer* textMeasurer = nullptr) {
|
||||
if (textMeasurer != nullptr &&
|
||||
!text.empty() &&
|
||||
fontSize > 0.0f) {
|
||||
return textMeasurer->MeasureTextWidth(
|
||||
::XCEngine::UI::Editor::UIEditorTextMeasureRequest{
|
||||
text,
|
||||
fontSize
|
||||
});
|
||||
}
|
||||
|
||||
return fontSize * 0.56f *
|
||||
static_cast<float>(::XCEngine::UI::Text::CountUtf8Codepoints(text));
|
||||
}
|
||||
|
||||
inline float MeasureUIEditorTextWidthToCaret(
|
||||
const std::string& text,
|
||||
std::size_t caretOffset,
|
||||
float fontSize,
|
||||
const ::XCEngine::UI::Editor::UIEditorTextMeasurer* textMeasurer = nullptr) {
|
||||
const std::size_t clampedCaretOffset = (std::min)(caretOffset, text.size());
|
||||
if (textMeasurer != nullptr &&
|
||||
clampedCaretOffset > 0u &&
|
||||
fontSize > 0.0f) {
|
||||
return textMeasurer->MeasureTextAdvance(
|
||||
::XCEngine::UI::Editor::UIEditorTextMeasureRequest{
|
||||
std::string_view(text.data(), clampedCaretOffset),
|
||||
fontSize
|
||||
});
|
||||
}
|
||||
|
||||
return fontSize * 0.56f *
|
||||
static_cast<float>(::XCEngine::UI::Text::CountUtf8CodepointsInRange(
|
||||
text,
|
||||
0u,
|
||||
clampedCaretOffset));
|
||||
}
|
||||
|
||||
inline std::uint64_t GetUIEditorTextCaretClockNanoseconds() {
|
||||
using Clock = std::chrono::steady_clock;
|
||||
const auto now = Clock::now().time_since_epoch();
|
||||
return static_cast<std::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(now).count());
|
||||
}
|
||||
|
||||
inline bool ShouldBlinkUIEditorTextCaret(std::uint64_t blinkStartNanoseconds) {
|
||||
constexpr std::uint64_t kInitialVisibleDurationNanoseconds = 500000000ull;
|
||||
constexpr std::uint64_t kBlinkPhaseDurationNanoseconds = 500000000ull;
|
||||
|
||||
if (blinkStartNanoseconds == 0u) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::uint64_t nowNanoseconds = GetUIEditorTextCaretClockNanoseconds();
|
||||
if (nowNanoseconds <= blinkStartNanoseconds) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::uint64_t elapsedNanoseconds = nowNanoseconds - blinkStartNanoseconds;
|
||||
if (elapsedNanoseconds < kInitialVisibleDurationNanoseconds) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::uint64_t blinkElapsedNanoseconds =
|
||||
elapsedNanoseconds - kInitialVisibleDurationNanoseconds;
|
||||
return ((blinkElapsedNanoseconds / kBlinkPhaseDurationNanoseconds) % 2u) == 0u;
|
||||
}
|
||||
|
||||
inline void AppendUIEditorTextCaret(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const ::XCEngine::UI::UIRect& rect,
|
||||
const std::string& text,
|
||||
std::size_t caretOffset,
|
||||
std::uint64_t blinkStartNanoseconds,
|
||||
const ::XCEngine::UI::UIColor& color,
|
||||
float fontSize,
|
||||
float insetX,
|
||||
float insetY = 0.0f,
|
||||
float thickness = 1.0f,
|
||||
const ::XCEngine::UI::Editor::UIEditorTextMeasurer* textMeasurer = nullptr) {
|
||||
if (color.a <= 0.0f || !ShouldBlinkUIEditorTextCaret(blinkStartNanoseconds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float caretX = (std::min)(
|
||||
rect.x + rect.width - 1.0f,
|
||||
rect.x + insetX +
|
||||
MeasureUIEditorTextWidthToCaret(
|
||||
text,
|
||||
caretOffset,
|
||||
fontSize,
|
||||
textMeasurer));
|
||||
const float top = ResolveUIEditorControlTextTop(rect, fontSize, insetY);
|
||||
const float bottom = top + MeasureUIEditorTextLayoutHeight(fontSize);
|
||||
drawList.AddLine(
|
||||
::XCEngine::UI::UIPoint(caretX, top),
|
||||
::XCEngine::UI::UIPoint(caretX, bottom),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
Reference in New Issue
Block a user