// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef toolx_Xt_sg_viewer #define toolx_Xt_sg_viewer #include "session" #ifndef GL_GLEXT_LEGACY #define GL_GLEXT_LEGACY #endif #include #ifdef TOOLS_USE_GL_VERSION_3_2 #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #include #endif #include "../GL/gl_functions" #include "../sg/GL_action" #include "../sg/GL_viewer" namespace toolx { namespace sg { using GL_action = GL_action_T; using GL_manager = GL_manager_T; using GL_viewer = GL_viewer_T; }} #include "OpenGLArea" #include #include #include #include #include #include namespace toolx { namespace Xt { class sg_viewer : public sg::GL_viewer { typedef sg::GL_viewer parent; public: sg_viewer(session& a_session, int a_x = 0,int a_y = 0, unsigned int a_width = 500,unsigned int a_height = 500, const std::string& a_win_title = "") :parent(a_session.out(),a_width,a_height) ,m_session(a_session) ,m_shell(0) ,m_glarea(0) ,m_interactor(0) { Widget app_widget = a_session.get_app_widget(); if(!app_widget) return; std::string sgeom; tools::numas(a_width,sgeom); sgeom += "x"; tools::numas(a_height,sgeom); sgeom += "+"; tools::numas(a_x,sgeom); sgeom += "+"; tools::numas(a_y,sgeom); Arg args[2]; XtSetArg(args[0],XtNgeometry,XtNewString(sgeom.c_str())); XtSetArg(args[1],XtNborderWidth,0); m_shell = ::XtAppCreateShell((char*)a_win_title.c_str(), (char*)"sg_viewer_shell", topLevelShellWidgetClass,XtDisplay(app_widget),args,2); ::XtSetMappedWhenManaged(m_shell,True); m_glarea = ::XtCreateManagedWidget("glarea",OpenGLArea::widget_class(),m_shell,args,0); ::XtAddCallback(m_glarea,XoNpaintCallback,paint_cbk,(XtPointer)this); ::XtAddCallback(m_glarea,XoNeventCallback,event_cbk,(XtPointer)this); ::XtAddCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this); ::XtRealizeWidget(m_shell); } virtual ~sg_viewer() { if(m_shell) { ::XtRemoveCallback(m_glarea,XoNpaintCallback,paint_cbk,(XtPointer)this); ::XtRemoveCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this); ::XtDestroyWidget(m_shell); } m_shell = 0; m_glarea = 0; } protected: sg_viewer(const sg_viewer& a_from) :parent(a_from) ,m_session(a_from.m_session) ,m_shell(0) ,m_glarea(0) ,m_interactor(0) {} sg_viewer& operator=(const sg_viewer& a_from){ parent::operator=(a_from); return *this; } public: bool has_window() const {return m_glarea?true:false;} bool show() { if(!m_shell) return false; ::XtRealizeWidget(m_shell); ::XtMapWidget(m_shell); // Raise window : if(XtIsWidget(m_shell) && XtIsRealized(m_shell) ) { Display* display = XtDisplay(m_shell); Atom atom = ::XInternAtom(display,"WM_DELETE_WINDOW",False); ::XSetWMProtocols(display,XtWindow(m_shell),&atom,1); ::XRaiseWindow(display,XtWindow(m_shell)); } return true; } void win_render() { if(!m_glarea) return; OpenGLArea::paint(m_glarea); m_session.sync(); } void emit_win_render() { if(!m_glarea) return; if(!post_expose(m_glarea)) {} } bool window_size(unsigned int& a_w,unsigned int& a_h) { if(!m_glarea) {a_w = 0;a_h = 0;return false;} a_w = (unsigned int)m_glarea->core.width; a_h = (unsigned int)m_glarea->core.height; return true; } void render_area_size(unsigned int& a_w,unsigned int& a_h) { a_w = parent::width(); a_h = parent::height(); } public: void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership. protected: static void paint_cbk(Widget a_widget,XtPointer a_tag,XtPointer){ unsigned int width = a_widget->core.width; unsigned int height = a_widget->core.height; sg_viewer* _this = (sg_viewer*)a_tag; _this->set_size(width,height); _this->render(); } static void event_cbk(Widget,XtPointer a_tag,XtPointer a_data){ sg_viewer* _this = (sg_viewer*)a_tag; if(!_this->m_interactor) return; XoAnyCallbackStruct* data = (XoAnyCallbackStruct*)a_data; XEvent* xevent = data->event; switch( xevent->type ) { case KeyPress:{ KeySym key_sym; ::XLookupString(&(xevent->xkey),NULL,0,&key_sym,NULL); tools::sg::key_down_event event(_this->convert(key_sym)); _this->m_interactor->key_press(event); }return; case KeyRelease:{ KeySym key_sym; ::XLookupString(&(xevent->xkey),NULL,0,&key_sym,NULL); tools::sg::key_up_event event(_this->convert(key_sym)); _this->m_interactor->key_release(event); }return; case ButtonPress:{ bool shift_modifier = xevent->xkey.state & ShiftMask; bool control_modifier = xevent->xkey.state & ControlMask; if(xevent->xbutton.button==Button4) { //4=wheel down, or move down double touch on trackpad = zoom in. tools::sg::wheel_rotate_event event(8,xevent->xbutton.x,xevent->xbutton.y,shift_modifier,control_modifier); //8=cooking. _this->m_interactor->wheel_rotate(event); } else if(xevent->xbutton.button==Button5) { //5=wheel up, or move up double touch on trackpad = zoom out. tools::sg::wheel_rotate_event event(-8,xevent->xbutton.x,xevent->xbutton.y,shift_modifier,control_modifier); //8=cooking. _this->m_interactor->wheel_rotate(event); } else if(xevent->xbutton.button==Button1) { tools::sg::mouse_down_event event(xevent->xbutton.x,xevent->xbutton.y,shift_modifier,control_modifier); _this->m_interactor->mouse_press(event); } }return; case ButtonRelease:{ if(xevent->xbutton.button==Button1) { bool shift_modifier = xevent->xkey.state & ShiftMask; bool control_modifier = xevent->xkey.state & ControlMask; tools::sg::mouse_up_event event(xevent->xbutton.x,xevent->xbutton.y,shift_modifier,control_modifier); _this->m_interactor->mouse_release(event); } }return; case MotionNotify:{ if((xevent->xmotion.state & Button1MotionMask)==Button1MotionMask) { bool shift_modifier = xevent->xkey.state & ShiftMask; bool control_modifier = xevent->xkey.state & ControlMask; tools::sg::mouse_move_event event(xevent->xmotion.x,xevent->xmotion.y,shift_modifier,control_modifier,0,0,false); _this->m_interactor->mouse_move(event); } }return; default:return;} } static void destroy_shell_callback(Widget,XtPointer a_tag,XtPointer) { sg_viewer* _this = (sg_viewer*)a_tag; _this->m_shell = 0; _this->m_glarea = 0; } protected: tools::key_code convert(KeySym a_key) { if(a_key==XK_Shift_L) return tools::sg::key_shift(); if(a_key==XK_Shift_R) return tools::sg::key_shift(); return (tools::key_code)a_key; } protected: session& m_session; Widget m_shell; Widget m_glarea; tools::sg::device_interactor* m_interactor; }; }} #endif