X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2FNasalCanvas.cxx;h=2e0b0c034ebc79a2c59cacbfff0a3ddda292f70e;hb=7c31654b3a570b275f224e143399968cf9bde719;hp=bbafebd0a4be62150e6facdd354795c2f0973732;hpb=f703882ffa73e70f555caa1867c1650534d5e3dc;p=flightgear.git diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx index bbafebd0a..2e0b0c034 100644 --- a/src/Scripting/NasalCanvas.cxx +++ b/src/Scripting/NasalCanvas.cxx @@ -22,243 +22,436 @@ # include "config.h" #endif -#include - #include "NasalCanvas.hxx" - -#include -#include +#include +#include +#include
+#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern naRef propNodeGhostCreate(naContext c, SGPropertyNode* n); -static naRef canvasPrototype; -static naRef elementPrototype; -static naRef eventPrototype; +namespace sc = simgear::canvas; -static void canvasGhostDestroy(void* g); -static void elementGhostDestroy(void* g); -static void eventGhostDestroy(void* g); +template +naRef elementGetNode(Element& element, naContext c) +{ + return propNodeGhostCreate(c, element.getProps()); +} -static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out); -naGhostType CanvasGhostType = { canvasGhostDestroy, "canvas", canvasGhostGetMember, 0 }; +typedef nasal::Ghost NasalEvent; +typedef nasal::Ghost NasalCustomEvent; +typedef nasal::Ghost NasalMouseEvent; -static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out); -static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value); -naGhostType ElementGhostType = { elementGhostDestroy, "canvas.element", - elementGhostGetMember, elementGhostSetMember }; +struct CustomEventDetailWrapper; +typedef SGSharedPtr CustomEventDetailPtr; +typedef nasal::Ghost NasalCustomEventDetail; -static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out); -naGhostType EventGhostType = { eventGhostDestroy, "ga-event", eventGhostGetMember, 0 }; +typedef nasal::Ghost NasalPropertyBasedElement; +typedef nasal::Ghost NasalCanvas; +typedef nasal::Ghost NasalElement; +typedef nasal::Ghost NasalGroup; +typedef nasal::Ghost NasalText; +typedef nasal::Ghost NasalWindow; -static void hashset(naContext c, naRef hash, const char* key, naRef val) +naRef to_nasal_helper(naContext c, const osg::BoundingBox& bb) { - naRef s = naNewString(c); - naStr_fromdata(s, (char*)key, strlen(key)); - naHash_set(hash, s, val); + std::vector bb_vec(4); + bb_vec[0] = bb._min.x(); + bb_vec[1] = bb._min.y(); + bb_vec[2] = bb._max.x(); + bb_vec[3] = bb._max.y(); + + return nasal::to_nasal(c, bb_vec); } -static naRef stringToNasal(naContext c, const std::string& s) +SGPropertyNode* from_nasal_helper(naContext c, naRef ref, SGPropertyNode**) { - return naStr_fromdata(naNewString(c), - const_cast(s.c_str()), - s.length()); + SGPropertyNode* props = ghostToPropNode(ref); + if( !props ) + naRuntimeError(c, "Not a SGPropertyNode ghost."); + + return props; } -static naRef eventTypeToNasal(naContext c, osgGA::GUIEventAdapter::EventType ty) +sc::CanvasWeakPtr from_nasal_helper(naContext c, naRef ref, sc::CanvasWeakPtr const*) { - switch (ty) { - case osgGA::GUIEventAdapter::PUSH: return stringToNasal(c, "push"); - case osgGA::GUIEventAdapter::RELEASE: return stringToNasal(c, "release"); - case osgGA::GUIEventAdapter::DOUBLECLICK: return stringToNasal(c, "double-click"); - case osgGA::GUIEventAdapter::DRAG: return stringToNasal(c, "drag"); - case osgGA::GUIEventAdapter::MOVE: return stringToNasal(c, "move"); - case osgGA::GUIEventAdapter::SCROLL: return stringToNasal(c, "scroll"); - case osgGA::GUIEventAdapter::KEYUP: return stringToNasal(c, "key-up"); - case osgGA::GUIEventAdapter::KEYDOWN: return stringToNasal(c, "key-down"); - - default: - ; // fall through - } - - return naNil(); + return nasal::from_nasal(c, ref); } -static canvas::Element* elementGhost(naRef r) +CanvasMgr& requireCanvasMgr(naContext c) { - if (naGhost_type(r) == &ElementGhostType) - return (canvas::Element*) naGhost_ptr(r); - return 0; + CanvasMgr* canvas_mgr = + static_cast(globals->get_subsystem("Canvas")); + if( !canvas_mgr ) + naRuntimeError(c, "Failed to get Canvas subsystem"); + + return *canvas_mgr; } -static Canvas* canvasGhost(naRef r) +GUIMgr& requireGUIMgr(naContext c) { - if (naGhost_type(r) == &CanvasGhostType) - return (Canvas*) naGhost_ptr(r); - return 0; + GUIMgr* mgr = + static_cast(globals->get_subsystem("CanvasGUI")); + if( !mgr ) + naRuntimeError(c, "Failed to get CanvasGUI subsystem"); + + return *mgr; } -static void elementGhostDestroy(void* g) +/** + * Create new Canvas and get ghost for it. + */ +static naRef f_createCanvas(const nasal::CallContext& ctx) { + return NasalCanvas::create(ctx.c, requireCanvasMgr(ctx.c).createCanvas()); } -static void canvasGhostDestroy(void* g) +/** + * Create new Window and get ghost for it. + */ +static naRef f_createWindow(const nasal::CallContext& ctx) { + return NasalWindow::create + ( + ctx.c, + requireGUIMgr(ctx.c).createWindow( ctx.getArg(0) ) + ); } -static void eventGhostDestroy(void* g) +/** + * Get ghost for existing Canvas. + */ +static naRef f_getCanvas(naContext c, naRef me, int argc, naRef* args) { - osgGA::GUIEventAdapter* gea = static_cast(g); - gea->unref(); + nasal::CallContext ctx(c, argc, args); + SGPropertyNode& props = *ctx.requireArg(0); + CanvasMgr& canvas_mgr = requireCanvasMgr(c); + + sc::CanvasPtr canvas; + if( canvas_mgr.getPropertyRoot() == props.getParent() ) + { + // get a canvas specified by its root node + canvas = canvas_mgr.getCanvas( props.getIndex() ); + if( !canvas || canvas->getProps() != &props ) + return naNil(); + } + else + { + // get a canvas by name + if( props.hasValue("name") ) + canvas = canvas_mgr.getCanvas( props.getStringValue("name") ); + else if( props.hasValue("index") ) + canvas = canvas_mgr.getCanvas( props.getIntValue("index") ); + } + + return NasalCanvas::create(c, canvas); } -static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out) +naRef f_canvasCreateGroup(sc::Canvas& canvas, const nasal::CallContext& ctx) { - const char* fieldName = naStr_data(field); - osgGA::GUIEventAdapter* gea = (osgGA::GUIEventAdapter*) g; - - if (!strcmp(fieldName, "parents")) { - *out = naNewVector(c); - naVec_append(*out, eventPrototype); - } else if (!strcmp(fieldName, "type")) *out = eventTypeToNasal(c, gea->getEventType()); - else if (!strcmp(fieldName, "windowX")) *out = naNum(gea->getWindowX()); - else if (!strcmp(fieldName, "windowY")) *out = naNum(gea->getWindowY()); - else if (!strcmp(fieldName, "time")) *out = naNum(gea->getTime()); - else if (!strcmp(fieldName, "button")) *out = naNum(gea->getButton()); - else { - return 0; - } - - return ""; + return NasalGroup::create + ( + ctx.c, + canvas.createGroup( ctx.getArg(0) ) + ); } -static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out) +/** + * Get group containing all gui windows + */ +naRef f_getDesktop(naContext c, naRef me, int argc, naRef* args) { - const char* fieldName = naStr_data(field); - Canvas* cvs = (Canvas*) g; - - if (!strcmp(fieldName, "parents")) { - *out = naNewVector(c); - naVec_append(*out, canvasPrototype); - } else if (!strcmp(fieldName, "sizeX")) *out = naNum(cvs->getSizeX()); - else if (!strcmp(fieldName, "sizeY")) *out = naNum(cvs->getSizeY()); - else { - return 0; - } - - return ""; + return NasalGroup::create(c, requireGUIMgr(c).getDesktop()); } -static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out) +naRef f_groupCreateChild(sc::Group& group, const nasal::CallContext& ctx) { - const char* fieldName = naStr_data(field); - canvas::Element* e = (canvas::Element*) g; - - if (!strcmp(fieldName, "parents")) { - *out = naNewVector(c); - naVec_append(*out, elementPrototype); - } else { - return 0; - } - - return ""; + return NasalElement::create + ( + ctx.c, + group.createChild( ctx.requireArg(0), + ctx.getArg(1) ) + ); } -static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value) +naRef f_groupGetChild(sc::Group& group, const nasal::CallContext& ctx) { - const char* fieldName = naStr_data(field); - canvas::Element* e = (canvas::Element*) g; + return NasalElement::create + ( + ctx.c, + group.getChild( ctx.requireArg(0) ) + ); } +naRef f_groupGetElementById(sc::Group& group, const nasal::CallContext& ctx) +{ + return NasalElement::create + ( + ctx.c, + group.getElementById( ctx.requireArg(0) ) + ); +} -static naRef f_canvas_getElement(naContext c, naRef me, int argc, naRef* args) +static void propElementSetData( simgear::PropertyBasedElement& el, + const std::string& name, + naContext c, + naRef ref ) { - Canvas* cvs = canvasGhost(me); - if (!cvs) { - naRuntimeError(c, "canvas.getElement called on non-canvas object"); - } - - return naNil(); + if( naIsNil(ref) ) + return el.removeDataProp(name); + + std::string val = nasal::from_nasal(c, ref); + + char* end = NULL; + + long val_long = strtol(val.c_str(), &end, 10); + if( !*end ) + return el.setDataProp(name, val_long); + + double val_double = strtod(val.c_str(), &end); + if( !*end ) + return el.setDataProp(name, val_double); + + el.setDataProp(name, val); } -static naRef f_element_addButtonCallback(naContext c, naRef me, int argc, naRef* args) +/** + * Accessor for HTML5 data properties. + * + * # set single property: + * el.data("myKey", 5); + * + * # set multiple properties + * el.data({myProp1: 12, myProp2: "test"}); + * + * # get value of properties + * el.data("myKey"); # 5 + * el.data("myProp2"); # "test" + * + * # remove a single property + * el.data("myKey", nil); + * + * # remove multiple properties + * el.data({myProp1: nil, myProp2: nil}); + * + * # set and remove multiple properties + * el.data({newProp: "some text...", removeProp: nil}); + * + * + * @see http://api.jquery.com/data/ + */ +static naRef f_propElementData( simgear::PropertyBasedElement& el, + const nasal::CallContext& ctx ) { - canvas::Element* e = elementGhost(me); - if (!e) { - naRuntimeError(c, "element.addButtonCallback called on non-canvas-element object"); + if( ctx.isHash(0) ) + { + // Add/delete properties given as hash + nasal::Hash obj = ctx.requireArg(0); + for(nasal::Hash::iterator it = obj.begin(); it != obj.end(); ++it) + propElementSetData(el, it->getKey(), ctx.c, it->getValue()); + + return ctx.to_nasal(&el); } - + + std::string name = ctx.getArg(0); + if( !name.empty() ) + { + if( ctx.argc == 1 ) + { + // name + additional argument -> add/delete property + SGPropertyNode* node = el.getDataProp(name); + if( !node ) + return naNil(); + + return ctx.to_nasal( node->getStringValue() ); + } + else + { + // only name -> get property + propElementSetData(el, name, ctx.c, ctx.requireArg(1)); + return ctx.to_nasal(&el); + } + } + return naNil(); } -static naRef f_element_addDragCallback(naContext c, naRef me, int argc, naRef* args) +template +naRef f_eventGetModifier(sc::MouseEvent& event, naContext) { - canvas::Element* e = elementGhost(me); - if (!e) { - naRuntimeError(c, "element.addDragCallback called on non-canvas-element object"); - } - - return naNil(); + return naNum((event.getModifiers() & Mask) != 0); } -static naRef f_element_addMoveCallback(naContext c, naRef me, int argc, naRef* args) +static naRef f_createCustomEvent(const nasal::CallContext& ctx) { - canvas::Element* e = elementGhost(me); - if (!e) { - naRuntimeError(c, "element.addMoveCallback called on non-canvas-element object"); + std::string const& type = ctx.requireArg(0); + if( type.empty() ) + return naNil(); + + simgear::StringMap detail; + if( ctx.isHash(1) ) + { + nasal::Hash const& cfg = ctx.requireArg(1); + naRef na_detail = cfg.get("detail"); + if( naIsHash(na_detail) ) + detail = ctx.from_nasal(na_detail); } - - return naNil(); + + return NasalCustomEvent::create( + ctx.c, + sc::CustomEventPtr(new sc::CustomEvent(type, detail)) + ); } -static naRef f_element_addScrollCallback(naContext c, naRef me, int argc, naRef* args) +struct CustomEventDetailWrapper: + public SGReferenced { - canvas::Element* e = elementGhost(me); - if (!e) { - naRuntimeError(c, "element.addScrollCallback called on non-canvas-element object"); + sc::CustomEventPtr _event; + + CustomEventDetailWrapper(const sc::CustomEventPtr& event): + _event(event) + { + } - - return naNil(); + + bool _get( const std::string& key, + std::string& value_out ) const + { + if( !_event ) + return false; + + simgear::StringMap::const_iterator it = _event->detail.find(key); + if( it == _event->detail.end() ) + return false; + + value_out = it->second; + return true; + } + + bool _set( const std::string& key, + const std::string& value ) + { + if( !_event ) + return false; + + _event->detail[ key ] = value; + return true; + } +}; + +static naRef f_customEventGetDetail( sc::CustomEvent& event, + naContext c ) +{ + return nasal::to_nasal( + c, + CustomEventDetailPtr(new CustomEventDetailWrapper(&event)) + ); } -static naRef f_canvas(naContext c, naRef me, int argc, naRef* args) +naRef to_nasal_helper(naContext c, const sc::ElementWeakPtr& el) { - return naNil(); + return NasalElement::create(c, el.lock()); } -// Table of extension functions. Terminate with zeros. -static struct { const char* name; naCFunction func; } funcs[] = { - { "canvas", f_canvas }, - { 0, 0 } -}; +naRef to_nasal_helper(naContext c, const sc::CanvasWeakPtr& canvas) +{ + return NasalCanvas::create(c, canvas.lock()); +} -naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave) +naRef initNasalCanvas(naRef globals, naContext c) { - canvasPrototype = naNewHash(c); - hashset(c, gcSave, "canvasProto", canvasPrototype); - - hashset(c, canvasPrototype, "getElement", naNewFunc(c, naNewCCode(c, f_canvas_getElement))); - - eventPrototype = naNewHash(c); - hashset(c, gcSave, "eventProto", eventPrototype); - // set any event methods - - elementPrototype = naNewHash(c); - hashset(c, gcSave, "elementProto", elementPrototype); + using osgGA::GUIEventAdapter; + NasalEvent::init("canvas.Event") + .member("type", &sc::Event::getTypeString) + .member("target", &sc::Event::getTarget) + .member("currentTarget", &sc::Event::getCurrentTarget) + .method("stopPropagation", &sc::Event::stopPropagation); + + NasalCustomEvent::init("canvas.CustomEvent") + .bases() + .member("detail", &f_customEventGetDetail, &sc::CustomEvent::setDetail); + NasalCustomEventDetail::init("canvas.CustomEventDetail") + ._get(&CustomEventDetailWrapper::_get) + ._set(&CustomEventDetailWrapper::_set); + + NasalMouseEvent::init("canvas.MouseEvent") + .bases() + .member("screenX", &sc::MouseEvent::getScreenX) + .member("screenY", &sc::MouseEvent::getScreenY) + .member("clientX", &sc::MouseEvent::getClientX) + .member("clientY", &sc::MouseEvent::getClientY) + .member("localX", &sc::MouseEvent::getLocalX) + .member("localY", &sc::MouseEvent::getLocalY) + .member("deltaX", &sc::MouseEvent::getDeltaX) + .member("deltaY", &sc::MouseEvent::getDeltaY) + .member("button", &sc::MouseEvent::getButton) + .member("buttons", &sc::MouseEvent::getButtonMask) + .member("modifiers", &sc::MouseEvent::getModifiers) + .member("ctrlKey", &f_eventGetModifier) + .member("shiftKey", &f_eventGetModifier) + .member("altKey", &f_eventGetModifier) + .member("metaKey", &f_eventGetModifier) + .member("click_count", &sc::MouseEvent::getCurrentClickCount); + + NasalPropertyBasedElement::init("PropertyBasedElement") + .method("data", &f_propElementData); + NasalCanvas::init("Canvas") + .bases() + .member("_node_ghost", &elementGetNode) + .member("size_x", &sc::Canvas::getSizeX) + .member("size_y", &sc::Canvas::getSizeY) + .method("_createGroup", &f_canvasCreateGroup) + .method("_getGroup", &sc::Canvas::getGroup) + .method("addEventListener", &sc::Canvas::addEventListener) + .method("dispatchEvent", &sc::Canvas::dispatchEvent); + NasalElement::init("canvas.Element") + .bases() + .member("_node_ghost", &elementGetNode) + .method("_getParent", &sc::Element::getParent) + .method("_getCanvas", &sc::Element::getCanvas) + .method("addEventListener", &sc::Element::addEventListener) + .method("dispatchEvent", &sc::Element::dispatchEvent) + .method("getBoundingBox", &sc::Element::getBoundingBox) + .method("getTightBoundingBox", &sc::Element::getTightBoundingBox); + NasalGroup::init("canvas.Group") + .bases() + .method("_createChild", &f_groupCreateChild) + .method("_getChild", &f_groupGetChild) + .method("_getElementById", &f_groupGetElementById); + NasalText::init("canvas.Text") + .bases() + .method("getNearestCursor", &sc::Text::getNearestCursor); + + NasalWindow::init("canvas.Window") + .bases() + .member("_node_ghost", &elementGetNode) + .method("_getCanvasDecoration", &sc::Window::getCanvasDecoration); - hashset(c, elementPrototype, "addButtonCallback", naNewFunc(c, naNewCCode(c, f_element_addButtonCallback))); - hashset(c, elementPrototype, "addDragCallback", naNewFunc(c, naNewCCode(c, f_element_addDragCallback))); - hashset(c, elementPrototype, "addMoveCallback", naNewFunc(c, naNewCCode(c, f_element_addMoveCallback))); - hashset(c, elementPrototype, "addScrollCallback", naNewFunc(c, naNewCCode(c, f_element_addScrollCallback))); - - for(int i=0; funcs[i].name; i++) { - hashset(c, globals, funcs[i].name, - naNewFunc(c, naNewCCode(c, funcs[i].func))); - } - + nasal::Hash globals_module(globals, c), + canvas_module = globals_module.createHash("canvas"); + + canvas_module.set("_newCanvasGhost", f_createCanvas); + canvas_module.set("_newWindowGhost", f_createWindow); + canvas_module.set("_getCanvasGhost", f_getCanvas); + canvas_module.set("_getDesktopGhost", f_getDesktop); + + canvas_module.createHash("CustomEvent") + .set("new", &f_createCustomEvent); return naNil(); }