1 | // LAF Library |
2 | // Copyright (c) 2021 Igara Studio S.A. |
3 | // |
4 | // This file is released under the terms of the MIT license. |
5 | // Read LICENSE.txt for more information. |
6 | |
7 | #include "os/os.h" |
8 | |
9 | class CustomWindow { |
10 | public: |
11 | void create(const std::string& title, |
12 | int w, int h, |
13 | os::Window* parent = nullptr) { |
14 | os::WindowSpec spec; |
15 | |
16 | if (parent) { |
17 | spec.floating(true); |
18 | spec.parent(parent); |
19 | spec.minimizable(false); |
20 | |
21 | gfx::Rect rc = parent->frame(); |
22 | spec.frame(gfx::Rect(rc.x2()-w/2, rc.y+rc.h/2-h/2, w, h)); |
23 | spec.position(os::WindowSpec::Position::Frame); |
24 | } |
25 | else { |
26 | spec.contentRect(gfx::Rect(0, 0, w, h)); |
27 | spec.position(os::WindowSpec::Position::Default); |
28 | } |
29 | |
30 | m_nativeWindow = os::instance()->makeWindow(spec); |
31 | m_nativeWindow->setTitle(title); |
32 | m_nativeWindow->setUserData(this); |
33 | |
34 | redraw(); |
35 | } |
36 | |
37 | void close() { |
38 | m_nativeWindow = nullptr; |
39 | } |
40 | |
41 | void focus() { |
42 | m_nativeWindow->activate(); |
43 | } |
44 | |
45 | bool isVisible() const { |
46 | return (m_nativeWindow && m_nativeWindow->isVisible()); |
47 | } |
48 | |
49 | void redraw() { |
50 | auto rc = m_nativeWindow->surface()->bounds(); |
51 | onRedraw(m_nativeWindow->surface(), rc); |
52 | |
53 | if (m_nativeWindow->isVisible()) |
54 | m_nativeWindow->invalidateRegion(gfx::Region(rc)); |
55 | else |
56 | m_nativeWindow->setVisible(true); |
57 | } |
58 | |
59 | virtual bool isFloating() const { |
60 | return false; |
61 | } |
62 | |
63 | virtual bool handleEvent(os::Event& ev) { |
64 | switch (ev.type()) { |
65 | |
66 | case os::Event::CloseWindow: |
67 | return false; |
68 | |
69 | case os::Event::ResizeWindow: |
70 | redraw(); |
71 | break; |
72 | |
73 | case os::Event::KeyDown: |
74 | if (ev.scancode() == os::kKeyEsc) |
75 | return false; |
76 | else if (ev.scancode() == os::kKeyEnter || |
77 | ev.scancode() == os::kKeyEnterPad) |
78 | onEnterKey(); |
79 | break; |
80 | } |
81 | return true; |
82 | } |
83 | |
84 | protected: |
85 | virtual void onRedraw(os::Surface* surface, const gfx::Rect& rc) { } |
86 | virtual void onEnterKey() { } |
87 | |
88 | os::WindowRef nativeWindow() const { return m_nativeWindow; } |
89 | |
90 | private: |
91 | os::WindowRef m_nativeWindow; |
92 | }; |
93 | |
94 | class FloatingWindow : public CustomWindow { |
95 | public: |
96 | void recreate(os::Window* parent) { |
97 | create("Floating" , 200, 200, parent); |
98 | } |
99 | |
100 | bool isFloating() const override { |
101 | return true; |
102 | } |
103 | |
104 | private: |
105 | void onRedraw(os::Surface* surface, const gfx::Rect& rc) override { |
106 | os::Paint paint; |
107 | paint.color(gfx::rgba(200, 150, 150)); |
108 | surface->drawRect(rc, paint); |
109 | } |
110 | |
111 | bool handleEvent(os::Event& ev) override { |
112 | if (!CustomWindow::handleEvent(ev)) |
113 | close(); |
114 | return true; |
115 | } |
116 | |
117 | }; |
118 | |
119 | class MainWindow : public CustomWindow { |
120 | public: |
121 | MainWindow() { |
122 | create("Main" , 500, 400); |
123 | createFloating(); |
124 | } |
125 | |
126 | private: |
127 | void onRedraw(os::Surface* surface, const gfx::Rect& rc) override { |
128 | os::Paint p; |
129 | p.color(gfx::rgba(150, 150, 200)); |
130 | surface->drawRect(rc, p); |
131 | |
132 | p.color(gfx::rgba(50, 50, 100)); |
133 | |
134 | gfx::Point pos = rc.center(); |
135 | os::draw_text(surface, nullptr, "Press ENTER key to hide/show the floating window" , |
136 | pos, &p, os::TextAlign::Center); |
137 | |
138 | pos.y += 24; |
139 | os::draw_text(surface, nullptr, "Press ESC to quit" , |
140 | pos, &p, os::TextAlign::Center); |
141 | } |
142 | |
143 | void onEnterKey() override { |
144 | if (m_floating.isVisible()) |
145 | m_floating.close(); |
146 | else { |
147 | createFloating(); |
148 | } |
149 | } |
150 | |
151 | void createFloating() { |
152 | m_floating.recreate(nativeWindow().get()); |
153 | |
154 | // Focus the main window (so the floating window is not focused by |
155 | // default) |
156 | focus(); |
157 | } |
158 | |
159 | FloatingWindow m_floating; |
160 | }; |
161 | |
162 | int app_main(int argc, char* argv[]) |
163 | { |
164 | auto system = os::make_system(); |
165 | system->setAppMode(os::AppMode::GUI); |
166 | system->handleWindowResize = |
167 | [](os::Window* window){ |
168 | window->userData<CustomWindow>()->redraw(); |
169 | }; |
170 | |
171 | MainWindow mainWindow; |
172 | |
173 | system->finishLaunching(); |
174 | system->activateApp(); |
175 | |
176 | os::EventQueue* queue = system->eventQueue(); |
177 | os::Event ev; |
178 | bool done = false; |
179 | while (!done) { |
180 | queue->getEvent(ev); |
181 | |
182 | // Closing the app |
183 | if (ev.type() == os::Event::CloseApp) { |
184 | break; |
185 | } |
186 | // Each window handle the event |
187 | else if (ev.window()) { |
188 | CustomWindow* win = ev.window()->userData<CustomWindow>(); |
189 | if (!win->handleEvent(ev)) |
190 | break; |
191 | } |
192 | } |
193 | |
194 | return 0; |
195 | } |
196 | |