608 lines
23 KiB
C++
608 lines
23 KiB
C++
/*
|
|
* 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_0(btn1, fl_beep);
|
|
...
|
|
Fl_Button *btn2 = new Fl_Button(10, 40, 100, 20, "Hello");
|
|
FL_FUNCTION_CALLBACK_5(btn2,
|
|
fl_message,
|
|
const char *, "Hello\n%d %d %d %d",
|
|
int, 1, int, 2, int, 3, int, 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,
|
|
const char *, 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 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, NAME1, VALUE1, LAMBDA)
|
|
|
|
#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_ */
|