As I promised, I played around with an initial implementation of a
doubleclick button. Rather than code from scratch, the skeleton of
the DCButton object (as I have dubbed it) is based upon the cross
button described in the manual and provided in the XForms demo code.
There are a lot of things missing from the implementation -- changing
or querying the timeout value, for instance, but they should be
trivially easy to code.
I also didn't rigorously test all of the different button types --
I've tested the FL_NORMAL_BUTTON and FL_RETURN_BUTTON only (though I'm
not sure most of the other types make any particular sense in the
context of a double click button). I am also not as rigorous as I
might wish to be in testing the object type before I attempt to
dereference pointers, etc. I leave this as a programming exercise.
The button responds to either double and single clicks (adding a
tripleclick callback is left as a further exercise for the student),
as well as all clicks, if you wish.
In order to do this, I've added two new callbacks.
I relinquish copyright to this code. Inasmuch as it is derived from
the work of TC Zhao and Mark Overmars, I don't think I can place it in
the public domain but you may use it to the extent that you may use
any of the demo code supplied with XForms. [TC, would you give us
some statement as to the use of derived works?]
The API is described in the file `dcbutton.h':
- - -
/*
* Class DCButton header file
* Pinched from crossbut.h -- Class Crossbutton header file
*/
#ifndef DCBUTTON_H
#define DCBUTTON_H
#define FL_DCBUTTON (FL_USER_CLASS_START + 1)
FL_OBJECT *fl_add_dcbutton(
int type,
FL_Coord x,
FL_Coord y,
FL_Coord w,
FL_Coord h,
const char *label
);
void fl_add_dcbutton_double_click_callback(
FL_OBJECT *ob,
void (*callback)(FL_OBJECT *ob,
long parm),
long parm
);
void fl_add_dcbutton_single_click_callback(
FL_OBJECT *ob,
void (*callback)(FL_OBJECT *ob,
long parm),
long parm
);
FL_OBJECT *fl_create_dcbutton(
int type,
FL_Coord x,
FL_Coord y,
FL_Coord w,
FL_Coord h,
const char *label
);
#endif
- - -
The callbacks are added with fl_add_dcbutton_single_click_callback() and
fl_add_dcbutton_double_click_callback() respectively and have the same
argument lists as the standard fl_add_object_callback(). For
instance:
fl_add_dcbutton_single_click_callback( obj, singleclick_cb, 0 );
fl_add_dcbutton_double_click_callback( obj, doubleclick_cb, 0 );
adds callback actions for single and double click respectively.
Yes, I do tend to like long, descriptive function names. :-)
Note that since I didn't rewrite the Button object from scratch,
XForms will still call the normal object callback if it's registered
or cause fl_do_forms() to return the FL_OBJECT pointer if no object
callback is registered, even if the special callbacks are registered.
I suppose I could have registered a dummy callback in the
fl_create_dcbutton() function to prevent this.
The following is a my quick and dirty implementation of the button:
- - - dcbutton.c - - -
/*
* Routines implementing the "dcbutton" class
* Pinched from crossbut.c -- Routines implementing the "crossbutton" class
*/
#include <stdio.h>
#include <forms.h>
#include "dcbutton.h"
#include "dcbutton_internal.h"
static void single_click_timeout( int timeout_id, void *data )
{
FL_OBJECT *ob = ( FL_OBJECT *) data;
SPEC *spec = ( SPEC *) ob->spec;
DCButtonP dc_button_ptr = ( DCButtonP ) spec->cspecv;
dc_button_ptr->timer_id = 0;
if ( dc_button_ptr->single_click_callback ) {
long parm = dc_button_ptr->single_click_parm;
(*dc_button_ptr->single_click_callback)( ob, parm );
}
}
static void draw_dcbutton( FL_OBJECT *ob )
{
SPEC *spec = ( SPEC * ) ob->spec;
/* if redraw is demanded by FL_ENTER, ignore it */
if( spec->event != FL_ENTER ) {
/* draw the bounding box first */
fl_drw_box( ob->boxtype,
ob->x, ob->y, ob->w, ob->h, ob->col1, ob->bw );
/* if pushed, draw a down box */
if( spec->val )
fl_drw_box( FL_DOWN_BOX, ob->x, ob->y, ob->w, ob->h,
ob->col1, ob->bw );
else
fl_drw_box( FL_UP_BOX, ob->x, ob->y, ob->w, ob->h,
ob->col1, ob->bw );
/* label */
fl_drw_text( ob->align, ob->x, ob->y, ob->w, ob->h,
ob->lcol, ob->lstyle, ob->lsize, ob->label );
if ( ob->type == FL_RETURN_BUTTON )
fl_drw_text( FL_ALIGN_CENTER,
( FL_Coord ) ( ob->x + ob->w - 0.8 * ob->h ),
( FL_Coord ) ( ob->y + 0.2 * ob->h ),
( FL_Coord ) ( 0.6 * ob->h ),
( FL_Coord ) ( 0.6 * ob->h ), ob->lcol, 0, 0,
"@returnarrow" );
}
if ( ( spec->event == FL_RELEASE ) ||
( spec->event == FL_SHORTCUT ) ) {
DCButtonP dc_button_ptr = ( DCButtonP ) spec->cspecv;
if ( dc_button_ptr->timer_id ) {
/*
* Clear the time before it pops on us.
*/
fl_remove_timeout( dc_button_ptr->timer_id );
dc_button_ptr->timer_id = 0;
if ( dc_button_ptr->double_click_callback ) {
long parm = dc_button_ptr->double_click_parm;
(*dc_button_ptr->double_click_callback)( ob, parm );
}
} else if ( dc_button_ptr->timeout > 0 )
dc_button_ptr->timer_id =
fl_add_timeout( dc_button_ptr->timeout,
single_click_timeout, ( void *) ob );
}
}
FL_OBJECT *fl_create_dcbutton( int type, FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h, const char *label )
{
FL_OBJECT *ob;
DCButtonP dc_button_ptr;
fl_add_button_class( FL_DCBUTTON, draw_dcbutton, 0 );
ob = fl_create_generic_button( FL_DCBUTTON, type, x, y, w, h, label );
ob->boxtype = FL_NO_BOX;
dc_button_ptr =
( ( FL_BUTTON_SPEC *) ob->spec )->cspecv =
( DCButtonP ) fl_calloc( 1, sizeof( DCButton ) );
dc_button_ptr->timeout = FL_CLICK_TIMEOUT;
return ob;
}
FL_OBJECT *fl_add_dcbutton( int type, FL_Coord x, FL_Coord y, FL_Coord w,
FL_Coord h, const char *label )
{
FL_OBJECT *ob = fl_create_dcbutton( type, x, y, w, h, label );
fl_add_object( fl_current_form, ob );
return ob;
}
void fl_add_dcbutton_single_click_callback( FL_OBJECT *ob,
void (*callback)( FL_OBJECT *ob,
long parm ),
long parm )
{
DCButtonP dcbutton_ptr =
( DCButtonP ) ( ( FL_BUTTON_SPEC *) ob->spec )->cspecv;
dcbutton_ptr->single_click_callback = callback;
dcbutton_ptr->single_click_parm = parm;
}
void fl_add_dcbutton_double_click_callback( FL_OBJECT *ob,
void (*callback)( FL_OBJECT *ob,
long parm ),
long parm )
{
DCButtonP dcbutton_ptr =
( DCButtonP ) ( ( FL_BUTTON_SPEC *) ob->spec )->cspecv;
dcbutton_ptr->double_click_callback = callback;
dcbutton_ptr->double_click_parm = parm;
}
- - - dcbutton_internal.h - - -
typedef struct {
void (*single_click_callback)( FL_OBJECT *ob, long parm );
long single_click_parm;
void (*double_click_callback)( FL_OBJECT *ob, long parm );
long double_click_parm;
int timeout;
int timer_id; /* Internal use */
} DCButton, *DCButtonP;
typedef FL_BUTTON_SPEC SPEC;
- - - try.c - - -
/*
* Demo showing the use of user defined object class: DBBUTTON
* The program runs till killed with Control-C.
*/
#include "forms.h"
#include "dcbutton.h"
#include <stdlib.h>
#ifndef FD_newbut_h_
#define FD_newbut_h
/**** Forms and Objects ****/
typedef struct {
FL_FORM *newbut;
void *vdata;
long ldata;
FL_OBJECT *bexit;
} FD_newbut;
extern FD_newbut *create_form_newbut(void);
#endif /* FD_newbut_h_ */
int main(int argc, char *argv[])
{
FD_newbut *cbform ;
fl_initialize( &argc, argv, "FormDemo", 0, 0 );
cbform = create_form_newbut();
fl_show_form(cbform->newbut, FL_PLACE_CENTER, FL_TRANSIENT, "newbutton");
while( fl_do_forms() )
;
}
static void singleclick_cb( FL_OBJECT *ob, long parm )
{
fprintf( stderr, "called singleclick!\n" );
}
static void doubleclick_cb( FL_OBJECT *ob, long parm )
{
fprintf( stderr, "called doubleclick!\n" );
}
FD_newbut *create_form_newbut( void )
{
FL_OBJECT *obj;
FD_newbut *fdui = (FD_newbut *) fl_calloc(1, sizeof(*fdui));
fdui->newbut = fl_bgn_form(FL_NO_BOX, 320, 250);
obj = fl_add_box(FL_UP_BOX,0,0,320,250,"");
/* obj = fl_add_dcbutton(FL_NORMAL_BUTTON,30,40,250,130,"Button"); */
obj = fl_add_dcbutton(FL_RETURN_BUTTON,30,40,250,130,"Button");
fl_add_dcbutton_single_click_callback( obj, singleclick_cb, 0 );
fl_add_dcbutton_double_click_callback( obj, doubleclick_cb, 0 );
fl_end_form();
return fdui;
}
- - - ENDIT - - -
As usual, I disclaim all warranties and liabilities. Use at your own
risk. If your underwear suddenly all leaps a half a meter to your
left the moment you hit Return, that's your own lookout (though some
of you might enjoy the sensation, I suppose).
spl
_________________________________________________
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/