Warning, /include/Geant4/toolx/Windows/glarea is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef toolx_Windows_glarea
0005 #define toolx_Windows_glarea
0006
0007 #include <windows.h>
0008 #include <windowsx.h>
0009 #include <wingdi.h>
0010
0011 #include <tools/sg/device_interactor>
0012 #include <tools/sg/keys>
0013 //#include <tools/log_file>
0014
0015 #include <string>
0016
0017 #if defined(_MSC_VER) && _MSC_VER < 1900
0018 #elif defined(__MINGW32__)
0019 #else
0020 #define TOOLX_WINDOWS_TOUCH
0021 #endif
0022
0023 namespace toolx {
0024 namespace Windows {
0025
0026 #ifdef TOOLX_WINDOWS_TOUCH
0027 inline bool is_message_touch_event() {
0028 // from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen.
0029 static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
0030 static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
0031 LONG_PTR extraInfo = ::GetMessageExtraInfo();
0032 return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH );
0033 }
0034 #endif
0035
0036 class glarea {
0037 static const std::string& s_class() {
0038 static const std::string s_v("toolx::Windows::glarea");
0039 return s_v;
0040 }
0041 static void register_class(){
0042 static bool s_done = false; //not const, then not thread safe.
0043 if(!s_done) {
0044 WNDCLASS wc;
0045 wc.style = CS_HREDRAW | CS_VREDRAW;
0046 wc.lpfnWndProc = (WNDPROC)proc;
0047 wc.cbClsExtra = 0;
0048 wc.cbWndExtra = 0;
0049 wc.hInstance = ::GetModuleHandle(NULL);
0050 wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
0051 wc.hCursor = LoadCursor(NULL,IDC_ARROW);
0052 wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
0053 wc.lpszMenuName = s_class().c_str();
0054 wc.lpszClassName = s_class().c_str();
0055 ::RegisterClass(&wc);
0056 s_done = true;
0057 }
0058 }
0059 public:
0060 virtual void resize(unsigned int,unsigned int){}
0061 virtual void paint(unsigned int,unsigned int) {}
0062 virtual void close(){}
0063
0064 virtual void left_button_up(unsigned int,unsigned int) {}
0065 virtual void left_button_down(unsigned int,unsigned int) {}
0066 virtual void mouse_move(unsigned int,unsigned int,bool) {}
0067 public:
0068 glarea(HWND a_parent)
0069 :m_parent(a_parent)
0070 ,m_hwnd(0)
0071 ,m_context(0)
0072 ,m_HDC(0)
0073 ,m_touch_available(false)
0074 ,m_interactor(0)
0075 {
0076 register_class();
0077 // The WS_BORDER is needed. Else probleme of size at startup.
0078 RECT rect;
0079 ::GetClientRect(m_parent,&rect);
0080 //printf("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
0081 //toolx::log_file::get().writef("debug : glarea : ca : %d %d\n",rect.right-rect.left,rect.bottom-rect.top);
0082 m_hwnd = ::CreateWindow(s_class().c_str(),
0083 NULL,
0084 WS_CHILD | WS_VISIBLE,
0085 0,0,
0086 rect.right-rect.left,
0087 rect.bottom-rect.top,
0088 m_parent,NULL,
0089 GetWindowInstance(m_parent),
0090 NULL);
0091 if(!m_hwnd) return;
0092 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0093
0094 // initialize OpenGL rendering :
0095 m_HDC = ::GetDC(m_hwnd);
0096 if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
0097 m_context = ::wglCreateContext(m_HDC);
0098 }
0099
0100 #ifdef TOOLX_WINDOWS_TOUCH
0101 {BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER);
0102 if((digitizer_status & (0x80 + 0x40)) == 0) {
0103 m_touch_available = false;
0104 } else {
0105 //BYTE nInputs = (BYTE)::GetSystemMetrics(SM_MAXIMUMTOUCHES);
0106 m_touch_available = true;
0107 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0108 }}
0109 #endif
0110
0111 }
0112 virtual ~glarea(){
0113 if(::wglGetCurrentContext()!=NULL) ::wglMakeCurrent(NULL,NULL);
0114 if(m_context) {
0115 ::wglDeleteContext(m_context);
0116 m_context = 0;
0117 }
0118 if(m_HDC && m_hwnd) ::ReleaseDC(m_hwnd,m_HDC);
0119 if(m_hwnd) {
0120 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0121 ::DestroyWindow(m_hwnd);
0122 m_hwnd = 0;
0123 }
0124 }
0125 protected:
0126 glarea(const glarea& a_from)
0127 :m_parent(a_from.m_parent)
0128 ,m_hwnd(0)
0129 ,m_context(0)
0130 ,m_HDC(0)
0131 ,m_touch_available(a_from.m_touch_available)
0132 ,m_interactor(0)
0133 {
0134 if(!m_parent) return;
0135 register_class();
0136 RECT rect;
0137 ::GetClientRect(m_parent,&rect);
0138 m_hwnd = ::CreateWindow(s_class().c_str(),
0139 NULL,
0140 WS_CHILD | WS_VISIBLE,
0141 0,0,
0142 rect.right-rect.left,
0143 rect.bottom-rect.top,
0144 m_parent,NULL,
0145 GetWindowInstance(m_parent),
0146 NULL);
0147 if(!m_hwnd) return;
0148 ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0149
0150 // initialize OpenGL rendering :
0151 m_HDC = ::GetDC(m_hwnd);
0152 if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
0153 m_context = ::wglCreateContext(m_HDC);
0154 }
0155
0156 #ifdef TOOLX_WINDOWS_TOUCH
0157 if(a_from.m_touch_available) {
0158 if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0159 }
0160 #endif
0161 }
0162 protected:
0163 glarea& operator=(const glarea&){return *this;}
0164 public:
0165 void set_client_area_size(unsigned int a_w,unsigned int a_h) {
0166 RECT rect;
0167 ::GetClientRect(m_hwnd,&rect);
0168 ::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE);
0169 }
0170 HWND hwnd() const {return m_hwnd;}
0171 void post_WM_PAINT() const {
0172 ::PostMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0173 }
0174 void send_WM_PAINT() const {
0175 ::SendMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0176 }
0177 void wm_paint() {
0178 PAINTSTRUCT ps;
0179 //HDC hDC =
0180 BeginPaint(m_hwnd,&ps);
0181 if(m_HDC && m_context) {
0182 ::wglMakeCurrent(m_HDC,m_context);
0183
0184 RECT rect;
0185 ::GetClientRect(m_hwnd,&rect);
0186 unsigned int w = rect.right-rect.left;
0187 unsigned int h = rect.bottom-rect.top;
0188
0189 //printf("debug : glarea : paint : %d %d\n",w,h);
0190 //toolx::log_file::get().writef("debug : glarea : paint : %d %d\n",w,h);
0191
0192 paint(w,h);
0193
0194 ::SwapBuffers(m_HDC);
0195 ::wglMakeCurrent(m_HDC,0);
0196 }
0197 EndPaint(m_hwnd,&ps);
0198 }
0199 public:
0200 void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
0201 protected:
0202 bool is_touch_event() {
0203 #ifdef TOOLX_WINDOWS_TOUCH
0204 if(!m_touch_available) return false;
0205 return is_message_touch_event();
0206 #else
0207 return false;
0208 #endif
0209 }
0210 protected:
0211 static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
0212 switch (a_msg) {
0213 case WM_SIZE:{
0214 int width = LOWORD(a_lparam);
0215 int height = HIWORD(a_lparam);
0216 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0217 if(_this) {
0218 _this->resize(width,height);
0219 } else {
0220 // CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set.
0221 }
0222 }return 0;
0223 case WM_PAINT:{
0224 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0225 if(_this) _this->wm_paint();
0226 }return 0;
0227
0228 case WM_KEYDOWN:{
0229 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0230 if(_this) {
0231 if(_this->m_interactor) {
0232 tools::sg::key_down_event event(_this->convert(a_wparam));
0233 _this->m_interactor->key_press(event);
0234 }
0235 }
0236 } return 0;
0237 case WM_KEYUP:{
0238 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0239 if(_this) {
0240 if(_this->m_interactor) {
0241 tools::sg::key_up_event event(_this->convert(a_wparam));
0242 _this->m_interactor->key_release(event);
0243 }
0244 }
0245 } return 0;
0246
0247 case WM_LBUTTONDOWN:{
0248 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0249 if(_this) {
0250 if(_this->m_interactor) {
0251 tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam));
0252 _this->m_interactor->mouse_press(event);
0253 } else {
0254 RECT rect;
0255 ::GetClientRect(a_hwnd,&rect);
0256 unsigned int h = rect.bottom-rect.top;
0257 if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam));
0258 }
0259 }
0260 }return 0;
0261 case WM_LBUTTONUP:{
0262 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0263 if(_this) {
0264 if(_this->m_interactor) {
0265 tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam));
0266 _this->m_interactor->mouse_release(event);
0267 } else {
0268 RECT rect;
0269 ::GetClientRect(a_hwnd,&rect);
0270 unsigned int h = rect.bottom-rect.top;
0271 if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam));
0272 }
0273 }
0274 } return 0;
0275 case WM_MOUSEMOVE:{
0276 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0277 if(_this) {
0278 if(_this->m_interactor) {
0279 tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),0,0,false);
0280 _this->m_interactor->mouse_move(event);
0281 } else {
0282 WPARAM state = a_wparam;
0283 bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false;
0284 RECT rect;
0285 ::GetClientRect(a_hwnd,&rect);
0286 unsigned int h = rect.bottom-rect.top;
0287 if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown);
0288 }
0289 }
0290
0291 }return 0;
0292
0293 case WM_MOUSEWHEEL:{
0294 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0295 if(_this) {
0296 if(_this->m_interactor) {
0297 tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam));
0298 _this->m_interactor->wheel_rotate(event);
0299 }
0300 }
0301 } return 0;
0302
0303 #ifdef TOOLX_WINDOWS_TOUCH
0304 case WM_TOUCH:{
0305 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0306 if(_this && _this->m_touch_available) {
0307 RECT rect;
0308 //::GetWindowRect(hwnd,&rect); ???
0309 ::GetClientRect(a_hwnd,&rect);
0310 unsigned int h = rect.bottom-rect.top;
0311
0312 unsigned int num_inputs = (int)a_wparam;
0313 //::printf("debug : WM_TOUCH : 001 : %d\n",num_inputs);
0314 TOUCHINPUT* ti = new TOUCHINPUT[num_inputs];
0315 POINT p;
0316 if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) {
0317 for(unsigned int i=0;i<num_inputs; ++i) {
0318 p.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
0319 p.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
0320 if(!::ScreenToClient(a_hwnd,&p)) {}
0321 if(ti[i].dwFlags & TOUCHEVENTF_DOWN) {
0322 //::printf("debug : TOUCHEVENTF_DOWN %lu %lu\n",p.x,p.y);
0323 _this->left_button_down(p.x,h-p.y);
0324 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
0325 //::printf("debug : TOUCHEVENTF_UP %lu %lu\n",p.x,p.y);
0326 _this->left_button_up(p.x,h-p.y);
0327 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
0328 bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done.
0329 //::printf("debug : TOUCHEVENTF_MOVE %lu %lu\n",p.x,p.y);
0330 _this->mouse_move(p.x,h-p.y,ldown);
0331 }
0332 }
0333 }
0334 ::CloseTouchInputHandle((HTOUCHINPUT)a_lparam);
0335 delete [] ti;
0336 }
0337 }return 0;
0338 #endif //TOOLX_WINDOWS_TOUCH
0339 case WM_DESTROY:wm__destroy(a_hwnd);return 0;
0340 }
0341 return (DefWindowProc(a_hwnd,a_msg,a_wparam,a_lparam));
0342 }
0343 static bool SetWindowPixelFormat(HDC a_HDC){
0344 PIXELFORMATDESCRIPTOR pfd;
0345 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
0346 pfd.nVersion = 1;
0347 pfd.dwFlags =
0348 PFD_DRAW_TO_WINDOW |
0349 PFD_SUPPORT_OPENGL |
0350 PFD_DOUBLEBUFFER |
0351 PFD_STEREO_DONTCARE;
0352 pfd.iPixelType = PFD_TYPE_RGBA;
0353 pfd.cColorBits = 32;
0354 pfd.cRedBits = 8;
0355 pfd.cRedShift = 16;
0356 pfd.cGreenBits = 8;
0357 pfd.cGreenShift = 8;
0358 pfd.cBlueBits = 8;
0359 pfd.cBlueShift = 0;
0360 pfd.cAlphaBits = 0;
0361 pfd.cAlphaShift = 0;
0362 pfd.cAccumBits = 64;
0363 pfd.cAccumRedBits = 16;
0364 pfd.cAccumGreenBits = 16;
0365 pfd.cAccumBlueBits = 16;
0366 pfd.cAccumAlphaBits = 0;
0367 pfd.cDepthBits = 32;
0368 pfd.cStencilBits = 8;
0369 pfd.cAuxBuffers = 0;
0370 pfd.iLayerType = PFD_MAIN_PLANE;
0371 pfd.bReserved = 0;
0372 pfd.dwLayerMask = 0;
0373 pfd.dwVisibleMask = 0;
0374 pfd.dwDamageMask = 0;
0375
0376 int pixelIndex = ::ChoosePixelFormat(a_HDC,&pfd);
0377 if (pixelIndex==0) {
0378 // Let's choose a default index.
0379 pixelIndex = 1;
0380 if (::DescribePixelFormat(a_HDC,
0381 pixelIndex,
0382 sizeof(PIXELFORMATDESCRIPTOR),
0383 &pfd)==0) {
0384 return false;
0385 }
0386 }
0387
0388 if (::SetPixelFormat(a_HDC,pixelIndex,&pfd)==FALSE) return false;
0389
0390 return true;
0391 }
0392 static void wm__destroy(HWND a_hwnd) {
0393 glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0394 if(_this) { //How to be sure that we have a glarea* ???
0395 _this->close();
0396 if(_this->m_hwnd!=a_hwnd) {
0397 //::printf("WinTk::Component::wm_destroy : HWND mismatch !\n");
0398 }
0399 _this->m_hwnd = 0;
0400 }
0401 ::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0402 }
0403 protected:
0404 tools::key_code convert(WPARAM a_key) {
0405 if(a_key==VK_SHIFT) return tools::sg::key_shift();
0406 return (tools::key_code)a_key;
0407 }
0408 protected:
0409 HWND m_parent;
0410 HWND m_hwnd;
0411 HGLRC m_context;
0412 HDC m_HDC;
0413 bool m_touch_available;
0414 tools::sg::device_interactor* m_interactor;
0415 };
0416
0417 }}
0418
0419 #endif