Back to home page

EIC code displayed by LXR

 
 

    


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 
0014 #include <string>
0015 
0016 #if defined(_MSC_VER) && _MSC_VER < 1900
0017 #elif defined(__MINGW32__)
0018 #else
0019 #define TOOLX_WINDOWS_TOUCH
0020 #endif
0021 
0022 namespace toolx {
0023 namespace Windows {
0024 
0025 #ifdef TOOLX_WINDOWS_TOUCH
0026 inline bool is_message_touch_event() {
0027   // from https://stackoverflow.com/questions/29857587/detect-if-wm-mousemove-is-caused-by-touch-pen.
0028   static const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
0029   static const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
0030   LONG_PTR extraInfo = ::GetMessageExtraInfo();
0031   return ( ( extraInfo & c_SIGNATURE_MASK ) == c_MOUSEEVENTF_FROMTOUCH );
0032 }
0033 #endif
0034 
0035 class glarea {
0036   static const std::string& s_class() {
0037     static const std::string s_v("toolx::Windows::glarea");
0038     return s_v;
0039   }
0040   static void register_class(){
0041     static bool s_done = false; //not const, then not thread safe.
0042     if(!s_done) {
0043       WNDCLASS         wc;
0044       wc.style         = CS_HREDRAW | CS_VREDRAW;
0045       wc.lpfnWndProc   = (WNDPROC)proc;
0046       wc.cbClsExtra    = 0;
0047       wc.cbWndExtra    = 0;
0048       wc.hInstance     = ::GetModuleHandle(NULL);
0049       wc.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
0050       wc.hCursor       = LoadCursor(NULL,IDC_ARROW);
0051       wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
0052       wc.lpszMenuName  = (PTSTR)s_class().c_str();
0053       wc.lpszClassName = (PTSTR)s_class().c_str();
0054       ::RegisterClass(&wc);
0055       s_done = true;
0056     }
0057   }
0058 public:
0059   virtual void resize(unsigned int,unsigned int){}
0060   virtual void paint(unsigned int,unsigned int) {}
0061   virtual void close(){}
0062   
0063   virtual void left_button_up(unsigned int,unsigned int) {}
0064   virtual void left_button_down(unsigned int,unsigned int) {}
0065   virtual void mouse_move(unsigned int,unsigned int,bool) {}
0066 public:
0067   glarea(HWND a_parent)
0068   :m_parent(a_parent)
0069   ,m_hwnd(0)
0070   ,m_context(0)
0071   ,m_HDC(0)
0072   ,m_touch_available(false)
0073   ,m_interactor(0)
0074   {
0075     register_class();
0076     RECT rect;
0077     ::GetClientRect(m_parent,&rect);
0078     m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(),
0079                              NULL,
0080                              WS_CHILD | WS_VISIBLE,
0081                              0,0,
0082                              rect.right-rect.left,
0083                              rect.bottom-rect.top,
0084                              m_parent,NULL,
0085                              GetWindowInstance(m_parent),
0086                              NULL);
0087     if(!m_hwnd) return;
0088     ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0089 
0090     // initialize OpenGL rendering :
0091     m_HDC = ::GetDC(m_hwnd);
0092     if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
0093       m_context = ::wglCreateContext(m_HDC);
0094     }
0095 
0096 #ifdef TOOLX_WINDOWS_TOUCH
0097    {BYTE digitizer_status = (BYTE)::GetSystemMetrics(SM_DIGITIZER);
0098     if((digitizer_status & (0x80 + 0x40)) == 0) {
0099       m_touch_available = false;
0100     } else {
0101       m_touch_available = true;
0102       if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0103     }}
0104 #endif
0105 
0106   }
0107   virtual ~glarea(){
0108     if(::wglGetCurrentContext()!=NULL) ::wglMakeCurrent(NULL,NULL);
0109     if(m_context)        {
0110       ::wglDeleteContext(m_context);
0111       m_context = 0;
0112     }
0113     if(m_HDC && m_hwnd) ::ReleaseDC(m_hwnd,m_HDC);
0114     if(m_hwnd) {
0115       ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0116       ::DestroyWindow(m_hwnd);
0117       m_hwnd = 0;
0118     }
0119   }
0120 protected:
0121   glarea(const glarea& a_from)
0122   :m_parent(a_from.m_parent)
0123   ,m_hwnd(0)
0124   ,m_context(0)
0125   ,m_HDC(0)
0126   ,m_touch_available(a_from.m_touch_available)
0127   ,m_interactor(0)
0128   {
0129     if(!m_parent) return;
0130     register_class();
0131     RECT rect;
0132     ::GetClientRect(m_parent,&rect);
0133     m_hwnd = ::CreateWindow((PTSTR)s_class().c_str(),
0134                              NULL,
0135                              WS_CHILD | WS_VISIBLE,
0136                              0,0,
0137                              rect.right-rect.left,
0138                              rect.bottom-rect.top,
0139                              m_parent,NULL,
0140                              GetWindowInstance(m_parent),
0141                              NULL);
0142     if(!m_hwnd) return;
0143     ::SetWindowLongPtr(m_hwnd,GWLP_USERDATA,LONG_PTR(this));
0144 
0145     // initialize OpenGL rendering :
0146     m_HDC = ::GetDC(m_hwnd);
0147     if(m_HDC && SetWindowPixelFormat(m_HDC) ) {
0148       m_context = ::wglCreateContext(m_HDC);
0149     }
0150 
0151 #ifdef TOOLX_WINDOWS_TOUCH
0152     if(a_from.m_touch_available) {
0153       if(!::RegisterTouchWindow(m_hwnd,0)) m_touch_available = false;
0154     }
0155 #endif
0156   }
0157 protected:
0158   glarea& operator=(const glarea&){return *this;}
0159 public:
0160   void set_client_area_size(unsigned int a_w,unsigned int a_h) {
0161     RECT rect;
0162     ::GetClientRect(m_hwnd,&rect);
0163     ::MoveWindow(m_hwnd,rect.left,rect.top,a_w,a_h,TRUE);
0164   }
0165   HWND hwnd() const {return m_hwnd;}
0166   void post_WM_PAINT() const {
0167     ::PostMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0168   }
0169   void send_WM_PAINT() const {
0170     ::SendMessage(m_hwnd,WM_PAINT,(WPARAM)0,(LPARAM)0);
0171   }
0172   void wm_paint() {
0173     PAINTSTRUCT ps;
0174     BeginPaint(m_hwnd,&ps);
0175     if(m_HDC && m_context) {
0176       ::wglMakeCurrent(m_HDC,m_context);
0177 
0178       RECT rect;
0179       ::GetClientRect(m_hwnd,&rect);
0180       unsigned int w = rect.right-rect.left;
0181       unsigned int h = rect.bottom-rect.top;
0182 
0183       paint(w,h);
0184 
0185       ::SwapBuffers(m_HDC);
0186       ::wglMakeCurrent(m_HDC,0);
0187     }
0188     EndPaint(m_hwnd,&ps);
0189   }
0190 public:
0191   void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
0192 protected:
0193   bool is_touch_event() {
0194 #ifdef TOOLX_WINDOWS_TOUCH
0195     if(!m_touch_available) return false;
0196     return is_message_touch_event();
0197 #else
0198     return false;
0199 #endif
0200   }
0201 protected:
0202   static LRESULT CALLBACK proc(HWND a_hwnd,UINT a_msg,WPARAM a_wparam,LPARAM a_lparam) {
0203     switch (a_msg) {
0204     case WM_SIZE:{
0205       int width = LOWORD(a_lparam);
0206       int height = HIWORD(a_lparam);
0207       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0208       if(_this) {
0209         _this->resize(width,height);
0210       } else {
0211         // CreateWindow send a WM_SIZE but GWLP_USERDATA not yet set.
0212       }
0213     }return 0;
0214     case WM_PAINT:{
0215       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0216       if(_this) _this->wm_paint();
0217     }return 0;
0218 
0219     case WM_KEYDOWN:{
0220       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0221       if(_this) {
0222         if(_this->m_interactor) {
0223           tools::sg::key_down_event event(_this->convert(a_wparam));
0224           _this->m_interactor->key_press(event);
0225         }
0226       } 
0227     } return 0;
0228     case WM_KEYUP:{
0229       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0230       if(_this) {
0231         if(_this->m_interactor) {
0232           tools::sg::key_up_event event(_this->convert(a_wparam));
0233           _this->m_interactor->key_release(event);
0234         }
0235       } 
0236     } return 0;
0237 
0238     case WM_LBUTTONDOWN:{
0239       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0240       if(_this) {
0241         if(_this->m_interactor) {
0242           bool shift_modifier = ::GetKeyState(VK_SHIFT)  & 0x8000;
0243           bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0244           tools::sg::mouse_down_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier);
0245           _this->m_interactor->mouse_press(event);
0246         } else {
0247           RECT rect;
0248           ::GetClientRect(a_hwnd,&rect);
0249           unsigned int h = rect.bottom-rect.top;
0250           if(!_this->is_touch_event()) _this->left_button_down(LOWORD(a_lparam),h-HIWORD(a_lparam));
0251         }
0252       }
0253     }return 0;
0254     case WM_LBUTTONUP:{
0255       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0256       if(_this) {
0257         if(_this->m_interactor) {
0258           bool shift_modifier = ::GetKeyState(VK_SHIFT)  & 0x8000;
0259           bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0260           tools::sg::mouse_up_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier);
0261           _this->m_interactor->mouse_release(event);
0262         } else {
0263           RECT rect;
0264           ::GetClientRect(a_hwnd,&rect);
0265           unsigned int h = rect.bottom-rect.top;
0266           if(!_this->is_touch_event()) _this->left_button_up(LOWORD(a_lparam),h-HIWORD(a_lparam));
0267         }
0268       }
0269     } return 0;
0270     case WM_MOUSEMOVE:{
0271       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0272       if(_this) {
0273         WPARAM state = a_wparam;
0274         bool ldown = ((state & MK_LBUTTON)==MK_LBUTTON)?true:false;
0275         if(_this->m_interactor) {
0276           if(ldown) {
0277             bool shift_modifier = ::GetKeyState(VK_SHIFT)  & 0x8000;
0278             bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0279             tools::sg::mouse_move_event event(LOWORD(a_lparam),HIWORD(a_lparam),shift_modifier,control_modifier,0,0,false);
0280             _this->m_interactor->mouse_move(event);
0281           }
0282         } else {
0283           RECT rect;
0284           ::GetClientRect(a_hwnd,&rect);
0285           unsigned int h = rect.bottom-rect.top;
0286           if(!_this->is_touch_event()) _this->mouse_move(LOWORD(a_lparam),h-HIWORD(a_lparam),ldown);
0287         }
0288       }
0289 
0290     }return 0;
0291     
0292     case WM_MOUSEWHEEL:{
0293       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0294       if(_this) {
0295         if(_this->m_interactor) {
0296           bool shift_modifier = ::GetKeyState(VK_SHIFT)  & 0x8000;
0297           bool control_modifier = ::GetKeyState(VK_CONTROL) & 0x8000;
0298           POINT p;
0299           p.x = LOWORD(a_lparam);
0300           p.y = HIWORD(a_lparam);
0301           if(!::ScreenToClient(a_hwnd,&p)) {}
0302           tools::sg::wheel_rotate_event event(GET_WHEEL_DELTA_WPARAM(a_wparam),int(p.x),int(p.y),shift_modifier,control_modifier);
0303           _this->m_interactor->wheel_rotate(event);
0304         }         
0305       } 
0306     } return 0;
0307       
0308 #ifdef TOOLX_WINDOWS_TOUCH
0309     case WM_TOUCH:{
0310       glarea* _this = (glarea*)::GetWindowLongPtr(a_hwnd,GWLP_USERDATA);
0311       if(_this && _this->m_touch_available) {
0312         RECT rect;
0313         ::GetClientRect(a_hwnd,&rect);
0314         unsigned int h = rect.bottom-rect.top;
0315 
0316         unsigned int num_inputs = (int)a_wparam;
0317         TOUCHINPUT* ti = new TOUCHINPUT[num_inputs];
0318         POINT p;
0319         if(::GetTouchInputInfo((HTOUCHINPUT)a_lparam,num_inputs,ti,sizeof(TOUCHINPUT))) {
0320           for(unsigned int i=0;i<num_inputs; ++i) {
0321             p.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
0322             p.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
0323             if(!::ScreenToClient(a_hwnd,&p)) {}
0324             if(ti[i].dwFlags & TOUCHEVENTF_DOWN) {
0325               _this->left_button_down(p.x,h-p.y);
0326             } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
0327               _this->left_button_up(p.x,h-p.y);
0328             } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
0329               bool ldown = true; //we assume that a TOUCHEVENT_DOWN had been done.
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       }
0398       _this->m_hwnd = 0;
0399     }
0400     ::SetWindowLongPtr(a_hwnd,GWLP_USERDATA,LONG_PTR(NULL));
0401   }
0402 protected:
0403   tools::key_code convert(WPARAM a_key) {
0404     if(a_key==VK_SHIFT) return tools::sg::key_shift();
0405     return (tools::key_code)a_key;
0406   }
0407 protected:
0408   HWND m_parent;
0409   HWND m_hwnd;
0410   HGLRC m_context;
0411   HDC m_HDC;
0412   bool m_touch_available;
0413   tools::sg::device_interactor* m_interactor;
0414 };
0415 
0416 }}
0417 
0418 #endif