|
|
On 5/13/21 8:57 PM Dave Jordan wrote:
Thanks, Albrecht, for putting in as much effort as is apparent here.
Welcome!
Below are comments, clarifications, and a few much simpler questions.
On Thu, May 13, 2021 at 4:49 AM Albrecht Schlosser wrote:
On 5/12/21 12:13 PM Dave Jordan wrote:
> App *app also contains an Fl_Group which contains > 200
subclassed Fl_Boxes.
> I have written no explicit event handling in the Fl_Group.
> If I do, the Group is going to get /all/ the events before the
Boxes do,
> and that will open a whole 'nother can of worms.
Why? It could really be helpful if the group would get the events
before
the children so you could filter yourself which events to propagate to
the children and which not to propagate.
The can of worms is not the potential usefulness or lack thereof but
merely the extra work i would have of going back thru all the modules
and getting the new object references correct. I could see it maybe as a
necessity if i think of some new feature that won't work otherwise...
Hmm, I can't see that implementing a handle() method in your own group
widget (derived from Fl_Group) would change anything of the internal
logic. An example handle method might look like this:
MyGroup::handle(int ev) {
if (ev == FL_SHORTCUT) {
// preprocess event, decide which widgets
// should get it, maybe ignore it ?
if (some_condition ...)
return 0; // do NOT process, ignore
else if (uppercase...)
return 0;
}
// Process all other events:
return Fl_Group::handle(ev);
}
Note that this handle method is designed to *filter* events so they
don't reach the children, hence Fl_Group::handle(ev) is called /after/
the filter mechanism decided to ignore some events.
This handle() method could be the only method you need to implement,
except maybe constructor and destructor. The only necessary change would
be to change Fl_Group to MyGroup in the parent group widget of your cells.
This should be transparent to the rest of the implementation -- but I
don't know your code...
> class Cell : public Fl_Box {
>
> int handle(int e) { return brd_handle(this, e); }
> static int brd_handle(Cell *cell, int e);
As Greg wrote, that's an unnecessary extra step, you don't need the
static method brd_handle(). Just use Cell::handle() for your stuff.
I have the vague idea that i'm telling the compiler not to include all
the handling code in every instantiation.
That vague idea is wrong. Code is never included in object instantiations.
i have seen statically declared methods in fltk examples before .
Yes, those static methods exist. Imagine such methods as being "class
methods" rather than "object methods". There are two main reasons to use
static methods:
(1) Implementation of special constructors or for instance counters per
class, one example being an object id. The static counter is initialized
to 0 and every object calls the method
static int MyClass::get_id();
which increments the global/class counter and returns the id.
(2) FLTK callback functions must be static. Here it's the static method
that is used as the callback which then calls the (non-static) object
method for easier implementation. This is the opposite (calling
sequence) of what you were doing.
> int Cell::brd_handle(Cell *cell, int e) {
>
> #define S_NORM 0x100000 // raw bits of event states. to do: also
> detect capslock
> #define S_SHFT 0x110000
> #define S_CTRL 0x140000
> #define S_ALT 0x180000
*NEVER* do this, i.e. define your own macros with explicit bit values,
saw that coming!
;-)
use the symbolic names instead. That's why they are defined. Additional
information: we recently discussed /changing/ some of these bit values
which would break your code because you used bit numbers!
So "translating your code back" to defined names:
#define S_NORM FL_NUM_LOCK // raw bits ...
#define S_SHFT (FL_NUM_LOCK | FL_SHIFT)
#define S_CTRL (FL_NUM_LOCK | FL_CTRL)
#define S_ALT (FL_NUM_LOCK | FL_ALT)
Note that these bits are intended to be used to test if a particular
bit is set (i.e. a key is pressed or ON (NumLock)).
[...]
> int s = Fl::event_state();
So, given the bit structure of the defined constants you might at least
want to change this to
int s = Fl::event_state() &
(FL_NUM_LOCK|FL_SHIFT|FL_CTRL|FL_ALT);
which would ignore all other state bits than those you're interested in
(leaving the rest of your tests as-is).
> int k = Fl::event_key();
what if i want ctrl-x but not alt-x and not ctrl-alt-x?
First of all: testing Fl::event_key() is often the wrong test,
particularly if it comes to special keys or keys with NumLock on or off
or keys on international or OS specific keyboards. For instance, the
'key' you press on the numeric keypad is the same whether NumLock is on
or off, but the 'text' it generates is different. If I want to use the
'~' character I need to press AltGr/+ on my German PC (Notebook)
keyboard but Option/n on my MacBook.
In most cases it's more appropriate to test Fl::event_text() which is
the text created by the keypress -- in the example above that would be
"~". Think also of UTF-8 characters ...
Back to your question, short answer: that's what bit tests are used for.
Test specific bits...
Long answer: let's assume you want to ignore NumLock and you are only
interested in modifier keys SHIFT, CTRL, and ALT and all combinations.
The first step is to "mask out" all other event state bits as shown
above, but modified:
int s = Fl::event_state() & (FL_SHIFT|FL_CTRL|FL_ALT);
Now s can only be one of 8 different values and you can proceed with a
switch/case:
switch (s) {
case FL_CTRL:
process_ctrl_x();
break;
case FL_ALT:
process_alt_x();
break
default:
break;
}
or you can test for special combinations like this:
if (s == FL_CTRL|FL_ALT)
process_ctrl_alt_x();
etc. ...
Note that it's important to mask the irrelevant bits (mouse buttons
etc.) out if you want to test with "==" or a switch, but you can always
test for individual bits alone:
int ctrl = Fl::event_state() & FL_CTRL;
int alt = Fl::event_state() & FL_ALT;
int shift = Fl::event_state() & FL_SHIFT;
if (ctrl && shift && !alt)
do_something();
There are endless possibilities, the best way depends on what you want
to achieve.
That said, this is in parts basic programming and not FLTK specific but
I wanted to mention different ways to test for FLTK event states.
> // And i suppose this is also the source of the UI problem,
> wherein after all the searching about, if a shortcut
> function involves another
>
> // cell taking focus, the old cell will not receive
FL_UNFOCUS
> (leaving it highlighted).
Hmm, I believe this /should/ work. If you call take_focus() and the
focus is assigned to the other cell the current Fl::focus() widget
should IMHO get the FL_UNFOCUS event.
See my demo program which shows that it *does* work fine.
there is something in one of the functions that causes a cell to "forget
it has the focus"
i have a workaround for now, and i may become moot soon b/c i think i
know what it is.
Ok i just checked and the save() function calls the deactivate method of
the container for the cells. that seems like it could do it.
will test and get back.
Okay, that's specific to your code then. Glad you found it.
Here's the bug I mentioned before:
The events you want to be ignored by using 'break;' transfer control
after the switch statement and thus
> return EVHANDLED;
which tells FLTK that you /handled/ the event. That means that the
event
is actually _dropped without handling_ it at all and it can't be
handled
by any other widget. If that's what you mean with "ignored", well, then
yes, but that's in FLTK event handling two different things and you
should be aware of this.
right, i had those "ignored" cases there so i could see "interesting"
event names without scrolling thru hundreds of FL_ENTER and FL_LEAVE
which are irrelevant to everything so far in my UI design.
The important point is not that you had these cases in your handle
method but that you returned 1 (EVHANDLED) which lets FLTK drop this
event after your handle method got it. Just logging the event is
supposedly not "handling" it, so you may eclipse these events from other
widgets that would otherwise handle them.
--
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+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/53e89b08-fc7a-e94f-df4a-bd32ae89bc91%40online.de.
[ Direct Link to Message ] | |
|
| |