Re: XForms: C++ design wanted

Mark Edward Johnston (M.E.Johnston@damtp.cam.ac.uk)
Sat, 14 Jun 1997 13:18:04 +0100 (BST)

To subscribers of the xforms list from Mark Edward Johnston <M.E.Johnston@damtp.cam.ac.uk> :

What follows is an example of how to use member functions as callbacks
(you have to make them static, so the "this" pointer isn't passed, and
then you have to hang the "this" pointer of your C++ objects off the
"u_vdata" member of each XForms object associated with the C++ object).

Hope it helps.

Mark J.

//-----------------------------------
// This file is BFCExample.cc

/*

A quick demo of how to encapsulate XForms objects and their callbacks
in C++ classes.

Mark Johnston, DAMTP, Cambridge 1995.

This uses ANSI C++ std string class. If your compiler doesn't have this,
you'll have to modify the code to use C char[] arrays.

gcc-2.7.2 will compile it.

Compile with eg. :

gcc BFCExample.cc -o BFCExample -I../include -L../libALPHA \
-lforms -lX11 -lstdc++ -lm

(modify the -I and -L as appropriate, of course)
*/

#include <string>
#include "forms.h"
#include <iostream.h>
#include <strstream.h>
#include <stdlib.h>

// printing of objects to a string :

template <class T>
string toString(const T &obj)
{
ostrstream os;
os << obj << ends;
char *cs = os.str();
string ret(cs);
delete cs; // must explicitly delete memory used by os,
// as str() has been called
return ret;
}

class BoundedFloatParameter {
friend class BoundedFloatControl; // for simplicity

public:
BoundedFloatParameter(const string &label, float defaultval = 0.0,
float lowerbound = 0.0, float upperbound = 1.0) :
_label(label), _val(defaultval), _lb(lowerbound), _ub(upperbound) { }

// <- Should check default value is in range !

operator float() const { return _val; }

private:
string _label;
float _val, _lb, _ub;
};

class BoundedFloatControl {
public:
BoundedFloatControl(FL_FORM *parent, FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h,
BoundedFloatParameter *par);

~BoundedFloatControl();

private:
BoundedFloatParameter *_par;
FL_FORM *_parent;

FL_OBJECT *slider;
FL_OBJECT *input;

// Callback must be a _static_ member function to have the correct signature
// for use as an XForms callback (non-static members get passed the "this"
// pointer of the objects to which they are associated as their first argument).
//
// This means the callback doesn't know which C++ object it is associated with.
// We get around this by hanging the this pointer of the C++ object off the
// u_vdata member of the FL_OBJECT struct of each Xforms object it contains.
// (see constructor below)

static void callback(FL_OBJECT* obj, long data);
};

BoundedFloatControl::BoundedFloatControl(
FL_FORM *parent, FL_Coord x, FL_Coord y, FL_Coord w,
FL_Coord h, BoundedFloatParameter *par)
: _par(par), _parent(parent)
{
fl_addto_form(_parent);

slider = fl_add_slider(FL_HOR_NICE_SLIDER, x + 2 * w/3, y, w/3, h, "");
fl_set_object_callback(slider, callback, 0);
fl_set_slider_return(slider, FL_RETURN_CHANGED);
fl_set_slider_bounds(slider, _par->_lb, _par->_ub);
fl_set_slider_value(slider, _par->_val);
fl_set_object_gravity(slider, FL_NorthWest, FL_NorthWest);

input = fl_add_input(FL_FLOAT_INPUT, x + w/3, y, w/3, h,
_par->_label.c_str());
fl_set_object_lsize(input,FL_NORMAL_SIZE);
fl_set_object_callback(input, callback, 0);
fl_set_input(input, toString(_par->_val).c_str());
fl_set_object_gravity(input, FL_NorthWest, FL_NorthWest);

// This is the important bit :

slider->u_vdata = (void *) this;
input->u_vdata = (void *) this;

fl_end_form();
}

void BoundedFloatControl::callback(FL_OBJECT* obj, long data)
{
BoundedFloatControl *win = (BoundedFloatControl *) obj->u_vdata;

float value;

if (obj == win->input) value = atof(fl_get_input(obj));
else value = fl_get_slider_value(obj);

if (value < win->_par->_lb) value = win->_par->_lb;
else if (value > win->_par->_ub) value = win->_par->_ub;

win->_par->_val = value;

fl_set_input(win->input, toString(value).c_str());
fl_set_slider_value(win->slider, value);
}

BoundedFloatControl::~BoundedFloatControl()
{
fl_hide_object(slider);
fl_delete_object(slider);
fl_free_object(slider);
fl_hide_object(input);
fl_delete_object(input);
fl_free_object(input);
}

int main(int argc, char *argv[])
{
fl_initialize(&argc, argv, "", 0, 0);

BoundedFloatParameter data1("data1"), data2("data2", 1.0, -1.0, 2.5);

cout << "data1 = " << data1 << "; data2 = " << data2 << endl;

const int wd = 300, gap = 8, ht = 30;
int vpos = gap, vdelta = ht + gap;

int numctrls = 2;

//---------------
// In a real application, the form itself would often be contained in a C++
// object, and the follwing junk would be in its constructor.
//---------------

FL_FORM *pform =
fl_bgn_form(FL_UP_BOX, wd + 2 * gap, gap + (numctrls + 1) * vdelta);
fl_end_form();

BoundedFloatControl *floatinput1 =
new BoundedFloatControl(pform, gap, vpos, wd, ht, &data1);
vpos += vdelta;

BoundedFloatControl *floatinput2 =
new BoundedFloatControl(pform, gap, vpos, wd, ht, &data2);
vpos += vdelta;

fl_addto_form(pform);
FL_OBJECT *ok =
fl_add_button(FL_NORMAL_BUTTON, gap + wd/4, vpos, wd/2, ht, "OK");
fl_set_object_lsize(ok,FL_NORMAL_SIZE);
fl_end_form();

fl_show_form(pform, FL_PLACE_SIZE, FL_FULLBORDER, "Test");

while (fl_check_forms() != ok);

//---------------
// ... and this in its destructor :

delete floatinput1;
delete floatinput2;

fl_hide_form(pform);
fl_free_form(pform);

//---------------

cout << "data1 = " << data1 << "; data2 = " << data2 << endl;

return 0;
}

// end of example
//-----------------------------------

---
Mark Johnston.                    M.E.Johnston@damtp.cam.ac.uk
816 King's College, Cambridge, CB2 1ST, U.K.
 or: DAMTP, Silver St., Cambridge, CB3 9EW, U.K.
'phone: (home) +44 1223 500 585 (has voice mail, let it ring!)
WWW: http://www.damtp.cam.ac.uk/user/mej20/

On Fri, 13 Jun 1997, Sindre Mehus wrote:

> To subscribers of the xforms list from Sindre Mehus <mehus@darmstadt.gmd.de> : > > Dear XFormers, > > I was thinking of creating a nice C++ design for my next XForms > application, but surely someone must have done that already? > > With design I mean a set of convenient classes which encapsulates the > creation, behaviour and functionality of an XForms application. > > So, my question is whether someone has found a nice way to structure an > XForms application in C++, and is willing to share it with the rest of > us :) > > Thanks in advance, > Sindre > > PS: A more concrete question: > Is it possible to register class methods as callbacks? > -- > Sindre Mehus __ mailto:mehus@darmstadt.gmd.de > GMD-IPSI /\_\ http://www.cs.uit.no/~sindrem > Dolivostr. 15 \/_/ Tel: +49 6151 869 902 > D-64293 Darmstadt, Germany Fax: +49 6151 869 966 > _________________________________________________ > To unsubscribe, send the message "unsubscribe" to > xforms-request@bob.usuf2.usuhs.mil or see > http://bob.usuf2.usuhs.mil/mailserv/xforms.html > Xforms Home Page: http://bragg.phys.uwm.edu/xforms > List Archive: http://bob.usuf2.usuhs.mil/mailserv/list-archives/ > _________________________________________________ To unsubscribe, send the message "unsubscribe" to xforms-request@bob.usuf2.usuhs.mil or see http://bob.usuf2.usuhs.mil/mailserv/xforms.html Xforms Home Page: http://bragg.phys.uwm.edu/xforms List Archive: http://bob.usuf2.usuhs.mil/mailserv/list-archives/