chiark / gitweb /
Work in progress.
[jlisp] / dep-ui.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Dependency-based user interfaces
4 ;;;
5 ;;; (c) 2007 Mark Wooding
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 2 of the License, or
13 ;;; (at your option) any later version.
14 ;;;
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software Foundation,
22 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 (in-package #:dep-ui)
25
26 ;;;--------------------------------------------------------------------------
27 ;;; Generic interface.
28
29 (defvar *live-deps*)
30
31 (defun update-text-field-dep (field dep convert-func)
32   (let ((text (field-text field)))
33     (multiple-value-bind (value bogusp) (funcall convert-func text)
34       (cond (bogusp
35              (set-field-highlight field :bad)
36              (dep-make-bad dep))
37             (t
38              (unless (dep-goodp dep)
39                (set-field-highlight field :good))
40              (setf (dep-value dep) value))))))
41
42 (defun make-text-field-with-dep (convert-func dep)
43   (make-text-field
44    :notify (lambda (field)
45              (update-text-field-dep field dep convert-func))))
46
47 (defun update-dep-text-field (field dep convert-func)
48   (multiple-value-bind (highlight value)
49       (if (dep-goodp dep)
50           (values :good (dep-value dep))
51           (values :bad ""))
52     (set-field-highlight field highlight)
53     (setf (field-text field) (funcall convert-func value))))
54
55 (defun make-dependent-text-field
56     (dep &optional (convert-func #'princ-to-string))
57   (let ((field (make-text-field :readonly t)))
58     (flet ((kicked (&optional ev)
59              (declare (ignore ev))
60              (update-dep-text-field field dep convert-func)))
61       (dep-add-listener dep #'kicked)
62       (kicked))
63     field))
64
65 (defun safe-read-from-string (string continuation)
66   (with-input-from-string (stream string)
67     (ignore-errors
68       (let ((value (let ((*read-eval* nil)) (read stream))))
69         (if (peek-char t stream nil)
70             (values nil :junk)
71             (funcall continuation value))))))
72
73 (defun read-real-from-string (string)
74   (safe-read-from-string string
75                          (lambda (value)
76                            (values value (not (realp value))))))
77
78 (defun make-input (label dep &key (convert #'read-real-from-string))
79   (let ((text (make-text-field-with-dep convert dep)))
80     (pack-labelled-widget *panel* label text)))
81
82 (defun make-output (label dep &key (convert "~,3F"))
83   (let ((text (make-dependent-text-field dep
84                                          (etypecase convert
85                                            (string
86                                             (lambda (value)
87                                               (format nil convert value)))
88                                            ((or symbol function)
89                                             convert)))))
90     (pack-labelled-widget *panel* label text)))
91
92 (defun make-radio-dep (dep plist)
93   (let ((group (make-radio-group
94                 (lambda (value) (setf (dep-value dep) value))
95                 plist
96                 :default (if (dep-goodp dep)
97                              (dep-value dep)
98                              (setf (dep-value dep) (cadr plist))))))
99     (pack-single-widget *panel* group)))
100
101
102 (defmacro within-group ((label) &body body)
103   `(let ((*panel* (pack-single-widget *panel* (make-group ,label))))
104      ,@body))
105
106 (let ((reasons 0))
107   (defun add-reason ()
108     (incf reasons))
109   (defun drop-reason ()
110     (assert (plusp reasons))
111     (decf reasons)
112     (when (zerop reasons)
113       (exit))))
114
115 (defmacro defwindow (name bvl (title) &body body)
116   `(defun ,name ,bvl
117      (make-toplevel ,title (lambda () ,@body))))
118
119 ;;;----- That's all, folks --------------------------------------------------