/************************************************************ window.cpp - $Author: lsxi $ Copyright (C) 2005-2006 Masakazu Yonekura ************************************************************/ #ifdef HAVE_CALLBACK_H #include "window.h" /* * Document-class: OpenCV::GUI::Window * * Simple Window wedget. Window can show image(CvMat/IplImage). * * view image sample: * image = OpenCV::IplImage::load("opencv.bmp") #=> load image * window = OpenCV::GUI::Window.new("simple viewer")#=> create new window named "simaple viewer" * window.show(image) #=> show image */ __NAMESPACE_BEGIN_OPENCV __NAMESPACE_BEGIN_GUI __NAMESPACE_BEGIN_WINDOW const char* GET_WINDOW_NAME(VALUE object) { void *handle = DATA_PTR(object); if (!handle) rb_raise(rb_eStandardError, "window handle error"); const char *window_name = cvGetWindowName(handle); return window_name; } st_table *windows = st_init_numtable(); VALUE rb_klass; VALUE rb_class() { return rb_klass; } void define_ruby_class() { if (rb_klass) return; /* * opencv = rb_define_module("OpenCV"); * GUI = rb_define_module_under(opencv, "GUI"); * * note: this comment is used by rdoc. */ VALUE GUI = rb_module_GUI(); rb_klass = rb_define_class_under(GUI, "Window", rb_cObject); rb_define_singleton_method(rb_klass, "[]", RUBY_METHOD_FUNC(rb_aref), 1); rb_define_method(rb_klass, "initialize", RUBY_METHOD_FUNC(rb_initialize), -1); rb_define_method(rb_klass, "alive?", RUBY_METHOD_FUNC(rb_alive_q), 0); rb_define_method(rb_klass, "destroy", RUBY_METHOD_FUNC(rb_destroy), 0); rb_define_singleton_method(rb_klass, "destroy_all", RUBY_METHOD_FUNC(rb_destroy_all), 0); rb_define_method(rb_klass, "resize", RUBY_METHOD_FUNC(rb_resize), -1); rb_define_method(rb_klass, "move", RUBY_METHOD_FUNC(rb_move), -1); rb_define_method(rb_klass, "show_image", RUBY_METHOD_FUNC(rb_show_image), 1); rb_define_alias(rb_klass, "show", "show_image"); rb_define_method(rb_klass, "set_trackbar", RUBY_METHOD_FUNC(rb_set_trackbar), -1); rb_define_method(rb_klass, "set_mouse_callback", RUBY_METHOD_FUNC(rb_set_mouse_callback), 0); rb_define_alias(rb_klass, "on_mouse", "set_mouse_callback"); } VALUE rb_allocate(VALUE klass) { return Data_Wrap_Struct(klass, mark, free, 0); } void mark(void *ptr) { st_table *holder; if (st_lookup(windows, (st_data_t)ptr, (st_data_t*)&holder)) { st_foreach(holder, (int (*)(ANYARGS))each_protect, 0); } } VALUE each_protect(VALUE key, VALUE value) { rb_gc_mark(value); return ST_CONTINUE; } void free(void *ptr) { cvFree(&ptr); } /* * call-seq: * [name] * * Return window named name if exist, otherwise nil. */ VALUE rb_aref(VALUE klass, VALUE name) { VALUE window; Check_Type(name, T_STRING); void *handle = cvGetWindowHandle(StringValueCStr(name)); st_table *holder; if (st_lookup(windows, (st_data_t)handle, (st_data_t*)&holder) && st_lookup(holder, 0, (st_data_t*)&window)) { return window; } return Qnil; } /* * call-seq: * new(name[,autosize]) * * Create new window named name. * If autoresize is true(default), window size automatically resize when image given. */ VALUE rb_initialize(int argc, VALUE *argv, VALUE self) { VALUE name, autosize; rb_scan_args(argc, argv, "11", &name, &autosize); Check_Type(name, T_STRING); int mode; if (argc < 2) mode = CV_WINDOW_AUTOSIZE; else{ switch (TYPE(autosize)) { case T_TRUE: mode = CV_WINDOW_AUTOSIZE; break; case T_FALSE: mode = 0; break; default: rb_raise(rb_eTypeError, "argument 2 (auto-size) should be true or false."); } } cvNamedWindow(StringValueCStr(name), mode); void *handle = cvGetWindowHandle(StringValueCStr(name)); if (st_lookup(windows, (st_data_t)handle, 0)) { rb_raise(rb_eStandardError, "window name should be unique."); } DATA_PTR(self) = handle; st_table *holder = st_init_numtable(); st_insert(holder, (st_data_t)0, (st_data_t)self); st_insert(windows, (st_data_t)handle, (st_data_t)holder); return self; } /* * Return alive status of window. Return true if alive, otherwise return false. */ VALUE rb_alive_q(VALUE self) { if (st_lookup(windows, (st_data_t)DATA_PTR(self), 0)) { return Qtrue; } return Qfalse; } /* * Destroys a window. alive status of window be false. */ VALUE rb_destroy(VALUE self) { void *handle = DATA_PTR(self); st_table *holder; if (st_delete(windows, (st_data_t*)&handle, (st_data_t*)&holder)) { st_free_table(holder); } cvDestroyWindow(GET_WINDOW_NAME(self)); return self; } /* * Destorys all the windows. */ VALUE rb_destroy_all(VALUE klass) { st_free_table(windows); windows = st_init_numtable(); cvDestroyAllWindows(); return Qnil; } /* * call-seq: * resize(size) * resize(width, height) * * Set window size. */ VALUE rb_resize(int argc, VALUE *argv, VALUE self) { CvSize size; switch (argc) { case 1: size = VALUE_TO_CVSIZE(argv[0]); break; case 2: size = cvSize(FIX2INT(argv[0]), FIX2INT(argv[1])); break; default: rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); } cvResizeWindow(GET_WINDOW_NAME(self), size.width, size.height); return self; } /* * call-seq: * move(point) * move(x, y) * * Set window position. */ VALUE rb_move(int argc, VALUE *argv, VALUE self) { CvPoint point; switch (argc) { case 1: point = VALUE_TO_CVPOINT(argv[0]); break; case 2: point = cvPoint(FIX2INT(argv[0]), FIX2INT(argv[1])); break; default: rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); } cvMoveWindow(GET_WINDOW_NAME(self), point.x, point.y); return self; } /* * call-seq: * show_image(image) * * Show the image. If the window was created with autosize = true then the image is shown * with its original size, otherwize the image is scaled to fit the window. */ VALUE rb_show_image(VALUE self, VALUE image) { if (!rb_obj_is_kind_of(image, cCvMat::rb_class())) { rb_raise(rb_eTypeError, "argument should be %s.", rb_class2name(cCvMat::rb_class())); } cvShowImage(GET_WINDOW_NAME(self), CVARR(image)); st_table *holder; if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { st_insert(holder, cCvMat::rb_class(), image); return self; }else rb_raise(rb_eFatal, "invalid window operation."); return self; } /* * call-seq: * set_trackbar(trackbar) * set_trackbar(name,maxval[,val],&block) * set_trackbar(name,maxval[,val]){|value| ... } * * Create Trackbar on this window. Return new Trackbar. * see Trackbar.new */ VALUE rb_set_trackbar(int argc, VALUE *argv, VALUE self) { VALUE instance; if (argc == 1 && rb_obj_is_kind_of(argv[0], cTrackbar::rb_class())) { instance = argv[0]; }else{ instance = cTrackbar::rb_initialize(argc, argv, cTrackbar::rb_allocate(cTrackbar::rb_class())); } Trackbar *trackbar = TRACKBAR(instance); void *callback = (void *)alloc_callback(&trackbar_callback, trackbar->block); cvCreateTrackbar(trackbar->name, GET_WINDOW_NAME(self), &trackbar->val, trackbar->maxval, (CvTrackbarCallback)callback); st_table *holder; if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { st_insert(holder, (st_data_t)&trackbar->name, (st_data_t)instance); } return instance; } /* * call-seq: * set_mouse_callback(&block) * set_mouse_callback{|| ... } * * Set mouse callback. * When the mouse is operated on the window, block will be called. * Return Proc object. * block given mouse event object, see GUI::Window::MouseEvent * * e.g. display mouse event on console. * window = OpenCV::GUI::Window.new "sample window" * image = OpenCV::IplImage::load "sample.png" * window.show(image) * window.set_mouse_callback{|mouse| * e = "#{mouse.x}, #{mouse.y} : #{mouse.event} : " * e << "" if mouse.left_button? * e << "" if mouse.right_button? * e << "" if mouse.middle_button? * e << "[CTRL]" if mouse.ctrl_key? * e << "[SHIFT]" if mouse.shift_key? * e << "[ALT]" if mouse.alt_key? * puts e * } * OpenCV::GUI::wait_key */ VALUE rb_set_mouse_callback(VALUE self) { VALUE block = rb_block_given_p() ? rb_block_proc() : 0; if (!block) {rb_raise(rb_eArgError, "block not given.");} void *callback = (void *)alloc_callback(&mouse_callback, block); cvSetMouseCallback(GET_WINDOW_NAME(self), (CvMouseCallback)callback); st_table *holder; if (st_lookup(windows, (st_data_t)DATA_PTR(self), (st_data_t*)&holder)) { st_insert(holder, rb_cProc, block); }else{ rb_raise(rb_eStandardError, "window is destroied."); } return block; } void trackbar_callback(VALUE block, va_alist ap) { va_start_void(ap); rb_funcall(block, rb_intern("call"), 1, INT2FIX(va_arg_int(ap))); va_return_void(ap); } void mouse_callback(VALUE block, va_alist ap) { va_start_void(ap); //VALUE ary = rb_ary_new2(4); //for (int i = 0; i < 4; i++) // rb_ary_store(ary, i, INT2FIX(va_arg_int(ap))); //rb_apply(block, rb_intern("call"), ary); rb_funcall(block, rb_intern("call"), 1, cMouseEvent::new_object(va_arg_int(ap),va_arg_int(ap),va_arg_int(ap),va_arg_int(ap))); va_return_void(ap); } __NAMESPACE_END_WINDOW __NAMESPACE_END_GUI __NAMESPACE_END_OPENCV #endif // HAVE_CALLBACK_H