diff lisp/generic-widgets.el @ 462:0784d089fdc9 r21-2-46

Import from CVS: tag r21-2-46
author cvs
date Mon, 13 Aug 2007 11:44:37 +0200
parents
children 7039e6323819
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/generic-widgets.el	Mon Aug 13 11:44:37 2007 +0200
@@ -0,0 +1,330 @@
+;;; generic-widgets.el --- Generic UI building
+
+;; Copyright (C) 2000 Free Software Foundation
+
+;; Maintainer: William Perry <wmperry@gnu.org>
+;; Keywords: extensions, 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, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: Not in FSF
+
+;;; Commentary:
+
+;; This file is dumped with XEmacs.
+
+(defun build-ui (ui)
+  (if (null ui)
+      (gtk-label-new "[empty]")
+    (let ((builder-func (intern-soft (format "build-ui::%s" (car ui))))
+	  (widget nil))
+      (if (and builder-func (fboundp builder-func))
+	  (progn
+	    (setq widget (funcall builder-func ui))
+	    (setcdr ui (plist-put (cdr ui) :x-internal-widget widget))
+	    widget)
+	(error "Unknown ui element: %s" (car ui))))))
+
+(defun show-ui (ui)
+  (let ((widget (plist-get (cdr ui) :x-internal-widget)))
+    (if (not widget)
+	(error "Attempting to show unrealized UI"))
+    (gtk-widget-show-all widget)
+    (gtk-signal-connect widget 'destroy
+			(lambda (widget ui)
+			  (setcdr ui (plist-put (cdr ui) :x-internal-widget nil))) ui)))
+
+
+(defun build-ui::window (spec)
+  "Create a top-level window for containing other widgets.
+Properties:
+:items		list			A list of child UI specs.  Only the first is used.
+:type		toplevel/dialog/popup	What type of window to create.  Window managers
+					can (and usually do) treat each type differently.
+"
+  (let ((plist (cdr spec))
+	(window nil)
+	(child nil))
+    (setq window (gtk-window-new (plist-get plist :type 'toplevel))
+	  child (build-ui (car (plist-get plist :items))))
+    (gtk-container-add window child)
+    window))
+
+(defun build-ui::box (spec)
+  "Create a box for containing other widgets.
+Properties:
+:items		list			A list of child UI specs.
+:homogeneous	t/nil			Whether all children are the same width/height.
+:spacing	number			Spacing between children.
+:orientation	horizontal/vertical	How the widgets are stacked.
+
+Additional properties on child widgets:
+:expand		t/nil		Whether the new child is to be given extra space
+				allocated to box. The extra space will be divided
+				evenly between all children of box that use this
+				option.
+:fill		t/nil		Whether space given to child by the expand option is
+				actually allocated to child, rather than just padding
+				it. This parameter has no effect if :expand is set to
+				nil. A child is always allocated the full height of a
+				horizontal box and the full width of a vertical box.
+				This option affects the other dimension.
+:padding	number		Extra padding around this widget.
+"
+  (let* ((plist (cdr spec))
+	 (orientation (plist-get plist :orientation 'horizontal))
+	 (children (plist-get plist :items))
+	 (box nil)
+	 (child-widget nil)
+	 (child-plist nil))
+    (case orientation
+      (vertical (setq box (gtk-vbox-new (plist-get plist :homogeneous)
+					(plist-get plist :spacing))))
+      (horizontal (setq box (gtk-hbox-new (plist-get plist :homogeneous)
+					  (plist-get plist :spacing))))
+      (otherwise (error "Unknown orientation for box: %s" orientation)))
+    (mapc
+     (lambda (child)
+       (setq child-plist (cdr child)
+	     child-widget (build-ui child))
+       (if (listp child-widget)
+	   (mapc (lambda (w)
+		   (gtk-box-pack-start box w
+				       (plist-get child-plist :expand)
+				       (plist-get child-plist :fill)
+				       (plist-get child-plist :padding))) child-widget)
+	 (gtk-box-pack-start box child-widget
+			     (plist-get child-plist :expand)
+			     (plist-get child-plist :fill)
+			     (plist-get child-plist :padding))))
+     children)
+    box))
+
+(defun build-ui::tab-control (spec)
+  "Create a notebook widget.
+Properties:
+:items		list		A list of UI specs to use as notebook pages.
+:homogeneous	t/nil		Whether all tabs are the same width.
+:orientation	top/bottom/left/right	Position of tabs
+:show-tabs	t/nil		Show the tabs on screen?
+:scrollable	t/nil		Allow scrolling to view all tab widgets?
+
+Additional properties on child widgets:
+:tab-label	ui		A UI spec to use for the tab label.
+"
+  (let* ((plist (cdr spec))
+	 (notebook (gtk-notebook-new))
+	 (children (plist-get plist :items))
+	 (page-counter 1)
+	 (label-widget nil)
+	 (child-widget nil)
+	 (child-plist nil))
+    ;; Set all the properties
+    (gtk-notebook-set-homogeneous-tabs notebook (plist-get plist :homogeneous))
+    (gtk-notebook-set-scrollable notebook (plist-get plist :scrollable t))
+    (gtk-notebook-set-show-tabs notebook (plist-get plist :show-tabs t))
+    (gtk-notebook-set-tab-pos notebook (plist-get plist :orientation 'top))
+
+    ;; Now fill in the tabs
+    (mapc
+     (lambda (child)
+       (setq child-plist (cdr child)
+	     child-widget (build-ui child)
+	     label-widget (build-ui (plist-get child-plist :tab-label
+					       (list 'label :text (format "tab %d" page-counter))))
+	     page-counter (1+ page-counter))
+       (gtk-notebook-append-page notebook child-widget label-widget))
+     children)
+    notebook))
+
+(defun build-ui::text (spec)
+  "Create a multi-line text widget.
+Properties:
+:editable	t/nil		Whether the user can change the contents
+:word-wrap	t/nil		Automatic word wrapping?
+:line-wrap	t/nil		Automatic line wrapping?
+:text		string		Initial contents of the widget
+:file		filename	File for initial contents (takes precedence over :text)
+:face		facename	XEmacs face to use in the widget.
+"
+  (let* ((plist (cdr spec))
+	 (text (gtk-text-new nil nil))
+	 (face (plist-get plist :face 'default))
+	 (info (plist-get plist :text))
+	 (file (plist-get plist :file)))
+    (gtk-text-set-editable text (plist-get plist :editable))
+    (gtk-text-set-word-wrap text (plist-get plist :word-wrap))
+    (gtk-text-set-line-wrap text (plist-get plist :line-wrap))
+    (gtk-widget-set-style text 'default)
+
+    ;; Possible convert the file portion
+    (if (and file (not (stringp file)))
+	(setq file (eval file)))
+
+    (if (and info (not (stringp info)))
+	(setq info (eval info)))
+
+    (if (and file (file-exists-p file) (file-readable-p file))
+	(save-excursion
+	  (set-buffer (get-buffer-create " *improbable buffer name*"))
+	  (insert-file-contents file)
+	  (setq info (buffer-string))))
+
+    (gtk-text-insert text
+		     (face-font face)
+		     (face-foreground face)
+		     (face-background face)
+		     info (length info))
+    text))
+
+(defun build-ui::label (spec)
+  "Create a label widget.
+Properties:
+:text		string			Text inside the label
+:face		facename		XEmacs face to use in the widget.
+:justification  right/left/center	How to justify the text.
+"
+  (let* ((plist (cdr spec))
+	 (label (gtk-label-new (plist-get plist :text))))
+    (gtk-label-set-line-wrap label t)
+    (gtk-label-set-justify label (plist-get plist :justification))
+    (gtk-widget-set-style label (plist-get plist :face 'default))
+    label))
+
+(defun build-ui::pixmap (spec)
+  "Create a multi-line text widget.
+Properties:
+:text		string			Text inside the label
+:face		facename		XEmacs face to use in the widget.
+:justification  right/left/center	How to justify the text.
+"
+  (let* ((plist (cdr spec))
+	 (label (gtk-label-new (plist-get plist :text))))
+    (gtk-label-set-line-wrap label t)
+    (gtk-label-set-justify label (plist-get plist :justification))
+    (gtk-widget-set-style label (plist-get plist :face 'default))
+    label))
+
+(defun build-ui::radio-group (spec)
+  "A convenience when specifying a group of radio buttons."
+  (let ((build-ui::radio-group nil))
+    (mapcar 'build-ui (plist-get (cdr spec) :items))))
+
+(defun build-ui::button (spec)
+  "Create a button widget.
+Properties:
+:type		radio/check/toggle/nil	What type of button to create.
+:text		string			Text in the button.
+:glyph		glyph			Image in the button.
+:label		ui			A UI spec to use for the label.
+:relief		normal/half/none	How to draw button edges.
+
+NOTE: Radio buttons must be in a radio-group object for them to work.
+"
+  (let ((plist (cdr spec))
+	(button nil)
+	(button-type (plist-get plist :type 'normal))
+	(label nil))
+    (case button-type
+      (radio
+       (if (not (boundp 'build-ui::radio-group))
+	   (error "Attempt to use a radio button outside a radio-group"))
+       (setq button (gtk-radio-button-new build-ui::radio-group)
+	     build-ui::radio-group (gtk-radio-button-group button)))
+      (check
+       (setq button (gtk-check-button-new)))
+      (toggle
+       (setq button (gtk-toggle-button-new)))
+      (normal
+       (setq button (gtk-button-new)))
+      (otherwise
+       (error "Unknown button type: %s" button-type)))
+    (gtk-container-add
+     button
+     (build-ui (plist-get plist :label
+			  (list 'label :text
+				(plist-get plist
+					   :text (format "%s button" button-type))))))
+    button))
+
+(defun build-ui::progress-gauge (spec)
+  "Create a progress meter.
+Properties:
+:orientation		left-to-right/right-to-left/top-to-bottom/bottom-to-top
+:type			discrete/continuous
+
+"
+  (let ((plist (cdr spec))
+	(gauge (gtk-progress-bar-new)))
+    (gtk-progress-bar-set-orientation gauge (plist-get plist :orientation 'left-to-right))
+    (gtk-progress-bar-set-bar-style gauge (plist-get plist :type 'continuous))
+    gauge))
+
+(provide 'generic-widgets)
+
+(when (featurep 'gtk)			; just loading this file should be OK
+(gtk-widget-show-all
+  (build-ui
+   '(window :type dialog
+	    :items ((tab-control
+		     :homogeneous t
+		     :orientation bottom
+		     :items ((box :orientation vertical
+				  :tab-label (label :text "vertical")
+				  :items ((label :text "Vertical")
+					  (progress-gauge)					  
+					  (label :text "Box stacking")))
+			     (box :orientation horizontal
+				  :spacing 10
+				  :items ((label :text "Horizontal box")
+					  (label :text "stacking")))
+
+			     (box :orientation vertical
+				  :items
+				  ((radio-group
+				    :items ((button :type radio
+						    :expand nil
+						    :fill nil
+						    :text "Item 1")
+					    (button :type radio
+						    :expand nil
+						    :fill nil
+						    :text "Item 2")
+					    (button :type radio
+						    :expand nil
+						    :fill nil
+						    :text "Item 3")
+					    (button :type radio
+						    :expand nil
+						    :fill nil)))))
+			     (box :orientation vertical
+				  :items ((button :type check
+						  :text "Item 1")
+					  (button :type check
+						  :text "Item 2")
+					  (button :type normal
+						  :text "Item 3")
+					  (button :type toggle)))
+			     (text :editable t
+				   :word-wrap t
+				   :file (locate-data-file "COPYING"))
+			     (text :editable t
+				   :face display-time-mail-balloon-enhance-face
+				   :word-wrap t
+				   :text "Text with a face on it")))))))
+)