enhanced message/prompt dialog
Status: Alpha
Brought to you by:
junrue
Provide a better message dialog that applications can
use when notification is to be provided, to save the
effort of every application defining their own. Better
means allowing more control over number of and content
of buttons and display text than the built-in Win32
message box.
Allow for use of this dialog as a prompt.
Logged In: YES
user_id=816366
Originator: NO
I created my most used dialogs for my personal use. Message box was based on your demo code; input-prompt asks for a textual value, and y-or-n-prompt, well, you can figure it out :). But the macro with-dialog is able to support most kinds of message dialogs you want, easily. Here's the code:
(defvar *parent* nil "current parent widget")
(defmacro make-label (title &key parent)
`(let ((*parent* ,(or parent '*parent*)))
(make-instance 'gfw:label :text ,title :parent *parent*)))
(defmacro make-textbox (&key title parent (columns 50) (lines 1) (enabled t))
(let ((initial-string (make-blank-string columns lines)))
`(let ((*parent* ,(or parent '*parent*)))
,(when title
`(make-label ,(concatenate 'string title ":") :parent *parent*))
(let ((new-textbox
(make-instance 'gfw:edit
:parent *parent*
:text ,initial-string
:style ,(and (> lines 1) ''(:multi-line :auto-hscroll :auto-vscroll :vertical-scrollbar :want-return)))))
(gfw:enable new-textbox ,enabled)
new-textbox))))
(defmacro make-button (&key parent callback (style ''(:default-button)) text)
`(make-instance 'gfw:button :parent ,(or parent '*parent*) :callback ,callback :style ,style :text ,text))
(defmacro with-panel ((var &key parent (dispatcher 'gfw:event-dispatcher) (layout 'gfw:flow-layout) (style '(:vertical)) (spacing 4) (margins 4)) &body body)
`(let* ((,var (make-instance 'gfw:panel
:dispatcher ,(if (symbolp dispatcher)
`(make-instance ',dispatcher)
dispatcher)
:parent ,(or parent '*parent*)
:layout (make-instance ',layout :style ',style :spacing ,spacing :margins ,margins)))
(*parent* ,var))
,@body))
(defclass dialog-events (gfw:event-dispatcher)
((return-value :accessor dialog-return-value :initarg return)))
(defmethod gfw:event-close ((disp dialog-events) (dlg gfw:dialog))
(call-next-method)
(gfs:dispose dlg))
(defclass value-dialog ()
((box :accessor value-dialog-box :initarg :box)
(msgs :accessor value-dialog-messages)
(input :accessor value-dialog-input)
(retbtn :accessor value-dialog-result
:initform 'ok)))
(defmethod show ((vdlg value-dialog))
(let ((dlg (value-dialog-box vdlg)))
(gfw:pack dlg)
(gfw:center-on-owner dlg)
(gfw:show dlg t)
(value-dialog-result vdlg)))
(defmacro with-dialog ((var &key owner (title "Dialog") (dispatcher 'dialog-events) image-path (layout 'gfw:flow-layout) (style ''(:owner-modal)) (spacing 8) (margins 8)) &body body)
(let ((label-var (gensym "label"))
(image-var (gensym "img")))
`(let* ((,var (make-instance 'gfw:dialog :owner ,owner
:dispatcher ,(if (symbolp dispatcher)
`(make-instance ',dispatcher)
dispatcher)
:layout (make-instance ',layout
:margins ,margins
:spacing ,spacing)
:style ,style
:text ,(or title `(gfw:text ,owner))))
(*parent* ,var))
(when ,image-path
(let ((,label-var (make-instance 'gfw:label :parent *parent*))
(,image-var (and ,image-path (make-instance 'gfg:image
:file ,(if (stringp image-path)
(merge-pathnames image-path
*project-directory*)
image-path)))))
(unwind-protect
(gfg:with-image-transparency (,image-var (gfs:make-point))
(setf (gfw:image ,label-var) ,image-var))
(gfs:dispose ,image-var))))
,@body)))
(defun y-or-n-prompt (owner desc &key image-path title yes no (yes-text "Yes") (no-text "No"))
(with-dialog (dlg :owner owner :title title :image-path image-path)
(let ((res (make-instance 'value-dialog :box dlg)))
(with-panel (text-panel :spacing 2 :margins 0)
(dolist (desc-line (if (listp desc) desc (list desc)))
(make-label desc-line)))
(with-panel (btn-panel :margins 0 :spacing 0 :style (:horizontal :normalize))
(make-button :text yes-text
:callback (lambda (disp btn)
(declare (ignore disp btn))
(setf (value-dialog-result res) (or yes t))
(gfs:dispose dlg)))
(make-button :text no-text
:callback (lambda (disp btn)
(declare (ignore disp btn))
(setf (value-dialog-result res) no)
(gfs:dispose dlg))))
(show res))))
(defun input-prompt (owner desc &key image-path title (btn-text "Ok"))
(with-dialog (dlg :owner owner :title title :image-path image-path)
(let ((res (make-instance 'value-dialog :box dlg))
text-box)
(with-panel (text-panel :spacing 2 :margins 0)
(dolist (desc-line (if (listp desc) desc (list desc)))
(make-label desc-line))
(setf text-box (make-textbox)))
(with-panel (btn-panel :margins 0 :spacing 0 :style (:horizontal :normalize))
(make-button :text btn-text
:callback (lambda (disp btn)
(declare (ignore disp btn))
(setf (value-dialog-result res) (gfw:text text-box))
(gfs:dispose dlg))))
(show res))))
(defun message-box (owner desc &key image-path title)
(with-dialog (dlg :owner owner :title title :image-path image-path)
(with-panel (text-panel :spacing 2 :margins 0)
(dolist (desc-line (if (listp desc) desc (list desc)))
(make-label desc-line)))
(with-panel (btn-panel :margins 0 :spacing 0 :style (:vertical :normalize))
(make-button :text "Ok"
:callback (lambda (disp btn)
(declare (ignore disp btn))
(gfs:dispose dlg))))
(show (make-instance 'value-dialog :box dlg))))