Canvas: Allow using canvases as PUI widgets.
- Add new widget type canvas - Set canvas view dimension from the gui xml. - Expose mouse events to canvas widget properties.
This commit is contained in:
parent
36fe51c7f0
commit
373d511c69
12 changed files with 312 additions and 15 deletions
|
@ -18,11 +18,15 @@
|
|||
|
||||
#include "canvas.hxx"
|
||||
#include "elements/group.hxx"
|
||||
|
||||
#include <Canvas/property_helper.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Viewer/renderer.hxx>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Geode>
|
||||
#include <osgText/Text>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -97,13 +101,13 @@ Canvas::Canvas():
|
|||
_status(0),
|
||||
_sampling_dirty(false),
|
||||
_color_dirty(true),
|
||||
_node(0)
|
||||
_node(0),
|
||||
_render_always(false)
|
||||
{
|
||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||
|
||||
CameraCullCallback *camera_callback = new CameraCullCallback;
|
||||
_camera_callback = camera_callback;
|
||||
_cull_callback = new PlacementCullCallback(this, camera_callback);
|
||||
_camera_callback = new CameraCullCallback;
|
||||
_cull_callback = new PlacementCullCallback(this, _camera_callback);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -254,6 +258,9 @@ void Canvas::update(double delta_time_sec)
|
|||
_cull_callback
|
||||
);
|
||||
}
|
||||
|
||||
if( _render_always )
|
||||
_camera_callback->enableRendering();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -398,11 +405,38 @@ void Canvas::valueChanged(SGPropertyNode* node)
|
|||
|| node->getNameString() == "coverage-samples"
|
||||
|| node->getNameString() == "color-samples" )
|
||||
_sampling_dirty = true;
|
||||
else if( node->getNameString() == "render-always" )
|
||||
_render_always = node->getBoolValue();
|
||||
}
|
||||
|
||||
_root_group->valueChanged(node);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GLuint Canvas::getTexId() const
|
||||
{
|
||||
osg::Texture2D* tex = _texture.getTexture();
|
||||
if( !tex )
|
||||
return 0;
|
||||
|
||||
osgViewer::Viewer::Contexts contexts;
|
||||
globals->get_renderer()->getViewer()->getContexts(contexts);
|
||||
|
||||
if( contexts.empty() )
|
||||
return 0;
|
||||
|
||||
osg::State* state = contexts[0]->getState();
|
||||
if( !state )
|
||||
return 0;
|
||||
|
||||
osg::Texture::TextureObject* tobj =
|
||||
tex->getTextureObject( state->getContextID() );
|
||||
if( !tobj )
|
||||
return 0;
|
||||
|
||||
return tobj->_id;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace canvas
|
|||
class Group;
|
||||
}
|
||||
|
||||
class CameraCullCallback;
|
||||
class Canvas:
|
||||
public SGPropertyChangeListener
|
||||
{
|
||||
|
@ -71,6 +72,8 @@ class Canvas:
|
|||
SGPropertyNode * child );
|
||||
virtual void valueChanged (SGPropertyNode * node);
|
||||
|
||||
GLuint getTexId() const;
|
||||
|
||||
private:
|
||||
|
||||
Canvas(const Canvas&); // = delete;
|
||||
|
@ -93,8 +96,11 @@ class Canvas:
|
|||
SGPropertyNode_ptr _node;
|
||||
std::vector<SGPropertyNode_ptr> _color_background;
|
||||
|
||||
osg::ref_ptr<osg::NodeCallback> _camera_callback;
|
||||
osg::ref_ptr<CameraCullCallback> _camera_callback;
|
||||
osg::ref_ptr<osg::NodeCallback> _cull_callback;
|
||||
|
||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||
|
||||
std::vector<SGPropertyNode*> _dirty_placements;
|
||||
std::vector<Placements> _placements;
|
||||
|
||||
|
|
|
@ -107,6 +107,16 @@ void CanvasMgr::childRemoved( SGPropertyNode * parent,
|
|||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int CanvasMgr::getCanvasTexId(size_t index) const
|
||||
{
|
||||
if( index >= _canvases.size()
|
||||
|| !_canvases[index] )
|
||||
return 0;
|
||||
|
||||
return _canvases[index]->getTexId();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasMgr::textureAdded(SGPropertyNode* node)
|
||||
{
|
||||
|
@ -119,10 +129,8 @@ void CanvasMgr::textureAdded(SGPropertyNode* node)
|
|||
|
||||
_canvases.resize(index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
else if( _canvases[index] )
|
||||
SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
|
||||
}
|
||||
|
||||
_canvases[index].reset( new Canvas() );
|
||||
_canvases[index]->reset(node);
|
||||
|
|
|
@ -50,6 +50,14 @@ class CanvasMgr:
|
|||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
|
||||
/**
|
||||
* Get OpenGL texture name for given canvas
|
||||
*
|
||||
* @param Index of canvas
|
||||
* @return OpenGL texture name
|
||||
*/
|
||||
unsigned int getCanvasTexId(size_t index) const;
|
||||
|
||||
private:
|
||||
|
||||
/** Root node for everything concerning the canvas system */
|
||||
|
|
|
@ -2,6 +2,7 @@ include(FlightGearComponent)
|
|||
|
||||
set(SOURCES
|
||||
AirportList.cxx
|
||||
CanvasWidget.cxx
|
||||
MapWidget.cxx
|
||||
WaypointList.cxx
|
||||
dialog.cxx
|
||||
|
@ -21,6 +22,7 @@ set(SOURCES
|
|||
|
||||
set(HEADERS
|
||||
AirportList.hxx
|
||||
CanvasWidget.hxx
|
||||
MapWidget.hxx
|
||||
WaypointList.hxx
|
||||
dialog.hxx
|
||||
|
|
168
src/GUI/CanvasWidget.cxx
Normal file
168
src/GUI/CanvasWidget.cxx
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* CanvasWidget.cxx
|
||||
*
|
||||
* Created on: 03.07.2012
|
||||
* Author: tom
|
||||
*/
|
||||
|
||||
#include "CanvasWidget.hxx"
|
||||
|
||||
#include <Canvas/canvas_mgr.hxx>
|
||||
#include <Main/fg_os.hxx> // fgGetKeyModifiers()
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CanvasWidget::CanvasWidget( int x, int y,
|
||||
int width, int height,
|
||||
SGPropertyNode* props,
|
||||
const std::string& module ):
|
||||
puObject(x, y, width, height),
|
||||
_canvas_mgr( dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas")) ),
|
||||
_tex_id(0),
|
||||
_no_tex_cnt(0)
|
||||
{
|
||||
if( !_canvas_mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "CanvasWidget: failed to get canvas manager!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the first unused canvas slot
|
||||
SGPropertyNode* canvas_root = fgGetNode("/canvas", true);
|
||||
for(int index = 0;; ++index)
|
||||
{
|
||||
if( !canvas_root->getChild("texture", index) )
|
||||
{
|
||||
int view[2] = {
|
||||
// Get canvas viewport size. If not specified use the widget dimensions
|
||||
props->getIntValue("view[0]", width),
|
||||
props->getIntValue("view[1]", height)
|
||||
};
|
||||
_canvas = canvas_root->getChild("texture", index, true);
|
||||
_canvas->setIntValue("size[0]", view[0] * 2); // use higher resolution
|
||||
_canvas->setIntValue("size[1]", view[1] * 2); // for antialias
|
||||
_canvas->setIntValue("view[0]", view[0]);
|
||||
_canvas->setIntValue("view[1]", view[1]);
|
||||
_canvas->setBoolValue("render-always", true);
|
||||
_canvas->setStringValue( "name",
|
||||
props->getStringValue("name", "gui-anonymous") );
|
||||
SGPropertyNode* input = _canvas->getChild("input", 0, true);
|
||||
_mouse_x = input->getChild("mouse-x", 0, true);
|
||||
_mouse_y = input->getChild("mouse-y", 0, true);
|
||||
_mouse_down = input->getChild("mouse-down", 0, true);
|
||||
_mouse_drag = input->getChild("mouse-drag", 0, true);
|
||||
|
||||
SGPropertyNode *nasal = props->getNode("nasal");
|
||||
if( !nasal )
|
||||
break;
|
||||
|
||||
FGNasalSys *nas =
|
||||
dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
|
||||
if( !nas )
|
||||
SG_LOG( SG_GENERAL,
|
||||
SG_ALERT,
|
||||
"CanvasWidget: Failed to get nasal subsystem!" );
|
||||
|
||||
const std::string file = std::string("__canvas:")
|
||||
+ _canvas->getStringValue("name");
|
||||
|
||||
SGPropertyNode *load = nasal->getNode("load");
|
||||
if( load )
|
||||
{
|
||||
const char *s = load->getStringValue();
|
||||
nas->handleCommand(module.c_str(), file.c_str(), s, _canvas);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
CanvasWidget::~CanvasWidget()
|
||||
{
|
||||
if( _canvas )
|
||||
_canvas->getParent()
|
||||
->removeChild(_canvas->getName(), _canvas->getIndex(), false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasWidget::doHit(int button, int updown, int x, int y)
|
||||
{
|
||||
puObject::doHit(button, updown, x, y);
|
||||
|
||||
// CTRL allows resizing and SHIFT allows moving the window
|
||||
if( fgGetKeyModifiers() & (KEYMOD_CTRL | KEYMOD_SHIFT) )
|
||||
return;
|
||||
|
||||
_mouse_x->setIntValue(x - abox.min[0]);
|
||||
_mouse_y->setIntValue(y - abox.min[1]);
|
||||
|
||||
if( updown == PU_DRAG )
|
||||
_mouse_drag->setIntValue(button);
|
||||
else if( updown == PU_DOWN )
|
||||
_mouse_down->setIntValue(button);
|
||||
|
||||
if( button != active_mouse_button )
|
||||
return;
|
||||
|
||||
if (updown == PU_UP)
|
||||
puDeactivateWidget();
|
||||
else if (updown == PU_DOWN)
|
||||
puSetActiveWidget(this, x, y);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int CanvasWidget::checkKey(int key, int updown)
|
||||
{
|
||||
return puObject::checkKey(key, updown);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasWidget::setSize(int w, int h)
|
||||
{
|
||||
puObject::setSize(w, h);
|
||||
|
||||
_canvas->setIntValue("view[0]", w);
|
||||
_canvas->setIntValue("view[1]", h);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CanvasWidget::draw(int dx, int dy)
|
||||
{
|
||||
if( !_tex_id )
|
||||
{
|
||||
_tex_id = _canvas_mgr->getCanvasTexId(_canvas->getIndex());
|
||||
|
||||
// Normally we should be able to get the texture after one frame. I don't
|
||||
// know if there are circumstances where it can take longer, so we don't
|
||||
// log a warning message until we have tried a few times.
|
||||
if( !_tex_id )
|
||||
{
|
||||
if( ++_no_tex_cnt == 5 )
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "CanvasWidget: failed to get texture!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( _no_tex_cnt >= 5 )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GENERAL,
|
||||
SG_INFO,
|
||||
"CanvasWidget: got texture after " << _no_tex_cnt << " tries."
|
||||
);
|
||||
_no_tex_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, _tex_id);
|
||||
glBegin( GL_QUADS );
|
||||
glColor3f(1,1,1);
|
||||
glTexCoord2f(0,0); glVertex2f(dx + abox.min[0], dy + abox.min[1]);
|
||||
glTexCoord2f(1,0); glVertex2f(dx + abox.max[0], dy + abox.min[1]);
|
||||
glTexCoord2f(1,1); glVertex2f(dx + abox.max[0], dy + abox.max[1]);
|
||||
glTexCoord2f(0,1); glVertex2f(dx + abox.min[0], dy + abox.max[1]);
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
47
src/GUI/CanvasWidget.hxx
Normal file
47
src/GUI/CanvasWidget.hxx
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* CanvasWidget.hxx
|
||||
*
|
||||
* Created on: 03.07.2012
|
||||
* Author: tom
|
||||
*/
|
||||
|
||||
#ifndef CANVASWIDGET_HXX_
|
||||
#define CANVASWIDGET_HXX_
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <plib/pu.h>
|
||||
|
||||
class CanvasMgr;
|
||||
|
||||
class CanvasWidget:
|
||||
public puObject
|
||||
{
|
||||
public:
|
||||
CanvasWidget( int x, int y,
|
||||
int width, int height,
|
||||
SGPropertyNode* props,
|
||||
const std::string& module );
|
||||
virtual ~CanvasWidget();
|
||||
|
||||
virtual void doHit (int button, int updown, int x, int y);
|
||||
virtual int checkKey(int key , int updown);
|
||||
|
||||
virtual void setSize ( int w, int h );
|
||||
virtual void draw(int dx, int dy);
|
||||
|
||||
private:
|
||||
|
||||
CanvasMgr *_canvas_mgr; // TODO maybe we should store this in some central
|
||||
// location or make it static...
|
||||
|
||||
GLuint _tex_id; //<! OpenGL texture id if canvas
|
||||
size_t _no_tex_cnt;//<! Count since how many frames we were not
|
||||
// able to get the texture (for debugging)
|
||||
SGPropertyNode_ptr _canvas; //<! Canvas root property node
|
||||
SGPropertyNode *_mouse_x,
|
||||
*_mouse_y,
|
||||
*_mouse_down,
|
||||
*_mouse_drag;
|
||||
};
|
||||
|
||||
#endif /* CANVASWIDGET_HXX_ */
|
|
@ -18,6 +18,7 @@
|
|||
#include "property_list.hxx"
|
||||
#include "layout.hxx"
|
||||
#include "WaypointList.hxx"
|
||||
#include "CanvasWidget.hxx"
|
||||
#include "MapWidget.hxx"
|
||||
#include "FGFontCache.hxx"
|
||||
#include "FGColor.hxx"
|
||||
|
@ -827,6 +828,13 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
|
|||
MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
|
||||
setupObject(mapWidget, props);
|
||||
return mapWidget;
|
||||
} else if (type == "canvas") {
|
||||
CanvasWidget* canvasWidget = new CanvasWidget( x, y,
|
||||
x + width, y + height,
|
||||
props,
|
||||
_module );
|
||||
setupObject(canvasWidget, props);
|
||||
return canvasWidget;
|
||||
} else if (type == "combo") {
|
||||
fgComboBox *obj = new fgComboBox(x, y, x + width, y + height, props,
|
||||
props->getBoolValue("editable", false));
|
||||
|
|
|
@ -132,9 +132,9 @@ public:
|
|||
/**
|
||||
* Get the OSG camera for drawing this gauge.
|
||||
*/
|
||||
osg::Camera* getCamera() { return camera.get(); }
|
||||
osg::Camera* getCamera() const { return camera.get(); }
|
||||
|
||||
osg::Texture2D* getTexture() { return texture.get(); }
|
||||
osg::Texture2D* getTexture() const { return texture.get(); }
|
||||
//void setTexture(osg::Texture2D* t) { texture = t; }
|
||||
|
||||
// Real initialization function. Bad name.
|
||||
|
|
|
@ -1163,7 +1163,7 @@ bool fgInitSubsystems() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize the canvas 2d drawing subsystem.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
globals->add_subsystem("Canvas2D", new CanvasMgr, SGSubsystemMgr::DISPLAY);
|
||||
globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialise the ATIS Manager
|
||||
|
|
|
@ -816,11 +816,12 @@ naRef FGNasalSys::parse(const char* filename, const char* buf, int len)
|
|||
return naBindFunction(_context, code, _globals);
|
||||
}
|
||||
|
||||
bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
|
||||
bool FGNasalSys::handleCommand( const char* moduleName,
|
||||
const char* fileName,
|
||||
const char* src,
|
||||
const SGPropertyNode* arg )
|
||||
{
|
||||
const char* nasal = arg->getStringValue("script");
|
||||
const char* moduleName = arg->getStringValue("module");
|
||||
naRef code = parse(arg->getPath(true).c_str(), nasal, strlen(nasal));
|
||||
naRef code = parse(fileName, src, strlen(src));
|
||||
if(naIsNil(code)) return false;
|
||||
|
||||
// Commands can be run "in" a module. Make sure that module
|
||||
|
@ -845,6 +846,17 @@ bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
|
||||
{
|
||||
const char* src = arg->getStringValue("script");
|
||||
const char* moduleName = arg->getStringValue("module");
|
||||
|
||||
return handleCommand( moduleName,
|
||||
arg ? arg->getPath(true).c_str() : moduleName,
|
||||
src,
|
||||
arg );
|
||||
}
|
||||
|
||||
// settimer(func, dt, simtime) extension function. The first argument
|
||||
// is a Nasal function to call, the second is a delta time (from now),
|
||||
// in seconds. The third, if present, is a boolean value indicating
|
||||
|
|
|
@ -102,6 +102,10 @@ public:
|
|||
naRef cmdArgGhost();
|
||||
|
||||
// Callbacks for command and timer bindings
|
||||
virtual bool handleCommand( const char* moduleName,
|
||||
const char* fileName,
|
||||
const char* src,
|
||||
const SGPropertyNode* arg = 0 );
|
||||
virtual bool handleCommand(const SGPropertyNode* arg);
|
||||
|
||||
bool createModule(const char* moduleName, const char* fileName,
|
||||
|
|
Loading…
Add table
Reference in a new issue