aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui/controls/toggle_button.cpp
blob: ea2329ea24c6037122350fd6c57bc789fb33599e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "toggle_button.h"

#include "graph/graph.h"

namespace cru::ui::controls
{
    using graph::CreateSolidBrush;

    // ui length parameters of toggle button.
    constexpr float half_height = 15;
    constexpr float half_width = half_height * 2;
    constexpr float stroke_width = 3;
    constexpr float inner_circle_radius = half_height - stroke_width;
    constexpr float inner_circle_x = half_width - half_height;

    ToggleButton::ToggleButton()
    {
        graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRoundedRectangleGeometry(D2D1::RoundedRect(D2D1::RectF(-half_width, -half_height, half_width, half_height), half_height, half_height), &frame_path_);

        on_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightBlue));
        off_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightGray));
    }

    inline D2D1_POINT_2F ConvertPoint(const Point& point)
    {
        return D2D1::Point2F(point.x, point.y);
    }

    bool ToggleButton::IsPointInside(const Point& point)
    {
        const auto size = GetSize();
        const auto transform = D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2);
        BOOL contains;
        frame_path_->FillContainsPoint(ConvertPoint(point), transform, &contains);
        if (!contains)
            frame_path_->StrokeContainsPoint(ConvertPoint(point), stroke_width, nullptr, transform, &contains);
        return contains != 0;
    }

    void ToggleButton::SetState(const bool state)
    {
        if (state != state_)
        {
            state_ = state;
            OnToggleInternal(state);
            Repaint();
        }
    }

    void ToggleButton::Toggle()
    {
        SetState(!GetState());
    }

    void ToggleButton::OnToggle(events::ToggleEventArgs& args)
    {

    }

    void ToggleButton::OnDraw(ID2D1DeviceContext* device_context)
    {
        const auto size = GetSize();
        graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2), [this](ID2D1DeviceContext* device_context)
        {
            if (state_)
            {
                device_context->DrawGeometry(frame_path_.Get(), on_brush_.Get(), stroke_width);
                device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(inner_circle_x, 0), inner_circle_radius, inner_circle_radius), on_brush_.Get());
            }
            else
            {
                device_context->DrawGeometry(frame_path_.Get(), off_brush_.Get(), stroke_width);
                device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(-inner_circle_x, 0), inner_circle_radius, inner_circle_radius), off_brush_.Get());
            }
        });
    }

    void ToggleButton::OnMouseClickCore(events::MouseButtonEventArgs& args)
    {
        Control::OnMouseClickCore(args);
        Toggle();
    }

    Size ToggleButton::OnMeasure(const Size& available_size)
    {
        const auto layout_params = GetLayoutParams();

        auto&& get_measure_length = [](const MeasureLength& layout_length, const float available_length, const float fix_length) -> float
        {
            switch (layout_length.mode)
            {
            case MeasureMode::Exactly:
            {
                return std::max(std::min(layout_length.length, available_length), fix_length);
            }
            case MeasureMode::Stretch:
            {
                return std::max(available_length, fix_length);
            }
            case MeasureMode::Content:
            {
                return fix_length;
            }
            default:
                UnreachableCode();
            }
        };

        const Size result_size(
            get_measure_length(layout_params->width, available_size.width, half_width * 2 + stroke_width),
            get_measure_length(layout_params->height, available_size.height, half_height * 2 + stroke_width)
        );

        return result_size;
    }

    void ToggleButton::OnToggleInternal(bool new_state)
    {
        events::ToggleEventArgs args(this, this, new_state);
        OnToggle(args);
        toggle_event.Raise(args);
    }
}