Repository navigation
Expand file tree
/
Copy pathTitleBarWindow.h
More file actions
265 lines (242 loc) · 9.11 KB
/
Copy pathTitleBarWindow.h
File metadata and controls
265 lines (242 loc) · 9.11 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#pragma once
#include "ViewDesign/view/widget/UndecoratedWindow.h"
#include "ViewDesign/view/frame/MutableFrame.h"
#include "ViewDesign/view/frame/PaddingFrame.h"
#include "ViewDesign/view/frame/BorderFrame.h"
#include "ViewDesign/view/frame/CenterFrame.h"
#include "ViewDesign/view/frame/ClipFrame.h"
#include "ViewDesign/view/frame/MaxFrame.h"
#include "ViewDesign/view/frame/BackgroundFrame.h"
#include "ViewDesign/view/layout/SplitLayout.h"
#include "ViewDesign/view/layout/StackLayout.h"
#include "ViewDesign/view/layout/ListLayout.h"
#include "ViewDesign/view/control/Placeholder.h"
#include "ViewDesign/view/control/TextView.h"
#include "ViewDesign/view/wrapper/Button.h"
#include "ViewDesign/view/wrapper/Background.h"
#include "ViewDesign/view/wrapper/Cursor.h"
#include "ViewDesign/view/wrapper/HitTestHelper.h"
#include "ViewDesign/view/widget/Tooltip.h"
#include "ViewDesign/event/mouse_tracker.h"
#include "ViewDesign/messaging/context.h"
#include "ViewDesign/geometry/border_position.h"
#include "ViewDesign/system/window.h"
#if defined(VIEWDESIGN_BACKEND_WIN32)
#include <ViewDesign/platform/win32/aero_snap.h>
#endif
namespace ViewDesign {
class TitleBarWindow : public UndecoratedWindow, ContextProvider {
public:
using child_type = UndecoratedWindow::child_type;
using menu_type = view_ptr<Auto, Fixed>;
public:
struct TitleBarStyle : TextStyle {
struct BarStyle {
public:
float _height = 30.0f;
float _max_title_length = 300.0f;
Color _background_color = ColorCode::CadetBlue;
Color _foreground_color = ColorCode::White;
public:
constexpr BarStyle& height(float height) { _height = height; return *this; }
constexpr BarStyle& max_title_length(float max_title_length) { _max_title_length = max_title_length; return *this; }
constexpr BarStyle& background_color(Color background_color) { _background_color = background_color; return *this; }
constexpr BarStyle& foreground_color(Color foreground_color) { _foreground_color = foreground_color; return *this; }
} bar;
};
struct FrameStyle {
Padding padding = Padding(2.0f);
Border border = Border(2.0f, 2.0f, ColorCode::CadetBlue);
Color background_color = ColorCode::White;
};
struct Style : UndecoratedWindow::Style, FrameStyle {
TitleBarStyle title;
Style() {
title.font.color(title.bar._foreground_color);
}
};
protected:
class ResizeBorder : public CustomizedCursor<CursorStyle::NoChange, HitSelfFallback<BorderFrame<Fixed, Fixed>>> {
public:
using Base::Base;
protected:
virtual void OnMouseEvent(MouseEvent event) override {
if (event.type == MouseEvent::Move || event.type == MouseEvent::LeftDown) {
BorderPosition border_position = HitTestBorderPosition(size, border._width + border._radius, event.point);
if (event.type == MouseEvent::Move) {
SetWindowCursor(desktop.GetWindow(*this).GetHandle(), GetCursor(GetResizeCursorStyle(border_position)));
} else {
#if defined(VIEWDESIGN_BACKEND_WIN32)
Win32::AeroSnapBorderResizingEffect(desktop.GetWindow(*this).GetHandle(), border_position);
#endif
}
}
}
};
class TitleBar : public HitSelfFallback<DefaultBackground<MaxFrame<Fixed, Auto>>>, Context<TitleBarWindow> {
public:
class Title : public TextView {
public:
Title(const TitleBarStyle& style, const u16string& text) : TextView(style, text) {}
};
protected:
class ButtonBase : public Button<DefaultBackground<Placeholder<Auto, Fixed>>>, protected Context<TitleBarWindow> {
public:
ButtonBase(const TitleBarStyle::BarStyle& style, const u16string& tooltip_text = u"") : Base(50.0f), Context(AsViewBase()), foreground(style._foreground_color), tooltip_text(tooltip_text), background_normal(style._background_color) {
this->background = background_normal;
}
~ButtonBase() {
DestroyTooltip(*this);
}
protected:
Color foreground;
const u16string tooltip_text;
protected:
Color background_normal;
protected:
static constexpr Color background_hovered = ColorCode::Gray;
static constexpr Color background_pressed = ColorCode::DimGray;
protected:
virtual void OnHover() override { SetBackground(background_hovered); }
virtual void OnPress() override { SetBackground(background_pressed); }
virtual void OnLeave() override { SetBackground(background_normal); }
protected:
virtual void OnFocusEvent(FocusEvent event) override {
Button::OnFocusEvent(event);
switch (event) {
case FocusEvent::MouseEnter: ShowTooltip(*this, tooltip_text); break;
case FocusEvent::MouseLeave: HideTooltip(*this); break;
}
}
};
class MinimizeButton : public ButtonBase {
public:
using ButtonBase::ButtonBase;
protected:
virtual void OnDraw(Canvas& canvas, Rect draw_region) override {
ButtonBase::OnDraw(canvas, draw_region);
canvas.draw(Point(20.0f, 15.0f), new Rectangle(Size(10.0f, 1.0f), 1.0f, foreground));
}
protected:
virtual void OnClick() override { Context::Get().Minimize(); }
};
class MaximizeButton : public ButtonBase {
public:
using ButtonBase::ButtonBase;
protected:
virtual void OnDraw(Canvas& canvas, Rect draw_region) override {
ButtonBase::OnDraw(canvas, draw_region);
if (Context::Get().IsMaximized()) {
canvas.draw(Point(22.0f, 10.0f), new Rectangle(Size(8.0f, 8.0f), 1.0f, foreground));
canvas.draw(Point(20.0f, 12.0f), new Rectangle(Size(8.0f, 8.0f), background, 1.0f, foreground));
} else {
canvas.draw(Point(20.0f, 10.0f), new Rectangle(Size(10.0f, 10.0f), 1.0f, foreground));
}
}
protected:
virtual void OnClick() override { Context::Get().MaximizeOrRestore(); }
protected:
virtual void OnFocusEvent(FocusEvent event) override {
Button::OnFocusEvent(event);
switch (event) {
case FocusEvent::MouseEnter: ShowTooltip(*this, Context::Get().IsMaximized() ? u"restore" : u"maximize"); break;
case FocusEvent::MouseLeave: HideTooltip(*this); break;
}
}
};
class CloseButton : public ButtonBase {
public:
using ButtonBase::ButtonBase;
protected:
virtual void OnDraw(Canvas& canvas, Rect draw_region) override {
ButtonBase::OnDraw(canvas, draw_region);
canvas.draw(Point(20.0f, 10.0f), new Line(Vector(10.0f, 10.0f), 1.0f, foreground));
canvas.draw(Point(20.0f, 20.0f), new Line(Vector(10.0f, -10.0f), 1.0f, foreground));
}
protected:
virtual void OnClick() override { Context::Get().Close(); }
};
public:
TitleBar(const TitleBarStyle::BarStyle& style, menu_type menu, owner_ptr<Title> title) : Base(
style._height,
new StackLayoutMultiple(
create<HitThrough<CenterFrame<Fixed, Fixed>>>(
new MaxFrame<Auto, Auto>(
Size(style._max_title_length, length_infinite),
std::move(title)
)
),
create<HitThroughMargin<ClipFrame<Fixed, Fixed, Left>>>(
std::move(menu)
),
create<HitThroughMargin<ClipFrame<Fixed, Fixed, Right>>>(
new ListLayoutHorizontal(
0.0f,
create<MinimizeButton>(style, u"minimize"),
create<MaximizeButton>(style),
create<CloseButton>(style, u"close")
)
)
)
), Context(AsViewBase()) {
background = style._background_color;
}
protected:
MouseTracker mouse_tracker;
protected:
virtual void OnMouseEvent(MouseEvent event) override {
switch (mouse_tracker.Track(event)) {
#if defined(VIEWDESIGN_BACKEND_WIN32)
case MouseTrackEvent::LeftDown: Win32::AeroSnapDraggingEffect(desktop.GetWindow(*this).GetHandle()); break;
#endif
case MouseTrackEvent::LeftDoubleClick: Context::Get().MaximizeOrRestore(); break;
}
}
};
public:
TitleBarWindow(const Style& style, const u16string& title, child_type child, menu_type menu = new Placeholder<Auto, Fixed>(0.0f)) : UndecoratedWindow(
style, title,
outer_frame = new MutableFrame(
new PaddingFrame(
style.padding,
border = new ResizeBorder(
style.border,
inner_frame = new MutableFrame(
new SplitLayoutVertical(
new TitleBar(
style.title.bar,
std::move(menu),
title_text_view = new TitleBar::Title(style.title, title)
),
new BackgroundFrame(
style.background_color,
std::move(child)
)
)
)
)
)
)
), ContextProvider(AsViewBase()) {}
protected:
ref_ptr<ResizeBorder> border;
ref_ptr<TitleBar::Title> title_text_view;
public:
void SetTitle(const u16string& str) { title_text_view->Assign(str); Window::SetTitle(str); }
protected:
ref_ptr<MutableFrame<Fixed, Fixed>> outer_frame;
ref_ptr<MutableFrame<Fixed, Fixed>> inner_frame;
view_ptr<Fixed, Fixed> inner_frame_placeholder = new Placeholder<Fixed, Fixed>;
view_ptr<Fixed, Fixed> outer_frame_placeholder = view_ptr<Fixed, Fixed>();
protected:
bool IsMaximized() { return GetState() == State::Maximized; }
void MaximizeOrRestore() { if (GetState() == State::Normal) { Maximize(); } else if (GetState() == State::Maximized) { Restore(); } }
protected:
virtual void OnStateChange(State state) override {
switch (state) {
case State::Normal: if (outer_frame_placeholder) { inner_frame->RotateWith(*outer_frame, outer_frame_placeholder, inner_frame_placeholder); } break;
case State::Maximized: if (inner_frame_placeholder) { inner_frame->RotateWith(inner_frame_placeholder, outer_frame_placeholder, *outer_frame); } break;
}
}
};
} // namespace ViewDesign