;;;; ;;;; {\bf Utilities} ;;;; (define make-tk-name (lambda (parent) (gensym (format #f "~A.v" (if (eq? parent *root*) "" (Id parent)))))) (define split-options (lambda (valid-slots initargs) (letrec ((separate (lambda (valids args tk-opt other) (if (null? args) (cons tk-opt other) (if (member (car args) valids) (separate valids (cddr args) (list* (car args) (cadr args) tk-opt) other) (separate valids (cddr args) tk-opt (list* (car args) (cadr args) other))))))) (separate valid-slots initargs '() '())))) ;;;; ;;;; {\bf Simple widgets} ;;;; ;; ;; class definition and associated methods ;; (define-class () ((valid-options :accessor Tk-valid-options))) (define-method initialize ((class ) initargs) (next-method) ;; Build a list of allowed keywords. These keywords will be passed to ;; the Tk-command at build time (let ((slots (slot-ref class 'slots)) (res '()) (tk-virtual? (lambda(s) (eqv? (get-slot-allocation s) :tk-virtual)))) (for-each (lambda (s) (when (tk-virtual? s) (let ((key (make-keyword (car s)))) (set! res (cons key res))))) slots) ;; Store this list in the new allocated class (set! (Tk-valid-options class) res))) (define-method compute-get-n-set ((class ) slot) (if (eqv? (get-slot-allocation slot) :tk-virtual) ;; this is a Tk-virtual slot (let ((opt (make-keyword (car slot)))) (list (lambda (o) (list-ref ((Id o) 'configure opt) 4)) (lambda (o v) ((Id o) 'configure opt v)))) ;; call super compute-get-n-set (next-method))) ;; ;; Basic virtual classes for widgets: , and ;; ;; (define-class () ((Id :accessor Id) ;; Widget Id (parent :accessor parent :init-keyword :parent))) ;; Parent widget (define-class () ()) (define-class () ;; Each widget has at least the slot bg for its background colour ((bg :accessor bg :init-keyword :bg :allocation :tk-virtual)) :metaclass ) (define-method initialize ((self ) initargs) ;; Use split-options on initargs to separate STklos slots ;; from Tk ones. Set parent to the root window if not specified ;; in initargs (let* ((options (split-options (Tk-valid-options (class-of self)) initargs)) (parent (get-keyword :parent (cdr options) *root*))) ;; Call the Tk command which creates the widget (set! (Id self) (apply (tk-constructor self) (make-tk-name parent) (car options))) ;; Initialize other slots (i.e. non Tk-virtual ones) (next-method self (cdr options)))) ;; ;; We can now define three widget classes: