// Copyright (c) 2009 The Foundry Visionmongers Ltd. All Rights Reserved. static const char* const CLASS = "Handle"; static const char* const HELP = "Sample source code to make your Op get mouse interaction from the Viewer. " "Clicking and dragging in the viewer prints messages on stdout."; #include "DDImage/NoIop.h" #include "DDImage/Row.h" #include "DDImage/Knobs.h" #include "DDImage/ViewerContext.h" #include using namespace DD::Image; class TestOp : public NoIop { public: #if DD_IMAGE_VERSION_MAJOR >= 5 TestOp(Node* node) : NoIop(node) #else TestOp() : NoIop() #endif { } virtual void knobs(Knob_Callback); const char* Class() const { return CLASS; } const char* node_help() const { return HELP; } static const Iop::Description d; bool handle(ViewerContext* ctx, int index); }; // This is the eventual function that will be called, where you put // in whatever you really want to have happen as the user clicks on // the viewer: bool TestOp::handle(ViewerContext* ctx, int index) { printf("Index %d: ", index); switch (ctx->event()) { case PUSH: printf("PUSH"); break; case DRAG: printf("DRAG"); break; case RELEASE: printf("RELEASE"); break; case MOVE: printf("MOVE"); break; // MOVE will only work if you use ANYWHERE_MOUSEMOVES instead of // ANYWHERE below. case KEY: printf("KEY"); break; // KEY appears to be broken in Qt version of Nuke. Probably won't // be fixed soon. You can define popup menus with shortcuts that // work but that is a whole further subject... default: printf("event()==%d", ctx->event()); break; } printf(" xyz=%g,%g,%g", ctx->x(), ctx->y(), ctx->z()); printf(" mousexy=%d,%d", ctx->mouse_x(), ctx->mouse_y()); printf(" key=%d", ctx->key()); printf("\n"); return true; // true means we are interested in the event } // Ugly glue needed to fool Nuke into calling this: // Interaction requires a "knob". This will probably be fixed in the // future so that all this glue code is not needed and you can directly // tell it to call your handle() method. For now you have to make // this dummy knob, and your control panel must be open to get any // interaction. class GlueKnob : public Knob { TestOp* theOp; const char* Class() const { return "Glue"; } public: // This is what Nuke will call once the below stuff is executed: static bool handle_cb(ViewerContext* ctx, Knob* knob, int index) { return ((GlueKnob*)knob)->theOp->handle(ctx, index); } // Nuke calls this to draw the handle, this then calls make_handle // which tells Nuke to call the above function when the mouse does // something... void draw_handle(ViewerContext* ctx) { if (ctx->event() == DRAW_OPAQUE || ctx->event() == PUSH // true for clicking hit-detection || ctx->event() == DRAG // true for selection box hit-detection ) { // Draw something in OpenGL that can be hit-detected. If this // is hit-detected then handle() is called with index = 1 begin_handle(ctx, handle_cb, 1 /*index*/, 0, 0, 0); glBegin(GL_POLYGON); glVertex2i(10, 10); glVertex2i(30, 5); glVertex2i(35, 35); glVertex2i(10, 35); glEnd(); // Draw a dot that is hit-detected. If it is then handle() is // called with index = 2 make_handle(ctx, handle_cb, 2 /*index*/, 50, 50, 0 /*xyz*/); // Make clicks anywhere in the viewer call handle() with index = 0. // This takes the lowest precedence over, so above will be detected // first. begin_handle(Knob::ANYWHERE, ctx, handle_cb, 0 /*index*/, 0, 0, 0 /*xyz*/); end_handle(ctx); } } // And you need to implement this just to make it call draw_handle: bool build_handle(ViewerContext* ctx) { // If your handles only work in 2D or 3D mode, only return true // in those cases: // return (ctx->transform_mode() == VIEWER_2D); return true; } GlueKnob(Knob_Closure* kc, TestOp* t, const char* n) : Knob(kc, n) { theOp = t; } }; void TestOp::knobs(Knob_Callback f) { // create the knob needed to get mouse interaction: CustomKnob1(GlueKnob, f, this, "kludge"); // create other knobs here! } #if DD_IMAGE_VERSION_MAJOR >= 5 static Iop* build(Node* node) { return new TestOp(node); } #else static Iop* build() { return new TestOp(); } #endif const Iop::Description TestOp::d(CLASS, 0, build);