// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef toolx_Windows_window #define toolx_Windows_window #include #include #include 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