Covellite++  Version: 2.3.0 Revision: ??? Platform: x64 Build: 23:13 04.01.2025
Кроссплатформенный фреймворк для разработки приложений на С++
Загрузка...
Поиск...
Не найдено
Window.windows.cpp
1
2#include "stdafx.h"
3#include <Covellite/Os/Window.hpp>
4#include <windowsx.h>
5#include <windef.h>
6#include <winuser.h>
7#include <alicorn/std/string.hpp>
8#include <alicorn/std/string-cast.hpp>
9#include <alicorn/platform/winapi-check.hpp>
10#include <alicorn/version.hpp>
11#include <Covellite/Events.hpp>
12#include <Covellite/App/IApplication.hpp>
13#include <Covellite/App/Settings.hpp>
14#include <Covellite/App/Events.hpp>
15#include <Covellite/Os/Events.hpp>
16#include <Covellite.App/Covellite.App/ClassName.windows.hpp>
17
18#undef CreateWindow
19
20namespace covellite
21{
22
23namespace os
24{
25
26static HWND CreateWindow(const wchar_t * _ClassName,
27 const alicorn::modules::settings::Section & _WindowSettings,
28 long & _MinWindowWidth, long & _MinWindowHeight)
29{
30 using Info_t = alicorn::system::version::Info;
31 using namespace ::alicorn::extension::std;
32
33 const auto ApplicationName =
34 string_cast<::std::wstring>(Info_t{}.GetValue(uT("ApplicationName")));
35
36 const auto ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
37 const auto ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
38
39 auto WindowFlags = WS_POPUP;
40 auto WindowFlagsEx = 0;
41
42 auto X = 0;
43 auto Y = 0;
44 auto WindowWidth = ScreenWidth;
45 auto WindowHeight = ScreenHeight;
46
47 const auto IsFullScreen = _WindowSettings.Get<String>(uT("IsFullScreen"));
48 if (IsFullScreen == uT("false"))
49 {
50 WindowFlags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
51 WindowFlagsEx = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
52
53 const auto & SizeSection = _WindowSettings[uT("Size")];
54
55 const auto IsResized = _WindowSettings.Get<String>(uT("IsResized"));
56 if (IsResized == uT("false"))
57 {
58 WindowFlags ^= WS_THICKFRAME | WS_MAXIMIZEBOX;
59 }
60 else
61 {
62 const auto MinClientWidth = SizeSection.Get<int>(uT("MinClientWidth"));
63 const auto MinClientHeight = SizeSection.Get<int>(uT("MinClientHeight"));
64
65 RECT WindowRect = { 0, 0, MinClientWidth, MinClientHeight };
66 WINAPI_CHECK USING_MOCK ::AdjustWindowRectEx(&WindowRect,
67 WindowFlags, FALSE, WindowFlagsEx);
68
69 _MinWindowWidth = WindowRect.right - WindowRect.left;
70 _MinWindowHeight = WindowRect.bottom - WindowRect.top;
71 }
72
73 const auto ClientWidth = SizeSection.Get<int>(uT("Width"));
74 const auto ClientHeight = SizeSection.Get<int>(uT("Height"));
75
76 RECT WindowRect = { 0, 0, ClientWidth, ClientHeight };
77 WINAPI_CHECK USING_MOCK ::AdjustWindowRectEx(&WindowRect,
78 WindowFlags, FALSE, WindowFlagsEx);
79
80 const auto CalculatedWindowWidth = WindowRect.right - WindowRect.left;
81 WindowWidth = (CalculatedWindowWidth > ScreenWidth) ?
82 ScreenWidth : CalculatedWindowWidth;
83
84 const auto CalculatedWindowHeight = WindowRect.bottom - WindowRect.top;
85 WindowHeight = (CalculatedWindowHeight > ScreenHeight) ?
86 ScreenHeight : CalculatedWindowHeight;
87
88 X = (ScreenWidth - WindowWidth) / 2;
89 Y = (ScreenHeight - WindowHeight) / 2;
90 }
91
92 const auto hWnd = USING_MOCK ::CreateWindowEx(WindowFlagsEx,
93 _ClassName, ApplicationName.c_str(), WindowFlags,
94 X, Y, WindowWidth, WindowHeight, nullptr, nullptr,
95 GetModuleHandle(nullptr), nullptr);
96 WINAPI_CHECK (hWnd != NULL);
97
98 // Игнорирование предупреждений при анализе кода (анализатор не понимает,
99 // что макрос WINAPI_CHECK вызывает исключение при нулевом значении
100 // m_Handle и что в этом случае последующий код не может быть выполнен).
101# pragma warning(push)
102# pragma warning(disable: 6387)
103 USING_MOCK ::ShowWindow(hWnd, SW_SHOW);
104# pragma warning(pop)
105
106 return hWnd;
107}
108
109Window::Window(const ::covellite::app::IApplication & _Application) :
110 m_Events(_Application),
111 m_Handle(::covellite::os::CreateWindow(::covellite::app::ClassName,
112 ::covellite::app::Settings_t::GetInstance()[uT("Window")],
113 m_MinWindowWidth, m_MinWindowHeight)),
114 m_LastTypeSizeMessage(SIZE_RESTORED)
115{
116 USING_MOCK ::SetWindowLongPtrW(::covellite::any_cast<HWND>(m_Handle),
117 GWLP_USERDATA, reinterpret_cast<LONG_PTR>(&m_Events));
118
119 ActivateApplicationEvents();
120 ActivateResizeEvents();
121 ActivateMouseEvents();
122 ActivateKeyEvents();
123}
124
125Window::~Window(void) noexcept
126{
127 USING_MOCK ::DestroyWindow(::covellite::any_cast<HWND>(m_Handle));
128}
129
130Rect Window::GetClientRect(void) const /*override*/
131{
132 RECT ClientRect = { 0 };
133 WINAPI_CHECK USING_MOCK ::GetClientRect(
134 ::covellite::any_cast<HWND>(m_Handle), &ClientRect);
135 return { 0, 0,
136 ClientRect.right - ClientRect.left, ClientRect.bottom - ClientRect.top };
137}
138
139void Window::ActivateApplicationEvents(void)
140{
141 using RawParams_t = ::std::pair<WPARAM, LPARAM>;
142
143 m_Events[(UINT)WM_CLOSE].Connect([=](void)
144 {
145 m_Events[events::Application.Exit]();
146 });
147
148 m_Events[(UINT)WM_ACTIVATEAPP].Connect([=](const RawParams_t & _Params)
149 {
150 if (_Params.first == TRUE)
151 {
152 m_Events[events::Window.Activate]();
153 }
154 else if (_Params.first == FALSE)
155 {
156 m_Events[events::Window.Deactivate]();
157 }
158 });
159}
160
161void Window::ActivateResizeEvents(void)
162{
163 using RawParams_t = ::std::pair<WPARAM, LPARAM>;
164
165 m_Events[(UINT)WM_EXITSIZEMOVE].Connect([=](void)
166 {
167 // Это событие вызывается также и в конце перетаскивания окна за заголовок
168 // (без изменения размера), но задержки перерисовки окна это не вызывает.
169 m_Events[events::Window.Resize]();
170 });
171
172 m_Events[(UINT)WM_SIZE].Connect([=](const RawParams_t & _Params)
173 {
174 // SIZE_MAXIMIZED - развернуто на весь экран.
175 // SIZE_MINIMIZED - свернуто в панель задач (при этом размеры окна
176 // устанавливаются в 0 и это вызывает проблемы рисования).
177 // SIZE_RESTORED - вернулось в обычный размер из панели задач или
178 // всего экрана и при изменении размеров окна мышью.
179 const auto Type = _Params.first;
180
181 if (Type == SIZE_MAXIMIZED ||
182 (Type == SIZE_RESTORED && m_LastTypeSizeMessage != SIZE_RESTORED))
183 {
184 m_Events[events::Window.Resize]();
185 }
186
187 if (Type == SIZE_MAXIMIZED ||
188 Type == SIZE_MINIMIZED ||
189 Type == SIZE_RESTORED)
190 {
191 m_LastTypeSizeMessage = Type;
192 }
193 });
194
195 m_Events[(UINT)WM_GETMINMAXINFO].Connect([=](const RawParams_t & _Params)
196 {
197 auto * const pInfo = reinterpret_cast<MINMAXINFO *>(_Params.second);
198 pInfo->ptMinTrackSize.x = m_MinWindowWidth;
199 pInfo->ptMinTrackSize.y = m_MinWindowHeight;
200 });
201}
202
203void Window::ActivateMouseEvents(void)
204{
205 using RawParams_t = ::std::pair<WPARAM, LPARAM>;
206 using Position_t = events::Cursor_t::Position;
207
208 m_Events[(UINT)WM_MOUSEMOVE].Connect([&](const RawParams_t & _Params)
209 {
210 const auto X = GET_X_LPARAM(_Params.second);
211 const auto Y = GET_Y_LPARAM(_Params.second);
212 m_Events[events::Cursor.Motion](Position_t{ X, Y });
213 });
214
215 m_Events[(UINT)WM_LBUTTONDOWN].Connect([=](void)
216 {
217 m_Events[events::Cursor.Touch]();
218 });
219
220 m_Events[(UINT)WM_LBUTTONUP].Connect([=](void)
221 {
222 m_Events[events::Cursor.Release]();
223 });
224}
225
226void Window::ActivateKeyEvents(void)
227{
228 using RawParams_t = ::std::pair<WPARAM, LPARAM>;
229
230 m_Events[(UINT)WM_CHAR].Connect([=](const RawParams_t & _Params)
231 {
232 auto KeyCode = static_cast<int32_t>(_Params.first);
233
234 // Управляющие символы (кроме перевода строки) должны передавать через
235 // сигнал KeyUp.
236 if (KeyCode < VK_SPACE && KeyCode != VK_RETURN) return;
237
238 // Это преобразование виртуального кода кнопки ENTER в Unicode код символа
239 // переноса строки.
240 if (KeyCode == VK_RETURN) KeyCode = 0x0A;
241
242 m_Events[events::Key.Pressed](KeyCode);
243 });
244
245 const auto pKeyMap = ::std::make_shared<::std::map<int32_t, bool>>();
246
247 m_Events[(UINT)WM_KEYDOWN].Connect([=](const RawParams_t & _Params)
248 {
249 const auto KeyCode = static_cast<int32_t>(_Params.first);
250
251 if ((*pKeyMap)[KeyCode]) return;
252
253 (*pKeyMap)[KeyCode] = true;
254 m_Events[events::Key.Down](KeyCode);
255 });
256
257 m_Events[(UINT)WM_KEYUP].Connect([=](const RawParams_t & _Params)
258 {
259 const auto KeyCode = static_cast<int32_t>(_Params.first);
260
261 (*pKeyMap)[KeyCode] = false;
262 m_Events[events::Key.Up](KeyCode);
263 });
264
265 m_Events[(UINT)WM_SYSKEYUP].Connect([=](const RawParams_t & _Params)
266 {
267 if (_Params.first == VK_LEFT)
268 {
269 m_Events[events::Key.Back]();
270 }
271 else if (_Params.first == VK_SPACE)
272 {
273 m_Events[events::Key.Menu]();
274 }
275 });
276}
277
278} // namespace os
279
280} // namespace covellite
::alicorn::extension::std::Singleton< const Section_t & > Settings_t
Класс входит в проект Covellite.App Класс доступа к настройкам фреймворка.
Definition Settings.hpp:37