227 lines
7.8 KiB
Plaintext
227 lines
7.8 KiB
Plaintext
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
|
// See the file tools.license for terms.
|
|
|
|
#ifndef toolx_Xt_zb_viewer
|
|
#define toolx_Xt_zb_viewer
|
|
|
|
#include "session"
|
|
#include "ImageArea"
|
|
#include "../X11/pixwin"
|
|
|
|
#include <X11/Shell.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <X11/IntrinsicP.h>
|
|
|
|
#include <tools/sg/zb_viewer>
|
|
#include <tools/num2s>
|
|
#include <tools/sg/device_interactor>
|
|
#include <tools/sg/keys>
|
|
|
|
namespace toolx {
|
|
namespace Xt {
|
|
|
|
class zb_viewer: public tools::sg::zb_viewer {
|
|
typedef tools::sg::zb_viewer parent;
|
|
public:
|
|
zb_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_image_area(0)
|
|
,m_pixwin(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*)"zb_viewer_shell",
|
|
topLevelShellWidgetClass,XtDisplay(app_widget),args,2);
|
|
::XtSetMappedWhenManaged(m_shell,True);
|
|
|
|
m_image_area = ::XtCreateManagedWidget("imagearea",ImageArea::widget_class(),m_shell,args,0);
|
|
::XtAddCallback(m_image_area,ImageArea::XoN_resizeCallback(),resize_cbk,(XtPointer)this);
|
|
::XtAddCallback(m_image_area,ImageArea::XoN_paintCallback(),paint_cbk,(XtPointer)this);
|
|
::XtAddCallback(m_image_area,ImageArea::XoN_eventCallback(),event_cbk,(XtPointer)this);
|
|
|
|
::XtAddCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this);
|
|
|
|
::XtRealizeWidget(m_shell);
|
|
|
|
{int iscreen;
|
|
Screen* screen = XtScreen(m_image_area);
|
|
iscreen = XScreenNumberOfScreen(screen);
|
|
m_pixwin = new toolx::X11::pixwin(a_session.out(),iscreen,XtDisplay(app_widget));
|
|
m_pixwin->set_size(m_image_area->core.width,m_image_area->core.height);}
|
|
}
|
|
virtual ~zb_viewer() {
|
|
delete m_pixwin;
|
|
if(m_shell) {
|
|
::XtRemoveCallback(m_image_area,ImageArea::XoN_paintCallback(),paint_cbk,(XtPointer)this);
|
|
::XtRemoveCallback(m_shell,XtNdestroyCallback,destroy_shell_callback,(XtPointer)this);
|
|
::XtDestroyWidget(m_shell);
|
|
}
|
|
m_shell = 0;
|
|
m_image_area = 0;
|
|
}
|
|
protected:
|
|
zb_viewer(const zb_viewer& a_from)
|
|
:parent(a_from)
|
|
,m_session(a_from.m_session)
|
|
,m_shell(0)
|
|
,m_image_area(0)
|
|
,m_interactor(0)
|
|
{}
|
|
zb_viewer& operator=(const zb_viewer& a_from){
|
|
parent::operator=(a_from);
|
|
return *this;
|
|
}
|
|
public:
|
|
bool has_window() const {return m_image_area?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_image_area) return;
|
|
ImageArea::paint(m_image_area);
|
|
m_session.sync();
|
|
}
|
|
|
|
void emit_win_render() {
|
|
if(!m_image_area) return;
|
|
if(!post_expose(m_image_area)) {}
|
|
}
|
|
|
|
bool window_size(unsigned int& a_w,unsigned int& a_h) {
|
|
if(!m_image_area) {a_w = 0;a_h = 0;return false;}
|
|
a_w = m_image_area->core.width;
|
|
a_h = m_image_area->core.height;
|
|
return true;
|
|
}
|
|
void render_area_size(unsigned int& a_w,unsigned int& a_h) {
|
|
a_w = parent::width();
|
|
a_h = parent::height();
|
|
}
|
|
|
|
void set_device_interactor(tools::sg::device_interactor* a_interactor) {m_interactor = a_interactor;} //we do not have ownership.
|
|
protected:
|
|
static void resize_cbk(Widget a_widget,XtPointer a_tag,XtPointer){
|
|
if(!XtIsRealized(a_widget)) return;
|
|
unsigned int width = a_widget->core.width;
|
|
unsigned int height = a_widget->core.height;
|
|
zb_viewer* _this = (zb_viewer*)a_tag;
|
|
_this->set_size(width,height);
|
|
_this->m_pixwin->set_size(width,height);
|
|
}
|
|
static void paint_cbk(Widget a_widget,XtPointer a_tag,XtPointer){
|
|
if(!XtIsRealized(a_widget)) return;
|
|
unsigned int width = a_widget->core.width;
|
|
unsigned int height = a_widget->core.height;
|
|
zb_viewer* _this = (zb_viewer*)a_tag;
|
|
if(!_this->render(tools::sg::zb_viewer::get_rgbas,false)) return; //rgbas because Qt wants an image 32 bits aligned.
|
|
_this->m_pixwin->put_buffer(XtWindow(a_widget),width,height,_this->out_buffer().data());
|
|
_this->out_buffer_clear();
|
|
}
|
|
static void event_cbk(Widget,XtPointer a_tag,XtPointer a_data){
|
|
zb_viewer* _this = (zb_viewer*)a_tag;
|
|
if(!_this->m_interactor) return;
|
|
ImageArea::XoAnyCallbackStruct* data = (ImageArea::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(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(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) {
|
|
zb_viewer* _this = (zb_viewer*)a_tag;
|
|
_this->m_shell = 0;
|
|
_this->m_image_area = 0;
|
|
}
|
|
protected:
|
|
tools::key_code convert_key(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_image_area;
|
|
toolx::X11::pixwin* m_pixwin;
|
|
tools::sg::device_interactor* m_interactor;
|
|
};
|
|
|
|
}}
|
|
|
|
|
|
#endif
|
|
|