EASY HACK TO PLACE CALLBACKS INSIDE OF CLASS AS NON-STATIC FUNCTION - Chapter 6

24 views
Skip to first unread message

wm201...@gmail.com

unread,
Nov 17, 2016, 4:24:22 PM11/17/16
to fltk.general
#ifndef FL_CALLBACK_H
#define FL_CALLBACK_H

// EASY HACK TO PLACE CALLBACKS INSIDE OF CLASS AS NON-STATIC FUNCTION:

#define FL_CALLBACK(classname) \
\
    typedef void (classname::*cbfun_t)(Fl_Widget*, void*); \
\
    typedef struct { \
      classname*     inst; \
      cbfun_t        func; \
      void*          data; \
      Fl_Widget*     widget; \
    } d$; \
\
    inline static void x$(Fl_Widget* widget, void* data) { \
       CB_DATA* cb_data = (CB_DATA*)data; \
       cb_data->widget = widget; \
       (cb_data->inst->*(cb_data->func))(cb_data->widget, cb_data->data); \
    } \

// EXAMPLE USAGE:
//
//#include <FL/Fl.H>
//#include <FL/Fl_Input.H>
//#include <FL/Fl_Button.H>
//#include <FL/Fl_Return_Button.H>
//#include <FL/Fl_Text_Editor.H>
//#include <FL/Fl_Menu_Bar.H>
//#include <Fl/Fl_Window.H>
//#include <Fl/Fl_Double_Window.H>
//#include <iostream>
//using std::cout;
//
//class EditorWindow : public Fl_Double_Window
//{
//public:
//  FL_CALLBACK(EditorWindow);
//
//  EditorWindow(int w, int h, const char* t) :
//    Fl_Double_Window{w, h, t}
//  {
//      create_menu();
//  }
//
//    ~EditorWindow() {
//    }
//    void create_menu();
//
//    Fl_Window*             replace_dlg;
//    Fl_Input*              replace_find;
//    Fl_Input*              replace_with;
//    Fl_Button*             replace_all;
//    Fl_Return_Button*      replace_next;
//    Fl_Button*             replace_cancel;
//    Fl_Text_Editor*        editor;
//    Fl_Menu_Item*          menuitems;
//    Fl_Menu_Bar*           menubar;
//    char                   search[256];
//
//    void cb_new      (Fl_Widget* widget, void* data) {cout << "new\n";}
//    void cb_open     (Fl_Widget* widget, void* data) {cout << "open\n";}
//    void cb_insert   (Fl_Widget* widget, void* data) {cout << "insert\n";}
//    void cb_save     (Fl_Widget* widget, void* data) {cout << "save\n";}
//    void cb_saveas   (Fl_Widget* widget, void* data) {cout << "saveas\n";}
//    void cb_view     (Fl_Widget* widget, void* data) {cout << "view\n";}
//    void cb_close    (Fl_Widget* widget, void* data) {cout << "close\n";}
//    void cb_quit     (Fl_Widget* widget, void* data) {cout << "quit\n";}
//    void cb_undo     (Fl_Widget* widget, void* data) {cout << "undo\n";}
//    void cb_cut      (Fl_Widget* widget, void* data) {cout << "cut\n";}
//    void cb_copy     (Fl_Widget* widget, void* data) {cout << "copy\n";}
//    void cb_paste    (Fl_Widget* widget, void* data) {cout << "paste\n";}
//    void cb_delete   (Fl_Widget* widget, void* data) {cout << "delete\n";}
//    void cb_find     (Fl_Widget* widget, void* data) {cout << "find\n";}
//    void cb_find2    (Fl_Widget* widget, void* data) {cout << "find2\n";}
//    void cb_replace  (Fl_Widget* widget, void* data) {cout << "replace\n";}
//    void cb_replace2 (Fl_Widget* widget, void* data) {cout << "replace2\n";}
//};
//
//#include <Fl/Fl_Menu_Item.H>
//#include <Fl/Fl_Menu_Bar.H>
//
//#include "win_first.h"
//
//
//void EditorWindow::create_menu() {
//  menuitems = new Fl_Menu_Item[100] {
//    { "&File",            0,                           0,  0,                                    FL_SUBMENU },
//    { "&New File",        0,                           x$, new d${this, cb_new,      nullptr},   0},
//    { "&Open File...",    FL_COMMAND + 'o',            x$, new d${this, cb_open,     nullptr},   0},
//    { "&Insert File...",  FL_COMMAND + 'i',            x$, new d${this, cb_insert,   nullptr},   FL_MENU_DIVIDER},
//    { "&Save File",       FL_COMMAND + 's',            x$, new d${this, cb_save,     nullptr},   0},
//    { "Save File &As...", FL_COMMAND + FL_SHIFT + 's', x$, new d${this, cb_saveas,   nullptr},   FL_MENU_DIVIDER},
//    { "New &View",        FL_ALT + 'v',                x$, new d${this, cb_view,     nullptr},   0},
//    { "&Close View",      FL_COMMAND + 'w',            x$, new d${this, cb_close,    nullptr},   FL_MENU_DIVIDER},
//    { "E&xit",            FL_COMMAND + 'q',            x$, new d${this, cb_quit,     nullptr},   0},
//    { 0 },
//
//    { "&Edit",            0,                           0, 0,                                     FL_SUBMENU },
//    { "&Undo",            FL_COMMAND + 'z',            x$, new d${this, cb_undo,     nullptr},   FL_MENU_DIVIDER},
//    { "Cu&t",             FL_COMMAND + 'x',            x$, new d${this, cb_cut,      nullptr},   0},
//    { "&Copy",            FL_COMMAND + 'c',            x$, new d${this, cb_copy,     nullptr},   0},
//    { "&Paste",           FL_COMMAND + 'v',            x$, new d${this, cb_paste,    nullptr},   0},
//    { "&Delete",          0,                           x$, new d${this, cb_delete,   nullptr},   0},
//    { 0 } ,
//
//    { "&Search", 0, 0, 0, FL_SUBMENU },
//    { "&Find...",         FL_COMMAND + 'f',            x$, new d${this, cb_find,     nullptr},   0},
//    { "F&ind Again",      FL_COMMAND + 'g',            x$, new d${this, cb_find2,    nullptr},   0},
//    { "&Replace...",      FL_COMMAND + 'r',            x$, new d${this, cb_replace,  nullptr},   0},
//    { "Re&place Again",   FL_COMMAND + 't',            x$, new d${this, cb_replace2, nullptr},   0},
//    { 0 },
//
//    { 0 }
//  };
//
//  menubar = new Fl_Menu_Bar (0, 0, 640, 30);
//  menubar->copy (menuitems);
//}

#endif

// EASY HACK TO PLACE CALLBACKS INSIDE OF CLASS AS NON-STATIC FUNCTION:

// Requires: C++11
//
// How to Use:
//   (1) Add macro to public section:
//     FL_CALLBACK(<name of class>);
//
//   (2) add callbacks to class as normal non-static member function
//
//   (3) When you need a Callback pointer, Use:
//      x$
//
//   (3) When you need corresponding callback data, Use:
//      new d${this, non_static_class_method_callback, data}
//
// Explanation:
//
//   x$ is the static callback method that use d$ data to dispatch
//     non_static_call_method as callback with given data
//
// Warning:
//   use of "new d${...}" is a memory leak ...
//   but most user won't notice
//   if you don't create too many windows.
//   (Also, Operating system will automatically
//   garbage collect when the program is closed.)
//
//Suggestions?
//  replace 'new $d' with base class function
//  that will create 'new $d struct' and garbage collect
//  these pointers when the class destructor is called.
//
//======================================================================

Reply all
Reply to author
Forward
0 new messages