chiark / gitweb /
Register integer as alias for foreign type int.
[clg] / examples / testgtk.lisp
index 6ea078906edc70737396f203ad04fb0b54620d24..b688c166ecf11d73bb03f9925c3f9a5053b7d6f0 100644 (file)
 ;; License along with this library; if not, write to the Free Software
 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-;; $Id: testgtk.lisp,v 1.21 2005-02-27 13:28:19 espen Exp $
+;; $Id: testgtk.lisp,v 1.25 2005-03-13 18:16:08 espen Exp $
 
+(defpackage "TESTGTK"
+  (:use "COMMON-LISP" "GTK"))
 
-;(use-package "GTK")
-(in-package "GTK")
+(in-package "TESTGTK")
 
 (defmacro define-toplevel (name (window title &rest initargs) &body body)
   `(let ((,window nil))
@@ -29,9 +30,10 @@      (defun ,name ()
         (signal-connect ,window 'destroy #'(lambda () (setq ,window nil)))
         ,@body)
        
-       (if (not (widget-visible-p ,window))
-          (widget-show ,window)
-        (widget-hide ,window)))))
+       (when ,window
+        (if (not (widget-visible-p ,window))
+            (widget-show ,window)
+          (widget-hide ,window))))))
 
 
 (defmacro define-dialog (name (dialog title &optional (class 'dialog)
@@ -44,9 +46,10 @@      (defun ,name ()
         (signal-connect ,dialog 'destroy #'(lambda () (setq ,dialog nil)))
         ,@body)
        
-       (if (not (widget-visible-p ,dialog))
-          (widget-show ,dialog)
-        (widget-hide ,dialog)))))
+       (when ,dialog
+        (if (not (widget-visible-p ,dialog))
+            (widget-show ,dialog)
+          (widget-hide ,dialog))))))
 
 
 (defmacro define-simple-dialog (name (dialog title &rest initargs) &body body)
@@ -452,6 +455,12 @@ (define-simple-dialog create-expander (dialog "Expander" :resizable nil)
 ;; File chooser dialog
 
 (define-dialog create-file-chooser (dialog "File Chooser" 'file-chooser-dialog)
+  (file-chooser-add-filter dialog 
+   (make-instance 'file-filter :name "All files" :pattern "*"))
+  (file-chooser-add-filter dialog 
+   (make-instance 'file-filter :name "Common Lisp source code" 
+    :patterns '("*.lisp" "*.lsp")))
+
   (dialog-add-button dialog "gtk-cancel" #'widget-destroy :object t)
   (dialog-add-button dialog "gtk-ok" 
    #'(lambda ()
@@ -493,9 +502,125 @@ (define-toplevel create-handle-box (window "Handle Box Test" :border-width 20)
    :child (make-instance 'h-separator)
    :child (create-label "Below")))
 
+
+;;; Icon View
+
+#+gtk2.6
+(let ((file-pixbuf nil)
+      (folder-pixbuf nil))
+  (defun load-pixbufs ()
+    (unless file-pixbuf
+      (handler-case 
+          (setf
+          file-pixbuf (gdk:pixbuf-load #p"clg:examples;gnome-fs-regular.png")
+          folder-pixbuf (gdk:pixbuf-load #p"clg:examples;gnome-fs-directory.png"))
+       (glib:glib-error (condition)
+         (make-instance 'message-dialog 
+          :message-type :error :visible t
+          :text "<b>Failed to load an image</b>" 
+          :secondary-text (glib:gerror-message condition)
+          :signal (list :close #'widget-destroy :object t))
+         (return-from load-pixbufs nil))))
+    t)
+
+  (defun fill-store (store directory)
+    (list-store-clear store)
+    (let ((dir #+cmu(unix:open-dir directory)
+              #+sbcl(sb-posix:opendir directory)))
+      (unwind-protect 
+         (loop
+          as filename = #+cmu(unix:read-dir dir)
+                        #+sbcl(let ((dirent (sb-posix:readdir dir)))
+                                (unless (sb-grovel::foreign-nullp dirent)
+                                  (sb-posix:dirent-name dirent)))
+          while filename
+          unless (or (equal filename ".") (equal filename ".."))
+          do (let* ((pathname (format nil "~A~A" directory filename))
+                    (directory-p
+                     #+cmu(eq (unix:unix-file-kind pathname) :directory)
+                     #+sbcl(sb-posix:s-isdir (sb-posix:stat-mode (sb-posix:stat pathname)))))
+               (list-store-append store 
+                (vector
+                 filename 
+                 (if directory-p folder-pixbuf file-pixbuf)
+                 directory-p))))
+       #+cmu(unix:close-dir dir)
+       #+sbcl(sb-posix:closedir dir))))
+
+  (defun sort-func (store a b)
+    (let ((a-dir-p (tree-model-value store a 'directory-p))
+         (b-dir-p (tree-model-value store b 'directory-p))
+         (a-name (tree-model-value store a 'filename))
+         (b-name (tree-model-value store b 'filename)))
+      (cond
+       ((and a-dir-p (not b-dir-p)) :before)
+       ((and (not a-dir-p) b-dir-p) :after)
+       ((string< a-name b-name) :before)
+       ((string> a-name b-name) :after)
+       (t :equal))))
+
+  (defun parent-dir (dir)
+    (let ((end (1+ (position #\/ dir :from-end t :end (1- (length dir))))))
+      (subseq dir 0 end)))
+
+  (define-toplevel create-icon-view (window "Icon View demo"
+                                    :default-width 650 
+                                    :default-height 400)
+    (if (not (load-pixbufs))
+       (widget-destroy window)
+      (let* ((directory "/")
+            (store (make-instance 'list-store 
+                    :column-types '(string gdk:pixbuf boolean)
+                    :column-names '(filename pixbuf directory-p)))
+            (icon-view (make-instance 'icon-view
+                        :model store :selection-mode :multiple
+                        :text-column 'filename :pixbuf-column 'pixbuf))
+            (up (make-instance 'tool-button 
+                 :stock "gtk-go-up" :is-important t :sensitive nil))
+            (home (make-instance 'tool-button 
+                   :stock  "gtk-home" :is-important t)))
+       (tree-sortable-set-sort-func store :default #'sort-func)
+       (tree-sortable-set-sort-column store :default :ascending)
+       (fill-store store directory)
+
+       (signal-connect icon-view 'item-activated
+         #'(lambda (path)
+            (when (tree-model-value store path 'directory-p)
+              (setq directory
+                    (concatenate 'string directory (tree-model-value store path 'filename) "/"))
+              (fill-store store directory)
+              (setf (widget-sensitive-p up) t))))
+
+       (signal-connect up 'clicked
+        #'(lambda ()
+            (unless (string= directory "/")
+              (setq directory (parent-dir directory))
+              (fill-store store directory)
+              (setf 
+               (widget-sensitive-p home)
+               (not (string= directory (namestring (truename #p"clg:")))))
+              (setf (widget-sensitive-p up) (not (string= directory "/"))))))
+
+       (signal-connect home 'clicked
+         #'(lambda ()
+            (setq directory (namestring (truename #p"clg:")))
+            (fill-store store directory)
+            (setf (widget-sensitive-p up) t)
+            (setf (widget-sensitive-p home) nil)))
+      
+       (make-instance 'v-box 
+         :parent window
+        :child (list
+                (make-instance 'toolbar :child up :child home)          
+                :fill nil :expand nil)
+        :child (make-instance 'scrolled-window
+                :shadow-type :etched-in :policy :automatic
+                :child icon-view))))))
+
+
 ;;; Image
 
-(define-toplevel create-image (window "Image")
+(define-toplevel create-image (window "Image" :resizable nil)
   (make-instance 'image :file #p"clg:examples;gtk.png" :parent window))
 
 
@@ -1217,17 +1342,20 @@ (define-simple-dialog create-spins (dialog "Spin buttons" :has-separator nil)
                      :label label :xalign 0.0 :yalign 0.5)
              :child (make-instance 'spin-button
                      :adjustment adjustment :wrap t))))
-      (make-instance 'frame 
-       :label "Not accelerated" :parent main
-       :child (make-instance 'h-box 
-              :border-width 10
-              :child-args '(:padding 5)
-              :child (create-date-spinner "Day : " 
-                      (adjustment-new 1.0 1.0 31.0 1.0 5.0 0.0) :out)
-              :child (create-date-spinner "Month : " 
-                      (adjustment-new 1.0 1.0 12.0 1.0 5.0 0.0) :etched-in)
-              :child (create-date-spinner "Year : " 
-                      (adjustment-new 1998.0 0.0 2100.0 1.0 100.0 0.0) :in))))
+      (multiple-value-bind (sec min hour date month year day daylight-p zone)
+         (get-decoded-time)
+       (declare (ignore sec min hour day daylight-p zone))
+       (make-instance 'frame 
+        :label "Not accelerated" :parent main
+        :child (make-instance 'h-box 
+                :border-width 10
+                :child-args '(:padding 5)
+                :child (create-date-spinner "Day : " 
+                        (adjustment-new date 1 31 1 5 0) :out)
+                :child (create-date-spinner "Month : " 
+                        (adjustment-new month 1 12 1 5 0) :etched-in)
+                :child (create-date-spinner "Year : " 
+                        (adjustment-new year 0 2100 1 100 0) :in)))))
 
     (let ((spinner1 (make-instance 'spin-button
                     :adjustment (adjustment-new 0.0 -10000.0 10000.0 0.5 100.0 0.0)
@@ -1713,6 +1841,7 @@ (defun create-main-window ()
            ("file chooser" create-file-chooser)
            ("font selection" create-font-selection)
            ("handle box" create-handle-box)
+#+gtk2.6    ("icon view" create-icon-view)
            ("image" create-image)
            ("labels" create-labels)
            ("layout" create-layout)
@@ -1769,6 +1898,13 @@ (defun create-main-window ()
      :child-args '(:expand nil)
      :child (list (make-instance 'label :label (gtk-version)) :fill nil)
      :child (list (make-instance 'label :label "clg CVS version") :fill nil)
+     :child (list (make-instance 'label                          
+                  :label #-cmu(format nil "~A (~A)" 
+                               (lisp-implementation-type)
+                               (lisp-implementation-version))
+                         ;; The version string in CMUCL is far too long
+                         #+cmu(lisp-implementation-type))
+                 :fill nil)
      :child (list scrolled-window :expand t)
      :child (make-instance 'h-separator)
      :child (make-instance 'v-box