1 ;;; toolbar-x.el --- fancy toolbar handling in Emacs and XEmacs
3 ;; Copyright (C) 2004, 2005, 2008, 2014, 2016 Free Software Foundation, Inc.
5 ;; This program is free software; you can redistribute it and/or
6 ;; modify it under the terms of the GNU General Public License as
7 ;; published by the Free Software Foundation; either version 3 of
8 ;; the License, or (at your option) any later version.
10 ;; This program is distributed in the hope that it will be
11 ;; useful, but WITHOUT ANY WARRANTY; without even the implied
12 ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 ;; PURPOSE. See the GNU General Public License for more details.
15 ;; You should have received a copy of the GNU General Public
16 ;; License along with this program; if not, write to the Free
17 ;; Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 ;;; Author: Miguel Vinicius Santini Frasson
23 ;; This program implements a common interface to display toolbar
24 ;; buttons in both Emacs and XEmacs. A toolbar should be basicly
25 ;; defined by a image and a command to run when the button is pressed,
26 ;; and additional properties could be added. This is the idea of this
27 ;; program. See the documentation of function
28 ;; `toolbarx-install-toolbar' for a description of how to specify
33 ;; * Button properties are given in the toolbar definition (BUTTON
34 ;; paramenter in `toolbarx-install-toolbar') and/or in an alist with
35 ;; associates the symbol with properties (MEANING-ALIST paramenter in
36 ;; `toolbarx-install-toolbar').
38 ;; * Supported properties:
39 ;; - All editors: `:insert', `:image', `:command', `:help', `:enable',
40 ;; `:append-command' and `:prepend-command';
41 ;; - Emacs only: `:visible' and `:button';
42 ;; - XEmacs only: `:toolbar'.
43 ;; For the precise value-type for each property, see documentation of
44 ;; the function `toolbarx-install-toolbar'.
45 ;; (ps: properties that are particular to an editor are just ignored
46 ;; the other editor flavour.)
48 ;; * Button properties may depend on the editor flavour, if the value
49 ;; is a vector; the first element will be used for Emacs and the 2nd
50 ;; for XEmacs. Example: `:image ["new" toolbar-file-icon]'
52 ;; * Properties can have value specified by function (with no
53 ;; argument) or variables that evaluate to an object of the correct
54 ;; type for a particular property. The evaluation is done when the
55 ;; roolbar is refresh (a call of `toolbarx-refresh'.)
56 ;; (ps: this is valid only for properties that *not* have \`form\' as
59 ;; * On `refresh time' (a call `toolbarx-refresh', necessary when the
60 ;; toolbar should change), the `:insert' property (if present) is
61 ;; evaluated to decide if button will be displayed.
63 ;; Properties can be distributed to several buttons, using \`groups\'.
64 ;; Example: (for (bar baz :toolbar (bottom . top) :insert foo-form)
65 ;; means that `foo', `bar' and `baz' have `:insert foo-form' and `bar' and
66 ;; `baz' have the property `:toolbar (bottom . top)'. (ps: this type
67 ;; of value for the `:toolbar' property (XEmacs only) means that the
68 ;; buttons will be in the bottom toolbar unless the default toolbar is
69 ;; in the bottom, and in this case, this buttons go to the top
72 ;; * (Part of) the toolbar definition can be stored in a variable,
73 ;; evaluated in `installation time'. See `:eval-group' on the
74 ;; documentation of the function `toolbarx-install-toolbar'.
76 ;; * It is possible to define sets of buttons that appear according to
77 ;; an option selected in a dropdown menu. See `:dropdown-group' on
78 ;; the documentation of the function `toolbarx-install-toolbar'.
80 ;;; Rough description of the implementation
81 ;; There are 3 \`engines\' implemented:
83 ;; == the 1st one (parsing) parses the toolbar definition
84 ;; independently of editor flavour and store the parsed buttons with
85 ;; their properties, in the same order that they appear in the
86 ;; definitions, in a variable `toolbarx-internal-button-switches';
88 ;; == the 2nd one (refresh for Emacs) inserts buttons in the Emacs
89 ;; toolbar in the same order that they appear in the definitions;
90 ;; buttons with a `:insert' property value that evaluates to nil are
91 ;; ignored; if a (real) button does not have at least (valid) image
92 ;; and command properties, they are silently ignored;
94 ;; == the 3rd engine (refresh for XEmacs) is similar to the 2nd, but
95 ;; inserts buttons in XEmacs.
99 ;; This program was motivated by the intention of implementation of a
100 ;; good toolbar for AUCTeX, that would work in both Emacs and XEmacs.
101 ;; Since toolbars are very different in behaviour and implementation
102 ;; (for instance, in Emacs one can display as many toolbar buttons as
103 ;; wanted, because it becomes mult-line, and in XEmacs, there is one
104 ;; line, but toolbars and all sides of a frame.)
109 (eval-when-compile (require 'cl))
111 ;; Note that this just gives a useful default. Icons are expected to
112 ;; be in subdirectory "images" or "toolbar" relative to the load-path.
113 ;; Packages loading toolbarx are advised to explicitly add their own
114 ;; searchpath with add-to-list here even when they fulfill that
115 ;; criterion: another package might have loaded toolbar-x previously
116 ;; when load-path was not yet correctly set. The default setting
117 ;; really caters only for toolbar-x' stock icons.
118 (globally-declare-boundp 'tool-bar-map)
120 (defvar toolbarx-image-path
122 (delq nil (mapcar #'(lambda(x)
125 (file-name-nondirectory
126 (directory-file-name x))
127 '("toolbar" "images"))
128 ;;(file-directory-p x)
131 (list data-directory))
132 "List of directories where toolbarx finds its images.")
134 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
135 ;;; First engine: Parsing buttons
137 ;; it obtains button information, process it and stores result in
138 ;; `toolbarx-internal-button-switches', which is a list with 1st
139 ;; element the symbol `:switches', the 2nd element as a list of
140 ;; processed buttons, and the 3rd element is used for Emacs to store
141 ;; the keys used in ``constant'' buttons.
143 ;; The 2nd element of `toolbarx-internal-button-switches' is a list
144 ;; where each element is either:
145 ;; * a button-list, that is, a list with elements to define a button.
146 ;; * a list where 1st elem is `:insert' and 2nd is a form, and the
147 ;; following elements are in the same format of the 2nd element of
148 ;; `toolbarx-internal-button-switches'.
150 (defun toolbarx-make-string-from-symbol (symbol)
151 "Return a string from the name of a SYMBOL.
152 Upcase initials and replace dashes by spaces."
153 (let* ((str (upcase-initials (symbol-name symbol)))
155 (dolist (i (append str nil))
156 (if (eq i 45) ; if dash, push space
158 (push i str2))) ; else push identical
159 (concat (nreverse str2))))
161 (defun toolbarx-make-symbol-from-string (string)
162 "Return a (intern) symbol from STRING.
163 Downcase string and replace spaces by dashes."
164 (let* ((str1 (append (downcase string) nil))
167 (if (eq i 32) ; if dash, push space
170 (intern (concat (nreverse str2)))))
172 (defun toolbarx-good-option-list-p (option-list valid-options)
173 "Non-nil means the OPTION-LIST is of form (OPT FORM ... OPT FORM).
174 Each OPT is member of VALID-OPTIONS and OPT are pairwise
175 different. OPTION-LIST equal to nil is a good option list."
176 (let ((elt-in-valid t)
177 (temp-opt-list option-list)
179 (n (/ (length option-list) 2)))
182 (setq temp-opt-list (cddr temp-opt-list)))
183 (pushnew (car temp-opt-list) list-diff :test #'equal)
184 (setq elt-in-valid (and elt-in-valid
185 (memq (car temp-opt-list)
187 (and elt-in-valid ; options are on VALID-OPTOPNS
188 ;; OPTION-LIST has all option different from each other
189 (eq (length list-diff) n)
190 ;; OPTION-LIST has even number of elements
191 (eq (% (length option-list) 2) 0))))
193 (defun toolbarx-separate-options (group-list valid-options &optional check)
194 "Return a cons cell with non-options and options of GROUP-LIST.
195 The options-part is the largest tail of the list GROUP-LIST that
196 has an element of VALID-OPTIONS (the comparation is made with
197 `memq'.) The non-options-part is the beginning of GROUP-LIST
198 less its tail. Return a cons cell which `car' is the
199 non-options-part and the `cdr' is the options-part.
201 If CHECK is non-nil, the tail is the largest that yield non-nil
202 when applied to `toolbarx-good-option-list-p'."
205 (dolist (i valid-options)
206 (setq temp (memq i group-list))
207 (when (and (> (length temp) (length maximal))
209 (toolbarx-good-option-list-p temp valid-options)
211 (setq maximal (memq i group-list))))
212 (cons (butlast group-list (length maximal)) maximal)))
215 (defun toolbarx-merge-props (inner-props outer-props override add)
216 "Merge property lists INNER-PROPS and OUTER-PROPS.
217 INNER-PROPS and OUTER-PROPS are two lists in the format
218 (PROP VAL PROP VAL ... PROP VAL).
219 Returns a list with properties and values merged.
221 OVERRIDE and ADD are supposed to be lists of symbols. The value
222 of a property in OVERRIDE is the one on OUTER-PROPS or
223 INNER-PROPS, but if the property is in both, the value in
224 INNER-PROPS is used. The value of a property in ADD will be a
225 list with first element the symbol `:add-value-list' and the rest
226 are the properties, inner properties first."
230 (dolist (prop override)
231 (if (memq prop inner-props)
232 (setq merged (append merged
233 (list prop (cadr (memq prop inner-props)))))
234 (when (memq prop outer-props)
235 (setq merged (append merged
236 (list prop (cadr (memq prop outer-props))))))))
237 (dolist (prop add merged)
238 (setq inner-prop (memq prop inner-props))
240 (if (and (listp (cadr inner-prop))
241 (eq (car (cadr inner-prop)) :add-value-list))
242 (setq inner-prop (cdr (cadr inner-prop)))
243 (setq inner-prop (list (cadr inner-prop)))))
244 (setq outer-prop (memq prop outer-props))
246 (if (and (listp (cadr outer-prop))
247 (eq (car (cadr outer-prop)) :add-value-list))
248 (setq outer-prop (cdr (cadr outer-prop)))
249 (setq outer-prop (list (cadr outer-prop)))))
250 (when (append inner-prop outer-prop)
251 (setq merged (append merged
252 (list prop (cons :add-value-list
256 (defun toolbarx-make-command (comm prep app)
257 "Return a command made from COMM, PREP and APP.
258 COMM is a command or a form. PREP and APP are forms. If PREP or
259 APP are non-nil, they are added to the resulting command at the
260 beginning and end, respectively. If both are nil and COMM is a
261 command, COMM is returned."
262 (let ((comm-is-command (commandp comm)))
267 (append '(lambda nil (interactive))
268 (when prep (list prep))
271 `((call-interactively (function ,comm)))
273 (when app (list app))))))
275 ;; in Emacs, menus are made of keymaps (vectors are possible, but editors
276 ;; handle `menu titles' differently) meanwhile in XEmacs, menus are lists of
279 (defmacro toolbarx--if-when-compile (test then else)
280 (declare (indent 1) (debug t))
281 (if (eval test) then else))
283 (toolbarx--if-when-compile (not (featurep 'xemacs))
284 (defun toolbarx-emacs-mount-popup-menu
285 (strings var type &optional title save)
286 "Return an interactive `lambda'-expression that shows a popup menu.
287 This function is the action of `toolbarx-mount-popup-menu' if
288 inside Emacs. See documentation of that function for more."
289 ;; making the menu keymap by adding each menu-item definition
290 ;; see (info "(elisp)Menu keymaps")
291 (let* ((keymap (make-sparse-keymap title))
293 (used-symbols '(nil))
295 (real-type (if (eq type 'toggle) 'toggle 'radio))
296 (real-save (when save (if (eq save 'offer) 'offer 'always))))
297 ;; warn if type is not `radio' ot `toggle'; use `radio' if incorrect.
298 (unless (eq type real-type)
299 (display-warning 'toolbarx
300 (format (concat "TYPE should be symbols `radio' or "
301 "`toggle', but %s found; using `radio'")
303 ;; warn if save is not `nil', `offer' or `always'; use nil when incorrect
304 (unless (eq save real-save)
306 (display-warning 'toolbarx
307 (format (concat "SAVE should be symbols `nil', "
308 "`offer' or `always', but %s found; "
312 ;; finding a new symbol
314 (i-symb (toolbarx-make-symbol-from-string i)))
316 (while (memq key used-symbols)
317 (setq aux-count (1+ aux-count))
318 (setq key (intern (format "%s-%d" i-symb aux-count))))
319 (setq used-symbols (cons key used-symbols)))
320 (define-key-after keymap (vector key)
323 `(lambda nil (interactive)
324 ,(if (eq real-type 'radio)
326 `(if (memq ,count ,var)
327 (setq ,var (delete ,count ,var))
328 (setq ,var (sort (cons ,count ,var) '<))))
330 (when (eq real-save 'always)
331 `((customize-save-variable
334 :button ,(if (eq real-type 'radio)
335 `(:radio eq ,var ,count)
336 `(:toggle memq ,count ,var))))
337 (setq count (1+ count)))
338 (when (eq real-save 'offer)
339 (define-key-after keymap [sep] '(menu-item "--shadow-etched-in-dash"))
341 (i-symb 'custom-save))
343 (while (memq key used-symbols)
344 (setq aux-count (1+ aux-count))
345 (setq key (intern (format "%s-%d" i-symb aux-count))))
346 (setq used-symbols (cons key used-symbols)))
347 (define-key-after keymap (vector key)
348 `(menu-item "Save state of this menu"
349 (lambda nil (interactive)
350 (customize-save-variable (quote ,var) ,var)))))
351 ;; returns a `lambda'-expression
352 `(lambda nil (interactive) (popup-menu (quote ,keymap)))))
354 (defun toolbarx-xemacs-mount-popup-menu
355 (strings var type &optional title save)
356 "Return an interactive `lambda'-expression that shows a popup menu.
357 This function is the action of `toolbarx-mount-popup-menu' if
358 inside XEmacs. See documentation of that function for more."
359 (let* ((menu (if (and title (stringp title))
362 (list "Dropdown menu")))
366 (real-type (if (eq type 'toggle) 'toggle 'radio))
367 (real-save (when save (if (eq save 'offer) 'offer 'always))))
368 ;; warn if type is not `radio' ot `toggle'; use `radio' if incorrect.
369 (unless (eq type real-type)
370 (warn (concat "TYPE should be symbols `radio' or `toggle', "
371 "but %s found; using `radio'")
373 ;; warn if save is not `nil', `offer' or `always'; use nil when incorrect
374 (unless (eq save real-save)
376 (display-warning 'toolbarx
377 (format (concat "SAVE should be symbols `nil', "
378 "`offer' or `always', but %s found; "
381 ;; making the menu list of vectors
382 (dolist (str strings)
383 (setq count (1+ count))
384 (setq menu-callback (list 'progn
385 (if (eq real-type 'radio)
387 `(if (memq ,count ,var)
388 (setq ,var (delete ,count ,var))
389 (setq ,var (sort (cons ,count ,var) '<))))
390 '(toolbarx-refresh)))
391 (when (eq real-save 'always)
392 (setq menu-callback (append menu-callback
393 (list (list 'customize-save-variable
394 (list 'quote var) var)))))
395 (setq menu-item (vector str menu-callback
397 :selected (if (eq real-type 'radio)
399 `(memq ,count ,var))))
400 (setq menu (append menu (list menu-item))))
401 (when (eq real-save 'offer)
402 (setq menu (append menu (list "--:shadowEtchedInDash")))
403 (setq menu (append menu (list
405 "Save state of this menu"
406 `(customize-save-variable (quote ,var)
408 ;; returnung the lambda-expression
409 `(lambda nil (interactive)
410 (let ((popup-menu-titles ,(if title t nil)))
411 (popup-menu (quote ,menu)))))))
413 (defun toolbarx-mount-popup-menu (strings var type &optional title save)
414 "Return a command that show a popup menu.
415 The return is a `lambda'-expression with a interactive declaration.
417 STRINGS is a list of strings which will be the itens of the menu.
419 VAR is a symbol that is set when an item is clicked. TYPE should
420 be one of the symbols `radio' or `toggle': `radio' means that the
421 nth item is selected if VAR is `n' and this item sets VAR to `n';
422 `toggle' means that VAR should be a list of integers and the nth
423 item is selected if `n' belongs to VAR. The item inserts or
424 deletes `n' from VAR.
426 TITLE is a string (the title of the popup menu) or nil for no
429 SAVE is one of the symbols nil, `offer' or `always'. If value
430 is nil, do not try to save anything. If it is `offer', a menu
431 item is added offering the user the possibiity to save state of
432 that dropdown menu for future sesseions (using `custom'). If it
433 is `always', state is saved every time that a item is clicked."
434 (if (featurep 'xemacs)
435 (toolbarx-xemacs-mount-popup-menu strings var type title save)
436 (toolbarx-emacs-mount-popup-menu strings var type title save)))
438 (defun toolbarx-option-value (opt)
439 "Return option value according to Emacs flavour.
440 If OPT is a vector, return first element if in Emacs or
441 second if in XEmacs. Otherwise, return OPT.
442 If OPT is vector and length is smaller than the necessary (like
443 if in XEmacs and vector has length 1), then nil is returned."
445 (if (featurep 'xemacs)
446 (when (> (length opt) 1)
448 (when (> (length opt) 0)
452 (defun toolbarx-eval-function-or-symbol (object type-test-func)
453 "Return a cons cell (GOOD-OBJ . VAL).
454 GOOD-OBJ non-nil means that VAL is a valid value, according to
455 the car of the result of TYPE-TEST-FUNCTION, that should return a
456 cons cell in the same format as the return of this function.
458 If OBJECT applied to TYPE-TEST-FUNC return (GOOD-OBJ . VAL), and
459 GOOD-OBJ is non-nil, return that. Else, check if OBJECT is a
460 function. If so, evaluate and test again with TYPE-TEST-FUNC. If
461 not a function or if GOOD-OBJ is again nil, test if OBJECT is a
462 bound symbol, evaluate that and return the result of
464 (let* ((ret (funcall type-test-func object)))
466 (if (functionp object)
468 (setq ret (funcall type-test-func (funcall object)))
470 (when (and (symbolp object) (boundp object))
471 (setq ret (funcall type-test-func (symbol-value object))))))
472 ;; ok, obj is not function; try symbol
473 (when (and (symbolp object) (boundp object))
474 (setq ret (funcall type-test-func (symbol-value object))))))
477 (defun toolbarx-test-image-type (obj)
478 "Return a cons cell (GOOD-OBJ . VAL).
479 GOOD-OBJ is non-nil if OBJ yields a valid image object VAL (see
480 documentation of function `toolbarx-process-symbol')."
481 (let ((toolbarx-test-image-type-simple
483 (let* ((val (toolbarx-option-value img))
486 (if (featurep 'xemacs)
488 (or (stringp val) ; a string
489 (glyphp val) ; or a glyph
490 (and (symbolp val) ; or a symbol bound to a
491 (boundp val) ; glyph-list
492 (check-toolbar-button-syntax
494 (lambda nil (interactive))
496 (and (listp val) ; or a glyph-or-string list
499 (dolist (i val all-obj-ok)
506 (or (stringp val) ; string
507 (and (consp val) ; or image descriptor
508 (eq (car val) 'image))
509 (and (symbolp val) ; or a symbol bound to a
510 (boundp val) ; image descriptor
511 ; (defined with `defimage')
513 (eq (car (eval val)) 'image))
514 (and (listp val) ; or list with 4 strings or
517 (dolist (i val all-obj-ok)
524 (cons good-obj val)))))
525 (toolbarx-eval-function-or-symbol obj toolbarx-test-image-type-simple)))
527 (defun toolbarx-test-button-type (obj)
528 "Return a cons cell (GOOD-OBJ . VAL).
529 GOOD-OBJ is non-nil if OBJ yields a valid button object VAL (see
530 documentation of function `toolbarx-process-symbol')."
531 (let ((toolbarx-test-button-type-simple
533 (let* ((val (toolbarx-option-value but))
534 (good-obj (if (featurep 'xemacs)
539 (memq (car val) '(:toggle :radio))))))
540 (cons good-obj val)))))
541 (toolbarx-eval-function-or-symbol obj toolbarx-test-button-type-simple)))
543 (defun toolbarx-test-any-type (obj)
544 "Return a cons cell (t . VAL).
545 If OBJ is vector, return VAL according to editor. Else, return
546 OBJ, because it is a form anyway."
547 (cons t (toolbarx-option-value obj)))
549 (defun toolbarx-test-string-or-nil (obj)
550 "Return a cons cell (GOOD-OBJ . VAL).
551 GOOD-OBJ is non-nil if OBJ yields a valid help object VAL (see
552 documentation of function `toolbarx-process-symbol')."
553 (let ((toolbarx-test-string-or-nil-simple
555 (let* ((val (toolbarx-option-value obj))
556 (good-obj (or (stringp val)
558 (cons good-obj val)))))
559 (toolbarx-eval-function-or-symbol obj toolbarx-test-string-or-nil-simple)))
561 (defun toolbarx-test-toolbar-type (obj)
562 "Return a cons cell (GOOD-OBJ . VAL).
563 GOOD-OBJ is non-nil if OBJ yields a valid toolbar property object
564 VAL (see documentation of function `toolbarx-process-symbol')."
565 (let ((toolbarx-test-toolbar-type-simple
567 (let* ((val (toolbarx-option-value obj))
568 (all-but-def-opts '(top bottom left right))
569 (all-opts '(default top bottom left right))
571 (if (featurep 'xemacs)
576 (memq (car val) all-but-def-opts)
577 (memq (cdr val) all-but-def-opts)))
580 (cons good-obj val)))))
581 (toolbarx-eval-function-or-symbol obj toolbarx-test-toolbar-type-simple)))
583 (defun toolbarx-test-dropdown-type (obj)
584 "Return a cons cell (GOOD-OBJ . VAL).
585 GOOD-OBJ is non-nil if OBJ yields a valid `:type' property object
586 VAL of a dropdown group (see documentation of function
587 `toolbarx-process-dropdown-group'."
588 (let ((toolbarx-test-dropdown-type-simple
590 (let* ((val (toolbarx-option-value obj))
591 (good-obj (memq val '(radio toggle))))
592 (cons good-obj val)))))
593 (toolbarx-eval-function-or-symbol obj toolbarx-test-dropdown-type-simple)))
595 (defun toolbarx-test-symbol (obj)
596 "Return a cons cell (GOOD-OBJ . VAL).
597 GOOD-OBJ is non-nil if OBJ yields a valid `:variable' property
598 object VAL of a dropdown group (see documentation of function
599 `toolbarx-process-dropdown-group'."
600 (let ((toolbarx-test-symbol-simple
602 (let* ((val (toolbarx-option-value obj))
603 (good-obj (symbolp val)))
604 (cons good-obj val)))))
605 (toolbarx-eval-function-or-symbol obj toolbarx-test-symbol-simple)))
607 (defun toolbarx-test-dropdown-default (obj)
608 "Return a cons cell (GOOD-OBJ . VAL).
609 GOOD-OBJ is non-nil if OBJ yields a valid `:default' property
610 object VAL of a dropdown group (see documentation of function
611 `toolbarx-process-dropdown-group'."
612 (let ((toolbarx-test-dropdown-default-simple
614 (let* ((val (toolbarx-option-value obj))
615 (good-obj (or (integerp val)
619 (setq ok (and ok (integerp i)))))))))
620 (cons good-obj val)))))
621 (toolbarx-eval-function-or-symbol obj
622 toolbarx-test-dropdown-default-simple)))
624 (defun toolbarx-test-dropdown-save (obj)
625 "Return a cons cell (GOOD-OBJ . VAL).
626 GOOD-OBJ is non-nil if OBJ yields a valid `:save' property
627 object VAL of a dropdown group (see documentation of function
628 `toolbarx-process-dropdown-group'."
629 (let ((toolbarx-test-dropdown-save-simple
631 (let* ((val (toolbarx-option-value obj))
632 (good-obj (memq val '(nil offer always))))
633 (cons good-obj val)))))
634 (toolbarx-eval-function-or-symbol obj toolbarx-test-dropdown-save-simple)))
636 (defconst toolbarx-button-props
637 (let* ((props-types-alist
638 '((:image toolbarx-test-image-type)
639 (:command toolbarx-test-any-type)
640 (:enable toolbarx-test-any-type)
641 (:visible toolbarx-test-any-type)
642 (:help toolbarx-test-string-or-nil)
643 (:insert toolbarx-test-any-type . and)
644 (:toolbar toolbarx-test-toolbar-type)
645 (:button toolbarx-test-button-type)
646 (:append-command toolbarx-test-any-type . progn)
647 (:prepend-command toolbarx-test-any-type . progn)))
648 (possible-props (nreverse (let* ((props ()))
649 (dolist (p props-types-alist props)
650 (setq props (cons (car p) props))))))
651 (props-override (nreverse (let* ((props ()))
652 (dolist (p props-types-alist props)
654 (setq props (cons (car p) props)))))))
655 (props-add (nreverse (let* ((props ()))
656 (dolist (p props-types-alist props)
658 (setq props (cons (car p) props))))))))
659 (list props-types-alist possible-props props-override props-add))
660 "List yielding all encarnations of properties of a button.
661 First element: alist, where each element is of form
662 (PROP . (TYPE-TEST-FUNCTION . ADD-OR-NIL))
663 Second is a list with all properties.
664 Third, a list with properties that override when merging.
665 Fourth, a list of lists, each in the format (PROP ADD).")
667 (defconst toolbarx-dropdown-props
668 ;; for naming dropdown properties see `Convention' in the doc string
669 (let* ((props-types-alist
670 '((:type toolbarx-test-dropdown-type)
671 (:variable toolbarx-test-symbol)
672 (:default toolbarx-test-dropdown-default)
673 (:save toolbarx-test-dropdown-save)
674 (:title toolbarx-test-string-or-nil)
675 (:dropdown-image toolbarx-test-image-type)
676 (:dropdown-enable toolbarx-test-any-type)
677 (:dropdown-visible toolbarx-test-any-type)
678 (:dropdown-insert toolbarx-test-any-type . and)
679 (:dropdown-help toolbarx-test-string-or-nil)
680 (:dropdown-toolbar toolbarx-test-toolbar-type)
681 (:dropdown-append-command toolbarx-test-any-type . progn)
682 (:dropdown-prepend-command toolbarx-test-any-type . progn)))
683 (possible-props (nreverse (let* ((props ()))
684 (dolist (p props-types-alist props)
685 (setq props (cons (car p) props))))))
686 (props-override (nreverse (let* ((props ()))
687 (dolist (p props-types-alist props)
689 (setq props (cons (car p) props)))))))
690 (props-add (nreverse (let* ((props ()))
691 (dolist (p props-types-alist props)
693 (setq props (cons (car p) props))))))))
694 (list props-types-alist possible-props props-override props-add))
695 "List yielding all encarnations of properties of a dropdown group.
696 First element: alist, where each element is of form
697 (PROP . (TYPE-TEST-FUNCTION . ADD-OR-NIL))
698 Second is a list with all properties.
699 Third, a list with properties that override when merging.
700 Fourth, a list of lists, each in the format (PROP ADD).
702 Convention: properties for the dropdown button should be formed
703 with the strings \":dropdown-\" with the button property name
704 without `:'. This is used on the implementation.")
706 (defun toolbarx-process-group-without-insert (group-without-props
707 merged-props-without-insert
708 meaning-alist switches)
709 "Return an updated version of SWITCHES.
710 GROUP-WITHOUT-PROPS and MERGED-PROPS-WITHOUT-INSERT are
711 preprocessed variables in `toolbarx-process-group'."
712 (let ((current-switches switches))
713 (dolist (i group-without-props current-switches)
714 (setq i (toolbarx-option-value i))
716 (setq current-switches
717 (toolbarx-process-symbol i meaning-alist
718 merged-props-without-insert
721 (setq current-switches
722 (toolbarx-process-group i meaning-alist
723 merged-props-without-insert
724 current-switches)))))))
726 (defun toolbarx-process-group (group meaning-alist props switches)
727 "Return an updated version of SWITCHES.
728 Append to already processed buttons (stored in SWITCHES) a
729 processed version of GROUP. Groups are useful to distribute
730 properties. External properties are given in PROPS, and merged
731 with the internal properties that are in the end of GROUP. If
732 properties (after merge) contain a `:insert' property, return a
733 list where the first and second elements are `:insert' and its
734 value, and after that a list in the same format as SWITCHES."
737 ((eq (car group) :dropdown-group)
738 (toolbarx-process-dropdown-group group meaning-alist props switches))
740 ((eq (car group) :eval-group)
741 (let ((current-switches switches))
742 (dolist (elt (cdr group) current-switches)
743 (let ((eval-elt (eval elt)))
744 (setq current-switches
745 (toolbarx-process-group (if (listp eval-elt)
749 current-switches))))))
752 (let* ((splited-props
753 (toolbarx-separate-options
754 group (append (nth 1 toolbarx-button-props)
755 (nth 1 toolbarx-dropdown-props))))
756 (intern-props (cdr splited-props))
757 (group-without-props (car splited-props))
759 (toolbarx-merge-props intern-props props
760 (append (nth 2 toolbarx-button-props)
761 (nth 2 toolbarx-dropdown-props))
762 (append (nth 3 toolbarx-button-props)
763 (nth 3 toolbarx-dropdown-props)))))
764 ;; check whether merged props have an `:insert'
765 (if (memq :insert merged-props)
766 ;; if yes, prepend switches with a (:insert cond elements)
767 (let* ((memq-ins (memq :insert merged-props))
768 (ins-val (if (and (listp (cadr memq-ins))
770 (car (cadr memq-ins))))
771 ;; if property is add-value property
774 (nth 0 toolbarx-button-props)))
775 (add-list (list (cddr p)))
777 (dolist (val (cdr (cadr memq-ins)))
778 (setq prop-good-val (funcall (cadr p) val))
779 (when (car prop-good-val)
780 (setq add-list (cons (cdr prop-good-val)
782 ;; return: (nreverse add-list)
783 (setq add-list (nreverse add-list))
784 (if (eq 2 (length add-list))
785 (cadr add-list) ; just 1 value, no
786 add-list)) ; add-function
787 ;; if property is not add-value
789 (merged-props-without-insert
790 (append (butlast merged-props (length memq-ins))
793 (toolbarx-process-group-without-insert
794 group-without-props merged-props-without-insert
797 (nreverse (cons (append (list :insert ins-val)
799 (nreverse switches))))
800 ;; if not, just append what is processed to switches
801 (toolbarx-process-group-without-insert group-without-props
802 merged-props meaning-alist
805 (defun toolbarx-process-symbol (symbol meaning-alist props switches)
806 "Process a button given by SYMBOL in MEANING-ALIST.
807 The processed button is appended in SWITCHES, which is returned.
808 Look for a association of SYMBOL in MEANING-ALIST for collecting
809 properties. Such association is a list that represents either a
810 normal button (a description of the button) or an alias
811 group (the symbol is an alias for a group of buttons). PROPS is
812 a externel list of properties that are merged and then applied to
813 the button. Scope is given by GLOBAL-FLAG."
814 ;; there are 3 situations: symbol is :new-line, there is an alias group
815 ;; or a normal button
816 (let ((button-assq (cdr (assq symbol meaning-alist))))
818 ((eq (car button-assq) :alias)
819 ;; button association is ALIAS GROUP is passed to
820 ;; `toolbarx-process-group' as is but without the car.
821 ;; return: (toolbarx-process-group... returns updates switch
822 (toolbarx-process-group (cdr button-assq) meaning-alist props switches))
824 ;; NORMAL BUTTON (association is a list of properties)
826 ;; properties need to be processed, that is, merge internal
827 ;; and external (given by PROPS) properties
828 (let* (;; button properties defined in `toolbarx-button-props'
829 (props-override (nth 2 toolbarx-button-props))
830 (props-add (nth 3 toolbarx-button-props))
831 ;; split considering also dropdown-group properties
833 (toolbarx-separate-options
835 (append (nth 1 toolbarx-button-props)
836 (nth 1 toolbarx-dropdown-props))))
837 (button-split-no-props (car button-assq-split))
838 (button-split-props (cdr button-assq-split))
839 ;; if there is no :image or :command in the props,
840 ;; try to get them from no-props part
841 (button-image-no-prop
842 (unless (memq :image button-split-props)
843 (when (> (length button-split-no-props) 0)
844 (list :image (nth 0 button-split-no-props)))))
845 (button-command-no-prop
846 (unless (memq :command button-split-props)
847 (when (> (length button-split-no-props) 1)
848 (list :command (nth 1 button-split-no-props)))))
849 (button-props (append button-split-props
851 button-command-no-prop))
853 (merged-props (toolbarx-merge-props button-props props
857 (nreverse (cons (cons symbol merged-props) (nreverse switches))))))))
859 (defun toolbarx-process-dropdown-group (dropdown meaning-alist props switches)
860 "Process buttons that appear according to dropdown menu.
861 Process a dropdown group DROPDOWN with meaning alist
862 MEANING-ALIST, external property list PROP and GLOBAL-FLAG
863 specifying scope. For a complete description, see documentation
864 of `toolbarx-install-toolbar'. The processed buttons are stored
865 in the end of SWITCHES, which is returned."
866 (let* ((dropdown-group (if (eq (car dropdown) :dropdown-group)
869 (dropdown-list-splited
870 (toolbarx-separate-options dropdown-group
872 (nth 1 toolbarx-button-props)
873 (nth 1 toolbarx-dropdown-props))))
874 (dropdown-list (car dropdown-list-splited))
875 (dropdown-props (cdr dropdown-list-splited))
877 (toolbarx-merge-props dropdown-props props
878 (append (nth 2 toolbarx-button-props)
879 (nth 2 toolbarx-dropdown-props))
880 (append (nth 3 toolbarx-button-props)
881 (nth 3 toolbarx-dropdown-props))))
882 (merged-props-button-only
883 (let* ((props-button-only)
885 (dolist (p (nth 1 toolbarx-button-props) props-button-only)
886 (setq prop (memq p merged-props))
888 (setq props-button-only
889 (append (list p (cadr prop))
890 props-button-only))))))
891 (merged-props-dropdown-only
892 (let* ((props-dropdown-only)
894 (dolist (p (nth 1 toolbarx-dropdown-props) props-dropdown-only)
895 (setq prop (memq p merged-props))
897 (setq props-dropdown-only
898 (append (list p (cadr prop))
899 props-dropdown-only))))))
900 ;; get value for each property and check type ONLY for props that do
901 ;; not concern the dropdown button, like `:type', `:save', etc. The
902 ;; props that concern the button are going to be handled in refresh
904 (filtered-dropdown-group-props-only
905 (let* ((filtered-props-temp)
909 (dolist (p (nth 0 toolbarx-dropdown-props) filtered-props-temp)
910 (unless (string-match "^:dropdown-.*$"
911 (symbol-name (car p)))
912 ;; property -> (car p)
913 ;; test type function -> (cadr p)
914 (setq prop (memq (car p) merged-props-dropdown-only))
915 ;; if so, check if value is of correct type
917 (setq prop-good-val (funcall (cadr p) (cadr prop)))
918 (if (car prop-good-val)
919 (setq filtered-props-temp
920 (append filtered-props-temp
921 (list (car p) (cdr prop-good-val))))
924 (format (concat "Wrong type for value in "
925 "property `%s' in dropdown group")
927 ;; properties for the dropdown button from dropdown merged properties
928 (dropdown-button-props
931 (dolist (pr (nth 1 toolbarx-dropdown-props))
932 (when (and (memq pr merged-props-dropdown-only)
933 (string-match "^:dropdown-\\(.*\\)$"
935 (let* ((new-pr (intern (concat ":"
936 (substring (symbol-name pr)
939 (val (cadr (memq pr merged-props-dropdown-only))))
940 (setq props (append (list new-pr val) props))))))
941 (unless (memq :image props)
942 (setq props (append (list :image "dropdown") props)))
944 (dropdown-button-without-command
945 (cons 'dropdown dropdown-button-props))
946 ;; `:type' defaults to `radio'
947 (type (if (memq :type filtered-dropdown-group-props-only)
948 (cadr (memq :type filtered-dropdown-group-props-only))
950 ;; `:default' defaults to 1 or nil depending on `type'
951 ;; if type is toggle and default is not a list, but a
952 ;; integer, set as the list with integer
954 (let* ((memq-default (memq :default
955 filtered-dropdown-group-props-only))
956 (def-temp (cadr memq-default))
957 (default-temp (if memq-default
959 (if (eq type 'radio) 1 (list 1)))))
961 ;; `:save' defaults to nil and require `:variable'
962 (save (let* ((save-temp
963 (when (memq :save filtered-dropdown-group-props-only)
965 filtered-dropdown-group-props-only)))))
968 filtered-dropdown-group-props-only)))
972 (concat "`:save' property with non-nil value should "
973 "be used only with the `:variable' property; "
974 "using value nil for `:save'."))
977 ;; `:title' defaults to nil
978 (title (when (memq :title filtered-dropdown-group-props-only)
979 (cadr (memq :title filtered-dropdown-group-props-only))))
980 ;; the menu variable is buildt from the `:variable' option or
981 ;; make a symbol not used
982 (variable (if (memq :variable filtered-dropdown-group-props-only)
983 (cadr (memq :variable
984 filtered-dropdown-group-props-only))
986 (symb (intern (format
987 "toolbarx-internal-menu-var-%d"
990 (setq count (1+ count))
992 (intern (format "toolbarx-internal-menu-var-%d"
995 ;; auxiliary variables
998 ;; setting `variable'
1000 (custom-declare-variable
1002 "Used as variable of dropdown menu defined with `toolbarx'.")
1003 (when (not (boundp variable))
1004 (set variable default)))
1005 ;; now check `variable' content
1007 (let ((val (eval variable)))
1008 (if (eq type 'toggle)
1014 ;; then, type is radio
1019 (integerp (car val)))
1022 ;; === buiding `list-strings' and `list-buttons' ===
1023 ;; if only symbols, build `list-strings' and `list-buttons' from symbols
1024 (if (let ((only-symbols-flag t))
1025 (dolist (i dropdown-list only-symbols-flag)
1026 (setq only-symbols-flag (and only-symbols-flag (symbolp i)))))
1028 (dolist (i dropdown-list)
1029 ;; list-strings and list-buttons are buildt reversed
1030 (setq list-strings (cons (toolbarx-make-string-from-symbol i)
1032 (setq count (1+ count))
1033 (setq list-buttons (cons (list i
1035 (if (eq type 'radio)
1036 (list 'eq count variable)
1037 (list 'memq count variable)))
1039 ;; if not, the it must start with string
1040 (unless (stringp (car dropdown-list))
1042 "If not all itens on dropdown are symbols, then a string"
1043 "must come before each set of buttons; no string found"
1044 "in first position."))
1047 (temp-list-buttons))
1048 (while dropdown-list
1049 (setq elem (car dropdown-list))
1050 (setq dropdown-list (cdr dropdown-list))
1052 ;; if string, output `temp-list-buttons' and prepair it again
1054 ;; list-strings and list-buttons are buildt reversed
1055 (setq list-strings (cons elem list-strings))
1056 (when temp-list-buttons
1057 (setq list-buttons (cons (append (nreverse temp-list-buttons)
1059 (if (eq type 'radio)
1065 (setq temp-list-buttons nil)
1066 (setq count (1+ count)))
1067 ;; else, if not string, just insert it to `temp-list-buttons'
1068 ;; which is also buildt reversed
1069 (setq temp-list-buttons (cons elem temp-list-buttons))))
1070 ;; output last temp list, left behind
1071 (when temp-list-buttons
1072 (setq list-buttons (cons (append (nreverse
1075 :insert (if (eq type 'radio)
1081 ;; lists were made reversed (elements inserted at the beginning)
1082 (setq list-strings (nreverse list-strings))
1083 (setq list-buttons (nreverse list-buttons))
1084 ;; now, pass `list-buttons' as a group to `toolbarx-process-group'
1085 (let ((current-switches switches))
1086 (setq current-switches
1087 (toolbarx-process-group list-buttons meaning-alist
1088 merged-props ; pass non-processed props
1090 (setq current-switches
1091 ;; outputing dropdown button
1092 (toolbarx-process-group (append dropdown-button-without-command
1094 (toolbarx-mount-popup-menu
1095 list-strings variable type
1097 meaning-alist merged-props-button-only
1103 ;; Still functions `toolbarx-install-toolbar' and `toolbarx-refresh'to
1104 ;; complete the parsing engine. Since they interface with other engines,
1105 ;; they must come in the end.
1107 ;;; How a image is made, giving a string as (part of) file name.
1109 ;; look at function `image-type-available-p' for Emacs !!!!
1111 (defun toolbarx-find-image (image)
1112 "Return image descriptor or glyph for IMAGE.
1113 In Emacs, return an image descriptor for IMAGE. In XEmacs,
1116 IMAGE is string. Usually IMAGE neither contains a directory nor
1117 an extension. If the extension is omitted, `xpm', `xbm' and
1118 `pbm' are tried. If the directory is omitted,
1119 `toolbarx-image-path' is searched."
1120 ;; `find-image' in Emacs 21 looks in `load-path' and `data-directory'. In
1121 ;; Emacs 22, we have `image-load-path' which includes `load-path' and
1122 ;; `data-directory'.
1124 ;; If there's some API in XEmacs to find the images, we should use it
1125 ;; instead of locate-library.
1127 ;; Emacs 22 has locate-file, but the other Emacsen don't. The
1128 ;; following should hopefully get us to all images ultimately.
1131 (dolist (i '("" ".xpm" ".xbm" ".pbm"))
1133 (setq file (locate-library (concat image i) t toolbarx-image-path))))
1134 (if (featurep 'xemacs)
1135 (and file (make-glyph file))
1138 (find-image `((:type xpm :file ,(concat image ".xpm"))
1139 (:type xbm :file ,(concat image ".xbm"))
1140 (:type pbm :file ,(concat image ".pbm"))))))))
1142 ;; next variable interfaces between parsing and display engines
1143 (defvar toolbarx-internal-button-switches nil
1144 "Store the list of processed buttons, used by `toolbarx-refresh'.
1145 This variable can store different values for the different buffers.")
1148 (toolbarx--if-when-compile (not (featurep 'xemacs))
1149 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1150 ;;; Second engine: display parsed buttons in Emacs
1152 (defun toolbarx-emacs-add-button (button used-keys keymap)
1153 "Insert a button where BUTTON is its description.
1154 USED-KEYS should be a list of symbols, where the first element is
1155 `:used-symbols'. This list should store the symbols of the
1156 buttons already inserted. This list is changed by side effect.
1157 KEYMAP is the keymap where the menu-item corresponding to the
1158 tool-bal button is going to be inserted. Insertion is made in
1161 BUTTON should be a list of form (SYMBOL . PROP-LIST). SYMBOL is
1162 a symbol that \"names\" this button. PROP-LIST is a list in the
1163 format (PROP VAL ... PROP VAL). The supported properties are
1164 `:image', `:command', `:append-command', `:prepend-command',
1165 `:help', `:enable', `:visible', `:button', `:insert' and
1166 `:toolbar'. For a description of properties, see documentation of
1167 function `toolbar-install-toolbar'."
1168 (let* ((symbol (nth 0 button))
1169 (used-keys-list (when used-keys
1172 (let* ((filtered-props-temp)
1175 (dolist (p (nth 0 toolbarx-button-props) filtered-props-temp)
1176 ;; property -> (car p)
1177 ;; test type function -> (cadr p)
1178 ;; add-function -> (cddr p)
1179 (setq prop (memq (car p) button))
1180 ;; if so, check if value is of correct type
1182 ;; if property is of add-type, them the value is a list
1183 ;; (:add-value-list VAL VAL). Each VAL should be checked.
1184 (if (and (cddr p) (eq :add-value-list (car (cadr prop))))
1185 (let* ((add-list (list (cddr p))))
1186 (dolist (val (cdr (cadr prop)))
1187 (setq prop-good-val (funcall (cadr p) val))
1188 (when (car prop-good-val)
1189 (setq add-list (cons (cdr prop-good-val) add-list))))
1190 (setq add-list (nreverse add-list))
1191 (when (eq 2 (length add-list)) ; just 1 value, no
1193 (setq add-list (cadr add-list)))
1194 (setq filtered-props-temp (append
1195 (list (car p) add-list)
1196 filtered-props-temp)))
1197 ;; if override-property
1198 (setq prop-good-val (funcall (cadr p) (cadr prop)))
1199 (when (car prop-good-val)
1200 (setq filtered-props-temp (append
1202 (cdr prop-good-val))
1203 filtered-props-temp))))))))
1204 (insert (or (not (memq :insert filtered-props))
1205 ;; (memq :insert filtered-props)
1206 (eval (nth 1 (memq :insert filtered-props))))))
1210 ;; symbol is not :new-line, therefore a normal button
1211 (let* ((image (cadr (memq :image filtered-props)))
1213 (when (memq :image filtered-props)
1215 ((stringp image) ; string
1216 (toolbarx-find-image image))
1217 ((and (consp image) ; or image descriptor
1218 (eq (car image) 'image))
1220 ((and (symbolp image) ; or a symbol bound to a
1221 (boundp image) ; image descriptor (defined
1223 (consp (eval image))
1224 (eq (car (eval image)) 'image))
1226 (t ; otherwise, must be a list
1227 ; with 4 strings or image
1229 (apply 'vector (mapcar (lambda (img)
1231 (toolbarx-find-image img)
1235 (let* ((com (nth 1 (memq :command filtered-props)))
1236 (app (nth 1 (memq :append-command filtered-props)))
1237 (prep (nth 1 (memq :prepend-command filtered-props))))
1238 (when (or com app prep)
1239 (toolbarx-make-command com prep app))))
1240 (help (cons (memq :help filtered-props)
1241 (cadr (memq :help filtered-props))))
1242 (enable (cons (memq :enable filtered-props)
1243 (cadr (memq :enable filtered-props))))
1244 (visible (cons (memq :visible filtered-props)
1245 (cadr (memq :visible filtered-props))))
1246 (button (cons (memq :button filtered-props)
1247 (cadr (memq :button filtered-props))))
1250 (toolbarx-make-string-from-symbol symbol)
1252 :image image-descriptor)
1254 (list :help (cdr help)))
1256 (list :enable (cdr enable)))
1258 (list :visible (cdr visible)))
1260 (list :button (cdr button)))))
1264 (while (memq symb used-keys-list)
1265 (setq count (1+ count))
1266 (setq symb (intern (format "%s-%d" symbol count))))
1268 (when (and image-descriptor command)
1269 (setq used-keys-list (cons key-not-used used-keys-list))
1270 (define-key-after keymap
1271 (vector key-not-used) menuitem))))))
1272 (when used-keys (setcdr used-keys used-keys-list))))
1275 (defun toolbarx-emacs-refresh-process-button-or-insert-list (switches
1278 "Process SWITCHES, inserting buttons in `tool-bar-map'.
1279 If a button is actually a `:insert' clause group (if `car' is
1280 `:insert') and evaluation of `cdr' yields non-nil, process `cddr'
1281 recursively as SWITCHES. USED-KEYS is a list which `car' is
1282 `:used-symbols' and which `cdr' is a list of symbols that have already
1283 been used as keys in the keymap `tool-bar-map'."
1284 (dolist (button switches)
1285 (if (eq (car button) :insert)
1286 (when (eval (cadr button))
1287 (toolbarx-emacs-refresh-process-button-or-insert-list (cddr button)
1290 (toolbarx-emacs-add-button button used-keys keymap))))
1294 (defun toolbarx-emacs-refresh (&optional global-flag)
1295 "Refresh and redraw the toolbar in Emacs.
1296 If GLOBAL-FLAG is non-nil, the default value of toolbar switches
1297 is used and the default value of `toolbarx-map' is changed."
1298 (let* ((switches (if global-flag
1299 (if (default-boundp 'toolbarx-internal-button-switches)
1300 (default-value 'toolbarx-internal-button-switches)
1301 toolbarx-internal-button-switches)
1302 toolbarx-internal-button-switches))
1303 (used-keys (list :used-symbols nil))
1304 (tool-bar-map-temp (make-sparse-keymap)))
1305 (toolbarx-emacs-refresh-process-button-or-insert-list switches used-keys
1308 (setq-default tool-bar-map tool-bar-map-temp)
1309 (setq tool-bar-map tool-bar-map-temp)))))
1312 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1313 ;;; Third engine: display parsed buttons in XEmacs
1315 (defun toolbarx-xemacs-image-properties (image)
1316 "Return a list of properties of IMAGE.
1317 IMAGE should be a string or a list of one to six strings or
1318 glyphs or nil, or a symbol bound to a list of one to six
1319 glyphs (them must be a valid image list, like one created with
1320 the function `toolbar-make-button-list'). Return a
1321 list (GLYPH-LIST HEIGHT WIDTH) where HEIGHT (resp. WIDTH) is the
1322 maximum of the heights (resp. widths) of all glyphs (or strings
1323 converted to glyphs) in GLYPH-LIST. If IMAGE is not a list, it
1324 is treated as a list with IMAGE as only element. Strings are
1325 converted to glyphs with the function `toolbarx-find-image'. If,
1326 after possible string-to-glyph convertions, the list of glyphs
1327 has nil as first element, GLYPH-LIST becomes nil."
1329 (if (symbolp image) ; if symbol, them must be a
1330 ; valid image list, like
1331 ; created by function
1332 ; `toolbar-make-button-list'
1334 (let ((img-list (if (listp image)
1339 (setq glyph-list-temp
1340 (dolist (glyph img-list (nreverse glyph-list-temp))
1342 (setq glyph-list-temp
1343 (cons (toolbarx-find-image glyph)
1345 (setq glyph-list-temp (cons glyph glyph-list-temp)))))
1346 (unless (car glyph-list-temp)
1347 (setq glyph-list-temp nil))
1350 ;; computing inheritage
1351 (let* ((usable-temp))
1352 (if toolbar-captioned-p ; problematic point :-(
1354 ;; CAP-UP: cap-up -> up
1355 (setq usable-temp (cons (cond
1356 ((nth 3 glyph-list))
1357 ((nth 0 glyph-list)))
1359 ;; CAP-DOWN: cap-down -> cap-up -> down -> up
1360 (setq usable-temp (cons (cond
1361 ((nth 4 glyph-list))
1362 ((nth 3 glyph-list))
1363 ((nth 1 glyph-list))
1364 ((nth 0 glyph-list)))
1366 ;; CAP-DISABLED: cap-disabled -> cap-up -> disabled -> up
1367 (setq usable-temp (cons (cond
1368 ((nth 5 glyph-list))
1369 ((nth 3 glyph-list))
1370 ((nth 2 glyph-list))
1371 ((nth 0 glyph-list)))
1374 (setq usable-temp (cons (nth 0 glyph-list) usable-temp))
1376 (setq usable-temp (cons (cond
1377 ((nth 1 glyph-list))
1378 ((nth 0 glyph-list)))
1380 ;; DISABLED: disabled -> up
1381 (setq usable-temp (cons (cond
1382 ((nth 2 glyph-list))
1383 ((nth 0 glyph-list)))
1386 (height (apply 'max 0 (mapcar (lambda (glyph)
1388 (glyph-height glyph)
1391 (width (apply 'max 0 (mapcar (lambda (glyph)
1396 (list (if (symbolp image) image glyph-list) height width)))
1400 (defun toolbarx-xemacs-button-properties (button)
1401 "Return a list of properties of BUTTON.
1402 The result is either nil (if not to be inserted) or a list in the format
1403 (TOOLBAR HEIGHT WIDTH BUTTON-DESCRIPTION)
1406 TOOLBAR is one of the symbols `default', `top', `right', `bottom'
1409 HEIGHT and WIDTH are the maximal dimentions of all the glyphs
1412 BUTTON-DESCRIPTION is button definition in XEmacs; see the
1413 documentation of variable `default-toolbar'."
1414 (let* ((filtered-props
1415 (let* ((filtered-props-temp)
1418 (dolist (p (nth 0 toolbarx-button-props) filtered-props-temp)
1419 ;; property -> (car p)
1420 ;; test type function -> (cadr p)
1421 ;; add-function -> (cddr p)
1422 (setq prop (memq (car p) button))
1423 ;; if so, check if value is of correct type
1425 ;; if property is of add-type, them the value is a list
1426 ;; (:add-value-list VAL VAL). Each VAL should be checked.
1427 (if (and (cddr p) (eq :add-value-list (car (cadr prop))))
1428 (let* ((add-list (list (cddr p))))
1429 (dolist (val (cdr (cadr prop)))
1430 (setq prop-good-val (funcall (cadr p) val))
1431 (when (car prop-good-val)
1432 (setq add-list (cons (cdr prop-good-val) add-list))))
1433 (setq add-list (nreverse add-list))
1434 (when (eq 2 (length add-list)) ; just 1 value, no
1436 (setq add-list (cadr add-list)))
1437 (setq filtered-props-temp (append
1438 (list (car p) add-list)
1439 filtered-props-temp)))
1440 ;; if override-property
1441 (setq prop-good-val (funcall (cadr p) (cadr prop)))
1442 (when (car prop-good-val)
1443 (setq filtered-props-temp (append
1445 (cdr prop-good-val))
1446 filtered-props-temp))))))))
1447 (insert (or (not (memq :insert filtered-props))
1448 ;; (memq :insert filtered-props) holds
1449 (eval (nth 1 (memq :insert filtered-props))))))
1451 (let* ((image-props (toolbarx-xemacs-image-properties
1452 (cadr (memq :image filtered-props))))
1453 (glyph-list (car image-props))
1454 (image-height (nth 1 image-props))
1455 (image-width (nth 2 image-props))
1457 (let* ((com (nth 1 (memq :command filtered-props)))
1458 (app (nth 1 (memq :append-command filtered-props)))
1459 (prep (nth 1 (memq :prepend-command filtered-props))))
1460 (when (or com app prep)
1461 (toolbarx-make-command com prep app))))
1462 ;; enable defaults to `t'
1463 (enable (if (memq :enable filtered-props)
1464 (cadr (memq :enable filtered-props))
1466 ;; help defaults to nil
1467 (help (when (memq :help filtered-props)
1468 (cadr (memq :help filtered-props))))
1469 ;; toolbar defaults to `default'
1470 (toolbar-prop (cons (memq :toolbar filtered-props)
1471 (cadr (memq :toolbar filtered-props))))
1472 (toolbar (if (car toolbar-prop)
1473 (if (symbolp (cdr toolbar-prop))
1475 ;; (cdr toolbar-prop) is cons cell
1476 (if (eq (cadr toolbar-prop)
1477 (default-toolbar-position))
1479 (cadr toolbar-prop)))
1482 (list toolbar image-height image-width
1483 (vector glyph-list command enable help)))))))
1485 (defun toolbarx-xemacs-refresh-process-button-or-insert-list (switches
1487 "Process SWITCHES, returning an updated version of TOOLBAR-PROPS.
1488 TOOLBAR-PROPS should be a list with 12 elements, each one representing
1489 properties (in this order) `locale', `default', `top', `right',
1490 `bottom', `left', `default-height', `default-width', `top-height',
1491 `right-width', `bottom-height' and `left-width'. The return is a list
1492 with the same properties updated.
1494 NB: Buttons (vectors) are inserted in front of the lists
1495 represented by `default', `top', `right', `bottom' and `left', so
1496 the lists are built reversed."
1497 (let ((locale (nth 0 toolbar-props))
1498 (default (nth 1 toolbar-props))
1499 (top (nth 2 toolbar-props))
1500 (right (nth 3 toolbar-props))
1501 (bottom (nth 4 toolbar-props))
1502 (left (nth 5 toolbar-props))
1503 (default-height (nth 6 toolbar-props))
1504 (default-width (nth 7 toolbar-props))
1505 (top-height (nth 8 toolbar-props))
1506 (right-width (nth 9 toolbar-props))
1507 (bottom-height (nth 10 toolbar-props))
1508 (left-width (nth 11 toolbar-props))
1509 (toolbar-props-temp))
1510 (dolist (button switches)
1511 (if (eq (car button) :insert)
1512 (when (eval (cadr button))
1513 ;; if insert group, process `cddr'
1515 (setq toolbar-props-temp
1516 (toolbarx-xemacs-refresh-process-button-or-insert-list
1518 (list locale default top right bottom left
1519 default-height default-width top-height
1520 right-width bottom-height left-width)))
1521 (setq default (nth 1 toolbar-props-temp))
1522 (setq top (nth 2 toolbar-props-temp))
1523 (setq right (nth 3 toolbar-props-temp))
1524 (setq bottom (nth 4 toolbar-props-temp))
1525 (setq left (nth 5 toolbar-props-temp))
1526 (setq default-height (nth 6 toolbar-props-temp))
1527 (setq default-width (nth 7 toolbar-props-temp))
1528 (setq top-height (nth 8 toolbar-props-temp))
1529 (setq right-width (nth 9 toolbar-props-temp))
1530 (setq bottom-height (nth 10 toolbar-props-temp))
1531 (setq left-width (nth 11 toolbar-props-temp))))
1532 ;; else, if normal button
1533 (let* ((button-props (toolbarx-xemacs-button-properties button))
1534 (toolbar (nth 0 button-props))
1535 (height (nth 1 button-props))
1536 (width (nth 2 button-props))
1537 (button-description (nth 3 button-props)))
1541 ((eq toolbar 'default)
1542 (setq default (cons button-description default))
1543 (setq default-height (max default-height height))
1544 (setq default-width (max default-width width)))
1547 (setq top (cons button-description top))
1548 (setq top-height (max top-height height)))
1550 ((eq toolbar 'right)
1551 (setq right (cons button-description right))
1552 (setq right-width (max right-width width)))
1554 ((eq toolbar 'bottom)
1555 (setq bottom (cons button-description bottom))
1556 (setq bottom-height (max bottom-height height)))
1559 (setq left (cons button-description left))
1560 (setq left-width (max left-width width))))))))
1561 ;; return a list similar to toolbar-props
1562 (list locale default top right bottom left default-height
1563 default-width top-height right-width bottom-height left-width)))
1566 (defun toolbarx-xemacs-refresh (&optional global-flag)
1567 "Refresh the toolbar in XEmacs."
1568 (let* ((switches (if global-flag
1569 (if (default-boundp 'toolbarx-internal-button-switches)
1570 (default-value 'toolbarx-internal-button-switches)
1571 toolbarx-internal-button-switches)
1572 toolbarx-internal-button-switches))
1573 (locale (if global-flag 'global (current-buffer)))
1574 (toolbar-init (list locale ; locale
1587 (toolbarx-xemacs-refresh-process-button-or-insert-list switches
1589 ;; NB: Buttons (vectors) are inserted in front of the lists
1590 ;; represented by `default', `top', `right', `bottom' and
1591 ;; `left', so the lists are built reversed.
1592 (default (nreverse (nth 1 toolbar-props)))
1593 (top (nreverse (nth 2 toolbar-props)))
1594 (right (nreverse (nth 3 toolbar-props)))
1595 (bottom (nreverse (nth 4 toolbar-props)))
1596 (left (nreverse (nth 5 toolbar-props)))
1597 (default-height (nth 6 toolbar-props))
1598 (default-width (nth 7 toolbar-props))
1599 (top-height (nth 8 toolbar-props))
1600 (right-width (nth 9 toolbar-props))
1601 (bottom-height (nth 10 toolbar-props))
1602 (left-width (nth 11 toolbar-props))
1603 (button-raised-border 2)
1604 (default-border (specifier-instance default-toolbar-border-width))
1605 (top-border (specifier-instance top-toolbar-border-width))
1606 (right-border (specifier-instance right-toolbar-border-width))
1607 (bottom-border (specifier-instance bottom-toolbar-border-width))
1608 (left-border (specifier-instance left-toolbar-border-width)))
1611 (setq default-height (+ (* 2 button-raised-border)
1612 (* 2 default-border)
1614 (setq default-width (+ (* 2 button-raised-border)
1615 (* 2 default-border)
1618 (setq top-height (+ (* 2 button-raised-border)
1622 (setq right-width (+ (* 2 button-raised-border)
1626 (setq bottom-height (+ (* 2 button-raised-border)
1630 (setq left-width (+ (* 2 button-raised-border)
1633 ;; deal with specifiers
1634 ;; - remove all specifiers for toolbars witout buttons
1637 ;; Only activate the tool bar if it is already visible.
1638 (when toolbar-visible-p
1639 (set-specifier default-toolbar-visible-p (not (not default)) locale)
1640 (if (memq (default-toolbar-position) '(top bottom))
1641 (set-specifier default-toolbar-height default-height locale)
1642 (set-specifier default-toolbar-width default-width locale)))
1643 (set-specifier default-toolbar default locale))
1644 (remove-specifier default-toolbar locale)
1645 (remove-specifier default-toolbar-visible-p locale)
1646 (remove-specifier default-toolbar-height locale)
1647 (remove-specifier default-toolbar-width locale))
1650 (set-specifier top-toolbar-visible-p (not (not top)) locale)
1651 (set-specifier top-toolbar-height top-height locale)
1652 (set-specifier top-toolbar top locale))
1653 (remove-specifier top-toolbar locale)
1654 (remove-specifier top-toolbar-visible-p locale)
1655 (remove-specifier top-toolbar-height locale))
1658 (set-specifier right-toolbar-visible-p (not (not right))
1660 (set-specifier right-toolbar-width right-width locale)
1661 (set-specifier right-toolbar right locale))
1662 (remove-specifier right-toolbar locale)
1663 (remove-specifier right-toolbar-visible-p locale)
1664 (remove-specifier right-toolbar-width locale))
1667 (set-specifier bottom-toolbar-visible-p (not (not bottom)) locale)
1668 (set-specifier bottom-toolbar-height bottom-height locale)
1669 (set-specifier bottom-toolbar bottom locale))
1670 (remove-specifier bottom-toolbar locale)
1671 (remove-specifier bottom-toolbar-visible-p locale)
1672 (remove-specifier bottom-toolbar-height locale))
1675 (set-specifier left-toolbar-visible-p (not (not left)) locale)
1676 (set-specifier left-toolbar-width left-width locale)
1677 (set-specifier left-toolbar left locale))
1678 (remove-specifier left-toolbar locale)
1679 (remove-specifier left-toolbar-visible-p locale)
1680 (remove-specifier left-toolbar-width locale))))))
1683 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1684 ;;; finishing parsing engine
1686 (defun toolbarx-refresh (&optional global-flag)
1687 "Redraw the toolbar, peviously installed with `toolbarx'.
1688 Force global refresh if GLOBAL-FLAG is non-nil."
1690 (if (featurep 'xemacs)
1691 (toolbarx-xemacs-refresh global-flag)
1692 (toolbarx-emacs-refresh global-flag)))
1694 ;;;###autoload (autoload 'toolbarx-install-toolbar "toolbar-x")
1696 (defun toolbarx-install-toolbar (buttons &optional meaning-alist global-flag)
1697 "Install toolbar buttons given in BUTTONS.
1698 Button properties are optionally given in MEANING-ALIST. If
1699 GLOBAL-FLAG is non-nil, toolbar is installed globally (on every
1700 buffer that does not have a toolbar set locally). BUTTONS is a
1702 (ELEM ... ELEM . PROPS),
1703 where each ELEM is either
1705 - a list in the same format od BUTTONS, which is going to be
1706 refered as a *group*; groups are used to distribute properties
1707 recursively to its elements; there are groups with special
1708 format for special purpose: *dropdown groups* and also *eval
1711 - a symbol, which could be associated in MEANING-ALIST with a
1712 list of button properties (symbol + properties = a *button*)
1713 or associated to a special kind of group (an *alias group*).
1715 - a vector, which elements are on the previous formats (but not
1716 another vector); this is useful to specify different
1717 ingredients to the toolbar depending if editor is Emacs or
1718 XEmacs; the first element will be used in Emacs; the second
1719 element is going to be used in XEmacs.
1724 MEANING-ALIST is a list where each element is in one of the
1725 formats (SYMB . BUTTON-PROPS-LIST) or (SYMB . ALIAS-GROUP).
1726 BUTTON-PROPS-LIST is a list in one of the formats
1727 (IMAGE COMMAND PROP VAL PROP VAL ... PROP VAL) or
1728 (PROP VAL PROP VAL ... PROP VAL).
1729 The IMAGE is going to be used as the `:image' property of the
1730 button (see button properties bellow), and COMMAND shall be used
1731 as the `:command' property of the button. Each PROP is one of
1732 the button properties, and VAL is its respective value.
1733 ALIAS-GROUP is a list which first element is the symbol `:alias'
1734 and the cdr shall be processed as a group.
1736 However, a symbol is not required to have an association in
1737 MEANING-ALIST, which is only a way to specify properties to a
1738 button. One can use groups to specify properties. Nil is a good
1744 A toolbar button in `toolbarx' is the set with a symbol and
1745 properties used to display the button, like a image and a command
1746 to call when the button is pressed (which are the minimal
1747 elements that a button should have.) The supported properties
1748 for buttons and their `basic types' (see note on how values of
1749 properties are obtained!) are:
1751 :image -- in Emacs, either a string or image descriptor (see
1752 info for a definition), or a variable bound to a image
1753 descriptor (like those defined with `defimage') or a list of 4
1754 strings or image descriptors; in XEmacs, either a string or a
1755 glyph, or a symbol bount to a glyph, or a list of at least 1
1756 and at most 6 strings or glyphs or nil (not the first element
1757 though); defines the image file displayed by the button. If
1758 it is a string, the image file found with that name (always
1759 using the function `toolbarx-find-image' to make the
1760 \`internal\' image descriptor) is used as button image. For
1761 the other formats, the button image is handled in the same way
1762 as it is treated by the editors; see info nodes bellow for a
1763 description of the capabilities of each editor
1764 Emacs: info file \"elisp\", node \"Tool Bar\" (see `:image'
1766 PS: a *vector* of four strings is used in the Emacs
1767 Lisp documentation as the `more ellaborated' image
1768 property format, but here we reserve vectors to
1769 provide editor-dependent values; this motivates our
1770 choice for a list instead of vector (however,
1771 internally the list becomes a vector when displaying
1773 XEmacs: info file \"lispref\", node \"Toolbar Descriptor
1774 Format\" (see GLYPH-LIST) or the documentation of
1775 the variable `default-toolbar'; check the inheritage
1776 in case of a ommited glyph or nil instead of glyph.
1778 :command -- a form; if the form happens to be a command, it will
1779 be called with `call-interactively'.
1781 :append-command -- a form added to the end of the value of
1784 :prepend-command -- a form added at the beginning of the value
1787 :help -- either a string or nil; defined the help string of the
1790 :enable -- a form, evaluated constantly by both editors to
1791 determine if a button is active (enabled) or not.
1793 :visible -- in Emacs, a form that is evaluated constantly to
1794 determine if a button is visible; in XEmacs, this property is
1797 :button -- in Emacs, a cons cell (TYPE . SELECTED) where the
1798 TYPE should be `:toggle' or `:radio' and the cdr should be a
1799 form. SELECTED is evaluated to determine when the button is
1800 selected. This property is ignored in XEmacs.
1802 :insert -- a form that is evaluated every time that the toolbar
1803 is refresh (a call of `toolbarx-refresh') to determine if the
1804 button is inserted or just ignored (until next refresh).
1806 :toolbar -- in XEmacs, either one of the symbols `default',
1807 `top', `bottom', `left', `right', or a cons cell
1808 (POS . POS-AVOID-DEFAULT) where POS and POS-AVOID-DEFAULT
1809 should be one of the symbols `top', `bottom', `left', `right';
1810 if a symbol, the button will be inserted in one of these
1811 toolbars; if a cons cell, button will be inserted in toolbar
1812 POS unless the position of the default toolbar is POS (then,
1813 the default toolbar would override the position-specific
1814 toolbar), and in this case, button will be inserted in toolbar
1815 POS-AVOID-DEFAULT; in Emacs, this property is meaningless, and
1816 therefore ignored. Hint of use of this property: in a
1817 program, use or everything with `default' and the cons format
1818 to avoid the default toolbar, or use only the position
1819 specific buttons (symbols that are not `default'), because of
1820 the `overriding' system in XEmacs, when a position-specific
1821 toolbar overrides the default toolbar; for instance, if you
1822 put a button in the default toolbar and another in the top
1823 toolbar (and the default toolbar is in the top), then *only*
1824 the ones in the top toolbar will be visible!
1826 How to specify a button
1827 =======================
1829 One can specify a button by its symbol or by a group to specify
1830 properties. For example,
1833 (bar :image [\"bar-Emacs\" \"bar-XEmacs\"]
1834 :command bar-function :help \"Bar help string\")
1836 MEANING-ALIST = ( (foo :image \"foo\" :command foo-function) )
1837 specifiy two buttons `foo' and `bar', each one with its necessary
1838 :image and :command properties, and both use the :insert property
1839 specified ate the end of BUTTONS (because groups distribute
1840 properties to all its elements). `foo' and `bar' will be
1841 inserted only if `foo-bar' evaluation yields non-nil. `bar' used
1842 a different :image property depending if editor is Emacs or
1845 Note on how values of properties are obtained
1846 =============================================
1848 For each property PROP, its value should be either:
1849 i) a vector of 2 elements; then each element should be of the
1851 ii) an element on the basic type of PROP.
1852 iii) a function (that does not need arguments); it is evaluated
1853 and the return should be ot type i) or ii) above
1854 iv) a symbol bound to a element of type i) or ii).
1856 The type is cheched in the order i), ii) iii) and iv). This
1857 evaluations are done every time that the oolbar is refresh.
1859 Ps.: in order to specify a vector as value of a property (like
1860 the :image in Emacs), it is necessary to provide the vector as
1861 element of another vector.
1869 If the first element of a group is the symbol `:eval-group', each
1870 element is evaluated (with `eval'), put inside a list and
1871 processed like a group. Eval groups are useful to store
1872 definition of buttons in a variable.
1877 The idea is to specify a set of buttons that appear when a
1878 determined menu item of a dropdown menu is active. The dropdown
1879 menu appears when a button (by default with a triangle pointing
1880 down) is clicked. This button is called `dropdown button'. The
1881 dropdown button appears on the left of the currently visible
1882 buttons of the dropdown group.
1884 A dropdown group is a list which first element is the symbol
1885 `:dropdown-group' and in one of the following formats
1886 (:dropdown-group SYMBOL-1 ... SYMBOL-n PROP-1 VAL-1 ... PROP-k VAL-k)
1889 STRING-1 ITEM-11 ... ITEM-1n
1890 STRING-2 ITEM-21 ... ITEM-2m
1892 STRING-n ITEM-n1 ... ITEM-np
1893 PROP-1 VAL-1 ... PROP-j VAL-j)
1895 SYMBOL-* is a symbol that defines a button in MEANING-ALIST;
1896 STRING-* is a string that will appear in the dropdown menu;
1897 ITEM-* is any format that define buttons or groups.
1899 \(a dropdown group of first format is internally converted to the
1900 second by making strings from the symbols and each symbol is the
1903 The same rules for obtaining property values, described above,
1904 apply here. Properties are also distributed by groups. The
1905 supported properties and their basic type are:
1907 :type -- one of the symbols `radio' (default) or `toggle'; if
1908 type is radio, only one of the itens may be active, and if
1909 type is toggle, any item number of itens can be active.
1911 :variable -- a symbol; it is the variable that govern the
1912 dropdown button; every time the value should be an integer
1913 starting from 1 (if type is radio) or a list of integers (if
1914 type is toggle). The Nth set of buttons is :insert'ed.
1916 :default -- determines the default value when the menu is
1917 installed; it is ignored if a value was saved with custom; it
1918 defaults to 1 if type is radio or nil if type is toggle. If
1919 value is a integer and type is `toggle', value used is a list
1922 :save -- one of the symbols nil (default), `offer' or
1923 `always'; determined if it is possible for the user to save
1924 the which menu itens are active, for a next session. If value
1925 is `offer', a item (offering to save) is added to the
1926 popup menu. If the value is `always', every time that a item
1927 is selected, the variable is saved. If value is nil, variable
1928 shall not be saved. If value is non-nil then `:variable' is
1931 :title -- a string or nil; if a string, the popup menu will show
1932 is as menu title; if nil, no title is shown.
1934 :dropdown-help -- a string or nil; the help string of the
1937 :dropdown-image -- in Emacs, either a string or a vector of 4
1938 strings; in XEmacs, either a string or a glyph or a list of at
1939 least 1 and at most 6 strings or glyphs; defines the image
1940 file displayed by the dropdown button; by default, it is the
1941 string \"dropdown\".
1943 :dropdown-append-command,
1944 :dropdownprepend-command -- a form; append or prepend forms to
1945 the command that shows the dropdown menu, allowing extra code
1946 to run before or after the menu appears (remember that every
1947 menu item clicked refresh the toolbar.)
1949 :dropdown-enable -- a form; evaluated constantly by both editors
1950 to determine if the dropdown button is active (enabled) or
1953 :dropdown-visible -- a form; in Emacs, it is evaluated
1954 constantly to determine if the dropdown button is visible; in
1955 XEmacs, this property is ignored.
1957 :dropdown-toolbar -- in XEmacs, one of the symbols `default',
1958 `opposite', `top', `bottom', `left' or `right'; ignored in
1959 Emacs; in XEmacs, the toolbar where the dropdown button will
1962 Also, if the symbol `dropdown' is associted in MEANING-ALIST
1963 with some properties, these properties override (or add) with
1969 If the symbol of a button is `:new-line', it is inserted
1970 a (faked) return, and the next button will be displayed a next
1971 line of buttons. The only property supported for this button is
1972 `:insert'. This feature is available only in Emacs. In XEmacs,
1973 this button is ignored."
1974 (let ((switches (toolbarx-process-group buttons meaning-alist nil nil)))
1976 (setq-default toolbarx-internal-button-switches
1978 (set (make-local-variable 'toolbarx-internal-button-switches)
1980 (unless (featurep 'xemacs)
1981 (make-local-variable 'tool-bar-map))))
1982 (toolbarx-refresh global-flag))
1985 (defconst toolbarx-default-toolbar-meaning-alist
1986 `((separator :image "sep" :command t :enable nil :help "")
1988 (,(if (and (not (featurep 'xemacs)) (>= emacs-major-version 22))
1991 :image ["new" toolbar-file-icon]
1992 :command [find-file toolbar-open]
1993 :enable [(not (window-minibuffer-p
1994 (frame-selected-window menu-updating-frame)))
1996 :help ["Specify a new file's name, to edit the file" "Visit new file"])
1998 ,(when (and (not (featurep 'xemacs)) (>= emacs-major-version 22))
1999 '(open-file :image ["open" toolbar-file-icon]
2000 :command [menu-find-file-existing toolbar-open]
2001 :enable [(not (window-minibuffer-p
2002 (frame-selected-window menu-updating-frame)))
2004 :help ["Read a file into an Emacs buffer" "Open a file"]))
2006 (dired :image [,(if (>= emacs-major-version 22)
2009 toolbar-folder-icon]
2010 :command [dired toolbar-dired]
2011 :help ["Read a directory, operate on its files" "Edit a directory"])
2013 (save-buffer :image ["save" toolbar-disk-icon]
2014 :command [save-buffer toolbar-save]
2018 (not (window-minibuffer-p
2019 (frame-selected-window menu-updating-frame))))
2021 :help ["Save current buffer to its file" "Save buffer"]
2022 :visible (or buffer-file-name
2024 (get major-mode 'mode-class)))))
2027 (write-file :image "saveas"
2030 (window-minibuffer-p
2031 (frame-selected-window menu-updating-frame)))
2033 :help "Write current buffer to another file"
2034 :visible (or buffer-file-name
2035 (not (eq 'special (get major-mode 'mode-class)))))
2037 (undo :image ["undo" toolbar-undo-icon]
2038 :command [undo toolbar-undo]
2039 :enable [(and (not buffer-read-only)
2040 (not (eq t buffer-undo-list))
2041 (if (eq last-command 'undo)
2043 (consp buffer-undo-list)))
2045 :help ["Undo last operation" "Undo edit"]
2046 :visible (not (eq 'special (get major-mode 'mode-class))))
2048 (cut :image ["cut" toolbar-cut-icon]
2049 :help ["Delete text in region and copy it to the clipboard"
2051 :command [clipboard-kill-region toolbar-cut]
2052 :visible (not (eq 'special (get major-mode 'mode-class))))
2054 (copy :image ["copy" toolbar-copy-icon]
2055 :help ["Copy text in region to the clipboard" "Copy region"]
2056 :command [clipboard-kill-ring-save toolbar-copy])
2058 (paste :image ["paste" toolbar-paste-icon]
2059 :help ["Paste text from clipboard" "Paste from clipboard"]
2060 :command [clipboard-yank toolbar-paste]
2061 :visible (not (eq 'special (get major-mode 'mode-class))))
2064 (search-forward :command nonincremental-search-forward
2065 :help "Search forward for a string"
2070 :image ["search-replace" toolbar-replace-icon]
2071 :command [query-replace toolbar-replace]
2072 :help ["Replace string interactively, ask about each occurrence"
2073 "Search & Replace"])
2075 (print-buffer :image ["print" toolbar-printer-icon]
2076 :command [print-buffer toolbar-print]
2077 :help ["Print current buffer with page headings"
2081 (customize :image "preferences"
2083 :help "Edit preferences (customize)"
2088 :command (lambda () (interactive) (popup-menu menu-bar-help-menu))
2089 :help "Pop up the Help menu"
2093 (kill-buffer :command kill-this-buffer
2094 :enable (kill-this-buffer-enabled-p)
2095 :help "Discard current buffer"
2100 (exit-emacs :image "exit"
2101 :command save-buffers-kill-emacs
2102 :help "Offer to save unsaved buffers, then exit Emacs"
2105 (spell-buffer :image ["spell" toolbar-spell-icon]
2106 :command [ispell-buffer toolbar-ispell]
2107 :help ["Check spelling of selected buffer" "Check spelling"])
2109 (info :image ["info" toolbar-info-icon]
2110 :command [info toolbar-info]
2111 :help ["Enter Info, the documentation browser" "Info documentation"])
2114 (mail :image toolbar-mail-icon
2115 :command toolbar-mail
2120 (compile :image toolbar-compile-icon
2121 :command toolbar-compile
2122 :help "Start a compilation"
2126 (debug :image toolbar-debug-icon
2127 :command toolbar-debug
2128 :help "Start a debugger"
2132 (news :image toolbar-news-icon
2133 :command toolbar-news
2136 "A meaning alist with definition of the default buttons.
2137 The following buttons are available:
2139 * Both Emacs and XEmacs: `open-file', `dired', `save-buffer',
2140 `undo', `cut', `copy', `paste', `search-replace', `print-buffer',
2141 `spell-buffer', `info'.
2143 * Emacs only: `new-file' (Emacs 22+) `write-file', `search-forward',
2144 `customize', `help', `kill-buffer', `exit-emacs'.
2146 * XEmacs only: `mail', `compile', `debug', `news'.
2148 To reproduce the default toolbar in both editors with use as BUTTON
2149 in `toolbarx-install-toolbar':
2151 \(toolbarx-install-toolbar
2152 '([(open-file dired kill-buffer save-buffer write-file undo cut
2153 copy paste search-forward print-buffer customize help)
2154 (open-file dired save-buffer print-buffer cut copy paste undo
2155 spell-buffer search-replace mail info compile debug news)])
2156 toolbarx-default-toolbar-meaning-alist)
2158 Ps.: there are more buttons available than suggested in the
2161 (provide 'toolbar-x)
2163 ;;; toolbar-x.el ends here