/*
 * 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_ */
