Skip to content

Instantly share code, notes, and snippets.

@Wunkolo
Created June 4, 2016 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Wunkolo/90a03640da014c97ff77bda7a4374bdf to your computer and use it in GitHub Desktop.
Save Wunkolo/90a03640da014c97ff77bda7a4374bdf to your computer and use it in GitHub Desktop.
Simple Painting Window
#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);
}
}
#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