I'm using a hold browser and i think its scrollbar is stealing a shortcut to a menu item i have assigned to ctrl-end. How can I prevent this? subclass the scrollbar? Or is it legit to have a handle and a callback for the same widget i.e. the browser?
--
You received this message because you are subscribed to the Google Groups "fltk.general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/d5a5b77f-3d72-a769-c490-17d7bf1491c7%40online.de.
On 8/4/21 5:02 AM, Dave Jordan wrote:
Hi everybody.I'm using a hold browser and i think its scrollbar is stealing a shortcut to a menu item i have assigned to ctrl-end. How can I prevent this? subclass the scrollbar? Or is it legit to have a handle and a callback for the same widget i.e. the browser?
Yes - looking at the code for src/Fl_Scrollbar.cxx, it
appears to react to FL_End
as a shortcut regardless of the keyboard modifiers, so
apparently Alt, Shift, Ctrl, etc.
can all be used with the End key to handle moving the
scrollbar.
I think order of widgets in the parent group matter for
shortcut event delivery;
the group's children are likely processed in order of
creation, so the first widget
to respond to the shortcut 'wins'.
So if possible, try creating your 'widget that needs ctrl-end'
/before/ creating the
hold browser. Or, you can rearrange the pointers in the parent
group using I think
remove() and add().
Or I think the better approach might be to make your own
subclass of the hold browser
that /doesn't/ react to Ctrl+End, which should be easy to do,
and will guarantee it doesn't
steal the events you want.
In your subclass handle() method, you can check for Ctrl+End
and ignore the event
by just doing a return(0); when it's received. This will
eclipse the event from the base class
so it can't react to it. Pretty sure this would work:
int MyHoldBrowser::handle(int e) {
// Specifically ignore the Fl_End + FL_Ctrl key combo
so that other widgets may use it
switch (e) {
case FL_KEYDOWN: // keyboard press
events (aka. FL_KEYBOARD)
case FL_KEYUP: // keyboard releae events
case FL_SHORTCUT: // keyboard shortcuts
switch ( Fl::event_key() ) {
case FL_End: //
Fl_End pressed?
if ( Fl::event_state() & FL_CTRL ) //
Ctrl key also pressed?
{ return 0; } // short
circuit this event from base class so other widgets can
use it
break;
}
break;
}
return Fl_Hold_Browser::handle(e); // all
other events pass to base class
}
You can easily tweak that to ignore other modifier key combos
as well that you might need,
like Alt-End, Shift-End, and ignore those combos with other
keys as well, like Home, PgUp/Dn, etc.
[..]
Or I think the better approach might be to make your own subclass of the hold browser
that /doesn't/ react to Ctrl+End, which should be easy to do, and will guarantee it doesn't
steal the events you want.
In your subclass handle() method, you can check for Ctrl+End and ignore the event
by just doing a return(0); when it's received. This will eclipse the event from the base class
so it can't react to it. Pretty sure this would work: [..]
Here's a small working example program that demonstrates that
technique.
Here I created two widgets:
When you run the app, hitting Ctrl+End should print the
message indicating MyEndWidget
was able to process the event.
As an experiment, you can try commenting out the
entire MyHoldBrowser::handle() method
(shown in blue below), then it will act like the default
Fl_Hold_Browser, and you'll see Ctrl+End no longer
prints the message, replicating the "event stealing" behavior
you mentioned. This would show the
subclassing technique with the handle() method solves the
issue.
#include <FL/Fl_Double_Window.H> #include <FL/Fl_Hold_Browser.H> #include <FL/Fl_Box.H> class MyHoldBrowser : public Fl_Hold_Browser { public: MyHoldBrowser(int X,int Y,int W,int H,const char *title=0) : Fl_Hold_Browser(X,Y,W,H,title) { } int handle(int e) { // Specifically ignore the Fl_End + FL_Ctrl key combo // so other widgets may use it switch (e) { case FL_KEYDOWN: // keyboard press events (aka. FL_KEYBOARD) case FL_KEYUP: // keyboard releae events case FL_SHORTCUT: // keyboard shortcuts switch ( Fl::event_key() ) { case FL_End: // Fl_End pressed? if ( Fl::event_state() & FL_CTRL ) // Ctrl key also pressed? { return 0; } // eclipse event from base class so other widgets can use it break; } break; } return Fl_Hold_Browser::handle(e); // all other events pass to base class } }; class MyEndWidget : public Fl_Box { public: MyEndWidget(int X,int Y,int W,int H,const char *title=0) : Fl_Box(X,Y,W,H,title) { } int handle(int e) { if ( e == FL_SHORTCUT && Fl::event_key() == FL_End && Fl::event_state() & FL_CTRL ) { printf("Handling Ctrl-End!\n"); // debugging return 1; } return Fl_Box::handle(e); } }; int main() { // Make window with the border color Fl_Double_Window *win = new Fl_Double_Window(800,800,"Test"); // Create our own Hold Browser subclass MyHoldBrowser *brow = new MyHoldBrowser(10,10,300,800-20,"Hold Browser"); { // Make 100 items in the browser so scrollbar appears char s[80]; for (int t=0; t<100; t++ ) { sprintf(s, "%04d", t); brow->add(s); } } // Create our own widget that needs Ctrl+End // If it receives that key combo, it prints a message to the screen. // Let's create this /last/, ensuring that widget creation order // doesn't matter to make this technique work. // MyEndWidget *myend = new MyEndWidget(400,10,300,800-20,"My Widget"); myend->color(FL_RED); myend->box(FL_FLAT_BOX); win->end(); win->show(); return Fl::run(); }
Although I didn't try it, I think what would also 'work' is if you left the default Fl_Hold_Browser
behavior intact, and just created the MyEndWidget first, and the hold browser after that.
Changing the order should (I think) also allow your widget to get the shortcut event first,
without having to subclass Fl_Hold_Browser.
But depending on widget order might be hard to maintain, and be too obscure, so I think
the above behavior might be the better choice.
On 8/5/21 12:24 PM, Greg Ercolano wrote:
[..]
Or I think the better approach might be to make your own subclass of the hold browser
that /doesn't/ react to Ctrl+End, which should be easy to do, and will guarantee it doesn't
steal the events you want.
In your subclass handle() method, you can check for Ctrl+End and ignore the event
by just doing a return(0); when it's received. This will eclipse the event from the base class
so it can't react to it. Pretty sure this would work: [..]
if(e == FL_SHORTCUT) return EVNOTHANDLED; // (aka 0)
// process tab and shift-tab -- they give other widgets the focus
if(e == FL_KEYBOARD && (! (Fl::event_state() & (FL_CTRL | FL_ALT | FL_META)))) {
if(Fl::event_key() == FL_Tab) {
// ...
}
}
return Fl_Hold_Browser::handle(e); // let other events/keystrokes do whatever they want