Files
2025-12-05 08:54:02 +01:00

233 lines
6.7 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef toolx_Windows_window
#define toolx_Windows_window
#include <windows.h>
#include <windowsx.h>
#include <string>
namespace toolx {
namespace Windows {
class window {
static const std::string& s_class() {
static const std::string s_v("toolx::Windows::window");
return s_v;
}
static void register_class(){
static bool s_done = false; //not const, then not thread safe.
if(!s_done) {
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ::GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = (PTSTR)s_class().c_str();
wc.lpszClassName = (PTSTR)s_class().c_str();
::RegisterClass(&wc);
s_done = true;
}
}
public:
virtual void key_up(){}
virtual void key_down(){}
virtual void key_left(){}
virtual void key_right(){}
virtual void key_escape(){}
virtual void close(){
::PostQuitMessage(0);
}
public:
window(const char* a_title,int a_x,int a_y,unsigned int a_w,unsigned int a_h,unsigned int a_mask = WS_OVERLAPPEDWINDOW)
:m_hwnd(0)
,m_key_shift(false)
,m_key_ctrl(false)
,m_focus_hwnd(0)
{
// WARNING : given a_w,a_h may not be the client area because of various decorations.
// See set_client_area_size() method to enforce a client area size.
register_class();
m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(),
NULL,
a_mask,
a_x,a_y,
a_w,a_h,
NULL,NULL,
::GetModuleHandle(NULL),
NULL);
if(!m_hwnd) return;
::SetWindowText(m_hwnd,(PTSTR)a_title);
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
}
virtual ~window(){
if(m_hwnd) {
::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
::DestroyWindow(m_hwnd);
m_hwnd = 0;
}
}
protected:
window(const window& a_from)
:m_hwnd(0)
,m_key_shift(a_from.m_key_shift)
,m_key_ctrl(a_from.m_key_ctrl)
,m_focus_hwnd(0)
{
}
window& operator=(const window& a_from){
m_key_shift = a_from.m_key_shift;
m_key_ctrl = a_from.m_key_ctrl;
return *this;
}
public:
const window& get_me() const {return *this;}
window& get_me() {return *this;}
bool key_shift() const {return m_key_shift;}
HWND hwnd() const {return m_hwnd;}
void set_client_area_size(unsigned int a_w,unsigned int a_h) {
if(!m_hwnd) return;
RECT wrect;
::GetWindowRect(m_hwnd,&wrect);
unsigned int ww = wrect.right-wrect.left;
unsigned int wh = wrect.bottom-wrect.top;
RECT carect;
::GetClientRect(m_hwnd,&carect);
unsigned int cw = carect.right-carect.left;
unsigned int ch = carect.bottom-carect.top;
unsigned int woffset = ww-cw;
unsigned int hoffset = wh-ch;
::MoveWindow(m_hwnd,wrect.left,wrect.top,a_w+woffset,a_h+hoffset,TRUE);
}
void move(unsigned int a_x,unsigned int a_y) {
if(!m_hwnd) return;
RECT rect;
::GetWindowRect(m_hwnd,&rect);
unsigned int w = rect.right-rect.left;
unsigned int h = rect.bottom-rect.top;
::MoveWindow(m_hwnd,a_x,a_y,w,h,TRUE);
}
void set_focus_hwnd(HWND a_hwnd) {m_focus_hwnd = a_hwnd;}
HWND focus_hwnd() const {return m_focus_hwnd;}
protected:
static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
switch (a_msg) {
// Else :
case WM_SIZE:{ // Assume one child window ! FIXME : have a message if not.
int width = LOWORD(a_lparam);
int height = HIWORD(a_lparam);
HWND hwnd = GetFirstChild(a_hwnd);
if(hwnd) {
::MoveWindow(hwnd,0,0,width,height,TRUE);
}
}return 0;
case WM_SETFOCUS:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) {
HWND hwnd = _this->focus_hwnd();
if(hwnd) ::SetFocus(hwnd);
}
}return 0;
case WM_KEYDOWN:{
switch(a_wparam){
case VK_SHIFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_shift = true;
return 0;
}
case VK_CONTROL:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_ctrl = true;
return 0;
}
case VK_UP:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_up();
return 0;
}
case VK_DOWN:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_down();
return 0;
}
case VK_LEFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_left();
return 0;
}
case VK_RIGHT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_right();
return 0;
}
case VK_ESCAPE:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->key_escape();
return 0;
}
} //end switch(a_wparam)
break;
}
case WM_KEYUP:{
switch(a_wparam){
case VK_SHIFT:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_shift = false;
return 0;
}
case VK_CONTROL:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->m_key_ctrl = false;
return 0;
}
} //end switch(a_wparam)
break;
}
case WM_CLOSE:{
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) _this->close();
}break; //NOTE : can't be return 0.
case WM_DESTROY:wm__destroy(a_hwnd);return 0;
}
return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
}
static void wm__destroy(HWND a_hwnd) {
window* _this = (window*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
if(_this) { //How to be sure that we have a window* ???
if(_this->m_hwnd!=a_hwnd) {
}
_this->m_hwnd = 0;
}
::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
}
protected:
void get_size(HWND a_hwnd,int& a_w,int& a_h){
RECT rect;
::GetWindowRect(a_hwnd,&rect);
a_w = rect.right-rect.left;
a_h = rect.bottom-rect.top;
}
protected:
HWND m_hwnd;
bool m_key_shift;
bool m_key_ctrl;
HWND m_focus_hwnd;
};
}}
#endif