chiark / gitweb /
0a66346dcfff9ce026486d803971e507f2d4773e
[clg] / examples / testgtk.lisp
1 ;; Common Lisp bindings for GTK+ v2.0
2 ;; Copyright (C) 1999-2005 Espen S. Johnsen <espen@users.sf.net>
3 ;;
4 ;; This library is free software; you can redistribute it and/or
5 ;; modify it under the terms of the GNU Lesser General Public
6 ;; License as published by the Free Software Foundation; either
7 ;; version 2 of the License, or (at your option) any later version.
8 ;;
9 ;; This library is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ;; Lesser General Public License for more details.
13 ;;
14 ;; You should have received a copy of the GNU Lesser General Public
15 ;; License along with this library; if not, write to the Free Software
16 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18 ;; $Id: testgtk.lisp,v 1.29 2005/04/21 12:30:23 espen Exp $
19
20 #+sbcl(require :gtk)
21 #+cmucl(asdf:oos 'asdf:load-op :gtk)
22
23 (defpackage "TESTGTK"
24   (:use "COMMON-LISP" "GTK"))
25
26 (in-package "TESTGTK")
27
28 (defmacro define-toplevel (name (window title &rest initargs) &body body)
29   `(let ((,window nil))
30      (defun ,name ()
31        (unless ,window
32          (setq ,window (make-instance 'window :title ,title ,@initargs :show-children t))
33          (signal-connect ,window 'destroy #'(lambda () (setq ,window nil)))
34          ,@body)
35        
36        (when ,window
37          (if (not (widget-visible-p ,window))
38              (widget-show ,window)
39            (widget-hide ,window))))))
40
41
42 (defmacro define-dialog (name (dialog title &optional (class 'dialog)
43                                &rest initargs)
44                          &body body)
45   `(let ((,dialog nil))
46      (defun ,name ()
47        (unless ,dialog
48          (setq ,dialog (make-instance ,class :title ,title ,@initargs :show-children t))
49          (signal-connect ,dialog 'destroy #'(lambda () (setq ,dialog nil)))
50          ,@body)
51        
52        (when ,dialog
53          (if (not (widget-visible-p ,dialog))
54              (widget-show ,dialog)
55            (widget-hide ,dialog))))))
56
57
58 (defmacro define-simple-dialog (name (dialog title &rest initargs) &body body)
59   `(define-dialog ,name (,dialog ,title 'dialog ,@initargs)
60     ,@body
61     (dialog-add-button ,dialog "gtk-close" #'widget-destroy :object t)))
62
63
64
65 ;;; Pixmaps used in some of the tests
66
67 (defvar gtk-mini-xpm
68   #("15 20 17 1"
69     "       c None"
70     ".      c #14121F"
71     "+      c #278828"
72     "@      c #9B3334"
73     "#      c #284C72"
74     "$      c #24692A"
75     "%      c #69282E"
76     "&      c #37C539"
77     "*      c #1D2F4D"
78     "=      c #6D7076"
79     "-      c #7D8482"
80     ";      c #E24A49"
81     ">      c #515357"
82     ",      c #9B9C9B"
83     "'      c #2FA232"
84     ")      c #3CE23D"
85     "!      c #3B6CCB"
86     "               "
87     "      ***>     "
88     "    >.*!!!*    "
89     "   ***....#*=  "
90     "  *!*.!!!**!!# "
91     " .!!#*!#*!!!!# "
92     " @%#!.##.*!!$& "
93     " @;%*!*.#!#')) "
94     " @;;@%!!*$&)'' "
95     " @%.%@%$'&)$+' "
96     " @;...@$'*'*)+ "
97     " @;%..@$+*.')$ "
98     " @;%%;;$+..$)# "
99     " @;%%;@$$$'.$# "
100     " %;@@;;$$+))&* "
101     "  %;;;@+$&)&*  "
102     "   %;;@'))+>   "
103     "    %;@'&#     "
104     "     >%$$      "
105     "      >=       "))
106
107 (defvar book-closed-xpm
108   #("16 16 6 1"
109     "       c None s None"
110     ".      c black"
111     "X      c red"
112     "o      c yellow"
113     "O      c #808080"
114     "#      c white"
115     "                "
116     "       ..       "
117     "     ..XX.      "
118     "   ..XXXXX.     "
119     " ..XXXXXXXX.    "
120     ".ooXXXXXXXXX.   "
121     "..ooXXXXXXXXX.  "
122     ".X.ooXXXXXXXXX. "
123     ".XX.ooXXXXXX..  "
124     " .XX.ooXXX..#O  "
125     "  .XX.oo..##OO. "
126     "   .XX..##OO..  "
127     "    .X.#OO..    "
128     "     ..O..      "
129     "      ..        "
130     "                "))
131
132 (defvar mini-page-xpm
133   #("16 16 4 1"
134     "       c None s None"
135     ".      c black"
136     "X      c white"
137     "o      c #808080"
138     "                "
139     "   .......      "
140     "   .XXXXX..     "
141     "   .XoooX.X.    "
142     "   .XXXXX....   "
143     "   .XooooXoo.o  "
144     "   .XXXXXXXX.o  "
145     "   .XooooooX.o  "
146     "   .XXXXXXXX.o  "
147     "   .XooooooX.o  "
148     "   .XXXXXXXX.o  "
149     "   .XooooooX.o  "
150     "   .XXXXXXXX.o  "
151     "   ..........o  "
152     "    oooooooooo  "
153     "                "))
154
155 (defvar book-open-xpm
156   #("16 16 4 1"
157     "       c None s None"
158     ".      c black"
159     "X      c #808080"
160     "o      c white"
161     "                "
162     "  ..            "
163     " .Xo.    ...    "
164     " .Xoo. ..oo.    "
165     " .Xooo.Xooo...  "
166     " .Xooo.oooo.X.  "
167     " .Xooo.Xooo.X.  "
168     " .Xooo.oooo.X.  "
169     " .Xooo.Xooo.X.  "
170     " .Xooo.oooo.X.  "
171     "  .Xoo.Xoo..X.  "
172     "   .Xo.o..ooX.  "
173     "    .X..XXXXX.  "
174     "    ..X.......  "
175     "     ..         "
176     "                "))
177
178
179
180 ;;; Button box
181
182 (defun create-bbox-in-frame (class frame-label spacing width height layout)
183   (declare (ignore width height))
184   (make-instance 'frame
185    :label frame-label
186    :child (make-instance class
187            :border-width 5 :layout-style layout :spacing spacing
188            :child (make-instance 'button :stock "gtk-ok")
189            :child (make-instance 'button :stock "gtk-cancel")
190            :child (make-instance 'button :stock "gtk-help"))))
191
192 (define-toplevel create-button-box (window "Button Boxes")
193   (make-instance 'v-box
194    :parent window :border-width 10 :spacing 10
195    :child (make-instance 'frame
196            :label "Horizontal Button Boxes"
197            :child (make-instance 'v-box
198                    :border-width 10 :spacing 10
199                    :children (mapcar    
200                               #'(lambda (args)
201                                   (apply #'create-bbox-in-frame 
202                                    'h-button-box args))
203                               '(("Spread" 40 85 20 :spread) 
204                                 ("Edge" 40 85 20 :edge)
205                                 ("Start" 40 85 20 :start) 
206                                 ("End" 40 85 20 :end)))))
207    :child (make-instance 'frame
208            :label "Vertical Button Boxes"
209            :child (make-instance 'h-box
210                    :border-width 10 :spacing 10
211                    :children (mapcar
212                               #'(lambda (args)
213                                   (apply #'create-bbox-in-frame
214                                    'v-button-box args))
215                               '(("Spread" 30 85 20 :spread) 
216                                 ("Edge" 30 85 20 :edge)
217                                 ("Start" 30 85 20 :start) 
218                                 ("End" 30 85 20 :end)))))))
219
220
221 ;; Buttons
222
223 (define-simple-dialog create-buttons (dialog "Buttons")
224   (let ((table (make-instance 'table
225                 :n-rows 3 :n-columns 3 :homogeneous nil
226                 :row-spacing 5 :column-spacing 5 :border-width 10
227                 :parent dialog))
228           (buttons (loop
229                     for n from 1 to 10
230                     collect (make-instance 'button 
231                              :label (format nil "button~D" (1+ n))))))
232
233     (dotimes (column 3)
234       (dotimes (row 3)
235         (let ((button (nth (+ (* 3 row) column) buttons))
236               (button+1 (nth (mod (+ (* 3 row) column 1) 9) buttons)))
237           (signal-connect button 'clicked
238                           #'(lambda ()
239                               (if (widget-visible-p button+1)
240                                   (widget-hide button+1)
241                                 (widget-show button+1))))
242           (table-attach table button column (1+ column) row (1+ row)
243                         :options '(:expand :fill)))))))
244
245
246 ;; Calenadar
247
248 (define-simple-dialog create-calendar (dialog "Calendar")
249   (make-instance 'v-box
250    :parent dialog :border-width 10
251    :child (make-instance 'calendar)))
252
253
254 ;;; Check buttons
255
256 (define-simple-dialog create-check-buttons (dialog "Check Buttons")
257   (make-instance 'v-box
258    :border-width 10 :spacing 10 :parent dialog
259    :children (loop
260               for n from 1 to 3
261               collect (make-instance 'check-button
262                        :label (format nil "Button~D" n)))))
263
264
265
266 ;;; Color selection
267
268 (define-dialog create-color-selection (dialog "Color selection dialog" 
269                                        'color-selection-dialog
270                                        :allow-grow nil :allow-shrink nil
271                                        :show-children nil)
272   (with-slots (colorsel) dialog
273     (let ((button (make-instance 'check-button :label "Show Opacity")))
274       (dialog-add-action-widget dialog button
275        #'(lambda () 
276           (setf 
277            (color-selection-has-opacity-control-p colorsel)
278            (toggle-button-active-p button)))))
279
280     (let ((button (make-instance 'check-button :label "Show Palette")))
281       (dialog-add-action-widget dialog button
282        #'(lambda () 
283           (setf 
284            (color-selection-has-palette-p colorsel)
285            (toggle-button-active-p button)))))
286
287     (signal-connect dialog :ok
288      #'(lambda ()
289          (let ((color (color-selection-current-color colorsel)))
290            (format t "Selected color: ~A~%" color)
291            (setf (color-selection-current-color colorsel) color)
292            (widget-hide dialog))))
293
294     (signal-connect dialog :cancel #'widget-destroy :object t)))
295
296
297 ;;; Cursors
298
299 (defun clamp (n min-val max-val)
300   (declare (number n min-val max-val))
301   (max (min n max-val) min-val))
302
303 (defun set-cursor (spinner drawing-area label)
304   (let ((cursor
305          (glib:int-enum
306           (logand (clamp (spin-button-value-as-int spinner) 0 152) #xFE)
307           'gdk:cursor-type)))
308     (setf (label-label label) (string-downcase cursor))
309     (setf (widget-cursor drawing-area) cursor)))
310
311 (defun cursor-expose (drawing-area event)
312   (declare (ignore event))
313   (multiple-value-bind (width height)
314       (widget-get-size-allocation drawing-area)
315     (let* ((window (widget-window drawing-area))
316            (style (widget-style drawing-area))
317            (white-gc (style-white-gc style))
318            (gray-gc (style-bg-gc style :normal))
319            (black-gc (style-black-gc style)))
320       (gdk:draw-rectangle window white-gc t 0 0 width (floor height 2))
321       (gdk:draw-rectangle window black-gc t 0 (floor height 2) width 
322                           (floor height 2))
323       (gdk:draw-rectangle window gray-gc t (floor width 3) 
324                           (floor height 3) (floor width 3) 
325                           (floor height 3))))
326   t)
327
328 (define-simple-dialog create-cursors (dialog "Cursors")
329   (let ((spinner (make-instance 'spin-button 
330                   :adjustment (adjustment-new 
331                                0 0 
332                                (1- (glib:enum-int :last-cursor 'gdk:cursor-type))
333                                2 10 0)))
334         (drawing-area (make-instance 'drawing-area
335                        :width-request 80 :height-request 80
336                        :events '(:exposure :button-press)))
337         (label (make-instance 'label :label "XXX")))
338
339     (signal-connect drawing-area 'expose-event #'cursor-expose :object t)
340
341     (signal-connect drawing-area 'button-press-event
342      #'(lambda (event)
343          (case (gdk:event-button event)
344            (1 (spin-button-spin spinner :step-forward))
345            (3 (spin-button-spin spinner :step-backward)))
346          t))
347
348     (signal-connect drawing-area 'scroll-event
349      #'(lambda (event)
350          (case (gdk:event-direction event)
351            (:up (spin-button-spin spinner :step-forward))
352            (:down (spin-button-spin spinner :step-backward)))
353          t))
354
355     (signal-connect spinner 'changed
356      #'(lambda ()
357          (set-cursor spinner drawing-area label)))
358
359     (make-instance 'v-box
360      :parent dialog :border-width 10 :spacing 5
361      :child (list
362              (make-instance 'h-box
363               :border-width 5
364               :child (list
365                       (make-instance 'label :label "Cursor Value : ")
366                       :expand nil)
367               :child spinner)
368              :expand nil)
369      :child (make-instance 'frame
370              :label "Cursor Area" :label-xalign 0.5 :border-width 10
371              :child drawing-area)
372      :child (list label :expand nil))
373
374     (widget-realize drawing-area)
375     (set-cursor spinner drawing-area label)))
376
377
378 ;;; Dialog
379
380 (let ((dialog nil))
381   (defun create-dialog ()
382     (unless dialog
383       (setq dialog (make-instance 'dialog 
384                     :title "Dialog" :default-width 200 
385                     :button "Toggle"
386                     :button (list "gtk-ok" #'widget-destroy :object t)
387                     :signal (list 'destroy 
388                              #'(lambda () 
389                                  (setq dialog nil)))))
390
391       (let ((label (make-instance 'label 
392                     :label "Dialog Test" :xpad 10 :ypad 10 :visible t
393                     :parent dialog)))
394         (signal-connect dialog "Toggle"
395          #'(lambda ()
396              (if (widget-visible-p label)
397                  (widget-hide label)
398                (widget-show label))))))
399
400     (if (widget-visible-p dialog)
401         (widget-hide dialog)
402        (widget-show dialog))))
403
404
405 ;; Entry
406
407 (define-simple-dialog create-entry (dialog "Entry")
408   (let ((main (make-instance 'v-box 
409                :border-width 10 :spacing 10 :parent dialog)))
410
411     (let ((entry (make-instance 'entry :text "hello world" :parent main)))
412       (editable-select-region entry 0 5) ; this has no effect when 
413                                          ; entry is editable
414 ;;     (editable-insert-text entry "great " 6)
415 ;;     (editable-delete-text entry 6 12)
416       
417       (let ((combo (make-instance 'combo-box-entry 
418                     :parent main
419                     :content '("item0"
420                                "item1 item1"
421                                "item2 item2 item2"
422                                "item3 item3 item3 item3"
423                                "item4 item4 item4 item4 item4"
424                                "item5 item5 item5 item5 item5 item5"
425                                "item6 item6 item6 item6 item6"
426                                "item7 item7 item7 item7"
427                                "item8 item8 item8"
428                                "item9 item9"))))
429         (with-slots (child) combo 
430           (setf (editable-text child) "hello world")
431           (editable-select-region child 0)))
432
433       (flet ((create-check-button (label slot)
434                (make-instance 'check-button
435                 :label label :active t :parent main
436                 :signal (list 'toggled
437                               #'(lambda (button)
438                                   (setf (slot-value entry slot)
439                                         (toggle-button-active-p button)))
440                               :object t))))
441       
442         (create-check-button "Editable" 'editable)
443         (create-check-button "Visible" 'visibility)
444         (create-check-button "Sensitive" 'sensitive)))))
445
446
447 ;; Expander
448
449 (define-simple-dialog create-expander (dialog "Expander" :resizable nil)
450   (make-instance 'v-box
451    :parent dialog :spacing 5 :border-width 5
452    :child (create-label "Expander demo. Click on the triangle for details.")
453    :child (make-instance 'expander
454            :label "Details"
455            :child (create-label "Details can be shown or hidden."))))
456
457
458 ;; File chooser dialog
459
460 (define-dialog create-file-chooser (dialog "File Chooser" 'file-chooser-dialog)
461   (file-chooser-add-filter dialog 
462    (make-instance 'file-filter :name "All files" :pattern "*"))
463   (file-chooser-add-filter dialog 
464    (make-instance 'file-filter :name "Common Lisp source code" 
465     :patterns '("*.lisp" "*.lsp")))
466
467   (dialog-add-button dialog "gtk-cancel" #'widget-destroy :object t)
468   (dialog-add-button dialog "gtk-ok" 
469    #'(lambda ()
470        (if (slot-boundp dialog 'filename)          
471            (format t "Selected file: ~A~%" (file-chooser-filename dialog))
472          (write-line "No files selected"))
473        (widget-destroy dialog))))
474
475
476 ;; Font selection dialog
477
478 (define-toplevel create-font-selection (window "Font Button" :resizable nil)
479   (make-instance 'h-box 
480    :parent window :spacing 8 :border-width 8
481    :child (make-instance 'label :label "Pick a font")
482    :child (make-instance 'font-button 
483            :use-font t :title "Font Selection Dialog")))
484
485
486 ;;; Icon View
487
488 #+gtk2.6
489 (let ((file-pixbuf nil)
490       (folder-pixbuf nil))
491   (defun load-pixbufs ()
492     (unless file-pixbuf
493       (handler-case 
494           (setf
495            file-pixbuf (gdk:pixbuf-load #p"clg:examples;gnome-fs-regular.png")
496            folder-pixbuf (gdk:pixbuf-load #p"clg:examples;gnome-fs-directory.png"))
497         (glib:glib-error (condition)
498           (make-instance 'message-dialog 
499            :message-type :error :visible t
500            :text "<b>Failed to load an image</b>" 
501            :secondary-text (glib:gerror-message condition)
502            :signal (list :close #'widget-destroy :object t))
503           (return-from load-pixbufs nil))))
504     t)
505
506   (defun fill-store (store directory)
507     (list-store-clear store)
508     (let ((dir #+cmu(unix:open-dir directory)
509                #+sbcl(sb-posix:opendir directory)))
510       (unwind-protect 
511           (loop
512            as filename = #+cmu(unix:read-dir dir)
513                          #+sbcl(let ((dirent (sb-posix:readdir dir)))
514                                  (unless (sb-grovel::foreign-nullp dirent)
515                                    (sb-posix:dirent-name dirent)))
516            while filename
517            unless (or (equal filename ".") (equal filename ".."))
518            do (let* ((pathname (format nil "~A~A" directory filename))
519                      (directory-p
520                       #+cmu(eq (unix:unix-file-kind pathname) :directory)
521                       #+sbcl(sb-posix:s-isdir (sb-posix:stat-mode (sb-posix:stat pathname)))))
522                 (list-store-append store 
523                  (vector
524                   filename 
525                   (if directory-p folder-pixbuf file-pixbuf)
526                   directory-p))))
527         #+cmu(unix:close-dir dir)
528         #+sbcl(sb-posix:closedir dir))))
529
530   (defun sort-func (store a b)
531     (let ((a-dir-p (tree-model-value store a 'directory-p))
532           (b-dir-p (tree-model-value store b 'directory-p))
533           (a-name (tree-model-value store a 'filename))
534           (b-name (tree-model-value store b 'filename)))
535       (cond
536        ((and a-dir-p (not b-dir-p)) :before)
537        ((and (not a-dir-p) b-dir-p) :after)
538        ((string< a-name b-name) :before)
539        ((string> a-name b-name) :after)
540        (t :equal))))
541
542   (defun parent-dir (dir)
543     (let ((end (1+ (position #\/ dir :from-end t :end (1- (length dir))))))
544       (subseq dir 0 end)))
545
546   (define-toplevel create-icon-view (window "Icon View demo"
547                                      :default-width 650 
548                                      :default-height 400)
549     (if (not (load-pixbufs))
550         (widget-destroy window)
551       (let* ((directory "/")
552              (store (make-instance 'list-store 
553                      :column-types '(string gdk:pixbuf boolean)
554                      :column-names '(filename pixbuf directory-p)))
555              (icon-view (make-instance 'icon-view
556                          :model store :selection-mode :multiple
557                          :text-column 'filename :pixbuf-column 'pixbuf))
558              (up (make-instance 'tool-button 
559                   :stock "gtk-go-up" :is-important t :sensitive nil))
560              (home (make-instance 'tool-button 
561                     :stock  "gtk-home" :is-important t)))
562         (tree-sortable-set-sort-func store :default #'sort-func)
563         (tree-sortable-set-sort-column store :default :ascending)
564         (fill-store store directory)
565
566         (signal-connect icon-view 'item-activated
567          #'(lambda (path)
568              (when (tree-model-value store path 'directory-p)
569                (setq directory
570                      (concatenate 'string directory (tree-model-value store path 'filename) "/"))
571                (fill-store store directory)
572                (setf (widget-sensitive-p up) t))))
573
574         (signal-connect up 'clicked
575          #'(lambda ()
576              (unless (string= directory "/")
577                (setq directory (parent-dir directory))
578                (fill-store store directory)
579                (setf 
580                 (widget-sensitive-p home)
581                 (not (string= directory (namestring (truename #p"clg:")))))
582                (setf (widget-sensitive-p up) (not (string= directory "/"))))))
583
584         (signal-connect home 'clicked
585          #'(lambda ()
586              (setq directory (namestring (truename #p"clg:")))
587              (fill-store store directory)
588              (setf (widget-sensitive-p up) t)
589              (setf (widget-sensitive-p home) nil)))
590       
591         (make-instance 'v-box 
592          :parent window
593          :child (list
594                  (make-instance 'toolbar :child up :child home)          
595                  :fill nil :expand nil)
596          :child (make-instance 'scrolled-window
597                  :shadow-type :etched-in :policy :automatic
598                  :child icon-view))))))
599
600
601 ;;; Image
602
603 (define-toplevel create-image (window "Image" :resizable nil)
604   (make-instance 'image :file #p"clg:examples;gtk.png" :parent window))
605
606
607 ;;; Labels
608       
609 (define-toplevel create-labels (window "Labels" :border-width 5 :resizable nil)
610   (flet ((create-label-in-frame (frame-label label-text &rest args)
611            (list 
612             (make-instance 'frame
613              :label frame-label
614              :child (apply #'make-instance 'label :label label-text :xpad 5 :ypad 5 args))
615             :fill nil :expand nil)))
616     (make-instance 'h-box
617      :spacing 5 :parent window
618      :child-args '(:fill nil :expand nil)
619      :child (make-instance 'v-box
620              :spacing 5
621              :child (create-label-in-frame "Normal Label" "This is a Normal label")
622              :child (create-label-in-frame "Multi-line Label"
623 "This is a Multi-line label.
624 Second line
625 Third line")
626              :child (create-label-in-frame "Left Justified Label"
627 "This is a Left-Justified
628 Multi-line.
629 Third line"
630                       :justify :left)
631              :child (create-label-in-frame "Right Justified Label"
632 "This is a Right-Justified
633 Multi-line.
634 Third line"
635                      :justify :right))
636      :child (make-instance 'v-box
637              :spacing 5
638              :child (create-label-in-frame "Line wrapped label"
639 "This is an example of a line-wrapped label.  It should not be taking up the entire             width allocated to it, but automatically wraps the words to fit.  The time has come, for all good men, to come to the aid of their party.  The sixth sheik's six sheep's sick.
640      It supports multiple paragraphs correctly, and  correctly   adds many          extra  spaces. "
641                       :wrap t)
642
643              :child (create-label-in-frame "Filled, wrapped label"
644 "This is an example of a line-wrapped, filled label.  It should be taking up the entire              width allocated to it.  Here is a seneance to prove my point.  Here is another sentence. Here comes the sun, do de do de do.
645     This is a new paragraph.
646     This is another newer, longer, better paragraph.  It is coming to an end, unfortunately."
647                       :justify :fill :wrap t)
648
649              :child (create-label-in-frame "Underlined label"
650 (#+cmu glib:latin1-to-unicode #+sbcl identity
651 "This label is underlined!
652 This one is underlined (æøåÆØÅ) in quite a funky fashion")
653                       :justify :left
654                       :pattern  "_________________________ _ _________ _ _____ _ __ __  ___ ____ _____")))))
655
656
657 ;;; Layout
658
659 (defun layout-expose (layout event)
660   (when (eq (gdk:event-window event) (layout-bin-window layout))
661     (with-slots (gdk:x gdk:y gdk:width gdk:height) event
662       (let ((imin (truncate gdk:x 10))
663             (imax (truncate (+ gdk:x gdk:width 9) 10))
664             (jmin (truncate gdk:y 10))
665             (jmax (truncate (+ gdk:y gdk:height 9) 10)))
666
667         (let ((window (layout-bin-window layout))
668               (gc (style-black-gc (widget-style layout))))
669           (loop
670            for i from imin below imax
671            do (loop 
672                for j from jmin below jmax
673                unless (zerop (mod (+ i j) 2))
674                do (gdk:draw-rectangle
675                    window gc t (* 10 i) (* 10 j) 
676                    (1+ (mod i 10)) (1+ (mod j 10)))))))))
677   nil)
678
679 (define-toplevel create-layout (window "Layout" :default-width 200
680                                                 :default-height 200)
681   (let ((layout (make-instance 'layout
682                  :parent (make-instance 'scrolled-window :parent window)
683                  :width 1600 :height 128000 :events '(:exposure)
684                  :signal (list 'expose-event #'layout-expose :object t))))
685
686     (with-slots (hadjustment vadjustment) layout
687       (setf
688        (adjustment-step-increment hadjustment) 10.0
689        (adjustment-step-increment vadjustment) 10.0))
690
691     (dotimes (i 16)
692       (dotimes (j 16)
693         (let ((text (format nil "Button ~D, ~D" i j)))
694           (layout-put layout
695            (make-instance (if (not (zerop (mod (+ i j) 2)))
696                               'button
697                             'label)
698                           :label text :visible t)
699            (* j 100) (* i 100)))))
700
701     (loop
702      for i from 16 below 1280
703      do (let ((text (format nil "Button ~D, ~D" i 0)))
704           (layout-put layout
705            (make-instance (if (not (zerop (mod i 2)))
706                               'button
707                             'label)
708                           :label text :visible t)
709            0 (* i 100))))))
710
711
712
713 ;;; List    
714     
715 (define-simple-dialog create-list (dialog "List" :default-height 400)
716   (let* ((store (make-instance 'list-store 
717                  :column-types '(string integer boolean)
718                  :column-names '(:foo :bar :baz)
719                  :initial-content '(#("First" 12321 nil)
720                                     (:foo "Yeah" :baz t))))
721          (tree (make-instance 'tree-view :model store)))
722
723     (loop
724      with iter = (make-instance 'tree-iter)
725      for i from 1 to 1000
726      do (list-store-append store (vector "Test" i (zerop (mod i 3))) iter))
727     
728     (let ((column (make-instance 'tree-view-column :title "Column 1"))
729           (cell (make-instance 'cell-renderer-text)))
730       (cell-layout-pack column cell :expand t)
731       (cell-layout-add-attribute column cell 'text (column-index store :foo))
732       (tree-view-append-column tree column))
733     
734     (let ((column (make-instance 'tree-view-column :title "Column 2"))
735           (cell (make-instance 'cell-renderer-text :background "orange")))
736       (cell-layout-pack column cell :expand t)
737       (cell-layout-add-attribute column cell 'text (column-index store :bar))
738       (tree-view-append-column tree column))      
739     
740     (let ((column (make-instance 'tree-view-column :title "Column 3"))
741           (cell (make-instance 'cell-renderer-text)))
742       (cell-layout-pack column cell :expand t)
743       (cell-layout-add-attribute column cell 'text (column-index store :baz))
744       (tree-view-append-column tree column))      
745
746     (make-instance 'v-box
747      :parent dialog :border-width 10 :spacing 10
748      :child (list
749              (make-instance 'h-box
750               :spacing 10
751               :child (make-instance 'button
752                       :label "Remove Selection"
753                       :signal (list 'clicked
754                                #'(lambda ()
755                                    (let ((references
756                                           (mapcar
757                                            #'(lambda (path)
758                                                (make-instance 'tree-row-reference :model store :path path))                                       
759                                            (tree-selection-get-selected-rows
760                                             (tree-view-selection tree)))))
761                                      (mapc
762                                       #'(lambda (reference)
763                                           (list-store-remove store reference))
764                                       references))))))
765              :expand nil)
766      :child (list
767              (make-instance 'h-box
768               :spacing 10
769               :child (make-instance 'check-button 
770                       :label "Show Headers" :active t
771                       :signal (list 'toggled
772                                #'(lambda (button)
773                                    (setf
774                                     (tree-view-headers-visible-p tree)
775                                     (toggle-button-active-p button)))
776                                :object t))
777               :child (make-instance 'check-button 
778                       :label "Reorderable" :active nil
779                       :signal (list 'toggled
780                                #'(lambda (button)
781                                    (setf
782                                     (tree-view-reorderable-p tree)
783                                     (toggle-button-active-p button)))
784                                :object t))
785               :child (list 
786                       (make-instance 'h-box
787                        :child (make-instance 'label :label "Selection Mode: ")
788                        :child (make-instance 'combo-box
789                                :content '("Single" "Browse" "Multiple") 
790                                :active 0
791                                :signal (list 'changed
792                                         #'(lambda (combo-box)
793                                             (setf 
794                                              (tree-selection-mode 
795                                               (tree-view-selection tree))
796                                              (svref 
797                                               #(:single :browse :multiple)
798                                               (combo-box-active combo-box))))
799                                         :object t)))
800                       :expand nil))
801              :expand nil)
802      :child (make-instance 'scrolled-window 
803             :child tree :hscrollbar-policy :automatic))))
804
805
806 ;; Menus
807
808 (defun create-menu (depth tearoff)
809   (unless (zerop depth)
810     (let ((menu (make-instance 'menu)))
811       (when tearoff
812         (let ((menu-item (make-instance 'tearoff-menu-item)))
813           (menu-shell-append menu menu-item)))
814       (let ((group nil))
815         (dotimes (i 5)
816           (let ((menu-item
817                  (make-instance 'radio-menu-item
818                   :label (format nil "item ~2D - ~D" depth (1+ i)))))
819             (if group
820                 (add-to-radio-group menu-item group)
821               (setq group menu-item))
822             (unless (zerop (mod depth 2))
823               (setf (check-menu-item-active-p menu-item) t))
824             (menu-shell-append menu menu-item)
825             (when (= i 3)
826               (setf (widget-sensitive-p menu-item) nil))
827             (let ((submenu (create-menu (1- depth) t)))
828               (when submenu
829                 (setf (menu-item-submenu menu-item) submenu))))))
830       menu)))
831
832
833 (define-simple-dialog create-menus (dialog "Menus" :default-width 200)
834   (let* ((main (make-instance 'v-box :parent dialog))
835 ;        (accel-group (make-instance 'accel-group))
836          (menubar (make-instance 'menu-bar :parent (list main :expand nil))))
837 ;    (window-add-accel-group dialog accel-group)
838
839     (let ((menu-item (make-instance 'menu-item 
840                       :label (format nil "test~%line2"))))
841       (setf (menu-item-submenu menu-item) (create-menu 2 t))
842       (menu-shell-append menubar menu-item))
843
844     (let ((menu-item (make-instance 'menu-item :label "foo")))
845       (setf (menu-item-submenu menu-item) (create-menu 3 t))
846       (menu-shell-append menubar menu-item))
847
848     (let ((menu-item (make-instance 'menu-item :label "bar")))
849       (setf (menu-item-submenu menu-item) (create-menu 4 t))
850       (setf (menu-item-right-justified-p menu-item) t)
851       (menu-shell-append menubar menu-item))
852
853     (make-instance 'v-box 
854      :spacing 10 :border-width 10 :parent main
855      :child (make-instance 'combo-box 
856              :active 3
857              :content (loop
858                        for i from 1 to 5
859                        collect (format nil "Item ~D" i))))
860       
861     (widget-show-all main)))
862
863
864 ;;; Notebook
865
866 (defun create-notebook-page (notebook page-num book-closed)
867   (let* ((title (format nil "Page ~D" page-num))
868          (page (make-instance 'frame :label title :border-width 10))
869          (v-box (make-instance 'v-box 
870                  :homogeneous t :border-width 10 :parent page)))
871      
872     (make-instance 'h-box 
873      :parent (list v-box :fill nil :padding 5) :homogeneous t
874      :child-args '(:padding 5)
875      :child (make-instance 'check-button 
876              :label "Fill Tab" :active t
877              :signal (list 'toggled
878                            #'(lambda (button)
879                                (setf 
880                                 (notebook-child-tab-fill-p page)
881                                 (toggle-button-active-p button)))
882                            :object t))
883      :child (make-instance 'check-button
884              :label "Expand Tab"
885              :signal (list 'toggled
886                            #'(lambda (button)
887                                (setf 
888                                 (notebook-child-tab-expand-p page)
889                                 (toggle-button-active-p button)))
890                            :object t))
891      :child (make-instance 'check-button
892              :label "Pack end"
893              :signal (list 'toggled
894                            #'(lambda (button)
895                                (setf 
896                                 (notebook-child-tab-pack page)
897                                 (if (toggle-button-active-p button)
898                                     :end
899                                   :start)))
900                            :object t))
901      :child (make-instance 'button
902              :label "Hide page"
903              :signal (list 'clicked #'(lambda () (widget-hide page)))))
904
905     (let ((label-box (make-instance 'h-box 
906                       :show-children t
907                       :child-args '(:expand nil)
908                       :child (make-instance 'image :pixbuf book-closed)
909                       :child (make-instance 'label :label title)))
910           (menu-box (make-instance 'h-box 
911                      :show-children t
912                      :child-args '(:expand nil)
913                      :child (make-instance 'image :pixbuf book-closed)
914                      :child (make-instance 'label :label title))))
915
916       (widget-show-all page)
917       (notebook-append notebook page label-box menu-box))))
918         
919
920 (define-simple-dialog create-notebook (dialog "Notebook")
921   (let ((main (make-instance 'v-box :parent dialog)))
922     (let ((book-open (gdk:pixbuf-new-from-xpm-data book-open-xpm))
923           (book-closed (gdk:pixbuf-new-from-xpm-data book-closed-xpm))
924           (notebook (make-instance 'notebook 
925                      :border-width 10 :tab-pos :top :parent main)))
926       (flet ((set-image (page func pixbuf)
927                (setf
928                 (image-pixbuf 
929                  (first (container-children (funcall func notebook page))))
930                 pixbuf)))
931         (signal-connect notebook 'switch-page
932          #'(lambda (pointer page)
933              (declare (ignore pointer))
934              (set-image page #'notebook-menu-label book-open)
935              (set-image page #'notebook-tab-label book-open)
936              (when (slot-boundp notebook 'current-page)
937                (let ((curpage (notebook-current-page notebook)))
938                  (set-image curpage #'notebook-menu-label book-closed)
939                  (set-image curpage #'notebook-tab-label book-closed))))))
940       (loop for i from 1 to 5 do (create-notebook-page notebook i book-closed))
941
942       (make-instance 'h-separator :parent (list main :expand nil :padding 10))
943         
944       (make-instance 'h-box 
945        :spacing 5 :border-width 10
946        :parent (list main :expand nil)
947        :child-args '(:fill nil)
948        :child (make-instance 'check-button 
949                :label "Popup menu"
950                :signal (list 'clicked
951                         #'(lambda (button)
952                             (if (toggle-button-active-p button)
953                                 (notebook-popup-enable notebook)
954                                 (notebook-popup-disable notebook)))
955                         :object t))
956        :child (make-instance 'check-button 
957                :label "Homogeneous tabs"
958                :signal (list 'clicked
959                         #'(lambda (button)
960                             (setf
961                              (notebook-homogeneous-p notebook)
962                              (toggle-button-active-p button)))
963                         :object t)))
964
965       (make-instance 'h-box 
966        :spacing 5 :border-width 10
967        :parent (list main :expand nil)
968        :child-args '(:expand nil)
969        :child (make-instance 'label :label "Notebook Style: ")
970        :child (let ((scrollable-p nil)) 
971                 (make-instance 'combo-box
972                  :content '("Standard" "No tabs" "Scrollable") :active 0
973                  :signal (list 'changed
974                           #'(lambda (combo-box)
975                               (case (combo-box-active combo-box)
976                                 (0 
977                                  (setf (notebook-show-tabs-p notebook) t)
978                                  (when scrollable-p
979                                    (setq scrollable-p nil)
980                                    (setf (notebook-scrollable-p notebook) nil)
981                                    (loop repeat 10 
982                                     do (notebook-remove-page notebook 5))))
983                                 (1
984                                  (setf (notebook-show-tabs-p notebook) nil)
985                                  (when scrollable-p
986                                    (setq scrollable-p nil)
987                                    (setf (notebook-scrollable-p notebook) nil)
988                                    (loop repeat 10 
989                                      do (notebook-remove-page notebook 5))))
990                                 (2
991                                  (unless scrollable-p
992                                    (setq scrollable-p t)
993                                    (setf (notebook-show-tabs-p notebook) t)
994                                    (setf (notebook-scrollable-p notebook) t)
995                                    (loop for i from 6 to 15 
996                                     do (create-notebook-page notebook i book-closed))))))
997                           :object t)))
998        :child (make-instance 'button
999                :label "Show all Pages"
1000                :signal (list 'clicked
1001                         #'(lambda ()
1002                             (map-container nil #'widget-show notebook)))))
1003
1004       (make-instance 'h-box 
1005        :spacing 5 :border-width 10
1006        :parent (list main :expand nil)
1007        :child (make-instance 'button 
1008                :label "prev"
1009                :signal (list 'clicked #'notebook-prev-page :object notebook))
1010        :child (make-instance 'button 
1011                :label "next"
1012                :signal (list 'clicked #'notebook-next-page :object notebook))
1013        :child (make-instance 'button 
1014                :label "rotate"
1015                :signal (let ((tab-pos 0))
1016                          (list 'clicked 
1017                           #'(lambda ()
1018                               (setq tab-pos (mod (1+ tab-pos) 4))
1019                               (setf
1020                                (notebook-tab-pos notebook)
1021                                (svref #(:top :right :bottom :left) tab-pos))))))))
1022     (widget-show-all main)))
1023
1024
1025 ;;; Panes
1026
1027 (defun toggle-resize (child)
1028   (setf (paned-child-resize-p child) (not (paned-child-resize-p child))))
1029
1030 (defun toggle-shrink (child)
1031   (setf (paned-child-shrink-p child) (not (paned-child-shrink-p child))))
1032
1033 (defun create-pane-options (paned frame-label label1 label2)
1034   (let* ((table (make-instance 'table :n-rows 3 :n-columns 2 :homogeneous t)))
1035     (table-attach table (create-label label1) 0 1 0 1 :options '(:expand :fill))
1036     (let ((check-button (make-instance 'check-button :label "Resize")))
1037       (table-attach table check-button 0 1 1 2 :options '(:expand :fill))
1038       (signal-connect check-button 'toggled 
1039        #'toggle-resize :object (paned-child1 paned)))
1040     (let ((check-button (make-instance 'check-button :label "Shrink" :active t)))
1041       (table-attach table check-button 0 1 2 3 :options '(:expand :fill))
1042       (signal-connect check-button 'toggled 
1043        #'toggle-shrink :object (paned-child1 paned)))
1044
1045     (table-attach table (create-label label2) 1 2 0 1 :options '(:expand :fill))
1046     (let ((check-button (make-instance 'check-button :label "Resize" :active t)))
1047       (table-attach table check-button 1 2 1 2 :options '(:expand :fill))
1048       (signal-connect check-button 'toggled 
1049        #'toggle-resize :object (paned-child2 paned)))
1050     (let ((check-button (make-instance 'check-button :label "Shrink" :active t)))
1051       (table-attach table check-button 1 2 2 3 :options '(:expand :fill))
1052       (signal-connect check-button 'toggled
1053        #'toggle-shrink :object (paned-child2 paned)))
1054     (make-instance 'frame :label frame-label :border-width 4 :child table)))
1055
1056 (define-toplevel create-panes (window "Panes")
1057   (let* ((hpaned (make-instance 'h-paned
1058                   :child1 (make-instance 'frame
1059                            :width-request 60 :height-request 60
1060                            :shadow-type :in 
1061                            :child (make-instance 'button :label "Hi there"))
1062                   :child2 (make-instance 'frame                     
1063                            :width-request 80 :height-request 60
1064                            :shadow-type :in)))
1065          (vpaned (make-instance 'v-paned
1066                   :border-width 5
1067                   :child1 hpaned
1068                   :child2 (make-instance 'frame
1069                            :width-request 80 :height-request 60
1070                            :shadow-type :in))))
1071     
1072     (make-instance 'v-box
1073      :parent window
1074      :child-args '(:expand nil)
1075      :child (list vpaned :expand t)
1076      :child (create-pane-options hpaned "Horizontal" "Left" "Right")
1077      :child (create-pane-options vpaned "Vertical" "Top" "Bottom"))))
1078   
1079
1080 ;;; Progress bar
1081
1082 (define-simple-dialog create-progress-bar (dialog "Progress Bar")
1083   (let* ((progress (make-instance 'progress-bar :pulse-step 0.05))
1084          (activity-mode-button (make-instance 'check-button 
1085                                 :label "Activity mode"))
1086          (timer (timeout-add 100
1087                  #'(lambda ()
1088                      (if (toggle-button-active-p activity-mode-button)
1089                          (progress-bar-pulse progress)
1090                        (let ((fract (+ (progress-bar-fraction progress) 0.01)))
1091                          (setf                
1092                           (progress-bar-fraction progress)
1093                           (if (> fract 1.0)
1094                               0.0
1095                             fract))))
1096                      t))))
1097
1098     (make-instance 'v-box
1099      :parent dialog :border-width 10 :spacing 10
1100      :child progress
1101      :child activity-mode-button)
1102
1103     (signal-connect dialog 'destroy 
1104      #'(lambda () (when timer (timeout-remove timer))))))
1105
1106
1107 ;;; Radio buttons
1108
1109 (define-simple-dialog create-radio-buttons (dialog "Radio buttons")
1110   (make-instance 'v-box
1111    :parent dialog :border-width 10 :spacing 10
1112    :children (make-radio-group 'radio-button
1113               '((:label "button1") (:label "button2") (:label "button3"))
1114               nil)))
1115
1116
1117 ;;; Rangle controls
1118
1119 (define-simple-dialog create-range-controls (dialog "Range controls")
1120   (let ((adjustment (adjustment-new 0.0 0.0 101.0 0.1 1.0 1.0)))
1121     (make-instance 'v-box
1122      :parent dialog :border-width 10 :spacing 10
1123      :child (make-instance 'h-scale
1124              :width-request 150 :adjustment adjustment :inverted t
1125              :update-policy :delayed :digits 1 :draw-value t)
1126      :child (make-instance 'h-scrollbar
1127              :adjustment adjustment :update-policy :continuous))))
1128
1129
1130 ;;; Reparent test
1131
1132 (define-simple-dialog create-reparent (dialog "Reparent")
1133   (let ((main (make-instance 'h-box 
1134                :homogeneous t :spacing 10 :border-width 10 :parent dialog))
1135         (label (make-instance 'label :label "Hello World")))
1136
1137     (flet ((create-frame (title)
1138              (let* ((frame (make-instance 'frame :label title :parent main))
1139                     (box (make-instance 'v-box 
1140                           :spacing 5 :border-width 5 :parent frame))
1141                     (button (make-instance 'button 
1142                              :label "switch" :parent (list box :expand nil))))
1143                (signal-connect button 'clicked
1144                 #'(lambda ()
1145                     (widget-reparent label box)))
1146                box)))
1147
1148       (box-pack-start (create-frame "Frame 1") label nil t 0)
1149       (create-frame "Frame 2"))
1150     (widget-show-all main)))
1151
1152
1153 ;;; Rulers
1154
1155 (define-toplevel create-rulers (window "Rulers" 
1156                                 :default-width 300 :default-height 300
1157                                 :events '(:pointer-motion :pointer-motion-hint))
1158   (let ((table (make-instance 'table :n-rows 2 :n-columns 2 :parent window))
1159         (h-ruler (make-instance 'h-ruler
1160                   :metric :centimeters :lower 100.0d0 :upper 0.0d0
1161                   :position 0.0d0 :max-size 20.0d0))
1162         (v-ruler (make-instance 'v-ruler
1163                   :lower 5.0d0 :upper 15.0d0 
1164                   :position 0.0d0 :max-size 20.0d0)))
1165     (signal-connect window 'motion-notify-event
1166      #'(lambda (event)
1167          (widget-event h-ruler event)
1168          (widget-event v-ruler event)))
1169     (table-attach table h-ruler 1 2 0 1 :options :fill :x-options :expand)
1170     (table-attach table v-ruler 0 1 1 2 :options :fill :y-options :expand)))
1171
1172
1173 ;;; Scrolled window
1174
1175 (define-simple-dialog create-scrolled-windows (dialog "Scrolled windows"
1176                                                       :default-width 300
1177                                                       :default-height 300)
1178   (let* ((scrolled-window
1179           (make-instance 'scrolled-window
1180            :parent dialog :border-width 10
1181            :vscrollbar-policy :automatic 
1182            :hscrollbar-policy :automatic))
1183          (table
1184           (make-instance 'table
1185            :n-rows 20 :n-columns 20 :row-spacing 10 :column-spacing 10
1186            :focus-vadjustment (scrolled-window-vadjustment scrolled-window)
1187            :focus-hadjustment (scrolled-window-hadjustment scrolled-window))))
1188
1189       (scrolled-window-add-with-viewport scrolled-window table)
1190       (dotimes (i 20)
1191         (dotimes (j 20)
1192           (let ((button
1193                  (make-instance 'toggle-button
1194                   :label (format nil "button (~D,~D)~%" i j))))
1195             (table-attach table button i (1+ i) j (1+ j)))))
1196       (widget-show-all scrolled-window)))
1197
1198
1199 ;;; Size group
1200
1201 (define-simple-dialog create-size-group (dialog "Size Group" :resizable nil)
1202   (let ((size-group (make-instance 'size-group)))
1203     (flet ((create-frame (label rows)
1204              (let ((table (make-instance 'table 
1205                            :n-rows (length rows) :n-columns 2 :homogeneous nil
1206                            :row-spacing 5 :column-spacing 10 :border-width 5)))
1207                (loop
1208                 for row in rows
1209                 for i from 0
1210                 do (table-attach table 
1211                     (create-label (first row) :xalign 0 :yalign 1)
1212                     0 1 i (1+ i) :x-options '(:expand :fill))
1213                    (let ((combo (make-instance 'combo-box 
1214                                  :content (rest row) :active 0)))
1215                      (size-group-add-widget size-group combo)
1216                      (table-attach table combo 1 2 i (1+ i))))
1217                (make-instance 'frame :label label :child table))))
1218
1219       (make-instance 'v-box
1220        :parent dialog :border-width 5 :spacing 5
1221        :child (create-frame "Color Options"
1222                '(("Foreground" "Red" "Green" "Blue")
1223                  ("Background" "Red" "Green" "Blue")))
1224        :child (create-frame "Line Options"
1225                '(("Dashing" "Solid" "Dashed" "Dotted")
1226                  ("Line ends" "Square" "Round" "Arrow")))
1227        :child (create-check-button "Enable grouping"
1228                #'(lambda (active)
1229                    (setf 
1230                     (size-group-mode size-group) 
1231                     (if active :horizontal :none)))
1232                t)))))
1233
1234
1235 ;;; Shapes
1236
1237 (defun create-shape-icon (xpm-file x y px py type root-window destroy)
1238   (let ((window
1239          (make-instance 'window
1240           :type type :default-width 100 :default-height 100
1241           :events '(:button-motion :pointer-motion-hint :button-press)
1242           :signal (list 'destroy destroy))))
1243       
1244     (widget-realize window)
1245     (multiple-value-bind (source mask) (gdk:pixmap-create xpm-file)
1246       (let ((fixed (make-instance 'fixed :parent window)))
1247         (fixed-put fixed (create-image-widget source mask) px py))
1248       (widget-shape-combine-mask window mask px py))
1249         
1250     (let ((x-offset 0)
1251           (y-offset 0))
1252       (declare (fixnum x-offset y-offset))
1253       (signal-connect window 'button-press-event
1254        #'(lambda (event)
1255            (when (typep event 'gdk:button-press-event)
1256              (setq x-offset (truncate (gdk:event-x event)))
1257              (setq y-offset (truncate (gdk:event-y event)))
1258              (grab-add window)
1259              (gdk:pointer-grab (widget-window window) 
1260               :events '(:button-release :button-motion :pointer-motion-hint)
1261               :owner-events t))))
1262
1263       (signal-connect window 'button-release-event
1264        #'(lambda (event)
1265            (declare (ignore event))
1266            (grab-remove window)
1267            (gdk:pointer-ungrab)))
1268         
1269       (signal-connect window 'motion-notify-event
1270        #'(lambda (event)
1271            (declare (ignore event))
1272            (multiple-value-bind (win xp yp mask) 
1273                (gdk:window-get-pointer root-window)
1274              (declare (ignore mask win) (fixnum xp yp))
1275              (window-move window (- xp x-offset) (- yp y-offset))))))
1276     
1277     (window-move window x y)
1278     (widget-show-all window)
1279     window))
1280
1281
1282 (let ((modeller nil)
1283       (sheets nil)
1284       (rings nil))
1285   (defun create-shapes ()
1286     (let ((root-window (gdk:get-root-window)))
1287       (if (not modeller)
1288           (setq
1289            modeller
1290            (create-shape-icon
1291             "clg:examples;Modeller.xpm" 440 140 0 0 :popup root-window
1292             #'(lambda () (setq modeller nil))))
1293         (widget-destroy modeller))
1294
1295       (if (not sheets)
1296           (setq
1297            sheets
1298            (create-shape-icon
1299             "clg:examples;FilesQueue.xpm" 580 170 0 0 :popup root-window
1300             #'(lambda () (setq sheets nil))))
1301         (widget-destroy sheets))
1302
1303       (if (not rings)
1304           (setq
1305            rings
1306            (create-shape-icon
1307             "clg:examples;3DRings.xpm" 460 270 25 25 :toplevel root-window
1308             #'(lambda () (setq rings nil))))
1309         (widget-destroy rings)))))
1310
1311
1312
1313 ;;; Spin buttons
1314
1315 (define-simple-dialog create-spins (dialog "Spin buttons" :has-separator nil)
1316   (let ((main (make-instance 'v-box 
1317                :spacing 5 :border-width 10 :parent dialog)))
1318
1319     (flet ((create-date-spinner (label adjustment shadow-type)
1320              (declare (ignore shadow-type))
1321              (make-instance 'v-box 
1322               :child-args '(:expand nil)
1323               :child (make-instance 'label
1324                       :label label :xalign 0.0 :yalign 0.5)
1325               :child (make-instance 'spin-button
1326                       :adjustment adjustment :wrap t))))
1327       (multiple-value-bind (sec min hour date month year day daylight-p zone)
1328           (get-decoded-time)
1329         (declare (ignore sec min hour day daylight-p zone))
1330         (make-instance 'frame 
1331          :label "Not accelerated" :parent main
1332          :child (make-instance 'h-box 
1333                  :border-width 10
1334                  :child-args '(:padding 5)
1335                  :child (create-date-spinner "Day : " 
1336                          (adjustment-new date 1 31 1 5 0) :out)
1337                  :child (create-date-spinner "Month : " 
1338                          (adjustment-new month 1 12 1 5 0) :etched-in)
1339                  :child (create-date-spinner "Year : " 
1340                          (adjustment-new year 0 2100 1 100 0) :in)))))
1341
1342     (let ((spinner1 (make-instance 'spin-button
1343                      :adjustment (adjustment-new 0.0 -10000.0 10000.0 0.5 100.0 0.0)
1344                       :climb-rate 1.0 :digits 2 :wrap t :width-request 100))
1345           (spinner2 (make-instance 'spin-button 
1346                      :adjustment (adjustment-new 2.0 1.0 5.0 1.0 1.0 0.0)
1347                      :climb-rate 1.0 :wrap t))
1348           (value-label (make-instance 'label :label "0")))
1349       (signal-connect (spin-button-adjustment spinner2) 'value-changed
1350        #'(lambda ()
1351            (setf 
1352             (spin-button-digits spinner1) 
1353             (floor (spin-button-value spinner2)))))
1354
1355       (make-instance 'frame 
1356        :label "Accelerated" :parent main
1357        :child (make-instance 'v-box 
1358                :border-width 5
1359                :child (list
1360                        (make-instance 'h-box 
1361                         :child-args '(:padding 5)
1362                         :child (make-instance 'v-box
1363                                 :child (make-instance 'label
1364                                         :label "Value :" 
1365                                         :xalign 0.0 :yalign 0.5)
1366                                 :child spinner1)
1367                         :child (make-instance 'v-box
1368                                 :child (make-instance 'label 
1369                                         :label "Digits :" 
1370                                         :xalign 0.0 :yalign 0.5)
1371                                 :child spinner2))
1372                        :expand nil :padding 5)
1373                :child (make-instance 'check-button 
1374                        :label "Snap to 0.5-ticks" :active t
1375                        :signal (list 'clicked
1376                                 #'(lambda (button)
1377                                     (setf
1378                                      (spin-button-snap-to-ticks-p spinner1)
1379                                      (toggle-button-active-p button)))
1380                                 :object t))
1381                :child (make-instance 'check-button
1382                        :label "Numeric only input mode" :active t
1383                        :signal (list 'clicked
1384                                 #'(lambda (button)
1385                                     (setf
1386                                      (spin-button-numeric-p spinner1)
1387                                      (toggle-button-active-p button)))
1388                                 :object t))
1389                :child value-label
1390                :child (list
1391                        (make-instance 'h-box
1392                         :child-args '(:padding 5)
1393                         :child (make-instance 'button 
1394                                 :label "Value as Int"
1395                                 :signal (list 'clicked
1396                                          #'(lambda ()
1397                                              (setf
1398                                               (label-label value-label)
1399                                               (format nil "~D" 
1400                                                (spin-button-value-as-int 
1401                                                 spinner1))))))
1402                         :child (make-instance 'button 
1403                                 :label "Value as Float"
1404                                 :signal (list 'clicked
1405                                          #'(lambda ()
1406                                              (setf
1407                                               (label-label value-label)
1408                                               (format nil
1409                                                (format nil "~~,~DF" 
1410                                                 (spin-button-digits spinner1))
1411                                                (spin-button-value spinner1)))))))
1412                        :padding 5 :expand nil))))
1413     (widget-show-all main)))
1414
1415
1416 ;;; Statusbar
1417
1418 (define-toplevel create-statusbar (window "Statusbar")
1419   (let ((statusbar (make-instance 'statusbar :has-resize-grip t))
1420         (close-button (create-button '("close" :can-default t)
1421                        #'widget-destroy :object window))
1422         (counter 0))
1423
1424     (signal-connect statusbar 'text-popped
1425      #'(lambda (context-id text)
1426          (declare (ignore context-id))
1427          (format nil "Popped: ~A~%" text)))
1428    
1429     (make-instance 'v-box
1430      :parent window
1431      :child (make-instance 'v-box
1432              :border-width 10 :spacing 10
1433              :child (create-button "push something"
1434                      #'(lambda ()
1435                          (statusbar-push statusbar 1
1436                           (format nil "something ~D" (incf counter)))))
1437              :child (create-button "pop" 
1438                      #'(lambda ()
1439                          (statusbar-pop statusbar 1)))
1440              :child (create-button "steal #4" 
1441                      #'(lambda ()
1442                          (statusbar-remove statusbar 1 4)))
1443              :child (create-button "dump stack")
1444              :child (create-button "test contexts"))
1445      :child (list (make-instance 'h-separator) :expand nil)
1446      :child (list 
1447              (make-instance 'v-box :border-width 10 :child close-button)
1448              :expand nil)
1449      :child (list statusbar :expand nil))
1450
1451     (widget-grab-focus close-button)))
1452
1453
1454 ;;; Idle test
1455
1456 (define-simple-dialog create-idle-test (dialog "Idle Test")
1457   (let ((label (make-instance 'label
1458                 :label "count: 0" :xpad 10 :ypad 10))
1459         (idle nil)
1460         (count 0))
1461     (signal-connect dialog 'destroy 
1462      #'(lambda () (when idle (idle-remove idle))))
1463  
1464     (make-instance 'v-box
1465      :parent dialog :border-width 10 :spacing 10
1466      :child label
1467      :child (make-instance 'frame
1468              :label "Label Container" :border-width 5
1469              :child(make-instance 'v-box
1470                    :children (make-radio-group 'radio-button
1471                               '((:label "Resize-Parent" :value :parent :active t)
1472                                 (:label "Resize-Queue" :value :queue)
1473                                 (:label "Resize-Immediate" :value :immediate))
1474                               #'(lambda (mode)
1475                                   (setf 
1476                                    (container-resize-mode (dialog-action-area dialog)) mode))))))
1477
1478     (dialog-add-button dialog "Start"
1479      #'(lambda ()
1480          (unless idle
1481            (setq idle
1482             (idle-add
1483              #'(lambda ()
1484                  (incf count)
1485                  (setf (label-label label) (format nil "count: ~D" count))
1486                  t))))))
1487       
1488     (dialog-add-button dialog "Stop"
1489      #'(lambda ()
1490          (when idle
1491            (idle-remove idle)
1492            (setq idle nil))))))
1493     
1494
1495
1496 ;;; Timeout test
1497
1498 (define-simple-dialog create-timeout-test (dialog "Timeout Test")
1499   (let ((label (make-instance 'label
1500                 :label "count: 0" :xpad 10 :ypad 10 :parent dialog :visible t))
1501         (timer nil)
1502         (count 0))
1503     (signal-connect dialog 'destroy 
1504      #'(lambda () (when timer (timeout-remove timer))))
1505
1506     (dialog-add-button dialog "Start"
1507      #'(lambda ()
1508          (unless timer
1509            (setq timer
1510             (timeout-add 100
1511              #'(lambda ()
1512                  (incf count)
1513                  (setf (label-label label) (format nil "count: ~D" count))
1514                  t))))))
1515
1516     (dialog-add-button dialog "Stop"
1517      #'(lambda ()
1518          (when timer
1519            (timeout-remove timer)
1520            (setq timer nil))))))
1521
1522
1523 ;;; Text
1524
1525 (define-simple-dialog create-text (dialog "Text" :default-width 400
1526                                                  :default-height 400)
1527   (let* ((text-view (make-instance 'text-view 
1528                      :border-width 10 :visible t :wrap-mode :word))
1529          (buffer (text-view-buffer text-view))
1530          (active-tags ()))
1531
1532     (text-buffer-create-tag buffer "Bold" :weight :bold)
1533     (text-buffer-create-tag buffer "Italic" :style :italic)
1534     (text-buffer-create-tag buffer "Underline" :underline :single)
1535     
1536     (flet ((create-toggle-callback (tag-name)
1537              (let ((tag (text-tag-table-lookup 
1538                          (text-buffer-tag-table buffer) tag-name)))
1539                #'(lambda (active)
1540                    (unless (eq (and (find tag active-tags) t) active)
1541                      ;; user activated
1542                      (if active 
1543                          (push tag active-tags)
1544                        (setq active-tags (delete tag active-tags)))
1545                      (multiple-value-bind (non-zero-p start end)
1546                          (text-buffer-get-selection-bounds buffer)
1547                        (declare (ignore non-zero-p))
1548                        (if active 
1549                            (text-buffer-apply-tag buffer tag start end)
1550                          (text-buffer-remove-tag buffer tag start end))))))))
1551
1552       (let* ((actions 
1553               (make-instance 'action-group 
1554                :action (make-instance 'toggle-action 
1555                         :name "Bold" :stock-id "gtk-bold" :label "Bold" 
1556                         :accelerator "<control>B" :tooltip "Bold"
1557                         :callback (create-toggle-callback "Bold"))
1558                :action (make-instance 'toggle-action 
1559                         :name "Italic" :stock-id "gtk-italic" :label "Italic" 
1560                         :accelerator "<control>I" :tooltip "Italic"
1561                         :callback (create-toggle-callback "Italic"))
1562                :action (make-instance 'toggle-action 
1563                         :name "Underline" :stock-id "gtk-underline" 
1564                         :label "Underline" :accelerator "<control>U" 
1565                         :tooltip "Underline"
1566                         :callback (create-toggle-callback "Underline"))))
1567              (ui (make-instance 'ui-manager
1568                   :action-group actions
1569                   :ui '((:toolbar "ToolBar"
1570                          (:toolitem "Bold")
1571                          (:toolitem "Italic")
1572                          (:toolitem "Underline"))))))
1573
1574         ;; Callback to activate/deactivate toolbar buttons when cursor
1575         ;; is moved
1576         (signal-connect buffer 'mark-set
1577          #'(lambda (location mark)
1578              (declare (ignore mark))
1579              (text-tag-table-foreach (text-buffer-tag-table buffer)
1580               #'(lambda (tag)
1581                   (let ((active
1582                          (or 
1583                           (and
1584                            (text-iter-has-tag-p location tag)
1585                            (not (text-iter-begins-tag-p location tag)))
1586                           (text-iter-ends-tag-p location tag))))
1587                     (unless (eq active (and (find tag active-tags) t))
1588                       (if active 
1589                           (push tag active-tags)
1590                         (setq active-tags (delete tag active-tags)))
1591                       (setf 
1592                        (toggle-action-active-p
1593                         (action-group-get-action actions (text-tag-name tag)))
1594                        active)))))))
1595
1596         ;; Callback to apply active tags when a character is inserted
1597         (signal-connect buffer 'insert-text
1598          #'(lambda (iter &rest args)
1599              (declare (ignore args))
1600              (let ((before (text-buffer-get-iter-at-offset buffer 
1601                             (1- (text-iter-offset iter)))))
1602                (loop
1603                 for tag in active-tags
1604                 do (text-buffer-apply-tag buffer tag before iter))))
1605          :after t)
1606         
1607         (container-add dialog (ui-manager-get-widget ui "/ToolBar") :expand nil)
1608         (container-add dialog text-view)))))
1609
1610
1611 ;;; Toggle buttons
1612
1613 (define-simple-dialog create-toggle-buttons (dialog "Toggle Button")
1614   (make-instance 'v-box
1615    :border-width 10 :spacing 10 :parent dialog
1616       :children (loop
1617               for n from 1 to 3
1618               collect (make-instance 'toggle-button
1619                        :label (format nil "Button~D" (1+ n))))))
1620
1621
1622
1623 ;;; Toolbar test
1624
1625 (defun create-toolbar (window)
1626   (make-instance 'toolbar 
1627    :show-tooltips t :show-arrow nil
1628
1629    ;; Insert a stock item
1630    :child (make-instance 'tool-button 
1631            :stock  "gtk-quit"
1632            :tip-text "Destroy toolbar"
1633            :tip-private "Toolbar/Quit"
1634            :signal (list 'clicked #'(lambda () (widget-destroy window))))
1635
1636    :child (make-instance 'separator-tool-item)
1637
1638    :child (make-instance 'tool-button
1639            :label "Horizontal" :stock "gtk-go-forward"
1640            :tip-text "Horizontal toolbar layout"
1641            :tip-private "Toolbar/Horizontal"
1642            :signal (list 'clicked 
1643                     #'(lambda (toolbar) 
1644                         (setf (toolbar-orientation toolbar) :horizontal))
1645                     :object :parent))
1646
1647    :child (make-instance 'tool-button
1648            :label "Vertical" :stock "gtk-go-down"
1649            :tip-text "Vertical toolbar layout"
1650            :tip-private "Toolbar/Vertical"
1651            :signal (list 'clicked 
1652                     #'(lambda (toolbar) 
1653                         (setf (toolbar-orientation toolbar) :vertical))
1654                     :object :parent))
1655
1656    :child (make-instance 'separator-tool-item)
1657
1658    :children (make-radio-group 'radio-tool-button
1659               '((:label "Icons" :stock "gtk-justify-left"
1660                  :tip-text "Only show toolbar icons"
1661                  :tip-private "Toolbar/IconsOnly"
1662                  :value :icons)
1663                 (:label "Both" :stock "gtk-justify-center"
1664                  :tip-text "Show toolbar icons and text"
1665                  :tip-private "Toolbar/Both"
1666                  :value :both :active t)
1667                 (:label "Text" :stock "gtk-justify-right"
1668                  :tip-text "Show toolbar text"
1669                  :tip-private "Toolbar/TextOnly"
1670                  :value :text))
1671               (list
1672                #'(lambda (toolbar style) 
1673                    (setf (toolbar-style toolbar) style))
1674                :object :parent))
1675
1676    :child (make-instance 'separator-tool-item)
1677
1678    :child (make-instance 'tool-item
1679            :child (make-instance 'entry)
1680            :tip-text "This is an unusable GtkEntry"
1681            :tip-private "Hey don't click me!")
1682
1683    :child (make-instance 'separator-tool-item)
1684
1685    :child (make-instance 'tool-button
1686            :label "Enable" :stock "gtk-add"
1687            :tip-text "Enable tooltips"
1688            :tip-private "Toolbar/EnableTooltips"
1689            :signal (list 'clicked 
1690                     #'(lambda (toolbar) 
1691                         (setf (toolbar-show-tooltips-p toolbar) t))
1692                     :object :parent))
1693
1694    :child (make-instance 'tool-button
1695            :label "Disable" :stock "gtk-remove"
1696            :tip-text "Disable tooltips"
1697            :tip-private "Toolbar/DisableTooltips"
1698            :signal (list 'clicked 
1699                     #'(lambda (toolbar) 
1700                         (setf (toolbar-show-tooltips-p toolbar) nil))
1701                     :object :parent))
1702
1703 ;;    :child (make-instance 'separator-tool-item)
1704
1705 ;;    :child (make-instance 'tool-button
1706 ;;         :label "GTK" :icon #p"clg:examples;gtk.png"
1707 ;;         :tip-text "GTK+ Logo"
1708 ;;         :tip-private "Toolbar/GTK+")
1709    ))
1710
1711 (define-toplevel create-toolbar-window (window "Toolbar test" :resizable nil)
1712   (container-add window (create-toolbar window)))
1713
1714
1715 ;;; Handle box
1716
1717 (define-toplevel create-handle-box (window "Handle Box Test" :border-width 20)
1718   (make-instance 'v-box 
1719    :parent window
1720    :child (create-label "Above")
1721    :child (make-instance 'h-separator)
1722    :child (make-instance 'h-box 
1723            :spacing 10
1724            :child (list
1725                    (make-instance 'handle-box
1726                     :child (create-toolbar window)
1727                     :signal (list 'child-attached
1728                              #'(lambda (child)
1729                                  (format t "~A attached~%" child)))
1730                     :signal (list 'child-detached
1731                              #'(lambda (child)
1732                                  (format t "~A detached~%" child))))
1733                    :expand nil :fill :nil))
1734    :child (make-instance 'h-separator)
1735    :child (create-label "Below")))
1736
1737
1738 ;;; Tooltips test
1739
1740 (define-simple-dialog create-tooltips (dialog "Tooltips" :default-width 200)
1741   (let ((tooltips (make-instance 'tooltips)))
1742     (flet ((create-button (label tip-text tip-private)
1743              (let ((button (make-instance 'toggle-button :label label)))
1744                (tooltips-set-tip tooltips button tip-text tip-private)
1745                button)))
1746       (make-instance 'v-box
1747        :parent dialog :border-width 10 :spacing 10
1748        :child (create-button "button1" "This is button 1" "ContextHelp/button/1")
1749        :child (create-button "button2" "This is button 2. This is also has a really long tooltip which probably won't fit on a single line and will therefore need to be wrapped. Hopefully the wrapping will work correctly." "ContextHelp/button/2")))))
1750
1751
1752 ;;; UI Manager
1753
1754 (defvar *ui-description*
1755   '((:menubar "MenuBar"
1756      (:menu "FileMenu"
1757       (:menuitem "New")
1758       (:menuitem "Open")
1759       (:menuitem "Save")
1760       (:menuitem "SaveAs")
1761       :separator
1762       (:menuitem "Quit"))
1763      (:menu "PreferencesMenu"
1764        (:menu "ColorMenu"
1765         (:menuitem "Red")
1766         (:menuitem "Green")
1767         (:menuitem "Blue"))
1768        (:menu "ShapeMenu"
1769         (:menuitem "Square")
1770         (:menuitem "Rectangle")
1771         (:menuitem "Oval"))
1772        (:menuitem "Bold"))
1773      (:menu "HelpMenu"
1774       (:menuitem "About")))
1775     (:toolbar "ToolBar"
1776      (:toolitem "Open")
1777      (:toolitem "Quit")
1778      :separator
1779      (:toolitem "Logo"))))
1780
1781 (define-toplevel create-ui-manager (window "UI Manager")
1782   (let ((ui (make-instance 'ui-manager)))
1783     (window-add-accel-group window (ui-manager-accel-group ui))
1784     (ui-manager-insert-action-group ui
1785      (make-instance 'action-group :name "Actions"
1786       :action (make-instance 'action :name "FileMenu" :label "_File")
1787       :action (make-instance 'action :name "PreferencesMenu" :label "_Preferences")
1788       :action (make-instance 'action :name "ColorMenu" :label "_Color")
1789       :action (make-instance 'action :name "ShapeMenu" :label "_Shape")
1790       :action (make-instance 'action :name "HelpMenu" :label "_Help")
1791       :action (make-instance 'action 
1792                :name "New" :stock-id "gtk-new" :label "_New" 
1793                :accelerator "<control>N" :tooltip "Create a new file")
1794       :action (make-instance 'action 
1795                :name "Open" :stock-id "gtk-open" :label "_Open" 
1796                :accelerator "<control>O" :tooltip "Open a file" 
1797                :callback #'create-file-chooser)
1798       :action (make-instance 'action 
1799                :name "Save" :stock-id "gtk-save" :label "_Save" 
1800                :accelerator "<control>S" :tooltip "Save current file")
1801       :action (make-instance 'action 
1802                :name "SaveAs" :stock-id "gtk-save" :label "Save _As..." 
1803                :tooltip "Save to a file")
1804       :action (make-instance 'action 
1805                :name "Quit" :stock-id "gtk-quit" :label "_Quit" 
1806                :accelerator "<control>Q" :tooltip "Quit" 
1807                :callback (list #'widget-destroy :object window))
1808       :action (make-instance 'action 
1809                :name "About" :label "_About" 
1810                :accelerator "<control>A" :tooltip "About")
1811       :action (make-instance 'action 
1812                :name "Logo" :stock-id "demo-gtk-logo" :tooltip "GTK+")
1813       :action (make-instance 'toggle-action 
1814                :name "Bold" :stock-id "gtk-bold" :label "_Bold" 
1815                :accelerator "<control>B" :tooltip "Bold" :active t)
1816       :actions (make-radio-group 'radio-action
1817                 '((:name "Red" :value :red :label "_Red" 
1818                    :accelerator "<control>R" :tooltip "Blood")
1819                   (:name "Green" :value :green :label "_Green" 
1820                    :accelerator "<control>G" :tooltip "Grass" :active t)
1821                   (:name "Blue" :value :blue :label "_Blue" 
1822                    :accelerator "<control>B" :tooltip "Sky"))
1823                 #'(lambda (active) (print active)))
1824       :actions (make-radio-group 'radio-action
1825                 '((:name "Square" :value :square :label "_Square" 
1826                    :accelerator "<control>S" :tooltip "Square")
1827                   (:name "Rectangle" :value :rectangle :label "_Rectangle" 
1828                    :accelerator "<control>R" :tooltip "Rectangle")
1829                   (:name "Oval" :value :oval :label "_Oval" 
1830                    :accelerator "<control>O" :tooltip "Egg"))
1831                 #'(lambda (active) (print active)))))    
1832
1833     (ui-manager-add-ui ui *ui-description*)
1834
1835     (make-instance 'v-box 
1836      :parent window
1837      :child (list 
1838              (ui-manager-get-widget ui "/MenuBar")
1839              :expand nil :fill nil)
1840      :child (list 
1841              (ui-manager-get-widget ui "/ToolBar")
1842              :expand nil :fill nil)
1843      :child (make-instance 'label
1844              :label "Type <alt> to start" 
1845              :xalign 0.5 :yalign 0.5
1846              :width-request 200 :height-request 200))))
1847                   
1848
1849
1850 ;;; Main window
1851       
1852 (defun create-main-window ()
1853 ;;   (rc-parse "clg:examples;testgtkrc2")
1854 ;;   (rc-parse "clg:examples;testgtkrc")
1855
1856   (let* ((button-specs
1857           '(("button box" create-button-box)
1858             ("buttons" create-buttons)
1859             ("calendar" create-calendar)
1860             ("check buttons" create-check-buttons)
1861             ("color selection" create-color-selection)
1862             ("cursors" create-cursors)
1863             ("dialog" create-dialog)
1864 ;; ;        ("dnd")
1865             ("entry" create-entry)
1866 ;;          ("event watcher")
1867             ("enxpander" create-expander)
1868             ("file chooser" create-file-chooser)
1869             ("font selection" create-font-selection)
1870             ("handle box" create-handle-box)
1871 #+gtk2.6    ("icon view" create-icon-view)
1872             ("image" create-image)
1873             ("labels" create-labels)
1874             ("layout" create-layout)
1875             ("list" create-list)
1876             ("menus" create-menus)
1877 ;;          ("modal window")
1878             ("notebook" create-notebook)
1879             ("panes" create-panes)
1880             ("progress bar" create-progress-bar)
1881             ("radio buttons" create-radio-buttons)
1882             ("range controls" create-range-controls)
1883 ;;          ("rc file")
1884             ("reparent" create-reparent)
1885             ("rulers" create-rulers)
1886 ;;          ("saved position")
1887             ("scrolled windows" create-scrolled-windows)
1888             ("size group" create-size-group)
1889             ("shapes" create-shapes)
1890             ("spinbutton" create-spins)
1891             ("statusbar" create-statusbar)
1892             ("test idle" create-idle-test)
1893 ;;          ("test mainloop")
1894 ;;          ("test scrolling")
1895 ;;          ("test selection")
1896             ("test timeout" create-timeout-test)
1897             ("text" create-text)
1898             ("toggle buttons" create-toggle-buttons)
1899             ("toolbar" create-toolbar-window)
1900             ("tooltips" create-tooltips)
1901 ;;          ("tree" #|create-tree|#)
1902             ("UI manager" create-ui-manager)
1903 ))
1904         (main-window (make-instance 'window
1905                       :title "testgtk.lisp" :name "main_window"
1906                       :default-width 200 :default-height 400
1907                       :allow-grow t :allow-shrink nil))
1908         (scrolled-window (make-instance 'scrolled-window
1909                           :hscrollbar-policy :automatic 
1910                           :vscrollbar-policy :automatic
1911                           :border-width 10))
1912         (close-button (make-instance 'button 
1913                        :label "close" :can-default t
1914                        :signal (list 'clicked #'widget-destroy 
1915                                      :object main-window)))) 
1916
1917     (let ((icon (gdk:pixbuf-load #p"clg:examples;gtk.png")))
1918       (setf 
1919        (window-icon main-window) 
1920        (gdk:pixbuf-add-alpha icon t 254 254 252)))
1921
1922     ;; Main box
1923     (make-instance 'v-box
1924      :parent main-window
1925      :child-args '(:expand nil)
1926      :child (list (make-instance 'label :label (gtk-version)) :fill nil)
1927      :child (list (make-instance 'label :label "clg CVS version") :fill nil)
1928      :child (list (make-instance 'label                           
1929                    :label #-cmu(format nil "~A (~A)" 
1930                                 (lisp-implementation-type)
1931                                 (lisp-implementation-version))
1932                           ;; The version string in CMUCL is far too long
1933                           #+cmu(lisp-implementation-type))
1934                   :fill nil)
1935      :child (list scrolled-window :expand t)
1936      :child (make-instance 'h-separator)
1937      :child (make-instance 'v-box 
1938              :homogeneous nil :spacing 10 :border-width 10 
1939              :child close-button))
1940
1941     (let ((content-box 
1942            (make-instance 'v-box
1943             :focus-vadjustment (scrolled-window-vadjustment scrolled-window)
1944             :children (mapcar #'(lambda (spec) 
1945                                   (apply #'create-button spec))
1946                               button-specs))))
1947       (scrolled-window-add-with-viewport scrolled-window content-box))
1948     
1949     (widget-grab-focus close-button)
1950     (widget-show-all main-window)
1951     main-window))
1952  
1953 (clg-init)
1954 (create-main-window)