From 7703063a5816b089483e78ccd74bb9902ccfbea8 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 13 Mar 2021 17:40:18 +0800 Subject: ... --- include/cru/platform/Matrix.hpp | 5 +++ include/cru/platform/graphics/Painter.hpp | 4 +- include/cru/platform/graphics/util/Painter.hpp | 2 +- include/cru/ui/render/ScrollBar.hpp | 3 ++ include/cru/win/graphics/direct/Painter.hpp | 2 + src/ui/render/ScrollBar.cpp | 56 ++++++++++++++++++++++---- src/win/graphics/direct/Painter.cpp | 8 ++++ test/CMakeLists.txt | 9 ++++- test/platform/CMakeLists.txt | 6 +++ test/platform/MatrixTest.cpp | 37 +++++++++++++++++ test/win/CMakeLists.txt | 1 + test/win/graphics/CMakeLists.txt | 1 + test/win/graphics/direct/CMakeLists.txt | 6 +++ test/win/graphics/direct/ConvertTest.cpp | 29 +++++++++++++ 14 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 test/platform/CMakeLists.txt create mode 100644 test/platform/MatrixTest.cpp create mode 100644 test/win/CMakeLists.txt create mode 100644 test/win/graphics/CMakeLists.txt create mode 100644 test/win/graphics/direct/CMakeLists.txt create mode 100644 test/win/graphics/direct/ConvertTest.cpp diff --git a/include/cru/platform/Matrix.hpp b/include/cru/platform/Matrix.hpp index e702df90..8ec5faaa 100644 --- a/include/cru/platform/Matrix.hpp +++ b/include/cru/platform/Matrix.hpp @@ -50,10 +50,15 @@ struct Matrix { return Matrix{1.0f, 0.0f, 0.0f, 1.0f, x, y}; } + static Matrix Translation(const Point& point) { + return Translation(point.x, point.y); + } + static Matrix Scale(float sx, float sy) { return Matrix{sx, 0.0f, 0.0f, sy, 0.0f, 0.0f}; } + // Clockwise. static Matrix Rotation(float angle) { float r = AngleToRadian(angle); float s = std::sin(r); diff --git a/include/cru/platform/graphics/Painter.hpp b/include/cru/platform/graphics/Painter.hpp index 76140c32..f75ea52b 100644 --- a/include/cru/platform/graphics/Painter.hpp +++ b/include/cru/platform/graphics/Painter.hpp @@ -9,6 +9,8 @@ struct IPainter : virtual INativeResource { virtual void Clear(const Color& color) = 0; + virtual void DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) = 0; virtual void StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) = 0; virtual void FillRectangle(const Rect& rectangle, IBrush* brush) = 0; @@ -26,4 +28,4 @@ struct IPainter : virtual INativeResource { virtual void EndDraw() = 0; }; -} // namespace cru::platform::graph +} // namespace cru::platform::graphics diff --git a/include/cru/platform/graphics/util/Painter.hpp b/include/cru/platform/graphics/util/Painter.hpp index af3a1997..90457cf4 100644 --- a/include/cru/platform/graphics/util/Painter.hpp +++ b/include/cru/platform/graphics/util/Painter.hpp @@ -10,7 +10,7 @@ void WithTransform(IPainter* painter, const Matrix& matrix, const Fn& action) { static_assert(std::is_invocable_v, "Action must can be be invoked with painter."); const auto old = painter->GetTransform(); - painter->SetTransform(old * matrix); + painter->SetTransform(matrix * old); action(painter); painter->SetTransform(old); } diff --git a/include/cru/ui/render/ScrollBar.hpp b/include/cru/ui/render/ScrollBar.hpp index 7cfd2576..3293e9d0 100644 --- a/include/cru/ui/render/ScrollBar.hpp +++ b/include/cru/ui/render/ScrollBar.hpp @@ -3,6 +3,7 @@ #include "cru/common/Base.hpp" #include "cru/common/Event.hpp" #include "cru/platform/graphics/Base.hpp" +#include "cru/platform/graphics/Geometry.hpp" #include "cru/platform/graphics/Painter.hpp" #include "cru/platform/gui/Cursor.hpp" #include "cru/platform/gui/UiApplication.hpp" @@ -102,6 +103,8 @@ class ScrollBar : public Object { protected: gsl::not_null render_object_; + std::unique_ptr arrow_geometry_; + private: Direction direction_; diff --git a/include/cru/win/graphics/direct/Painter.hpp b/include/cru/win/graphics/direct/Painter.hpp index 93c768e7..b34c1563 100644 --- a/include/cru/win/graphics/direct/Painter.hpp +++ b/include/cru/win/graphics/direct/Painter.hpp @@ -27,6 +27,8 @@ class D2DPainter : public DirectResource, void Clear(const Color& color) override; + void DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) override; void StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) override; void FillRectangle(const Rect& rectangle, IBrush* brush) override; diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp index 02e079e9..7f69c1e2 100644 --- a/src/ui/render/ScrollBar.cpp +++ b/src/ui/render/ScrollBar.cpp @@ -4,7 +4,9 @@ #include "cru/common/Base.hpp" #include "cru/platform/GraphBase.hpp" #include "cru/platform/graphics/Factory.hpp" +#include "cru/platform/graphics/Geometry.hpp" #include "cru/platform/graphics/Painter.hpp" +#include "cru/platform/graphics/util/Painter.hpp" #include "cru/platform/gui/Base.hpp" #include "cru/platform/gui/Cursor.hpp" #include "cru/ui/Base.hpp" @@ -16,6 +18,7 @@ #include #include #include +#include #include #include @@ -24,6 +27,7 @@ using namespace std::chrono_literals; constexpr float kScrollBarCollapseThumbWidth = 2; constexpr float kScrollBarCollapsedTriggerExpandAreaWidth = 5; constexpr float kScrollBarExpandWidth = 10; +constexpr float kScrollBarArrowHeight = 3.5; constexpr auto kScrollBarAutoCollapseDelay = 1500ms; constexpr std::array kScrollBarAreaKindList{ @@ -31,6 +35,17 @@ constexpr std::array kScrollBarAreaKindList{ ScrollBarAreaKind::UpSlot, ScrollBarAreaKind::DownSlot, ScrollBarAreaKind::Thumb}; +namespace { +std::unique_ptr CreateScrollBarArrowGeometry() { + auto geometry_builder = GetGraphFactory()->CreateGeometryBuilder(); + geometry_builder->BeginFigure({-kScrollBarArrowHeight / 2, 0}); + geometry_builder->LineTo({kScrollBarArrowHeight / 2, kScrollBarArrowHeight}); + geometry_builder->LineTo({kScrollBarArrowHeight / 2, -kScrollBarArrowHeight}); + geometry_builder->CloseFigure(true); + return geometry_builder->Build(); +} +} // namespace + ScrollBar::ScrollBar(gsl::not_null render_object, Direction direction) : render_object_(render_object), direction_(direction) { @@ -43,10 +58,11 @@ ScrollBar::ScrollBar(gsl::not_null render_object, expanded_thumb_brush_ = graphics_factory->CreateSolidColorBrush(colors::gray); expanded_slot_brush_ = graphics_factory->CreateSolidColorBrush(colors::seashell); - expanded_arrow_brush_ = - graphics_factory->CreateSolidColorBrush(colors::white); + expanded_arrow_brush_ = graphics_factory->CreateSolidColorBrush(colors::gray); expanded_arrow_background_brush_ = - graphics_factory->CreateSolidColorBrush(colors::black); + graphics_factory->CreateSolidColorBrush(colors::seashell); + + arrow_geometry_ = CreateScrollBarArrowGeometry(); } ScrollBar::~ScrollBar() { RestoreCursor(); } @@ -250,7 +266,7 @@ void ScrollBar::OnDraw(platform::graphics::IPainter* painter, if (up_arrow) this->DrawUpArrow(painter, *up_arrow); auto down_arrow = GetExpandedAreaRect(ScrollBarAreaKind::DownArrow); - if (down_arrow) this->DrawUpArrow(painter, *down_arrow); + if (down_arrow) this->DrawDownArrow(painter, *down_arrow); } else { auto optional_rect = GetCollapsedThumbRect(); if (optional_rect) { @@ -313,14 +329,26 @@ HorizontalScrollBar::HorizontalScrollBar( void HorizontalScrollBar::DrawUpArrow(platform::graphics::IPainter* painter, const Rect& area) { - // TODO: Do what you must! painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get()); + + platform::graphics::util::WithTransform( + painter, Matrix::Translation(area.GetCenter()), + [this](platform::graphics::IPainter* painter) { + painter->FillGeometry(arrow_geometry_.get(), + GetExpandedArrowBrush().get().get()); + }); } void HorizontalScrollBar::DrawDownArrow(platform::graphics::IPainter* painter, const Rect& area) { - // TODO: Do what you must! painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get()); + + platform::graphics::util::WithTransform( + painter, Matrix::Rotation(180) * Matrix::Translation(area.GetCenter()), + [this](platform::graphics::IPainter* painter) { + painter->FillGeometry(arrow_geometry_.get(), + GetExpandedArrowBrush().get().get()); + }); } bool HorizontalScrollBar::IsShowBar() { @@ -440,14 +468,26 @@ VerticalScrollBar::VerticalScrollBar( void VerticalScrollBar::DrawUpArrow(platform::graphics::IPainter* painter, const Rect& area) { - // TODO: Do what you must! painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get()); + + platform::graphics::util::WithTransform( + painter, Matrix::Rotation(90) * Matrix::Translation(area.GetCenter()), + [this](platform::graphics::IPainter* painter) { + painter->FillGeometry(arrow_geometry_.get(), + GetExpandedArrowBrush().get().get()); + }); } void VerticalScrollBar::DrawDownArrow(platform::graphics::IPainter* painter, const Rect& area) { - // TODO: Do what you must! painter->FillRectangle(area, GetExpandedArrowBackgroundBrush().get().get()); + + platform::graphics::util::WithTransform( + painter, Matrix::Rotation(270) * Matrix::Translation(area.GetCenter()), + [this](platform::graphics::IPainter* painter) { + painter->FillGeometry(arrow_geometry_.get(), + GetExpandedArrowBrush().get().get()); + }); } bool VerticalScrollBar::IsShowBar() { diff --git a/src/win/graphics/direct/Painter.cpp b/src/win/graphics/direct/Painter.cpp index 91392ba7..d6999cfa 100644 --- a/src/win/graphics/direct/Painter.cpp +++ b/src/win/graphics/direct/Painter.cpp @@ -32,6 +32,14 @@ void D2DPainter::Clear(const Color& color) { render_target_->Clear(Convert(color)); } +void D2DPainter::DrawLine(const Point& start, const Point& end, IBrush* brush, + float width) { + CheckValidation(); + const auto b = CheckPlatform(brush, GetPlatformId()); + render_target_->DrawLine(Convert(start), Convert(end), + b->GetD2DBrushInterface(), width); +} + void D2DPainter::StrokeRectangle(const Rect& rectangle, IBrush* brush, float width) { CheckValidation(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c534b909..3b9567cd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,7 +2,12 @@ find_package(GTest CONFIG REQUIRED) include(GoogleTest) -add_subdirectory(common) - add_library(cru_test_base INTERFACE) target_link_libraries(cru_test_base INTERFACE GTest::gtest GTest::gtest_main) + +add_subdirectory(common) +add_subdirectory(platform) + +if(WIN32) + add_subdirectory(win) +endif() diff --git a/test/platform/CMakeLists.txt b/test/platform/CMakeLists.txt new file mode 100644 index 00000000..9ad8fb51 --- /dev/null +++ b/test/platform/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(cru_platform_base_test + MatrixTest.cpp +) +target_link_libraries(cru_platform_base_test PRIVATE cru_platform_base cru_test_base) + +gtest_discover_tests(cru_platform_base_test) diff --git a/test/platform/MatrixTest.cpp b/test/platform/MatrixTest.cpp new file mode 100644 index 00000000..3b8aab27 --- /dev/null +++ b/test/platform/MatrixTest.cpp @@ -0,0 +1,37 @@ +#include "cru/platform/GraphBase.hpp" +#include "cru/platform/Matrix.hpp" + +#include + +using cru::platform::Matrix; +using cru::platform::Point; + +TEST(Matrix, Rotation) { + Point p(1, 1); + + Point p90 = Matrix::Rotation(90).TransformPoint(p); + ASSERT_FLOAT_EQ(p90.x, -1); + ASSERT_FLOAT_EQ(p90.y, 1); + + Point p180 = Matrix::Rotation(180).TransformPoint(p); + ASSERT_FLOAT_EQ(p180.x, -1); + ASSERT_FLOAT_EQ(p180.y, -1); + + Point p270 = Matrix::Rotation(270).TransformPoint(p); + ASSERT_FLOAT_EQ(p270.x, 1); + ASSERT_FLOAT_EQ(p270.y, -1); +} + +TEST(Matrix, TranslationAndRotation) { + Point p = + (Matrix::Translation(1, 1) * Matrix::Rotation(90)).TransformPoint({1, 1}); + ASSERT_FLOAT_EQ(p.x, -2); + ASSERT_FLOAT_EQ(p.y, 2); +} + +TEST(Matrix, RotationAndTranslation) { + Point p = + (Matrix::Rotation(90) * Matrix::Translation(1, 1)).TransformPoint({1, 1}); + ASSERT_FLOAT_EQ(p.x, 0); + ASSERT_FLOAT_EQ(p.y, 2); +} diff --git a/test/win/CMakeLists.txt b/test/win/CMakeLists.txt new file mode 100644 index 00000000..0ebdd7fe --- /dev/null +++ b/test/win/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(graphics) diff --git a/test/win/graphics/CMakeLists.txt b/test/win/graphics/CMakeLists.txt new file mode 100644 index 00000000..c90537ac --- /dev/null +++ b/test/win/graphics/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(direct) diff --git a/test/win/graphics/direct/CMakeLists.txt b/test/win/graphics/direct/CMakeLists.txt new file mode 100644 index 00000000..69e22ef7 --- /dev/null +++ b/test/win/graphics/direct/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(cru_win_graphics_direct_test + ConvertTest.cpp +) +target_link_libraries(cru_win_graphics_direct_test PRIVATE cru_win_graphics_direct cru_test_base) + +gtest_discover_tests(cru_win_graphics_direct_test) diff --git a/test/win/graphics/direct/ConvertTest.cpp b/test/win/graphics/direct/ConvertTest.cpp new file mode 100644 index 00000000..f8f95dac --- /dev/null +++ b/test/win/graphics/direct/ConvertTest.cpp @@ -0,0 +1,29 @@ +#include "cru/platform/Matrix.hpp" +#include "cru/win/graphics/direct/ConvertUtil.hpp" + +#include + +using cru::platform::Matrix; +using cru::platform::graphics::win::direct::Convert; + +TEST(MatrixConvert, Rotation) { + auto matrix = Convert(Matrix::Rotation(90)); + + auto m = *D2D1::Matrix3x2F::ReinterpretBaseType(&matrix); + + auto p = m.TransformPoint({1, 1}); + + ASSERT_FLOAT_EQ(p.x, -1); + ASSERT_FLOAT_EQ(p.y, 1); +} + +TEST(MatrixConvert, RotationAndTranslation) { + auto matrix = Convert(Matrix::Rotation(90) * Matrix::Translation(1, 1)); + + auto m = *D2D1::Matrix3x2F::ReinterpretBaseType(&matrix); + + auto p = m.TransformPoint({1, 1}); + + ASSERT_FLOAT_EQ(p.x, 0); + ASSERT_FLOAT_EQ(p.y, 2); +} -- cgit v1.2.3