Hello,
I am currently struggling with a problem which is somewhat related to
popup menus.
What I would like to achieve is the same behavior as a popup menu but
with arbitrary widgets.
The behavior should be
1) (the simple part - straight forward): click + release on some button
- then the dialog pops up and you can click on any of the widgets in it.
They all respond to FL_ENTER, FL_LEAVE, FL_PUSH and FL_RELEASE. Once a
widget has been pushed the dialog disappears again. Also a click outside
the dialog hides it again.
2) (the harder part - not working): click -> dialog pops up while the
mouse is still pressed and receives FL_DRAG. Messages are routed to the
popup windows as if the mouse is not pushed, i.e. the children receive
FL_ENTER, FL_LEAVE, FL_PUSH/FL_RELEASE (=actually FL_RELEASE on
menubutton) and react accordingly (redraw etc.).
If the mouse is released outside the dialog then it is hidden again.
I have tried several methods including:
1) call Fl::handle in button-handle with translated messages
(FL_DRAG->FL_MOVE, FL_RELEASE->FL_PUSH) -> crash
2) same but with Fl::add_timeout(0,..) + Fl::handle -> not working
3) call handle of the window directly -> crash
4) Fl::grab + Fl::wait -> not working
resulting mostly in either non working behavior or worse crashes. I'm
sure there is a simple way to achieve this, as so often in FLTK, I
simply haven't found it yet.
My testcode is below. There are four test cases, which you can uncomment
- needless to say, none of them works :-(
// M E N U T E S T . C X ///////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
// global for test case 4: grab while this variable is true
int g_popup=1;
class Fl_Active_Button:public Fl_Button
{
public:
Fl_Active_Button(int X, int Y, int W, int H, const char*
L=""):Fl_Button(X,Y,W,H,L)
{ color(FL_BLUE);
}
int handle(int e)
{ fprintf(stderr,"receive event in active button: %d\n",e);
switch(e)
{ case FL_ENTER: color(FL_RED); redraw(); return(1);
case FL_LEAVE: color(FL_BLUE); redraw(); return(1);
case FL_PUSH:
case FL_RELEASE: g_popup=0; return(1);
default: return(Fl_Button::handle(e));
}
}
};
// test cases: uncomment different scenarios
//
// test 1: send messages in handle with Fl::handle to redirect-window
// (uncomment in FL_RELEASE and FL_DRAG)
// test 2: call postsend (to send a message with Fl::add_timeout and
// Fl::handle)
// (uncomment in FL_RELEASE and FL_DRAG)
// test 3: call handle function of redirect window directly
// (uncomment in FL_RELEASE and FL_DRAG)
// test 4: use grab and and Fl::wait in FL_PUSH
// (uncomment in FL_PUSH)
class Fl_Redirect_Button:public Fl_Button
{ Fl_Window* _win;
int _msg;
public:
Fl_Redirect_Button(int X, int Y, int W, int H, const char*
L=""):Fl_Button(X,Y,W,H,L)
{ redirect(NULL);
_msg=0;
}
void redirect(Fl_Window* w) {_win=w;}
Fl_Window* redirect() {return(_win);}
static void s_sendmsg(void*o){ ((Fl_Redirect_Button*)o)->sendmsg(); }
void sendmsg() { if (redirect()) Fl::handle(_msg,redirect()); }
void postsend(int msg)
{ _msg=msg; Fl::add_timeout(0.0,s_sendmsg,this);}
int handle(int e)
{ switch(e)
{ case FL_PUSH:
{ if (redirect())
{ redirect()->position(window()->x()+x(),window()->y()+y()+h());
redirect()->show();
redirect()->set_modal();
// method 4 - Fl::grab - does not work
// Fl::grab(redirect());
// Fl::focus( redirect() );
// Fl::pushed( redirect() );
// g_popup=1;
// while( g_popup) Fl::wait();
// fprintf(stderr,"grab out\n");
// Fl::grab(0);
// redirect()->hide();
// Fl::focus(this);
return(1);
}
} break;
case FL_RELEASE:
{ if (redirect() && Fl::event_inside(redirect()))
{ // method 1
// Fl::handle(FL_PUSH,redirect());
// method 2
// postsend(FL_PUSH);
// method 3
// return(redirect()->handle(e));
redirect()->hide();
return(1);
}
else
{ redirect()->hide();
}
} break;
case FL_DRAG:
{ if (redirect())
{
// method 1: direct call in handle of Fl::handle => crash
// Fl::handle(FL_MOVE,redirect());
// method 2 - call it with a timeout(0.0)
// postsend(FL_MOVE);
// method 3 - call handle of widget directly => crash
// return(redirect()->handle(e));
return(1);
}
} break;
}
return(Fl_Button::handle(e));
}
};
int main(int argc, char** argv)
{
Fl_Window* hidden=new Fl_Window(120,100);
hidden->border(0);
hidden->set_modal();
Fl_Active_Button* ba=new Fl_Active_Button(10,10,100,50,"Hello");
hidden->end();
Fl_Window * win=new Fl_Window(120,100,"test menu");
Fl_Redirect_Button* b=new Fl_Redirect_Button(10,10,100,25,"clickme");
b->redirect(hidden);
win->end();
win->show(argc,argv);
return(Fl::run());
}
Has anybody made similar attempts, or even managed to solve the problem?
Any pointers, hints or example code would be greatly appreciated.
I have found Greg's example on the popup text window, which is nice but
this is only a prerequisite and does not show how events would be routed
to the window between FL_PUSH and FL_RELEASE events.
I am aware that in FLTK2 it seems to be possible to add widgets to menus
- but backporting seems to be a major undertaking. Also the FLTK3
manifesto mentions something along these lines - however, as I
understand - it is currently on the wish list only.
I would prefer if it were possible - with whatever means - to emulate
such a behavior in FLTK 1.3.
Thanks,
Herman
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk