// HQWidget.cpp - Implementation of the HOOPS/Qt
class HQWidget
//
// More
about this class
// Headers
// System Includes
#include <stdlib.h>
#include <stdio.h>
// hoops_mvo includes
#include "HBaseOperator.h"
#include "HDB.h"
#include "HBaseView.h"
#include "HEventInfo.h"
// hoops includes
#include "hc.h"
#if IS_X11
// X11 Includes
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xmu/StdCmap.h>
#if USE_GLX_VISUAL
#define INT8 dummy_INT8
#define INT32 dummy_INT32
#include <GL/glx.h>
#undef INT8
#undef INT32
#endif // USE_GLX_VISUAL
#include "qintdict.h"
#endif // IS_X11
// qt includes
#include "qevent.h"
// HOOPS/Qt Include
#include "HQWidget.h"
// pointer to an HOOPS/MVO HDB object
// needs to be created first in the application
extern HDB
* m_pHDB;
HQWidget::HQWidget(
QWidget *parent, const char *name, WFlags f )
: QWidget(parent,
name, f)
{
// More
about this class
// make sure that no Paint or Resize
events call HC_Update_Display
// before we finish initializing the
object
initDone = false;
// Make certain we have a valid paint
device
if ( this == 0 ) {
warning(
"HQWidget: Paint device cannot be null" );
}
if ( this->devType() != PDT_WIDGET &&
this->devType() != PDT_PIXMAP ) {
warning(
"HQWidget: Unsupported paint device type" );
}
// Initialize the pointers to associated
HOOPS/MVO
// Model and View objects
m_pHBaseModel = 0;
m_pHView = 0;
// Initialize Colormap and Window ID
resources
my_colormap = 0;
my_windowid = 0;
// this does all the work for palettes
and windowid
setup_window();
setBackgroundMode(
NoBackground );
}
HQWidget::~HQWidget()
{
// empty destructor
}
long
HQWidget::GetColorMap()
{
// Accessor method for private member
return my_colormap;
}
long
HQWidget::GetWindowId()
{
// Accessor method for private member
return my_windowid;
}
void
HQWidget::paintEvent( QPaintEvent * )
{
// make certain the constructor was
able to finish initialization
// which means the Window Id and color
map are valid and we can
// create a HOOPS/MVO HBaseView object.
if ( !initDone ) {
// Say Base blahh - View init can finally happen
Init();
initDone = true;
}
// initiate the HOOPS/3D Graphics System
update cycle
HC_Update_Display();
}
void
HQWidget::resizeEvent( QResizeEvent * )
{
// make certain the constructor was
able to finish initialization
if ( initDone )
// initiate the HOOPS/3D Graphics
System update cycle
HC_Update_Display();
}
unsigned
long HQWidget::state2flags( unsigned long state )
{
// Map Qt Mouse button state to HOOPS/MVO
flags
unsigned long flags=0;
// map the qt event's state to HOOPS/MVO
flags
if(state & LeftButton) flags|=MVO_LBUTTON;
if(state & RightButton) flags|=MVO_RBUTTON;
if(state & MidButton) flags|=MVO_MBUTTON;
if(state & ShiftButton) flags|=MVO_SHIFT;
if(state & ControlButton) flags|=MVO_CONTROL;
return flags;
}
void
HQWidget::mousePressEvent( QMouseEvent * e)
{
// The HQWidget Object has an associated
HOOPS/MVO View Object
// Pass the Qt Mouse Left Button Events
to the associated
// HOOPS/MVO View Object's current
Operator. Right Button events
// are sent to a Pop-Up dialog elsewhere
and should not make it this
// far - if they do make it this far,
they are sent to a null method.
// Left Button Mouse Event
if(e->button() == LeftButton) {
// Find the HOOPS/MVO View associated
with the HQWidget and call
// its method for Left Button Down
with
// the Qt event's state information
if (m_pHView) {
HEventInfo event(m_pHView);
HBaseOperator *op = m_pHView->GetCurrentOperator();
if (op) {
unsigned long flags = state2flags(e->state());
event.SetPoint(HE_LButtonDown, e->x(), e->y(),
flags);
op->OnLButtonDown(event);
}
}
}else{
// Right Button Mouse Event
if(e->button() == RightButton)
// call HQWidget's Right Button Down
method - a no-op
OnRightButtonDown();
// Note: if you want to use the HOOPS/MVO
Operator's
// Right Mouse Down Event Handler,
call it instead
// using the same approach used to
call op->OnLButtonDown above.
}
}
void
HQWidget::mouseReleaseEvent( QMouseEvent * e)
{
// The HQWidget Object has an associated
HOOPS/MVO View Object
// Pass the Qt Mouse Left Button Events
to the associated
// HOOPS/MVO View Object's current
Operator.
// Right Button events are sent to
a Pop-Up dialog elsewhere and
// should not make it this far - if
they do make it this far, they
// are sent to a null method.
// Left Button Mouse Event
if(e->button() == LeftButton) {
// Find the HOOPS/MVO View associated
with the HQWidget and call
// its method for Left Button Up with
// the Qt event's state information
if (m_pHView) {
HEventInfo event(m_pHView);
HBaseOperator *op = m_pHView->GetCurrentOperator();
if (op) {
unsigned long flags = state2flags(e->state());
event.SetPoint(HE_LButtonUp, e->x(), e->y(),
flags);
op->OnLButtonUp(event);
}
}
}
// Right Button Mouse Event
else{
// call HQWidget's Right Button Up
method - a no-op
if(e->button() == RightButton) OnRightButtonUp();
}
}
void
HQWidget::OnRightButtonDown()
{
// Virtual method - overload in derived
class to handle
// this event
}
void
HQWidget::OnRightButtonUp()
{
// Virtual method - overload in derived
class to handle
// this event
}
void
HQWidget::mouseMoveEvent( QMouseEvent * e)
{
// The HQWidget Object has an associated
HOOPS/MVO View Object
// Pass the Qt Mouse Move Button Events
to the associated
// HOOPS/MVO View Object's current
Operator.
// Find the HOOPS/MVO View associated
with the HQWidget and call
// its method for OnMouseMove with
the Qt event's state information
if (m_pHView) {
HEventInfo event(m_pHView);
HBaseOperator *op = m_pHView->GetCurrentOperator();
if (op) {
unsigned long flags = state2flags(e->state());
event.SetPoint(HE_MouseMove, e->x(), e->y(), flags);
op->OnMouseMove(event);
}
}
}
void
HQWidget::keyPressEvent ( QKeyEvent * e )
{
// The HQWidget Object has an associated
HOOPS/MVO View Object
// Pass the Qt Key Press Events to
the associated HOOPS/MVO View
// Object's current Operator.
// Find the HOOPS/MVO View associated
with the HQWidget and call
// its method for OnKeyDown with the
Qt event's state information
if (m_pHView) {
HEventInfo event(m_pHView);
HBaseOperator *op = m_pHView->GetCurrentOperator();
if (op) {
unsigned long flags = state2flags(e->state());
//these casts are nessary to
get the right Set
event.SetKey(HE_KeyDown, (unsigned int)e->ascii(),
(unsigned int)1, flags);
op->OnKeyDown(event);
}
}
}
void
HQWidget::keyReleaseEvent ( QKeyEvent * e )
{
// The HQWidget Object has an associated
HOOPS/MVO View Object
// Pass the Qt Key Release Events to
the associated HOOPS/MVO View
// Object's current Operator.
// Find the HOOPS/MVO View associated
with the HQWidget and call
// its method for OnKeyDown with the
Qt event's state information
if (m_pHView) {
HEventInfo event(m_pHView);
HBaseOperator *op = m_pHView->GetCurrentOperator();
if (op) {
unsigned long flags = state2flags(e->state());
//these casts are nessary to
get the right Set
event.SetKey(HE_KeyUp, (unsigned int)e->ascii(),
(unsigned int)1, flags);
op->OnKeyUp(event);
}
}
}
void HQWidget::Init()
{
// this is overloaded by the derived
class MyHQWidget and the actual
// creation of the HBaseView object
is performed there. (Go there.)
// This gives maximum flexibility of
how the application connects
// HBaseModel, HBaseView and HQWidget
objects to each other.
}
#if IS_WIN
// Windows window id and color palette configuration
void
HQWidget::setup_window()
{
// Find the MS Windows Window ID; to
be passed to the
// HOOPS/3D Graphics Systemt
my_windowid = (long)((QWidget *) this)->winId();
// Colormap set to null
my_colormap = 0;
}
#endif
#if IS_X11
// below is the ugly stuff for X11 window
id and palette
#ifndef USE_GLX_VISUAL
#ifdef __cplusplus
# define get_visual_class(vis_ptr)
((vis_ptr)->c_class)
#else
# define get_visual_class(vis_ptr)
((vis_ptr)->class)
#endif
#define INITIAL_VALUE (-1)
static
void get_best_visual (
Display *display,
XVisualInfo *visual) {
XVisualInfo f_template;
XVisualInfo * visuals;
int visual_count;
int best = INITIAL_VALUE;
// Find the best X11 visual available;
used to configure the X11
// Window into which the HOOPS/3D Graphics
System will draw
// Get a list of the deepest possible
visuals
f_template.screen = DefaultScreen (display);
f_template.depth = 24;
do
visuals = XGetVisualInfo (display, VisualScreenMask | VisualDepthMask,
&f_template, &visual_count);
while(! (visual_count > 0 || --f_template.depth == 0));
while(! (visual_count-- == 0)) {
if (visuals[visual_count].depth > 8) {
switch (get_visual_class (&visuals[visual_count]))
{
case TrueColor: {
best = visual_count;
} break;
case DirectColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == PseudoColor
||
get_visual_class (&visuals[best]) == StaticColor
||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case PseudoColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == StaticColor
||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case StaticColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case GrayScale: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case StaticGray: {
if (best == INITIAL_VALUE)
best = visual_count;
} break;
}
}
else {
switch (get_visual_class (&visuals[visual_count]))
{
case PseudoColor: {
best = visual_count;
} break;
case StaticColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == TrueColor
||
get_visual_class (&visuals[best]) == DirectColor
||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case TrueColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == DirectColor
||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case DirectColor: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == GrayScale
||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case GrayScale: {
if (best == INITIAL_VALUE ||
get_visual_class (&visuals[best]) == StaticGray)
best = visual_count;
} break;
case StaticGray: {
if (best == INITIAL_VALUE)
best = visual_count;
} break;
}/*switch*/
}/*if*/
} while (--visual_count >= 0);/*until*/
if (best != INITIAL_VALUE) {
//*visual = visuals[best].visual;
memcpy((void*)visual, (void*) &(visuals[best]), sizeof(XVisualInfo));
XFree ((char *) visuals);
}
}
#endif
struct CMapEntry {
// colormap accounting for x11
// the msdev browser show this in err
it's in #ifdef IS_X11
CMapEntry( Colormap m, bool a ) : cmap(m), alloc(a)
{}
~CMapEntry();
Colormap cmap;
bool alloc;
};
CMapEntry::~CMapEntry()
{
if ( alloc )
XFreeColormap( QPaintDevice::x__Display(), cmap );
}
static bool cmap_init = FALSE;
static QIntDict<CMapEntry> *cmap_dict = 0;
static void
cleanup_cmaps()
{
if ( !cmap_dict ) return;
cmap_dict->setAutoDelete( TRUE );
delete cmap_dict;
cmap_dict = 0;
}
static Colormap
choose_cmap( Display *dpy, XVisualInfo *vi )
{
if ( !cmap_init ) {
cmap_init = TRUE;
cmap_dict = new QIntDict<CMapEntry>;
qAddPostRoutine (cleanup_cmaps);
}
CMapEntry *x = cmap_dict->find( (long)vi->visualid );
// found colormap for visual
if ( x )
return x->cmap;
Colormap cmap = 0;
bool alloc = false;
XStandardColormap *c;
int n, i;
// is this the delault vis
if ( vi->visual==DefaultVisual(dpy,vi->screen) )
return DefaultColormap( dpy, vi->screen );
// try to find a shared colormap
if ( !cmap ) {
if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth,
XA_RGB_DEFAULT_MAP,FALSE,TRUE)
) {
if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
XA_RGB_DEFAULT_MAP) ) {
i = 0;
while ( i < n && cmap == 0 ) {
if ( c[i].visualid == vi->visualid )
cmap = c[i].colormap;
i++;
}
XFree( (char *)c );
}
}
}
// no shared cmap found
if ( !cmap ) {
cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen),
vi->visual,
AllocNone );
alloc = TRUE;
}
// add our new colormap to the lookup
for next time
x = new CMapEntry( cmap, alloc );
cmap_dict->insert( (long)vi->visualid, x );
return cmap;
}
void
HQWidget::setup_window()
{
// Find the right X11 visual and colormap.
// Different approach needed if using
OpenGL - handle this case.
Colormap cmap;
bool visible = isVisible();
if (visible) hide();
Display * dpy=this->x11Display();
#if USE_GLX_VISUAL
static int dbvisual[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
GLX_DOUBLEBUFFER,
None
};
XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy),
dbvisual);
#else
// get our own X visual
XVisualInfo visual;
get_best_visual(dpy, &visual);
XVisualInfo *vi = &visual;
#endif
// create and initialize XSetWindowAttributes
object
XSetWindowAttributes a;
// find best colormap
cmap = choose_cmap( dpy, vi );
a.colormap = cmap;
// Set Background and border color
a.background_pixel = backgroundColor().pixel();
a.border_pixel = black.pixel();
// Create and initialize an X11 Window
Window p = RootWindow( dpy, DefaultScreen(dpy) );
if ( parentWidget() )
p = parentWidget()->winId();
Window w = XCreateWindow( dpy, p, x(), y(), width(),
height(),
0, vi->depth,
InputOutput, vi->visual,
CWBackPixel|CWBorderPixel|CWColormap,
&a );
// record for later
my_windowid = w;
// X11 Color Map Configuration
Window wtl = topLevelWidget()->winId();
Window *cmw;
Window *cmwret;
int count;
// Get list of display's X11 Color Map
Windows
if ( XGetWMColormapWindows(dpy, wtl,&cmwret,&count)
){
cmw = new Window[count+1];
memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count
);
XFree( (char *)cmwret );
int i;
for ( i=0; i<count; i++ ) {
if ( cmw[i] == winId() ) { //
replace old window
cmw[i] = w;
break;
}
}
if ( i >= count ) // append
new window
cmw[count++] = w;
}
else {
count = 1;
cmw = new Window[count];
cmw[0] = w;
}
create( w );
XSetWMColormapWindows( dpy, topLevelWidget()->winId(),
cmw, count );
delete [] cmw;
if ( visible ) show();
XFlush(dpy);
//record for later
my_colormap = cmap;
}
#endif //IS_X11
|