feat(new_editor): add project panel and polish dock chrome

This commit is contained in:
2026-04-11 20:20:30 +08:00
parent 030230eb1f
commit 0a015b52ca
12 changed files with 1455 additions and 52 deletions

View File

@@ -38,6 +38,20 @@ D2D1_RECT_F ToD2DRect(const ::XCEngine::UI::UIRect& rect, float dpiScale) {
return D2D1::RectF(left, top, right, bottom);
}
D2D1_POINT_2F ToD2DPoint(
const ::XCEngine::UI::UIPoint& point,
float dpiScale,
float pixelOffset = 0.0f) {
return D2D1::Point2F(
SnapToPixel(point.x, dpiScale) + pixelOffset,
SnapToPixel(point.y, dpiScale) + pixelOffset);
}
float ResolveStrokePixelOffset(float thickness) {
const float roundedThickness = std::round(thickness);
return std::fmod(roundedThickness, 2.0f) == 1.0f ? 0.5f : 0.0f;
}
} // namespace
bool NativeRenderer::Initialize(HWND hwnd) {
@@ -458,6 +472,51 @@ void NativeRenderer::RenderCommand(
}
break;
}
case ::XCEngine::UI::UIDrawCommandType::FilledRectLinearGradient: {
const D2D1_RECT_F rect = ToD2DRect(command.rect, dpiScale);
const float rounding = command.rounding > 0.0f ? command.rounding * dpiScale : 0.0f;
const D2D1_GRADIENT_STOP stops[2] = {
D2D1::GradientStop(0.0f, ToD2DColor(command.color)),
D2D1::GradientStop(1.0f, ToD2DColor(command.secondaryColor))
};
Microsoft::WRL::ComPtr<ID2D1GradientStopCollection> stopCollection;
HRESULT hr = renderTarget.CreateGradientStopCollection(
stops,
2u,
stopCollection.ReleaseAndGetAddressOf());
if (FAILED(hr) || !stopCollection) {
break;
}
const D2D1_POINT_2F startPoint =
command.gradientDirection == ::XCEngine::UI::UILinearGradientDirection::Vertical
? D2D1::Point2F((rect.left + rect.right) * 0.5f, rect.top)
: D2D1::Point2F(rect.left, (rect.top + rect.bottom) * 0.5f);
const D2D1_POINT_2F endPoint =
command.gradientDirection == ::XCEngine::UI::UILinearGradientDirection::Vertical
? D2D1::Point2F((rect.left + rect.right) * 0.5f, rect.bottom)
: D2D1::Point2F(rect.right, (rect.top + rect.bottom) * 0.5f);
Microsoft::WRL::ComPtr<ID2D1LinearGradientBrush> gradientBrush;
hr = renderTarget.CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(startPoint, endPoint),
stopCollection.Get(),
gradientBrush.ReleaseAndGetAddressOf());
if (FAILED(hr) || !gradientBrush) {
break;
}
if (command.rounding > 0.0f) {
renderTarget.FillRoundedRectangle(
D2D1::RoundedRect(rect, rounding, rounding),
gradientBrush.Get());
} else {
renderTarget.FillRectangle(rect, gradientBrush.Get());
}
break;
}
case ::XCEngine::UI::UIDrawCommandType::RectOutline: {
const D2D1_RECT_F rect = ToD2DRect(command.rect, dpiScale);
const float thickness = (command.thickness > 0.0f ? command.thickness : 1.0f) * dpiScale;
@@ -472,6 +531,58 @@ void NativeRenderer::RenderCommand(
}
break;
}
case ::XCEngine::UI::UIDrawCommandType::Line: {
const float thickness = (command.thickness > 0.0f ? command.thickness : 1.0f) * dpiScale;
const float pixelOffset = ResolveStrokePixelOffset(thickness);
const D2D1_POINT_2F start = ToD2DPoint(command.position, dpiScale, pixelOffset);
const D2D1_POINT_2F end = ToD2DPoint(command.uvMin, dpiScale, pixelOffset);
renderTarget.DrawLine(start, end, &solidBrush, thickness);
break;
}
case ::XCEngine::UI::UIDrawCommandType::FilledTriangle: {
Microsoft::WRL::ComPtr<ID2D1PathGeometry> geometry;
HRESULT hr = m_d2dFactory->CreatePathGeometry(geometry.ReleaseAndGetAddressOf());
if (FAILED(hr) || !geometry) {
break;
}
Microsoft::WRL::ComPtr<ID2D1GeometrySink> sink;
hr = geometry->Open(sink.ReleaseAndGetAddressOf());
if (FAILED(hr) || !sink) {
break;
}
const D2D1_POINT_2F a = ToD2DPoint(command.position, dpiScale);
const D2D1_POINT_2F b = ToD2DPoint(command.uvMin, dpiScale);
const D2D1_POINT_2F c = ToD2DPoint(command.uvMax, dpiScale);
const D2D1_POINT_2F points[2] = { b, c };
sink->BeginFigure(a, D2D1_FIGURE_BEGIN_FILLED);
sink->AddLines(points, 2u);
sink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = sink->Close();
if (FAILED(hr)) {
break;
}
renderTarget.FillGeometry(geometry.Get(), &solidBrush);
break;
}
case ::XCEngine::UI::UIDrawCommandType::FilledCircle: {
const float radius = command.radius * dpiScale;
renderTarget.FillEllipse(
D2D1::Ellipse(ToD2DPoint(command.position, dpiScale), radius, radius),
&solidBrush);
break;
}
case ::XCEngine::UI::UIDrawCommandType::CircleOutline: {
const float radius = command.radius * dpiScale;
const float thickness = (command.thickness > 0.0f ? command.thickness : 1.0f) * dpiScale;
renderTarget.DrawEllipse(
D2D1::Ellipse(ToD2DPoint(command.position, dpiScale), radius, radius),
&solidBrush,
thickness);
break;
}
case ::XCEngine::UI::UIDrawCommandType::Text: {
if (command.text.empty()) {
break;