diff options
Diffstat (limited to 'FL/fl_callback_macros.H')
| -rw-r--r-- | FL/fl_callback_macros.H | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/FL/fl_callback_macros.H b/FL/fl_callback_macros.H new file mode 100644 index 000000000..589606377 --- /dev/null +++ b/FL/fl_callback_macros.H @@ -0,0 +1,607 @@ +/* + * Macros for easy callbacks for the Fast Light Tool Kit (FLTK). + * + * Copyright 2023 by Bill Spitzak and others. + * + * This library is free software. Distribution and use rights are outlined in + * the file "COPYING" which should have been included with this file. If this + * file is missing or damaged, see the license at: + * + * https://www.fltk.org/COPYING.php + * + * Please see the following page on how to report bugs and issues: + * + * https://www.fltk.org/bugs.php + */ + +#ifndef _FL_FL_CALLBACK_MACROS_H_ +#define _FL_FL_CALLBACK_MACROS_H_ + +#include <stdlib.h> + +/** + \file fl_callback_macros.H + This file provides macros for easy function and method callbacks + with multiple type safe arguments. +*/ + +#ifdef FL_DOXYGEN + +/** + \brief Declare a C function callback with custom parameters. + + You can declare a plain C function callback or a static method callback with + custom parameters using this macro. It simplifies the process of calling + arbitrary functions with up to five custom parameters. The macro generates + code that ensures type safety and expands FLTK's standard callbacks, which + are limited to a single `void*` or `long` argument. + + To use the macro, you provide the widget that will handle the callback as the + first argument. The second argument can be either a regular function or a + static method in any class. + + Following these arguments, you can include up to five pairs, where each + pair consists of a type and a value. For example, + `int, 3` specifies an integer parameter with a value of 3. If you need to + pass two arguments, you can use two pairs, like this: + `int, 3, int, 4`. The last digit of the macro name must be the same as + the number of pairs (0..5) + + Whenever the code generated by the macro is called, the custom parameters are + duplicated and marked for automatic deallocation using `delete` when the + callback widget is destroyed. + + \code{.cpp} + #include <FL/fl_callback_macros.H> + ... + Fl_Button *btn1 = new Fl_Button(10, 10, 100, 20, "Beep"); + FL_FUNCTION_CALLBACK(btn1, fl_beep); + ... + Fl_Button *btn2 = new Fl_Button(10, 40, 100, 20, "Hello"); + FL_FUNCTION_CALLBACK(btn2, + fl_message, + const char *, text, "Hello\n%d %d %d %d", + int, a, 1, int, b, 2, int, c, 3, int, d, 4 + ); + \endcode + + You can find a small demonstration program showcasing the usage of + `FL_*_CALLBACK_*` in the `examples/callbacks.cxx` file. + + \param WIDGET the widget that will call the callback + \param FUNC a C/C++ function or a static class method + \param TYPE0 VALUE0 TYPE1 VALUE1 TYPE2 VALUE2 a list of zero to five type/value pairs, all separated by commas + + \see FL_METHOD_CALLBACK_1, FL_INLINE_CALLBACK_2 + */ +#define FL_FUNCTION_CALLBACK_3(WIDGET, FUNC, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2) + +/** + \brief Declare a non-static class method callback with custom parameters. + + You can declare a callback for a non-static class method with custom parameters + using this macro. It provides a convenient way to call arbitrary methods in + any class, overcoming FLTK's limitation of passing only a single `void*` or + `long` argument. Furthermore, it ensures type safety. + + The first argument of the macro specifies the widget that will handle the + callback. The second argument indicates the class type to be called. The + third argument must be a pointer to an instance of that class. The + fourth argument is the name of the method within the class. That method must be + public and should not be static. + + Following these arguments, you can include up to five pairs, where each + pair consists of a type and a value. For example, + `int, 3` specifies an integer parameter with a value of 3. If you need to + pass two arguments, you can use two pairs, like this: + `int, 3, int, 4`. The last digit of the macro name must be the same as + the number of pairs (0..5) + + Whenever the code generated by the macro is called, the custom parameters are + duplicated and marked for automatic deallocation using `delete` when the + callback widget is destroyed. + + \code{.cpp} + #include <FL/fl_callback_macros.H> + ... + Fl_Button *btn = new Fl_Button(10, 10, 100, 20, "Test"); + FL_METHOD_CALLBACK_1(btn, Fl_Button, btn, color, Fl_Color, FL_GREEN); + \endcode + + You can find a small demonstration program showcasing the usage of + `FL_*_CALLBACK_*` in the `examples/callbacks.cxx` file. + + \param WIDGET the widget that will call the callback + \param CLASS the class type + \param SELF a pointer to an instance of the class + \param METH a C++ class method that must be public and not static + \param TYPE0 VALUE0 a list of zero to five type/value pairs, all separated by commas + + \see FL_FUNCTION_CALLBACK_3, FL_INLINE_CALLBACK_2 + */ +#define FL_METHOD_CALLBACK_1(WIDGET, CLASS, SELF, METH, TYPE0, VALUE0) + +/** + \brief Creates code to declare a callback function in line with instantiating a widget. + + You can use this macro to create a function as a callback, allowing you to + define the callback function right where the widget and callback are declared, + similar to a Lambda function. + + The first argument of the macro specifies the widget that will handle the + callback. Next, you can include up to five triplets, where each triplet + consists of a type, a parameter name, and a value. For example, `int, x, 3` + specifies an integer parameter with a value of 3. If you need to pass two + arguments, you can use two triplets, such as `int, x, 3, int, y, 4`. The last + digit of the macro name must be the same as the number of triplets (0..5). + + The last argument is the actual function body itself. + + The function body is limited to a syntax that the macro preprocessor can + handle. It should include the leading '{' and trailing '}' and may contain + local variable declarations, use global variables and functions, and use also + the variables listed and initialized in the argument triples of the macro. + Very large function bodies should be avoided because they may exceed the + admissible size of a macro argument. + + Whenever the code generated by the macro is called, the custom parameters are + duplicated and marked for automatic deallocation using `delete` when the + callback widget is destroyed. + + \code{.cpp} + #include <FL/fl_callback_macros.H> + ... + Fl_Button *btn = new Fl_Button(10, 10, 100, 20, "Test"); + FL_INLINE_CALLBACK_1(btn, + Fl_String, name, btn->label(), + { + fl_message("Greetings from the %s button", name); + } + ); + \endcode + + You can find a small demonstration program showcasing the usage of + `FL_*_CALLBACK_*` in the `examples/callbacks.cxx` file. + + \param WIDGET the widget that will call the callback + \param TYPE0 the type of the first parameter in the function call + \param NAME0 an arbitrary variable name that can be used as a parameter in the function body + \param VALUE0 a constant value or a variable; the value of the variable is copied when the callback is created + \param TYPE1 NAME1 VALUE1 as above; there are six macros that support 0 to 5 parameters + \param LAMBDA_FUNCTION_BODY the function body within the limits of the C macro preprocessor + + \see FL_METHOD_CALLBACK_1, FL_FUNCTION_CALLBACK_3 + */ +#define FL_INLINE_CALLBACK_2(WIDGET, TYPE0, NAME0, VALUE0, TYPE1, VALUE1, NAME1, LAMBDA_FUNCTION_BODY) + +#else // FL_DOXYGEN + +/* + These two macros make it possible to call macros with names that are created + by concatenating the name in x and (in this context) the number in y. + */ +#define _FL_CBD_CONCAT_IMPL(x, y) x##y +#define _FL_CBD_CONCAT(x, y) _FL_CBD_CONCAT_IMPL(x, y) + +/* + Create a unique name for the derived class based on the current source code + line number. + */ +#define _FL_CBD_CLASS_NAME _FL_CBD_CONCAT(Fl_Callback_User_Data_,__LINE__) + + +/* + These macros create boilerplate code for callbacks to functions and + static class methods with up to five arguments. + + This macro invocation for example + ``` + FL_FUNCTION_CALLBACK_2( func_cb_btn_2, hello_2_args_cb, + const char *, text, "FLTK", + int, number, 2 ); + ``` + will generate the following code: + + ``` + do { + class Fl_Callback_User_Data_92 : public Fl_Callback_User_Data { + public: + const char * p0_; + int p1_; + static void cb(Fl_Widget *w, void *user_data) { + Fl_Callback_User_Data_92 *d = (Fl_Callback_User_Data_92*)user_data; + hello_2_args_cb(d->p0_, d->p1_); + }; + Fl_Callback_User_Data_92(const char * p0, int p1) + : p0_(p0), + p1_(p1) + { } + }; + func_cb_btn_2->callback(Fl_Callback_User_Data_92::cb, + new Fl_Callback_User_Data_92("FLTK", 2), + true); + } while(0) + ``` + + Clicking the Fl_Button `func_cb_btn_2` will call `hello_2_args_cb("FLTK", 2)`. + Deleting the button will also delete the data that was created in our + boilerplate code. + */ +#define FL_FUNCTION_CALLBACK_5(WIDGET, FUNC, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; TYPE4 p4_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + FUNC(d->p0_, d->p1_, d->p2_, d->p3_, d->p4_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3, TYPE4 p4) \ + : p0_(p0), p1_(p1), p2_(p2), p3_(p3), p4_(p4) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2, VALUE3, VALUE4), true); \ + } while(0) + +#define FL_FUNCTION_CALLBACK_4(WIDGET, FUNC, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + FUNC(d->p0_, d->p1_, d->p2_, d->p3_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3) \ + : p0_(p0), p1_(p1), p2_(p2), p3_(p3) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2, VALUE3), true); \ + } while(0) + +#define FL_FUNCTION_CALLBACK_3(WIDGET, FUNC, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + FUNC(d->p0_, d->p1_, d->p2_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2) \ + : p0_(p0), p1_(p1), p2_(p2) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2), true); \ + } while(0) + +#define FL_FUNCTION_CALLBACK_2(WIDGET, FUNC, TYPE0, VALUE0, TYPE1, VALUE1) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + FUNC(d->p0_, d->p1_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1) \ + : p0_(p0), p1_(p1) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1), true); \ + } while(0) + +#define FL_FUNCTION_CALLBACK_1(WIDGET, FUNC, TYPE0, VALUE0) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + FUNC(d->p0_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0) \ + : p0_(p0) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0), true); \ + } while(0) + +#define FL_FUNCTION_CALLBACK_0(WIDGET, FUNC) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + static void cb(Fl_Widget *w, void *user_data) { \ + FUNC(); \ + }; \ + _FL_CBD_CLASS_NAME() { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(), true); \ + } while(0) + +/* + These macros create boilerplate code for callbacks to class methods + with up to five arguments. + + This macro invocation for example + ``` + FL_METHOD_CALLBACK_4(btn, + MyWindow, win, resize, + int, test_x+10, + int, test_y+10, + int, 320, + int, 400); + ``` + will generate the following code: + + ``` + do { + class Fl_Callback_User_Data_73 : public Fl_Callback_User_Data { + public: + int p0_; + int p1_; + int p2_; + int p3_; + MyWindow *self_; + static void cb(Fl_Widget *w, void *user_data) { + Fl_Callback_User_Data_73 *d = (Fl_Callback_User_Data_73*)user_data; + d->self_->resize(d->p0_, d->p1_, d->p2_, d->p3_); + }; + Fl_Callback_User_Data_73(MyWindow *self, int p0, int p1, int p2, int p3) + : self_(self), p0_(p0), p1_(p1), p2_(p2), p3_(p3) { } + }; + btn->callback(Fl_Callback_User_Data_73::cb, + new Fl_Callback_User_Data_73(win, test_x+10, test_y+10, 320, 400), + true); + } while(0); + ``` + + Clicking the Fl_Button `btn` will call + `win->resize(test_x+10, test_y+10, 320, 400);`. + Deleting the button will also delete the data that was created in our + boilerplate code. + */ + +#define FL_METHOD_CALLBACK_5(WIDGET, CLASS, SELF, METHOD, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3, TYPE4, VALUE4) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; TYPE4 p4_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(d->p0_, d->p1_, d->p2_, d->p3_, d->p4_); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self, TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3, TYPE4 p4) \ + : self_(self), p0_(p0), p1_(p1), p2_(p2), p3_(p3), p4_(p4) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF, VALUE0, VALUE1, VALUE2, VALUE3, VALUE4), true); \ + } while(0) + +#define FL_METHOD_CALLBACK_4(WIDGET, CLASS, SELF, METHOD, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2, TYPE3, VALUE3) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(d->p0_, d->p1_, d->p2_, d->p3_); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self, TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3) \ + : self_(self), p0_(p0), p1_(p1), p2_(p2), p3_(p3) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF, VALUE0, VALUE1, VALUE2, VALUE3), true); \ + } while(0) + +#define FL_METHOD_CALLBACK_3(WIDGET, CLASS, SELF, METHOD, TYPE0, VALUE0, TYPE1, VALUE1, TYPE2, VALUE2) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(d->p0_, d->p1_, d->p2_); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self, TYPE0 p0, TYPE1 p1, TYPE2 p2) \ + : self_(self), p0_(p0), p1_(p1), p2_(p2) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF, VALUE0, VALUE1, VALUE2), true); \ + } while(0) + +#define FL_METHOD_CALLBACK_2(WIDGET, CLASS, SELF, METHOD, TYPE0, VALUE0, TYPE1, VALUE1) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + TYPE0 p0_; TYPE1 p1_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(d->p0_, d->p1_); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self, TYPE0 p0, TYPE1 p1) \ + : self_(self), p0_(p0), p1_(p1) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF, VALUE0, VALUE1), true); \ + } while(0) + +#define FL_METHOD_CALLBACK_1(WIDGET, CLASS, SELF, METHOD, TYPE0, VALUE0) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + TYPE0 p0_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(d->p0_); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self, TYPE0 p0) \ + : self_(self), p0_(p0) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF, VALUE0), true); \ + } while(0) + +#define FL_METHOD_CALLBACK_0(WIDGET, CLASS, SELF, METHOD) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + CLASS *self_; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + d->self_->METHOD(); \ + }; \ + _FL_CBD_CLASS_NAME(CLASS *self) \ + : self_(self) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(SELF), true); \ + } while(0) + +/* + These macros create boilerplate code for callback functions inlined into + the widget creation code (similar to lambda functions in C++11 and up) + with up to five arguments. + + This macro invocation for example + ``` + FL_INLINE_CALLBACK_2( // callback has two parameters + btn, // attach callback to this button + const char *, text, "FLTK", // first parameter (type, name, value) + int, number, 2, // second parameter + { // function body + fl_message("We received the message %s with %d!", text, number); + } + ); + ``` + will generate the following code: + ``` + do { + class Fl_Callback_User_Data_133 : public Fl_Callback_User_Data { + public: + const char * p0_; // store first parameter here + int p1_; // store second parameter here + // lambda style function + static void fn(const char * text, int number ) { + fl_message("We received the message %s with %d!", text, number); + }; + // FLTK style callback + static void cb(Fl_Widget *w, void *user_data) { + Fl_Callback_User_Data_133 *d = (Fl_Callback_User_Data_133*)user_data; + fn(d->p0_, d->p1_); + }; + // class constructor + Fl_Callback_User_Data_133(const char * p0, int p1) + : p0_(p0), // copy parameter 0 + p1_(p1) // copy parameter 1 + { } // constructor body + }; + // connect our class to the widget callback + btn->callback(Fl_Callback_User_Data_133::cb, + new Fl_Callback_User_Data_133("FLTK", 2), + true); + } while(0); // user code adds semicolon + ``` + + Clicking the Fl_Button `btn` will call + `fl_message("We received the message %s with %d!", "FLTK", 2);`. + Deleting the button will also delete the data that was created in our + boilerplate code. + */ + +#define FL_INLINE_CALLBACK_5(WIDGET, TYPE0, NAME0, VALUE0, TYPE1, NAME1, VALUE1, TYPE2, NAME2, VALUE2, TYPE3, NAME3, VALUE3, TYPE4, NAME4, VALUE4, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; TYPE4 p4_; \ + static void fn(TYPE0 NAME0, TYPE1 NAME1, TYPE2 NAME2, TYPE3 NAME3, TYPE4 NAME4) \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + _FL_CBD_CLASS_NAME::fn(d->p0_, d->p1_, d->p2_, d->p3_, d->p4_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3, TYPE4 p4) \ + : p0_(p0), p1_(p1), p2_(p2), p3_(p3), p4_(p4) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2, VALUE3, VALUE4), true); \ + } while(0) + +#define FL_INLINE_CALLBACK_4(WIDGET, TYPE0, NAME0, VALUE0, TYPE1, NAME1, VALUE1, TYPE2, NAME2, VALUE2, TYPE3, NAME3, VALUE3, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; TYPE3 p3_; \ + static void fn(TYPE0 NAME0, TYPE1 NAME1, TYPE2 NAME2, TYPE3 NAME3) \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + _FL_CBD_CLASS_NAME::fn(d->p0_, d->p1_, d->p2_, d->p3_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2, TYPE3 p3) \ + : p0_(p0), p1_(p1), p2_(p2), p3_(p3) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2, VALUE3), true); \ + } while(0) + +#define FL_INLINE_CALLBACK_3(WIDGET, TYPE0, NAME0, VALUE0, TYPE1, NAME1, VALUE1, TYPE2, NAME2, VALUE2, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; TYPE2 p2_; \ + static void fn(TYPE0 NAME0, TYPE1 NAME1, TYPE2 NAME2) \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + _FL_CBD_CLASS_NAME::fn(d->p0_, d->p1_, d->p2_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1, TYPE2 p2) \ + : p0_(p0), p1_(p1), p2_(p2) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1, VALUE2), true); \ + } while(0) + +#define FL_INLINE_CALLBACK_2(WIDGET, TYPE0, NAME0, VALUE0, TYPE1, NAME1, VALUE1, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; TYPE1 p1_; \ + static void fn(TYPE0 NAME0, TYPE1 NAME1) \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + _FL_CBD_CLASS_NAME::fn(d->p0_, d->p1_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0, TYPE1 p1) \ + : p0_(p0), p1_(p1) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0, VALUE1), true); \ + } while(0) + +#define FL_INLINE_CALLBACK_1(WIDGET, TYPE0, NAME0, VALUE0, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + TYPE0 p0_; \ + static void fn(TYPE0 NAME0) \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME *d = (_FL_CBD_CLASS_NAME*)user_data; \ + _FL_CBD_CLASS_NAME::fn(d->p0_); \ + }; \ + _FL_CBD_CLASS_NAME(TYPE0 p0) \ + : p0_(p0) { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(VALUE0), true); \ + } while(0) + +#define FL_INLINE_CALLBACK_0(WIDGET, LAMBDA) \ + do { \ + class _FL_CBD_CLASS_NAME : public Fl_Callback_User_Data { \ + public: \ + static void fn() \ + LAMBDA; \ + static void cb(Fl_Widget *w, void *user_data) { \ + _FL_CBD_CLASS_NAME::fn(); \ + }; \ + _FL_CBD_CLASS_NAME() { }; \ + }; \ + WIDGET->callback(_FL_CBD_CLASS_NAME::cb, new _FL_CBD_CLASS_NAME(), true); \ + } while(0) + +#endif // FL_DOXYGEN + +#endif /* !_FL_FL_CALLBACK_MACROS_H_ */ |
