guile-gtk-general
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Tidier widget trees


From: Neil Jerram
Subject: Tidier widget trees
Date: Sun, 26 Nov 2006 23:07:43 +0000
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

Programming in guile-gnome is of course generally great fun, but there
is one aspect of it that I have found quite frustrating - namely, the
untidiness of the code that tends to emerge when creating a
non-trivial widget tree.

I think a large cause of this untidiness is the need for a temporary
variable whenever one is dealing with a container class.  For example,
a <gtk-vbox> typically requires

- one statement to create it

     (define vbox1 (make <gtk-vbox>))

- one statement to add or pack it into its container

     (add container vbox1)

- N statements to add or pack each of its own children

     (pack-start vbox1 ...)
     (pack-start vbox1 ...)
     
But then after that, vbox1 is probably never used again.

To address (or conceal) this, I've now written a macro that allows me
to create a widget tree like this ...

(let ((ok-button #f))
  (add window
       (create-widget <gtk-vbox>
                      (pack-start #:expand #t
                                  #:fill #t
                                  <gtk-scrolled-window>
                                  (add <gtk-text-view>))
                      (pack-start <gtk-label> #:label "Hello there!")
                      (pack-start <gtk-hbox>
                                  #:spacing 10
                                  (pack-end <gtk-button> #:label "Quit"
                                            (connect 'clicked
                                                     (lambda _ 
(gtk-main-quit))))
                                  (pack-end <gtk-button> #:label "Cancel")
                                  (pack-end <gtk-button> #:label "OK"
                                            (name ok-button)))))
  (connect ok-button
           'clicked
           (lambda _ (display "OK!\n"))))

... which I find a lot neater.  (My definition of create-widget is
appended below, in case anyone would like to use it.)

The point of this email is that I was wondering if other guile-gnome
users had similar thoughts, and/or if others have already built up a
similar macro / pseudo-language for specifying a widget tree.

Regards,
     Neil


(define (split-leading-keys spec)
  (let loop ((keys '())
             (spec spec))
    (if (or (null? spec)
            (not (keyword? (car spec))))
        (list (reverse keys) spec)
        (loop (cons* (cadr spec) (car spec) keys)
              (cddr spec)))))

(define-macro (create-widget class . rest)
  (apply (lambda (keys children)
           `(let ((w (make ,class ,@keys)))
              ,@(map (lambda (child-spec)
                       (case (car child-spec)
                         ((add)
                          (apply (lambda (keys rest)
                                   `(add/keys w (create-widget ,@rest) ,@keys))
                                 (split-leading-keys (cdr child-spec))))
                         ((pack-start)
                          (apply (lambda (keys rest)
                                   `(pack-start/keys w (create-widget ,@rest) 
,@keys))
                                 (split-leading-keys (cdr child-spec))))
                         ((pack-end)
                          (apply (lambda (keys rest)
                                   `(pack-end/keys w (create-widget ,@rest) 
,@keys))
                                 (split-leading-keys (cdr child-spec))))
                         ((name)
                          `(set! ,(cadr child-spec) w))
                         ((connect)
                          `(connect w ,@(cdr child-spec)))))
                     children)
              w))
         (split-leading-keys rest)))

(define (get-key-val keys key default)
  (cond ((memq key keys) => cadr)
        (else default)))

(define (add/keys w child . keys)
  (add w child))

(define (pack-start/keys w child . keys)
  (pack-start w
              child
              (get-key-val keys #:expand #f)
              (get-key-val keys #:fill #f)
              (get-key-val keys #:padding 0)))

(define (pack-end/keys w child . keys)
  (pack-end w
            child
            (get-key-val keys #:expand #f)
            (get-key-val keys #:fill #f)
            (get-key-val keys #:padding 0)))





reply via email to

[Prev in Thread] Current Thread [Next in Thread]