Skip to content

Instantly share code, notes, and snippets.

@davepkennedy
Created May 20, 2020 10:19
Show Gist options
  • Save davepkennedy/0d580748d3322b21b569abd29167fc2a to your computer and use it in GitHub Desktop.
Save davepkennedy/0d580748d3322b21b569abd29167fc2a to your computer and use it in GitHub Desktop.
Some Windowing snippets
#include "Application.h"
#include "BaseWindow.h"
Application::Application(BaseWindow* window)
: _window(window)
{
}
Application::~Application()
{
}
void Application::Run() const
{
MSG msg;
_window->Create();
_window->Show();
_window->Update();
ZeroMemory(&msg, sizeof(MSG));
while (true) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_window->Idle();
}
}
#pragma once
class BaseWindow;
class Application
{
private:
BaseWindow* _window;
public:
Application(BaseWindow* window);
~Application();
void Run() const;
};
#include "framework.h"
#include "BaseWindow.h"
#include "Logger.h"
LRESULT CALLBACK BaseWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
BaseWindow* window = nullptr;
if (msg == WM_CREATE) {
LPCREATESTRUCT lpCreateStruct = (LPCREATESTRUCT)lParam;
window = (BaseWindow*)lpCreateStruct->lpCreateParams;
window->_hwnd = hWnd;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)window);
}
else {
window = (BaseWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
}
if (window) {
window->Invoke(msg, wParam, lParam);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
bool BaseWindow::Register()
{
WNDCLASSEX wcx;
::ZeroMemory(&wcx, sizeof(WNDCLASSEX));
if (GetClassInfoEx(GetModuleHandle(nullptr), ClassName(), &wcx)) {
return true;
}
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.hbrBackground = Background();
wcx.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcx.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wcx.hIconSm = wcx.hIcon;
wcx.hInstance = GetModuleHandle(nullptr);
wcx.lpfnWndProc = WndProc;
wcx.lpszClassName = ClassName();
wcx.lpszMenuName = nullptr;
wcx.style = ClassStyle();
return RegisterClassEx(&wcx) != 0;
}
BaseWindow::BaseWindow()
: _hwnd(nullptr)
{
}
BaseWindow::~BaseWindow()
{
Close();
Destroy();
}
void BaseWindow::Create(HWND parent)
{
ATOM atom = Register();
if (!atom) {
OutputLogger::LOGGER.FailLastError();
}
if (!CreateWindow(ClassName(), WindowName(), WindowStyle(),
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent, nullptr, GetModuleHandle(nullptr), this)) {
OutputLogger::LOGGER.FailLastError();
}
Observe(WM_CLOSE, [](WPARAM, LPARAM) {PostQuitMessage(0); });
}
void BaseWindow::Close()
{
if (_hwnd) {
CloseWindow(_hwnd);
}
}
void BaseWindow::Destroy()
{
if (_hwnd) {
DestroyWindow(_hwnd);
_hwnd = nullptr;
}
}
void BaseWindow::Size(int cx, int cy)
{
SIZE sz = { cx, cy };
Size(sz);
}
void BaseWindow::Size(SIZE sz)
{
RECT rect{ 0, 0, sz.cx, sz.cy };
/*
DWORD style = GetWindowLong(_hwnd, GWL_STYLE);
DWORD exStyle = GetWindowLong(_hwnd, GWL_EXSTYLE);
AdjustWindowRectExForDpi(&rect , style, false, exStyle, GetDpiForWindow(_hwnd));
ClientToScreen(_hwnd, (LPPOINT)&rect.left);
ClientToScreen(_hwnd, (LPPOINT)&rect.right);
SetWindowPos(_hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOREPOSITION);
*/
SetBounds(rect, SWP_NOZORDER | SWP_NOREPOSITION);
}
void BaseWindow::Position(int x, int y)
{
POINT pt{ x, y };
Position(pt);
}
void BaseWindow::Position(POINT pt)
{
SIZE sz = Size();
//SetWindowPos(_hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER|SWP_NOSIZE);
//MoveWindow(*this, pt.x, pt.y, sz.cx, sz.cy, true);
RECT rect = { pt.x, pt.y, 0, 0 };
SetBounds(rect, SWP_NOZORDER | SWP_NOSIZE);
}
void BaseWindow::SetBounds(RECT rect, UINT flags)
{
DWORD style = GetWindowLong(_hwnd, GWL_STYLE);
DWORD exStyle = GetWindowLong(_hwnd, GWL_EXSTYLE);
AdjustWindowRectExForDpi(&rect, style, false, exStyle, GetDpiForWindow(_hwnd));
//ClientToScreen(_hwnd, (LPPOINT)& rect.left);
//ClientToScreen(_hwnd, (LPPOINT)& rect.right);
SetWindowPos(_hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags);
}
SIZE BaseWindow::Size() const
{
RECT rect;
SIZE size = { 0, 0 };
/*
if (GetWindowRect(_hwnd, &rect)) {
size.cx = rect.right - rect.left;
size.cy = rect.bottom - rect.top;
}
*/
if (GetClientRect(_hwnd, &rect)) {
size.cx = rect.right - rect.left;
size.cy = rect.bottom - rect.top;
}
return size;
}
POINT BaseWindow::Position() const
{
RECT rect;
POINT pt = { 0, 0 };
if (GetWindowRect(_hwnd, &rect)) {
pt.x = rect.left;
pt.y = rect.right;
}
return pt;
}
void BaseWindow::Text(LPCTSTR text)
{
SetWindowText(_hwnd, text);
}
void BaseWindow::Show(int show)
{
ShowWindow(_hwnd, show);
}
void BaseWindow::Update()
{
UpdateWindow(_hwnd);
}
#pragma once
#include <Windows.h>
#include "Observable.h"
#define BIND_HANDLER(x) (std::bind(&x, this, std::placeholders::_1, std::placeholders::_2))
class BaseWindow : public Observable<UINT, WPARAM, LPARAM>
{
private:
HWND _hwnd;
private:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void SetBounds(RECT rect, UINT flags);
protected:
operator HWND() const { return _hwnd; }
bool Register();
public:
BaseWindow();
~BaseWindow();
void Create(HWND parent = nullptr);
void Close();
virtual void Destroy();
virtual void Size(int cx, int cy);
virtual void Size(SIZE sz);
virtual void Position(int x, int y);
virtual void Position(POINT pt);
SIZE Size() const;
POINT Position() const;
void Text(LPCTSTR text);
virtual LPCTSTR ClassName() { return TEXT("BaseWindow"); }
virtual LPCTSTR WindowName() { return ClassName(); }
virtual UINT ClassStyle() { return CS_HREDRAW | CS_VREDRAW; }
virtual UINT WindowStyle() { return WS_OVERLAPPEDWINDOW; }
virtual HBRUSH Background() { return (HBRUSH)(COLOR_WINDOW + 1); }
void Show(int show = SW_SHOW);
void Update();
virtual void Idle() {};
};
#pragma once
#include <map>
#include <functional>
#include <vector>
template <typename MSG, typename ... ARGS>
class Observable
{
protected:
std::map<MSG, std::vector<std::function<void(ARGS...)>>> _callbacks;
public:
void Observe(MSG msg, std::function<void(ARGS...)> callback) {
//_callbacks[msg] = callback;
_callbacks[msg].push_back(callback);
}
void Invoke(MSG msg, ARGS... args) {
if (_callbacks.find(msg) != _callbacks.end()) {
//_callbacks[msg](std::forward<ARGS>(args)...);
for (auto f : _callbacks[msg]) {
f(std::forward<ARGS>(args)...);
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment