Created
June 4, 2016 19:28
-
-
Save Wunkolo/90a03640da014c97ff77bda7a4374bdf to your computer and use it in GitHub Desktop.
Simple Painting Window
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "SimpWind.hpp" | |
#include <mutex> | |
bool SimpWind::WindowImplementation::PopEvent(Event & event) | |
{ | |
if( Events.empty() ) | |
{ | |
// Populate Queue | |
ProcessEvents(); | |
} | |
if( !Events.empty() ) | |
{ | |
event = Events.front(); | |
Events.pop(); | |
return true; | |
} | |
return false; | |
} | |
void SimpWind::WindowImplementation::PushEvent(const Event & event) | |
{ | |
Events.push(event); | |
} | |
#ifdef _WIN32 | |
#include <Windows.h> | |
class WinImp : public SimpWind::WindowImplementation | |
{ | |
public: | |
WinImp(const char Title[], size_t Width, size_t Height) | |
{ | |
if( WindowCount == 0 ) | |
{ | |
// Register Window | |
WNDCLASSA WindowClass; | |
WindowClass.style = 0; | |
WindowClass.lpfnWndProc = &OnGlobalEvent; | |
WindowClass.cbClsExtra = 0; | |
WindowClass.cbWndExtra = 0; | |
WindowClass.hInstance = GetModuleHandleA(nullptr); | |
WindowClass.hIcon = LoadIcon(0, IDI_WINLOGO); | |
WindowClass.hCursor = LoadCursor(0, IDC_ARROW); | |
WindowClass.hbrBackground = 0; | |
WindowClass.lpszMenuName = nullptr; | |
WindowClass.lpszClassName = "SimpWind"; | |
RegisterClassA(&WindowClass); | |
} | |
// Center Window | |
HDC DesktopDC = GetDC(nullptr); | |
size_t Top = (GetDeviceCaps(DesktopDC, VERTRES) - Height) / 2; | |
size_t Left = (GetDeviceCaps(DesktopDC, HORZRES) - Width) / 2; | |
ReleaseDC(nullptr, DesktopDC); | |
WindowHandle = CreateWindowA( | |
"SimpWind", | |
Title, | |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU, | |
static_cast<int32_t>(Left), | |
static_cast<int32_t>(Top), | |
static_cast<int32_t>(Width), | |
static_cast<int32_t>(Height), | |
nullptr, | |
nullptr, | |
GetModuleHandleA(nullptr), | |
this); | |
WindowDC = GetDC(WindowHandle); | |
WindowCount++; | |
SetSize(static_cast<uint32_t>(Width), static_cast<uint32_t>(Height)); | |
SetBkColor(WindowDC, 0); | |
ExtTextOut(WindowDC, 0, 0, ETO_OPAQUE, nullptr, "", 0, 0); | |
} | |
~WinImp() | |
{ | |
ReleaseDC(WindowHandle, WindowDC); | |
DestroyWindow(WindowHandle); | |
WindowCount--; | |
if( WindowCount == 0 ) | |
{ | |
// UnRegister Window | |
UnregisterClassA("SimpWind", GetModuleHandleA(nullptr)); | |
} | |
} | |
void ProcessEvents() | |
{ | |
MSG Message; | |
while( PeekMessageA(&Message, nullptr, 0, 0, PM_REMOVE) ) | |
{ | |
TranslateMessage(&Message); | |
DispatchMessageA(&Message); | |
} | |
} | |
void WindowProc(UINT Message, WPARAM wParam, LPARAM lParam) | |
{ | |
if( WindowHandle ) | |
{ | |
switch( Message ) | |
{ | |
case WM_CLOSE: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::Closed; | |
PushEvent(event); | |
break; | |
} | |
case WM_SETFOCUS: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::Focused; | |
PushEvent(event); | |
break; | |
} | |
case WM_KILLFOCUS: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::UnFocused; | |
PushEvent(event); | |
break; | |
} | |
case WM_LBUTTONDOWN: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonDown; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Left; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_RBUTTONDOWN: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonDown; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Right; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_MBUTTONDOWN: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonDown; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Middle; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_LBUTTONUP: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonUp; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Left; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_RBUTTONUP: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonUp; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Right; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_MBUTTONUP: | |
{ | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseButtonUp; | |
event.MouseButtonDown.Button = SimpWind::MouseButton::Middle; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
case WM_MOUSEMOVE: | |
{ | |
int16_t X = static_cast<uint16_t>(LOWORD(lParam)); | |
int16_t Y = static_cast<uint16_t>(HIWORD(lParam)); | |
SimpWind::Event event; | |
event.Type = SimpWind::Event::EventType::MouseMove; | |
event.MouseMove.X = static_cast<uint16_t>(LOWORD(lParam)); | |
event.MouseMove.Y = static_cast<uint16_t>(HIWORD(lParam)); | |
PushEvent(event); | |
break; | |
} | |
default: | |
break; | |
} | |
} | |
} | |
static LRESULT CALLBACK OnGlobalEvent(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam) | |
{ | |
if( Message == WM_CREATE ) | |
{ | |
LONG_PTR WinImpPtr = (LONG_PTR)reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams; | |
SetWindowLongPtrA(Handle, GWLP_USERDATA, WinImpPtr); | |
} | |
WinImp* WindowInstance = Handle ? reinterpret_cast<WinImp*>(GetWindowLongPtrA(Handle, GWLP_USERDATA)) : nullptr; | |
if( WindowInstance ) | |
{ | |
WindowInstance->WindowProc(Message, wParam, lParam); | |
} | |
if( ((Message == WM_SYSCOMMAND) && (wParam == SC_KEYMENU)) || (Message == WM_CLOSE) ) | |
{ | |
return 0; | |
} | |
return DefWindowProcA(Handle, Message, wParam, lParam); | |
} | |
void GetPosition(uint32_t& X, uint32_t& Y) const | |
{ | |
RECT Bounds; | |
GetWindowRect(WindowHandle, &Bounds); | |
X = Bounds.left; | |
Y = Bounds.right; | |
} | |
void SetPosition(uint32_t X, uint32_t Y) const | |
{ | |
SetWindowPos(WindowHandle, nullptr, X, Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); | |
} | |
void GetSize(uint32_t& Width, uint32_t& Height) const | |
{ | |
RECT Bounds; | |
GetClientRect(WindowHandle, &Bounds); | |
Width = (Bounds.right - Bounds.left); | |
Height = (Bounds.bottom - Bounds.top); | |
} | |
void SetSize(uint32_t Width, uint32_t Height) const | |
{ | |
RECT Bounds = { 0,0,static_cast<long>(Width),static_cast<long>(Height) }; | |
AdjustWindowRect(&Bounds, GetWindowLong(WindowHandle, GWL_STYLE), false); | |
SetWindowPos( | |
WindowHandle, | |
nullptr, | |
0, 0, | |
Bounds.right - Bounds.left, | |
Bounds.bottom - Bounds.top, | |
SWP_NOMOVE | SWP_NOZORDER | |
); | |
} | |
void SetTitle(const char* Title) const | |
{ | |
SetWindowTextA(WindowHandle, Title); | |
} | |
void SetIcon(const uint32_t* Pixels, size_t Width, size_t Height) const | |
{ | |
} | |
void Paint(const uint32_t* Pixels, size_t Width, size_t Height) const | |
{ | |
static BITMAPV4HEADER BitmapInfo{ sizeof(BITMAPV4HEADER) }; | |
BitmapInfo.bV4Width = static_cast<LONG>(Width); | |
BitmapInfo.bV4Height = -static_cast<LONG>(Height); | |
BitmapInfo.bV4Planes = 1; | |
BitmapInfo.bV4BitCount = 32; | |
BitmapInfo.bV4V4Compression = BI_BITFIELDS; | |
BitmapInfo.bV4RedMask = 0xFF000000; | |
BitmapInfo.bV4GreenMask = 0x00FF0000; | |
BitmapInfo.bV4BlueMask = 0x0000FF00; | |
BitmapInfo.bV4AlphaMask = 0x000000FF; | |
uint32_t WindWidth, WindHeight; | |
GetSize(WindWidth, WindHeight); | |
StretchDIBits( | |
WindowDC, | |
0, 0, | |
static_cast<int32_t>(WindWidth), | |
static_cast<int32_t>(WindHeight), | |
0, 0, | |
static_cast<int32_t>(Width), | |
static_cast<int32_t>(Height), | |
Pixels, | |
reinterpret_cast<BITMAPINFO*>(&BitmapInfo), | |
DIB_RGB_COLORS, | |
SRCCOPY); | |
ValidateRect(WindowHandle, nullptr); | |
} | |
private: | |
HWND WindowHandle; | |
HDC WindowDC; | |
static size_t WindowCount; | |
}; | |
size_t WinImp::WindowCount = 0; | |
#else | |
#error "Unsupported Platform" | |
#endif | |
SimpWind::SimpWind() : Implementation(nullptr) | |
{ | |
#ifdef _WIN32 | |
Implementation = new WinImp("", 100, 100); | |
#else | |
#error "Unsupported Platform" | |
#endif | |
} | |
SimpWind::SimpWind(const char Title[], size_t Width, size_t Height) : Implementation(nullptr) | |
{ | |
Implementation = new WinImp(Title, Width, Height); | |
} | |
SimpWind::~SimpWind() | |
{ | |
if( Implementation ) | |
{ | |
delete Implementation; | |
} | |
} | |
bool SimpWind::IsOpen() const | |
{ | |
return Implementation != nullptr; | |
} | |
void SimpWind::Close() | |
{ | |
if( Implementation ) | |
{ | |
delete Implementation; | |
Implementation = nullptr; | |
} | |
} | |
bool SimpWind::PollEvent(Event& event) | |
{ | |
if( Implementation ) | |
{ | |
return Implementation->PopEvent(event); | |
} | |
return false; | |
} | |
void SimpWind::GetPosition(uint32_t& X, uint32_t& Y) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->GetPosition(X, Y); | |
} | |
} | |
void SimpWind::SetPosition(uint32_t X, uint32_t Y) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->SetPosition(X, Y); | |
} | |
} | |
void SimpWind::GetSize(uint32_t& Width, uint32_t& Height) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->GetSize(Width, Height); | |
} | |
} | |
void SimpWind::SetSize(uint32_t Width, uint32_t Height) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->SetSize(Width, Height); | |
} | |
} | |
void SimpWind::SetTitle(const char* Title) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->SetTitle(Title); | |
} | |
} | |
void SimpWind::SetIcon(const uint32_t* Pixels, size_t Width, size_t Height) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->SetIcon(Pixels, Width, Height); | |
} | |
} | |
void SimpWind::Paint(const uint32_t* Pixels, size_t Width, size_t Height) const | |
{ | |
if( Implementation ) | |
{ | |
Implementation->Paint(Pixels, Width, Height); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdint.h> | |
#include <queue> | |
class SimpWind | |
{ | |
public: | |
SimpWind(); | |
SimpWind(const char Title[], size_t Width, size_t Height); | |
~SimpWind(); | |
enum class MouseButton : uint16_t | |
{ | |
Left, | |
Right, | |
Middle | |
}; | |
struct Event | |
{ | |
enum class EventType : uint16_t | |
{ | |
Closed, | |
Focused, | |
UnFocused, | |
KeyDown, | |
KeyUp, | |
MouseButtonUp, | |
MouseButtonDown, | |
MouseMove, | |
} Type; | |
struct KeyboardEvent | |
{ | |
uint8_t Code; | |
bool Alt; | |
bool Ctrl; | |
bool Shift; | |
bool System; | |
} Keyboard; | |
struct MouseMoveEvent | |
{ | |
size_t X, Y; | |
} MouseMove; | |
struct MouseButtonDownEvent | |
{ | |
MouseButton Button; | |
size_t X, Y; | |
} MouseButtonDown; | |
struct MouseButtonUpEvent | |
{ | |
MouseButton Button; | |
size_t X, Y; | |
} MouseButtonUp; | |
}; | |
bool IsOpen() const; | |
void Close(); | |
bool PollEvent(Event& event); | |
void GetPosition(uint32_t& X, uint32_t& Y) const; | |
void SetPosition(uint32_t X, uint32_t Y) const; | |
void GetSize(uint32_t& Width, uint32_t& Height) const; | |
void SetSize(uint32_t Width, uint32_t Height) const; | |
void SetTitle(const char* Title) const; | |
// Assumes 32-bpp 8-bpc RGBA image | |
void SetIcon(const uint32_t* Pixels, size_t Width, size_t Height) const; | |
void Paint(const uint32_t* Pixels, size_t Width, size_t Height) const; | |
class WindowImplementation | |
{ | |
public: | |
~WindowImplementation() | |
{ | |
} | |
// No-copy | |
WindowImplementation(const WindowImplementation&) = delete; | |
WindowImplementation& operator=(const WindowImplementation&) = delete; | |
bool PopEvent(Event& event); | |
void PushEvent(const Event& event); | |
virtual void GetPosition(uint32_t& X, uint32_t& Y) const = 0; | |
virtual void SetPosition(uint32_t X, uint32_t Y) const = 0; | |
virtual void GetSize(uint32_t& Width, uint32_t& Height) const = 0; | |
virtual void SetSize(uint32_t Width, uint32_t Height) const = 0; | |
virtual void SetTitle(const char* Title) const = 0; | |
// Assumes 32-bpp 8-bpc RGBA image | |
virtual void SetIcon(const uint32_t* Pixels, size_t Width, size_t Height) const = 0; | |
virtual void Paint(const uint32_t* Pixels, size_t Width, size_t Height) const = 0; | |
protected: | |
WindowImplementation() | |
{ | |
} | |
// Populates Events queue with events to be processed | |
virtual void ProcessEvents() = 0; | |
std::queue<SimpWind::Event> Events; | |
}; | |
private: | |
WindowImplementation *Implementation; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment