On Thu, 5 Apr 2001, Angus Leeming wrote:
> On Thursday 05 April 2001 07:31, Allan Rae wrote:
> > BTW, what happens if after the user presses a key they then try to press
> > Okay? If the last key press in the edit box gave an invalid entry then
> > they shouldn't have an Okay button available.
>
> I've been thinking about (note no intention of implementing!) invalid input.
>
> When data is input to the button controller as invalid, why not then store a
> pointer to that widget in a vector of invalid data. Future input is checked
> against this vector and any (was invalid, now valid) data is removed from it.
> The dialog can then only be activated when all input is valid.
Then what do you do if it's the relationship between two inputs that is
wrong. Like the font size settings in Preferences. These are currently
restricted to being monotonic increasing (although consecutive sizes can
be the same size).
The way I had originally written the input() handling routine in the
dialogs I ported was that it checks _all_ these relationships _everytime_
it's called. Now there seem to be a few dialogs that only do checks for
individual widgets or at least for individual tabs of a tabbed dialog.
Where possible I think we should use a specific input filter on an
input/edit box to control what characters can be entered etc. Several of
these already exist for xforms and much of their implementation could be
shared with other toolkits. The overhead of input() operating the way
I described is negligable because this is triggered by a user typing or
clicking.
So maybe I should more clearly define what I expected in my design of BC.
The output of the dialog.input() processing callback defines whether the
dialog is in a valid state or not. Angus has extended this to allow it
say no change in previous state -- this was for handling cases where a
user clicked on a widget that had no effect upon the dialog state.
This should only be needed when input checking is shortcutted or at least
"optimized" but even then you still run into problems of tracking.
My original plan called for input() to check everything that could make a
dialog invalid. This was to work in conjunction with input-filtering
where possible. Under XForms all you can effectively do with an
input-filter is return a bool flag of whether that input/keypress is valid
or not. You can't do anything particularly tricky with it.
So input() checks relationships between inputs and checks other
requirements that you can't do in an input-filter. For example, typing in
a writable directory name: input-filtering lets you check for valid
filename characters but you can't do a check of whether or not the
directory exists in the input-filter because if you return FL_INVALID the
character isn't even entered in the input box making it impossible to
enter anything in the box!
If you want to get fancy and limit input checking to particular tabs of a
tabbed dialog or individual widgets (the one the user just typed in for
instance) then you need to do some invalid tracking. I have been
considering inverting the input box colours or just changing
it's background to red to make it more obvious to users which ones we
think they've gotten wrong. This also needs some sort of tracking or at
least reset to normal every time through when they are valid.
Personally, I'd rather process everything, everytime, until such time as
we start seeing interactive response problems.
[at this point I decided to take a look at FormPreferences.C instead of
just seeing how BC and co. where implemented]
Looking through FormPreferences.C I now see that the input() callback is
now being used as a general purpose callback and the object that triggered
the callback is being used to do all sorts of things from input checking
to running commands. I have this to say about that:
NNN NN OOOO III
NNNN NN OO OO III
NN NNNN OO OO III
NN NNN OO OO
NN NN OOOO OOO
Clearly, there's been a misunderstanding of how I'd intended this to work
and I hadn't noticed how this was being altered in my absence.
Personally, I'd rather things like FormPreferences::Converters::Add() got
their own callback. Direct to the function associated with the button --
which was why I'd written those callback macros in the first place. The
button doesn't need any input checking because it isn't an input. Only
inputs (like input boxes, sliders/counters and edit boxes) need to be
calling input(). Sigh, sigh again. [Obsenity deleted].
I really don't like the idea of centralizing the callbacks and then trying
to figure out who does what as a result. There's a mixture of control and
input processing being done now in what was intended to be an input-only
processing step. As a result you can't give BC a proper response and
people are getting frustrated. If you really, really like the idea of a
centralized _control_ callback then I would suggest that you create one.
Call it control() if you like and move most of the code out of input()
into control(). That way input() can again concentrate on input checking
and the controls can do whatever the hell they want and won't cause any
grief to the BC. Control stuff doesn't need to go anywhere near the
button controller because they don't affect the validity of the dialogs
contents. The controls (buttons that cause actions) are however likely to
be affected by whether the dialog has valid inputs or not. Here we have a
couple of options:
1. have a control list (like the readonly list) that get disabled when
invalid inputs are present.
2. leave the controls activated always and they do their own input
checking on the specific inputs they use. If invalid input exists
do nothing -- or maybe place an appropriate message.
3. almost a 2a: just check if BC says we have valid inputs -- or call
input() directly
Most of the controls present in Preferences at least, don't seem to be
affected by dialog validity -- except for Converters::Add perhaps if it is
given a collection of empty input fields. But those fields don't make the
whole dialog invalid anyway so that would be case (2) above. A specific test
could be put in (or called from) input() that controls the activation of
that button.
Now then, once a control has finished operating the dialog state may have
changed so it would probably make sense to code a callback in FormBase
something like:
void FormBase::ControlCB(FL_OBJECT * ob, long data)
{
control(ob, data); // handle control
bc().valid(input(ob, data)); // recheck validity of dialog
// ^^^^^
// I'd prefer this to go back to being the true/false arrangement
// we used to have in an effort to force correct input handling.
// This might restrict any future attempts to optimise
// input checking to per-tab basis with invalidity-tracking but
// I think that would also require an interface change and is
// unnecessarily complex.
}
likewise for:
void FormBase::InputCB(FL_OBJECT * ob, long data)
{
bc().valid(input(ob, data));
// ^^^^^
}
Maybe now I am starting to see the real confusion that Kalle and John have
expressed. Everybody is trying to use BC and input() the wrong way and
getting frustrated as a result.
Summary: Controls are not inputs. input() is for input checking only.
Sorry I didn't pick up on this sooner.
Allan. (ARRae)