chiark / gitweb /
Fix due to minor API change in message-dialog
[clg] / examples / testgtk.lisp
index ab958092419391b3a2314c90f92d3df9c502e974..858d89420c751106d75404abba34012bd1386228 100644 (file)
@@ -1,24 +1,38 @@
-;; Common Lisp bindings for GTK+ v2.0
-;; Copyright (C) 1999-2005 Espen S. Johnsen <espen@users.sf.net>
+;; Common Lisp bindings for GTK+ v2.x
+;; Copyright 1999-2006 Espen S. Johnsen <espen@users.sf.net>
 ;;
-;; This library is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU Lesser General Public
-;; License as published by the Free Software Foundation; either
-;; version 2 of the License, or (at your option) any later version.
+;; Permission is hereby granted, free of charge, to any person obtaining
+;; a copy of this software and associated documentation files (the
+;; "Software"), to deal in the Software without restriction, including
+;; without limitation the rights to use, copy, modify, merge, publish,
+;; distribute, sublicense, and/or sell copies of the Software, and to
+;; permit persons to whom the Software is furnished to do so, subject to
+;; the following conditions:
 ;;
-;; This library is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; Lesser General Public License for more details.
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
 ;;
-;; You should have received a copy of the GNU Lesser General Public
-;; License along with this library; if not, write to the Free Software
-;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-;; $Id: testgtk.lisp,v 1.28 2005-04-19 08:17:06 espen Exp $
+;; Parts of this file are direct translations of code from 'testgtk.c'
+;; distributed with the Gtk+ library, and thus covered by the GNU
+;; Lesser General Public License and copyright Peter Mattis, Spencer
+;; Kimball, Josh MacDonald and others.
+
+
+;; $Id: testgtk.lisp,v 1.41 2007-07-12 09:18:30 espen Exp $
+
+#+sbcl(require :gtk)
+#+(or cmu clisp)(asdf:oos 'asdf:load-op :gtk)
 
 (defpackage "TESTGTK"
-  (:use "COMMON-LISP" "GTK"))
+  (:use "COMMON-LISP" "CLG"))
 
 (in-package "TESTGTK")
 
@@ -291,7 +305,8 @@ (define-dialog create-color-selection (dialog "Color selection dialog"
     (signal-connect dialog :cancel #'widget-destroy :object t)))
 
 
-;;; Cursors
+;;; Cursors (Note: using the drawing function in Gdk is considered
+;;; deprecated in clg, new code should use Cairo instead)
 
 (defun clamp (n min-val max-val)
   (declare (number n min-val max-val))
@@ -299,11 +314,11 @@ (defun clamp (n min-val max-val)
 
 (defun set-cursor (spinner drawing-area label)
   (let ((cursor
-        (glib:int-enum
+        (gffi:int-enum
          (logand (clamp (spin-button-value-as-int spinner) 0 152) #xFE)
          'gdk:cursor-type)))
     (setf (label-label label) (string-downcase cursor))
-    (setf (widget-cursor drawing-area) cursor)))
+    (widget-set-cursor drawing-area cursor)))
 
 (defun cursor-expose (drawing-area event)
   (declare (ignore event))
@@ -326,7 +341,7 @@ (define-simple-dialog create-cursors (dialog "Cursors")
   (let ((spinner (make-instance 'spin-button 
                  :adjustment (adjustment-new 
                               0 0 
-                              (1- (glib:enum-int :last-cursor 'gdk:cursor-type))
+                              (1- (gffi:enum-int :last-cursor 'gdk:cursor-type))
                               2 10 0)))
        (drawing-area (make-instance 'drawing-area
                       :width-request 80 :height-request 80
@@ -482,7 +497,40 @@ (define-toplevel create-font-selection (window "Font Button" :resizable nil)
 
 ;;; Icon View
 
-#+gtk2.6
+#+(or cmu sbcl)
+(defun get-directory-listing (directory)
+  (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
+        collect (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 filename directory-p)))
+      #+cmu(unix:close-dir dir)
+      #+sbcl(sb-posix:closedir dir))))
+
+#+clisp
+(defun get-directory-listing (directory)
+  (nconc
+   (mapcar #'(lambda (entry)
+              (let ((pathname (namestring (first entry))))
+                (list (subseq pathname (1+ (position #\/ pathname :from-end t))) nil)))
+    (directory (format nil "~A*" directory) :full t))
+   (mapcar #'(lambda (entry)
+              (let ((pathname (namestring entry)))
+                (list (subseq pathname (1+ (position #\/ pathname :from-end t :end (1- (length pathname)))) (1- (length pathname))) nil)))
+
+    (directory (format nil "~A*/" directory)))))
+
+
+#?(pkg-config:pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0" :error nil)
 (let ((file-pixbuf nil)
       (folder-pixbuf nil))
   (defun load-pixbufs ()
@@ -496,33 +544,20 @@   (defun load-pixbufs ()
           :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))
+          :signal (list :ok #'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))))
+    (list-store-clear store)    
+    (loop
+     for (filename directory-p) in (get-directory-listing directory)
+     unless (or (string= filename ".") (string= filename ".."))
+     do (list-store-insert store 0
+        (vector
+         filename 
+         (if directory-p folder-pixbuf file-pixbuf)
+         directory-p))))
 
   (defun sort-func (store a b)
     (let ((a-dir-p (tree-model-value store a 'directory-p))
@@ -536,6 +571,7 @@   (defun sort-func (store a b)
        ((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)))
@@ -551,7 +587,8 @@   (define-toplevel create-icon-view (window "Icon View demo"
                     :column-names '(filename pixbuf directory-p)))
             (icon-view (make-instance 'icon-view
                         :model store :selection-mode :multiple
-                        :text-column 'filename :pixbuf-column 'pixbuf))
+                        :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 
@@ -564,7 +601,7 @@   (define-toplevel create-icon-view (window "Icon View demo"
          #'(lambda (path)
             (when (tree-model-value store path 'directory-p)
               (setq directory
-                    (concatenate 'string directory (tree-model-value store path 'filename) "/"))
+               (concatenate 'string directory (tree-model-value store path 'filename) "/"))
               (fill-store store directory)
               (setf (widget-sensitive-p up) t))))
 
@@ -605,16 +642,14 @@ (define-toplevel create-image (window "Image" :resizable nil)
       
 (define-toplevel create-labels (window "Labels" :border-width 5 :resizable nil)
   (flet ((create-label-in-frame (frame-label label-text &rest args)
-          (list 
-           (make-instance 'frame
-            :label frame-label
-            :child (apply #'make-instance 'label :label label-text :xpad 5 :ypad 5 args))
-           :fill nil :expand nil)))
+          (make-instance 'frame
+           :label frame-label
+           :child (apply #'make-instance 'label :label label-text :xpad 5 :ypad 5 args))))
     (make-instance 'h-box
      :spacing 5 :parent window
      :child-args '(:fill nil :expand nil)
      :child (make-instance 'v-box
-             :spacing 5
+             :spacing 5 :child-args '(:fill nil :expand nil)
             :child (create-label-in-frame "Normal Label" "This is a Normal label")
             :child (create-label-in-frame "Multi-line Label"
 "This is a Multi-line label.
@@ -631,7 +666,7 @@ (define-toplevel create-labels (window "Labels" :border-width 5 :resizable nil)
 Third line"
                      :justify :right))
      :child (make-instance 'v-box
-            :spacing 5
+            :spacing 5 :child-args '(:fill nil :expand nil)
             :child (create-label-in-frame "Line wrapped label"
 "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.
      It supports multiple paragraphs correctly, and  correctly   adds many          extra  spaces. "
@@ -644,14 +679,14 @@ (define-toplevel create-labels (window "Labels" :border-width 5 :resizable nil)
                       :justify :fill :wrap t)
 
             :child (create-label-in-frame "Underlined label"
-(#+cmu glib:latin1-to-unicode #+sbcl identity
 "This label is underlined!
-This one is underlined (æøåÆØÅ) in quite a funky fashion")
+This one is underlined in quite a funky fashion"
                       :justify :left
                      :pattern  "_________________________ _ _________ _ _____ _ __ __  ___ ____ _____")))))
 
 
-;;; Layout
+;;; Layout (Note: using the drawing function in Gdk is considered
+;;; deprecated in clg, new code should use Cairo instead)
 
 (defun layout-expose (layout event)
   (when (eq (gdk:event-window event) (layout-bin-window layout))
@@ -725,19 +760,19 @@ (define-simple-dialog create-list (dialog "List" :default-height 400)
     (let ((column (make-instance 'tree-view-column :title "Column 1"))
          (cell (make-instance 'cell-renderer-text)))
       (cell-layout-pack column cell :expand t)
-      (cell-layout-add-attribute column cell 'text (column-index store :foo))
+      (cell-layout-add-attribute column cell 'text (tree-model-column-index store :foo))
       (tree-view-append-column tree column))
     
     (let ((column (make-instance 'tree-view-column :title "Column 2"))
          (cell (make-instance 'cell-renderer-text :background "orange")))
       (cell-layout-pack column cell :expand t)
-      (cell-layout-add-attribute column cell 'text (column-index store :bar))
+      (cell-layout-add-attribute column cell 'text (tree-model-column-index store :bar))
       (tree-view-append-column tree column))      
     
     (let ((column (make-instance 'tree-view-column :title "Column 3"))
          (cell (make-instance 'cell-renderer-text)))
       (cell-layout-pack column cell :expand t)
-      (cell-layout-add-attribute column cell 'text (column-index store :baz))
+      (cell-layout-add-attribute column cell 'text (tree-model-column-index store :baz))
       (tree-view-append-column tree column))      
 
     (make-instance 'v-box
@@ -899,6 +934,7 @@ (defun create-notebook-page (notebook page-num book-closed)
             :label "Hide page"
             :signal (list 'clicked #'(lambda () (widget-hide page)))))
 
+
     (let ((label-box (make-instance 'h-box 
                      :show-children t
                      :child-args '(:expand nil)
@@ -910,16 +946,15 @@ (defun create-notebook-page (notebook page-num book-closed)
                     :child (make-instance 'image :pixbuf book-closed)
                     :child (make-instance 'label :label title))))
 
-      (widget-show-all page)
       (notebook-append notebook page label-box menu-box))))
        
-
 (define-simple-dialog create-notebook (dialog "Notebook")
   (let ((main (make-instance 'v-box :parent dialog)))
     (let ((book-open (gdk:pixbuf-new-from-xpm-data book-open-xpm))
-         (book-closed (gdk:pixbuf-new-from-xpm-data book-closed-xpm))
-         (notebook (make-instance 'notebook 
+         (book-closed (gdk:pixbuf-new-from-xpm-data book-closed-xpm))
+         (notebook (make-instance 'notebook 
                     :border-width 10 :tab-pos :top :parent main)))
+
       (flet ((set-image (page func pixbuf)
               (setf
                (image-pixbuf 
@@ -1002,13 +1037,13 @@ (define-simple-dialog create-notebook (dialog "Notebook")
        :spacing 5 :border-width 10
        :parent (list main :expand nil)
        :child (make-instance 'button 
-              :label "prev"
+              :label "Prev"
               :signal (list 'clicked #'notebook-prev-page :object notebook))
        :child (make-instance 'button 
-              :label "next"
+              :label "Next"
               :signal (list 'clicked #'notebook-next-page :object notebook))
        :child (make-instance 'button 
-              :label "rotate"
+              :label "Rotate"
               :signal (let ((tab-pos 0))
                         (list 'clicked 
                          #'(lambda ()
@@ -1019,6 +1054,7 @@ (define-simple-dialog create-notebook (dialog "Notebook")
     (widget-show-all main)))
 
 
+
 ;;; Panes
 
 (defun toggle-resize (child)
@@ -1255,12 +1291,13 @@ (defun create-shape-icon (xpm-file x y px py type root-window destroy)
             (grab-add window)
             (gdk:pointer-grab (widget-window window) 
              :events '(:button-release :button-motion :pointer-motion-hint)
-             :owner-events t :time event))))
+             :owner-events t))))
 
       (signal-connect window 'button-release-event
        #'(lambda (event)
+          (declare (ignore event))
           (grab-remove window)
-          (gdk:pointer-ungrab event)))
+          (gdk:pointer-ungrab)))
        
       (signal-connect window 'motion-notify-event
        #'(lambda (event)
@@ -1601,7 +1638,34 @@ (define-simple-dialog create-text (dialog "Text" :default-width 400
         :after t)
        
        (container-add dialog (ui-manager-get-widget ui "/ToolBar") :expand nil)
-       (container-add dialog text-view)))))
+       (container-add dialog text-view) 
+
+       (let ((position (make-instance 'label :visible t)))
+         (flet ((update-position (line column)
+                  (setf 
+                   (label-label position)
+                   (format nil "Cursor Position: ~d,~d" (1+ line) column))))
+           (update-position 0 0)
+
+           ;; Callback to display current position when cursor is moved
+           (signal-connect buffer 'mark-set
+            #'(lambda (iter mark)
+                (when (and 
+                       (slot-boundp mark 'name) 
+                       (string= (text-mark-name mark) "insert"))
+                  (update-position 
+                   (text-iter-line iter) (text-iter-line-offset iter)))))
+
+           ;; Callback to display current position after the
+           ;; buffer has been modified
+           (signal-connect buffer 'changed
+            #'(lambda ()
+                (let ((iter (text-buffer-get-iter-at-insert buffer)))
+                  (update-position 
+                   (text-iter-line iter) (text-iter-line-offset iter))))
+            :after t))
+
+         (container-add dialog position :expand nil))))))
 
 
 ;;; Toggle buttons
@@ -1837,7 +1901,7 @@ (define-toplevel create-ui-manager (window "UI Manager")
             (ui-manager-get-widget ui "/ToolBar")
             :expand nil :fill nil)
      :child (make-instance 'label
-            :label "Type <alt> to start" 
+            :label "Type Ctrl+Q to quit"
             :xalign 0.5 :yalign 0.5
             :width-request 200 :height-request 200))))
                  
@@ -1845,10 +1909,7 @@ (define-toplevel create-ui-manager (window "UI Manager")
 
 ;;; Main window
       
-(defun create-main-window ()
-;;   (rc-parse "clg:examples;testgtkrc2")
-;;   (rc-parse "clg:examples;testgtkrc")
-
+(defun create-main-window (&optional display)
   (let* ((button-specs
          '(("button box" create-button-box)
            ("buttons" create-buttons)
@@ -1857,14 +1918,13 @@ (defun create-main-window ()
            ("color selection" create-color-selection)
            ("cursors" create-cursors)
            ("dialog" create-dialog)
-;; ;       ("dnd")
            ("entry" create-entry)
-;;         ("event watcher")
            ("enxpander" create-expander)
            ("file chooser" create-file-chooser)
            ("font selection" create-font-selection)
            ("handle box" create-handle-box)
-#+gtk2.6    ("icon view" create-icon-view)
+           #?(pkg-config:pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0" :error nil)
+           ("icon view" create-icon-view)
            ("image" create-image)
            ("labels" create-labels)
            ("layout" create-layout)
@@ -1886,29 +1946,25 @@ (defun create-main-window ()
            ("spinbutton" create-spins)
            ("statusbar" create-statusbar)
            ("test idle" create-idle-test)
-;;         ("test mainloop")
-;;         ("test scrolling")
-;;         ("test selection")
            ("test timeout" create-timeout-test)
            ("text" create-text)
            ("toggle buttons" create-toggle-buttons)
            ("toolbar" create-toolbar-window)
            ("tooltips" create-tooltips)
-;;         ("tree" #|create-tree|#)
-           ("UI manager" create-ui-manager)
-))
-       (main-window (make-instance 'window
-                     :title "testgtk.lisp" :name "main_window"
-                     :default-width 200 :default-height 400
-                     :allow-grow t :allow-shrink nil))
-       (scrolled-window (make-instance 'scrolled-window
-                         :hscrollbar-policy :automatic 
-                         :vscrollbar-policy :automatic
-                         :border-width 10))
-       (close-button (make-instance 'button 
-                      :label "close" :can-default t
-                      :signal (list 'clicked #'widget-destroy 
-                                    :object main-window)))) 
+           ("UI manager" create-ui-manager)))
+
+        (main-window (make-instance 'window
+                      :display display
+                      :title "testgtk.lisp" :name "main_window"
+                      :default-width 200 :default-height 400
+                      :allow-grow t :allow-shrink nil))
+        (scrolled-window (make-instance 'scrolled-window
+                          :hscrollbar-policy :automatic 
+                          :vscrollbar-policy :automatic
+                          :border-width 10))
+        (close-button (make-instance 'button 
+                       :stock "gtk-close" :can-default t
+                       :signal (list 'clicked #'widget-destroy :object main-window))))
 
     (let ((icon (gdk:pixbuf-load #p"clg:examples;gtk.png")))
       (setf 
@@ -1920,11 +1976,16 @@ (defun create-main-window ()
      :parent 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 (clg-version)) :fill nil)
      :child (list (make-instance 'label                          
-                  :label #-cmu(format nil "~A (~A)" 
-                               (lisp-implementation-type)
-                               (lisp-implementation-version))
+                  :label #-cmu
+                         (format nil "~A (~A)" 
+                          (lisp-implementation-type)
+                          #-clisp
+                          (lisp-implementation-version)
+                          #+clisp
+                          (let ((version (lisp-implementation-version)))
+                            (subseq version 0 (position #\sp version))))
                          ;; The version string in CMUCL is far too long
                          #+cmu(lisp-implementation-type))
                  :fill nil)
@@ -1937,9 +1998,9 @@ (defun create-main-window ()
     (let ((content-box 
           (make-instance 'v-box
            :focus-vadjustment (scrolled-window-vadjustment scrolled-window)
-           :children (mapcar #'(lambda (spec) 
+           :children (mapcar #'(lambda (spec)
                                  (apply #'create-button spec))
-                             button-specs))))
+                      button-specs))))
       (scrolled-window-add-with-viewport scrolled-window content-box))
     
     (widget-grab-focus close-button)
@@ -1947,4 +2008,4 @@ (defun create-main-window ()
     main-window))
  
 (clg-init)
-(create-main-window)
+(within-main-loop (create-main-window))