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
9class CustomWindow {
10public:
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
84protected:
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
90private:
91 os::WindowRef m_nativeWindow;
92};
93
94class FloatingWindow : public CustomWindow {
95public:
96 void recreate(os::Window* parent) {
97 create("Floating", 200, 200, parent);
98 }
99
100 bool isFloating() const override {
101 return true;
102 }
103
104private:
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
119class MainWindow : public CustomWindow {
120public:
121 MainWindow() {
122 create("Main", 500, 400);
123 createFloating();
124 }
125
126private:
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
162int 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