10.5.2 Using popup-confirmer

The function
popup-confirmer
is a higher level function provided to add the standard buttons to user dialogs, and it is nearly always used in preference to
display-dialog
. In order to create a dialog using
popup-confirmer, all you need to do is to supply a pane to be placed inside the dialog along with the buttons and the title. The function also expects a title, like all of the prompter functions described earlier.

(popup-confirmer

(make-instance

'text-input-pane

:callback-type :data

:callback 'exit-dialog)

"Enter a string")

A common thing to want to do with a dialog is to get the return value from some state in the pane specified. For instance, in order to create a dialog that prompts for an integer the string entered into the text-input-pane would need to be converted into an integer. It is possible to do this once the dialog has returned, but
popup-confirmer
has a more convenient mechanism. The function provides a keyword argument,
:value-function, which gets passed the pane, and this function should return the value to return from the dialog. It can also indicate that the dialog cannot return by returning a second value which is non-nil.

In order to do this conversion,
popup-confirmer
provides an alternative exit function to the usual
exit-dialog
. This is called
exit-confirmer, and it does all of the necessary work on exiting.

You now have enough information to write a primitive version of
prompt-for-integer.

(defun text-input-pane-integer (pane)

(let* ((text

(text-input-pane-text pane))

(integer

(parse-integer

text

:junk-allowed t)))

(or (and (integerp integer) integer)

(values nil t))))

(popup-confirmer

(make-instance

'text-input-pane

:callback 'exit-confirmer)

"Enter an integer:"

:value-function 'text-input-pane-integer)

Figure 10.10 A example using
popup-confirmer

Note that the dialog's
OK
button never becomes activated, yet pressing
Return
once you have entered a valid integer
will
return the correct value. This is because the
OK
button is not being dynamically updated on each keystroke in the text-input-pane so that it activates when the text-input-pane contains a valid integer. The activation of the
OK
button is recalculated by the function
redisplay-interface
, and the CAPI provides a standard callback,
:redisplay-interface
, which calls this as appropriate.

Thus, to have an
OK
button that becomes activated and deactivated dynamically, you need to specify the change-callback for the text-input-pane to be
:redisplay-interface
.

(popup-confirmer

(make-instance

'text-input-pane

:change-callback :redisplay-interface

:callback 'exit-confirmer)

"Enter an integer:"

:value-function 'text-input-pane-integer)

Note that the
OK
button now changes dynamically so that it is only ever active when the text in the text-input-pane is a valid integer.

Note that the
Escape
key activates the
Cancel
button - this too was set up by
popup-confirmer
.

The next thing that you might want to do with your integer prompter is to make it accept only certain values. For instance, you may only want to accept negative numbers. This can be specified to popup-confirmer by providing a validation function with the keyword argument
:ok-check
. This function receives the potential return value (the value returned by the value function) and it must return non-nil if that value is valid. Thus to accept only negative numbers we could pass
minusp
as the
:ok-check.