Lisp HUG Maillist Archive

Editing callback interactions

Hello again, esteemed CAPI experts.

I have a dialog something like the example below: there is a text input box, which has an editing-callback that verifies the input, and if invalid, beeps and resets it to last valid value.  There are buttons in the dialog that do things with the text.

I would like to arrange it so that if the user enters an invalid value in the input box and then clicks on a button (without otherwise switching focus first), then the normal action of the button is NOT executed.  In other words, I'd like to arrange for the error in the input to somehow abort the action that caused the editing callback.

In experimenting with this, I run the test function below, type "bad" in the input box and click on the button.  I found the following strange behavior:

1.  On Windows, if I do (test nil), i.e. beep, then first the editing callback is called, then the button selection callback is called.

2.  On Windows, if I do (test t), i.e. do display-message, then the editing callback is called, but the button selection callback is NOT called.

3.  On the Mac, in either case, the editing callback is not called at all, only the selection callback.


The behavior in 2. is what I want, and I'm perfectly willing to put up a message dialog instead of just beeping, but I don't want to rely on whatever strange set of circumstances makes it happen in that case, since it might be a bug that will get fixed...  Is there a way to get the behavior I want reliably?  (I'm mostly concerned about Windows, I can deal with the Mac behavior)

FWIW, I tried an approach where the editing callback sets an "error occured" flag that the selection callback can look at, but I have not found a way to arrange for the flag to be reset in the case where the editing callback is invoked by an ordinary focus change not involving a button press (e.g. tab).

Perhaps editing-callback is not the right callback for error checking the text.  Is there some other callback I should be using?

Any help/advice would be greatly appreciated.

Gail

(defun test (dialog-p)
 (capi:contain
 (let* ((text
         (make-instance 'capi:text-input-pane
           :editing-callback
           #'(lambda (pane how)
               (when (eq how :end)
                 (when (equalp (capi:text-input-pane-text pane) "bad")
                   (if DIALOG-P
                     (capi:display-message "Don't be bad!")
                     (progn
                       (format *trace-output* "Don't be bad!~%")
                       (capi:beep-pane)))
                   (setf (capi:text-input-pane-text pane) "good"))))))
        (button (make-instance 'capi:push-button
                  :text "Do Something With Input"
                  :selection-callback
                  #'(lambda (item interface)
                      item interface
                      (capi:display-message
                       "Doing something with ~s"
                       (capi:text-input-pane-text text))))))
   (make-instance 'capi:column-layout
       :description (list text button)))))


Re: Editing callback interactions

Unable to parse email body. Email id is 7749

Re: Editing callback interactions

At 2/19/2008 01:41 PM, Nick Levine wrote:
>     I would like to arrange it so that if the user enters an invalid
>     value in the input box and then clicks on a button (without
>     otherwise switching focus first), then the normal action of the
>     button is NOT executed.
>
>Wouldn't it be better to disable the button when you don't want it
>pressed?

Ahh, I see.  So this would be something I'd do from a 
change-callback?  In the actual application, it's not just a single 
button, there are over half a dozen different buttons and option 
panes that apply to the text in the input box.  I worry a little 
about the visual noise of enabling/disabling so many widgets with 
each keystroke, but I'll give it a try...

Thanks.


>- nick
>
>Arthur: "I wonder what will happen if I push this button?" Ford:
>"Don't do it." A: "Too late." F: "What happened?" A: "A sign lit up
>saying, 'please don't press this button again.'"


Re: Editing callback interactions

On Tuesday 19 February 2008 1:22:50 pm Gail Zacharias wrote:
> Hello again, esteemed CAPI experts.
....
> I would like to arrange it so that if the user enters an invalid value in

Here's an orthogonal opinion...

Any sufficiently complicated UI (i.e. more than a few buttons) is a perfect 
candidate for being designed and implemented as a consolidated state machine 
(or more than one state machine).  This is especially true with gui's because 
the user can do anything / push anything at any time - you need a central 
coordinator to track the users' actions.

If you try to do everything with callbacks, you end up with a bunch of state 
variables anyway, but the result becomes unstructured and tough to maintain.  

What I do, is to point every callback in an interface to the same routine 
(which I usually call "transition" or "machine") which implements the state 
machine and tracks all of the inter-related behaviour of the UI components in 
one place.  Each callback provides an "event" symbol to denote what action 
occured, 
e.g. :mouse-move, :left-pressed, :left-released, :toolbar-button-xyz-pushed, 
etc.  The state machine decides whether the event causes some action in the 
current state or is ignored.

I recently posted a state machine macro to comp.lang.lisp.  It implements 
state machines with entry, transition and exit code - something which I know, 
from decades of experience using state machines - is the kind of state 
machine one should use in this problem space.  (Contact me directly if you 
can't find it, or want more info on how to use it).

You don't *need* the macro, you can implement the state machine by hand (but 
you probably lose entry and exit code).  A state machine is just a function 
that looks at the incoming event and the current state and executes 
one "step",  and possibly changes the state of the machine.  In CAPI, the 
state variable can conveniently be an instance variable of the interface, 
declared at the top of capi:define-interface.

pt

(and if Kenny were here, he would suggest that Cells be used :-).


Re: Editing callback interactions

Unable to parse email body. Email id is 7752

Updated at: 2020-12-10 08:43 UTC