This commit was manufactured by cvs2svn to create branch 'chise-r21-4-19'.
[chise/xemacs-chise.git-] / lisp / dialog-gtk.el
diff --git a/lisp/dialog-gtk.el b/lisp/dialog-gtk.el
new file mode 100644 (file)
index 0000000..1cfdaf2
--- /dev/null
@@ -0,0 +1,348 @@
+;;; dialog-gtk.el --- Dialog-box support for XEmacs w/GTK primitives
+
+;; Copyright (C) 2000 Free Software Foundation, Inc.
+
+;; Maintainer: William M. Perry <wmperry@gnu.org>
+;; Keywords: extensions, internal, dumped
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs 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
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the 
+;; Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;; This file is dumped with XEmacs (when dialog boxes are compiled in).
+
+(require 'cl)
+(require 'gtk-password-dialog)
+(require 'gtk-file-dialog)
+
+(defun gtk-popup-convert-underscores (str)
+  ;; Convert the XEmacs button accelerator representation to Gtk mnemonic
+  ;; form.  If no accelerator has been provided, put one at the start of the
+  ;; string (this mirrors the behaviour under X). This algorithm is also found
+  ;; in menubar-gtk.c:convert_underscores().
+  (let ((new-str (string))
+       (i 0)
+       (found-accel nil))
+    (while (< i (length str))
+      (let ((c (aref str i)))
+       (cond ((eq c ?%)
+              (setq i (1+ i))
+              (if (and (not (eq (aref str i) ?_)) (not (eq (aref str i) ?%)))
+                  (setq i (1- i)))
+              (setq found-accel 1)
+              )
+             ((eq c ?_)
+               (setq new-str (concat new-str "_")))
+              ))
+       (setq new-str (concat new-str (string (aref str i))))
+       (setq i (1+ i))
+       )
+    (if found-accel new-str (concat "_" new-str)) 
+    ))
+
+(defun popup-builtin-open-dialog (keys)
+  ;; Allowed keywords are:
+  ;;
+  ;;  :initial-filename fname
+  ;;  :initial-directory dir
+  ;;  :filter-list (filter-desc filter ...)
+  ;;  :directory t/nil
+  ;;  :title string
+  ;;  :allow-multi-select t/nil
+  ;;  :create-prompt-on-nonexistent t/nil
+  ;;  :overwrite-prompt t/nil
+  ;;  :file-must-exist t/nil
+  ;;  :no-network-button t/nil
+  ;;  :no-read-only-return t/nil
+  (let ((initial-filename (plist-get keys :initial-filename))
+       (clicked-ok nil)
+       (filename nil)
+       (widget nil))
+    (setq widget (gtk-file-dialog-new
+                 :directory (plist-get keys :directory)
+                 :callback `(lambda (f)
+                              (setq clicked-ok t
+                                    filename f))
+                 :initial-directory (or (plist-get keys :initial-directory nil)
+                                        (if initial-filename
+                                            (file-name-directory initial-filename)
+                                          default-directory))
+                 :filter-list (plist-to-alist
+                               (plist-get keys :filter-list nil))
+                 :file-must-exist (plist-get keys :file-must-exist nil)))
+
+    (gtk-signal-connect widget 'destroy (lambda (obj data) (gtk-main-quit)))
+
+    (gtk-window-set-transient-for widget (frame-property nil 'shell-widget))
+    (gtk-widget-show-all widget)
+    (gtk-main)
+    (if (not clicked-ok)
+       (signal 'quit nil)
+      filename)))
+
+(defalias 'popup-builtin-save-as-dialog 'popup-builtin-open-dialog)
+
+(defun popup-builtin-color-dialog (keys)
+  ;; Allowed keys:
+  ;;   :initial-color COLOR
+  (let ((initial-color (or (plist-get keys :initial-color) "white"))
+       (title (or (plist-get keys :title "Select color...")))
+       (dialog nil)
+       (clicked-ok nil)
+       (color nil))
+    (setq dialog (gtk-color-selection-dialog-new title))
+    (gtk-signal-connect
+     (gtk-color-selection-dialog-ok-button dialog) 'clicked
+     (lambda (button colorsel)
+       (gtk-widget-hide-all dialog)
+       (setq color (gtk-color-selection-get-color colorsel)
+            clicked-ok t)
+       (gtk-main-quit))
+     (gtk-color-selection-dialog-colorsel dialog))
+
+    (gtk-signal-connect
+     (gtk-color-selection-dialog-cancel-button dialog) 'clicked
+     (lambda (&rest ignored)
+       (gtk-main-quit)))
+
+    (put dialog 'modal t)
+    (put dialog 'type 'dialog)
+    (gtk-window-set-transient-for dialog (frame-property nil 'shell-widget))
+
+    (unwind-protect
+       (progn
+         (gtk-widget-show-now dialog)
+         (gtk-main))
+      '(gtk-widget-destroy dialog))
+    (if (not clicked-ok)
+       (signal 'quit nil))
+    ;; Need to convert from (R G B A) to #rrggbb
+    (format "#%02x%02x%02x"
+           (* 256 (nth 0 color))
+           (* 256 (nth 1 color))
+           (* 256 (nth 2 color)))))
+
+(defun popup-builtin-password-dialog (keys)
+  ;; Format is (default callback :keyword value)
+  ;; Allowed keywords are:
+  ;;
+  ;;  :title string
+  :;  :prompt string
+  ;;  :default string
+  ;;  :verify boolean
+  ;;  :verify-prompt string
+  (let* ((default (plist-get keys :default))
+        (dialog nil)
+        (clicked-ok nil)
+        (passwd nil)
+        (info nil)
+        (generic-cb (lambda (x)
+                      (setq clicked-ok t
+                            passwd x))))
+
+    ;; Convert the descriptor to keywords and create the dialog
+    (setq info (copy-list keys)
+         info (plist-put info :callback generic-cb)
+         info (plist-put info :default default)
+         dialog (apply 'gtk-password-dialog-new info))
+
+    ;; Clicking any button or closing the box exits the main loop.
+    (gtk-signal-connect (gtk-password-dialog-ok-button dialog)
+                       'clicked
+                       (lambda (&rest ignored)
+                         (gtk-main-quit)))
+
+    (gtk-signal-connect (gtk-password-dialog-cancel-button dialog)
+                       'clicked
+                       (lambda (&rest ignored)
+                         (gtk-main-quit)))
+
+    (gtk-signal-connect dialog
+                       'delete-event
+                       (lambda (&rest ignored)
+                         (gtk-main-quit)))
+
+    (gtk-widget-grab-focus (gtk-password-dialog-entry-widget dialog))
+
+    ;; Make us modal...
+    (put dialog 'modal t)
+    (gtk-window-set-transient-for dialog (frame-property nil 'shell-widget))
+
+    ;; Realize the damn thing & wait for some action...
+    (gtk-widget-show-all dialog)
+    (gtk-main)
+
+    (if (not clicked-ok)
+       (signal 'quit nil))
+
+    (gtk-widget-destroy dialog)
+    passwd))
+
+(defun popup-builtin-question-dialog (keys)
+  ;; Allowed keywords:
+  ;;   :question STRING
+  ;;   :buttons  BUTTONDESC
+  (let ((title (or (plist-get keys :title) "Question"))
+       (buttons-descr (plist-get keys :buttons))
+       (question (or (plist-get keys :question) "Question goes here..."))
+       (dialog nil)                    ; GtkDialog
+       (buttons nil)                   ; List of GtkButton objects
+       (activep t)
+       (callback nil)
+       (flushrightp nil)
+       (length nil)
+       (label nil)
+       (gui-button nil)
+       (accel-group (gtk-accel-group-new))
+       (accel-key nil)
+       (errp t))
+    (if (not buttons-descr)
+       (error 'syntax-error
+              "Dialog descriptor must supply at least one button"))
+
+    ;; Do the basics - create the dialog, set the window title, and
+    ;; add the label asking the question.
+    (unwind-protect
+       (progn
+         (setq dialog (gtk-dialog-new))
+         (gtk-window-set-title dialog title)
+         (gtk-container-set-border-width dialog 3)
+         (gtk-box-set-spacing (gtk-dialog-vbox dialog) 5)
+         (gtk-container-add (gtk-dialog-vbox dialog) (gtk-label-new question))
+
+         ;; Create the buttons.
+         (mapc (lambda (button)
+                 ;; Handle flushright buttons
+                 (if (null button)
+                     (setq flushrightp t)
+
+                   ;; More sanity checking first of all.
+                   (if (not (vectorp button))
+                       (error "Button descriptor is not a vector: %S" button))
+
+                   (setq length (length button))
+
+                   (cond
+                    ((= length 1)      ; [ "name" ]
+                     (setq callback nil
+                           activep nil))
+                    ((= length 2)      ; [ "name" callback ]
+                     (setq callback (aref button 1)
+                           activep t))
+                    ((and (or (= length 3) (= length 4))
+                          (not (keywordp (aref button 2))))
+                     ;; [ "name" callback active-p ] or
+                     ;; [ "name" callback active-p suffix ]
+                     ;; We ignore the 'suffix' entry, because that is
+                     ;; what the X code does.
+                     (setq callback (aref button 1)
+                           activep (aref button 2)))
+                    (t                 ; 100% keyword specification
+                     (let ((plist (cdr (mapcar 'identity button))))
+                       (setq activep (plist-get plist :active)
+                             callback (plist-get plist :callback)))))
+
+                   ;; Create the label and determine what the mnemonic key is.
+                   (setq label (gtk-label-new ""))
+                   (setq accel-key (gtk-label-parse-uline label
+                                                          (gtk-popup-convert-underscores (aref button 0))))
+                   ;; Place the label in the button.
+                   (gtk-misc-set-alignment label 0.5 0.5)
+                   (setq gui-button (gtk-button-new))
+                   (gtk-container-add gui-button label)
+                   ;; Add ALT-mnemonic to the dialog's accelerator group.
+                   (gtk-widget-add-accelerator gui-button "clicked" accel-group
+                                               accel-key
+                                               8 ; GDK_MOD1_MASK
+                                               4 ; GTK_ACCEL_LOCKED
+                                               )
+                   
+                   (push gui-button buttons)
+                   (gtk-widget-set-sensitive (car buttons) (eval activep))
+                   
+                   ;; Apply the callback
+                   (gtk-signal-connect
+                    (car buttons) 'clicked
+                    (lambda (button data)
+                      (push (make-event 'misc-user
+                                        (list 'object (car data)
+                                              'function
+                                              (if (symbolp (car data))
+                                                  'call-interactively
+                                                'eval)))
+                            unread-command-events)
+                      (gtk-main-quit)
+                      t)
+                    (cons callback dialog))
+
+                   (gtk-widget-show (car buttons))
+                   (funcall (if flushrightp 'gtk-box-pack-end 'gtk-box-pack-start)
+                            (gtk-dialog-action-area dialog) (car buttons)
+                            nil t 2)))
+               buttons-descr)
+
+         ;; Make sure they can't close it with the window manager
+         (gtk-signal-connect dialog 'delete-event (lambda (&rest ignored) t))
+         (gtk-window-set-transient-for dialog (frame-property nil 'shell-widget))
+         (put dialog 'type 'dialog)
+         (put dialog 'modal t)
+         ;; Make the dialog listen for global mnemonic keys.
+         (gtk-window-add-accel-group dialog accel-group)
+
+         (gtk-widget-show-all dialog)
+         (gtk-main)
+         (gtk-widget-destroy dialog)
+         (setq errp nil))
+      (if (not errp)
+         ;; Nothing, we successfully showed the dialog
+         nil
+       ;; We need to destroy all the widgets, just in case.
+       (mapc 'gtk-widget-destroy buttons)
+       (gtk-widget-destroy dialog)))))
+
+(defun gtk-make-dialog-box-internal (type keys)
+  (case type
+    (file
+     (popup-builtin-open-dialog keys))
+    (password
+     (popup-builtin-password-dialog keys))
+    (question
+     (popup-builtin-question-dialog keys))
+    (color
+     (popup-builtin-color-dialog keys))
+    (find
+     )
+    (font
+     )
+    (replace
+     )
+    (mswindows-message
+     ;; This should really be renamed!
+     )
+    (print
+     )
+    (page-setup
+     )
+    (print-setup
+     )
+    (default
+      (error "Unknown type of dialog: %S" type))))
+
+(provide 'dialog-gtk)