Mercurial > emacs
diff lisp/cus-theme.el @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 37645a051842 |
children |
line wrap: on
line diff
--- a/lisp/cus-theme.el Sun Jan 15 23:02:10 2006 +0000 +++ b/lisp/cus-theme.el Mon Jan 16 00:03:54 2006 +0000 @@ -1,6 +1,6 @@ ;;; cus-theme.el -- custom theme creation user interface ;; -;; Copyright (C) 2001 Free Software Foundation, Inc. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ;; ;; Author: Alex Schroeder <alex@gnu.org> ;; Maintainer: FSF @@ -20,8 +20,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Code: @@ -31,22 +31,85 @@ (eval-when-compile (require 'wid-edit)) -(defun custom-theme-create () +(defvar custom-new-theme-mode-map + (let ((map (make-keymap))) + (set-keymap-parent map widget-keymap) + (suppress-keymap map) + (define-key map "n" 'widget-forward) + (define-key map "p" 'widget-backward) + (define-key map [mouse-1] 'widget-move-and-invoke) + map) + "Keymap for `custom-new-theme-mode'.") + +(define-derived-mode custom-new-theme-mode nil "New-Theme" + "Major mode for the buffer created by `customize-create-theme'. +Do not call this mode function yourself. It is only meant for internal +use by `customize-create-theme'." + (use-local-map custom-new-theme-mode-map) + (define-key custom-new-theme-mode-map [mouse-1] 'widget-move-and-invoke) + (set (make-local-variable 'widget-documentation-face) 'custom-documentation) + (set (make-local-variable 'widget-button-face) custom-button) + (set (make-local-variable 'widget-button-pressed-face) custom-button-pressed) + (set (make-local-variable 'widget-mouse-face) custom-button-mouse) + (when custom-raised-buttons + (set (make-local-variable 'widget-push-button-prefix) "") + (set (make-local-variable 'widget-push-button-suffix) "") + (set (make-local-variable 'widget-link-prefix) "") + (set (make-local-variable 'widget-link-suffix) ""))) +(put 'custom-new-theme-mode 'mode-class 'special) + +(defvar custom-theme-name nil) +(defvar custom-theme-variables nil) +(defvar custom-theme-faces nil) +(defvar custom-theme-description) +(defvar custom-theme-insert-variable-marker) +(defvar custom-theme-insert-face-marker) + +;;;###autoload +(defun customize-create-theme () "Create a custom theme." (interactive) - (if (get-buffer "*New Custom Theme*") - (kill-buffer "*New Custom Theme*")) - (switch-to-buffer "*New Custom Theme*") - (kill-all-local-variables) + (switch-to-buffer (generate-new-buffer "*New Custom Theme*")) + (let ((inhibit-read-only t)) + (erase-buffer)) + (custom-new-theme-mode) (make-local-variable 'custom-theme-name) (make-local-variable 'custom-theme-variables) (make-local-variable 'custom-theme-faces) (make-local-variable 'custom-theme-description) - (let ((inhibit-read-only t)) - (erase-buffer)) + (make-local-variable 'custom-theme-insert-variable-marker) + (make-local-variable 'custom-theme-insert-face-marker) (widget-insert "This buffer helps you write a custom theme elisp file. -This will help you share your customizations with other people.\n\n") - (widget-insert "Theme name: ") +This will help you share your customizations with other people. + +Insert the names of all variables and faces you want the theme to include. +Invoke \"Save Theme\" to save the theme. The theme file will be saved to +the directory " custom-theme-directory "\n\n") + (widget-create 'push-button + :tag "Visit Theme" + :help-echo "Insert the settings of a pre-defined theme." + :action (lambda (widget &optional event) + (call-interactively 'custom-theme-visit-theme))) + (widget-insert " ") + (widget-create 'push-button + :tag "Merge Theme" + :help-echo "Merge in the settings of a pre-defined theme." + :action (lambda (widget &optional event) + (call-interactively 'custom-theme-merge-theme))) + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (when (y-or-n-p "Discard current changes?") + (kill-buffer (current-buffer)) + (customize-create-theme))) + "Reset Buffer") + (widget-insert " ") + (widget-create 'push-button + :notify (function custom-theme-write) + "Save Theme") + (widget-insert "\n") + + (widget-insert "\n\nTheme name: ") (setq custom-theme-name (widget-create 'editable-field :size 10 @@ -55,72 +118,262 @@ (setq custom-theme-description (widget-create 'text :value (format-time-string "Created %Y-%m-%d."))) - (widget-insert "\nVariables:\n\n") - (setq custom-theme-variables - (widget-create 'editable-list - :entry-format "%i %d %v" - 'variable)) - (widget-insert "\nFaces:\n\n") - (setq custom-theme-faces - (widget-create 'editable-list - :entry-format "%i %d %v" - 'face)) (widget-insert "\n") (widget-create 'push-button - :notify (function custom-theme-write) - "Done") - (widget-insert " ") + :tag "Insert Variable" + :help-echo "Add another variable to this theme." + :action (lambda (widget &optional event) + (call-interactively 'custom-theme-add-variable))) + (widget-insert "\n") + (setq custom-theme-insert-variable-marker (point-marker)) + (widget-insert "\n") (widget-create 'push-button - :notify (lambda (&rest ignore) - (custom-theme-create)) - "Reset") - (widget-insert " ") + :tag "Insert Face" + :help-echo "Add another face to this theme." + :action (lambda (widget &optional event) + (call-interactively 'custom-theme-add-face))) + (widget-insert "\n") + (setq custom-theme-insert-face-marker (point-marker)) + (widget-insert "\n") (widget-create 'push-button :notify (lambda (&rest ignore) - (bury-buffer)) - "Bury Buffer") + (when (y-or-n-p "Discard current changes?") + (kill-buffer (current-buffer)) + (customize-create-theme))) + "Reset Buffer") + (widget-insert " ") + (widget-create 'push-button + :notify (function custom-theme-write) + "Save Theme") (widget-insert "\n") - (use-local-map widget-keymap) + (widget-setup) + (goto-char (point-min)) + (message "")) + +;;; Theme variables + +(defun custom-theme-add-variable (symbol) + (interactive "vVariable name: ") + (cond ((assq symbol custom-theme-variables) + (message "%s is already in the theme" (symbol-name symbol))) + ((not (boundp symbol)) + (message "%s is not defined as a variable" (symbol-name symbol))) + ((eq symbol 'custom-enabled-themes) + (message "Custom theme cannot contain `custom-enabled-themes'")) + (t + (save-excursion + (goto-char custom-theme-insert-variable-marker) + (widget-insert "\n") + (let ((widget (widget-create 'custom-variable + :tag (custom-unlispify-tag-name symbol) + :custom-level 0 + :action 'custom-theme-variable-action + :custom-state 'unknown + :value symbol))) + (push (cons symbol widget) custom-theme-variables) + (custom-magic-reset widget)) + (widget-setup))))) + +(defvar custom-theme-variable-menu + `(("Reset to Current" custom-redraw + (lambda (widget) + (and (boundp (widget-value widget)) + (memq (widget-get widget :custom-state) + '(themed modified changed))))) + ("Reset to Theme Value" custom-variable-reset-theme + (lambda (widget) + (let ((theme (intern (widget-value custom-theme-name))) + (symbol (widget-value widget)) + found) + (and (custom-theme-p theme) + (dolist (setting (get theme 'theme-settings) found) + (if (and (eq (cadr setting) symbol) + (eq (car setting) 'theme-value)) + (setq found t))))))) + ("---" ignore ignore) + ("Delete" custom-theme-delete-variable nil)) + "Alist of actions for the `custom-variable' widget in Custom Theme Mode. +See the documentation for `custom-variable'.") + +(defun custom-theme-variable-action (widget &optional event) + "Show the Custom Theme Mode menu for a `custom-variable' widget. +Optional EVENT is the location for the menu." + (let ((custom-variable-menu custom-theme-variable-menu)) + (custom-variable-action widget event))) + +(defun custom-variable-reset-theme (widget) + "Reset WIDGET to its value for the currently edited theme." + (let ((theme (intern (widget-value custom-theme-name))) + (symbol (widget-value widget)) + found) + (dolist (setting (get theme 'theme-settings)) + (if (and (eq (cadr setting) symbol) + (eq (car setting) 'theme-value)) + (setq found setting))) + (widget-value-set (car (widget-get widget :children)) + (nth 3 found))) + (widget-put widget :custom-state 'themed) + (custom-redraw-magic widget) (widget-setup)) +(defun custom-theme-delete-variable (widget) + (setq custom-theme-variables + (assq-delete-all (widget-value widget) custom-theme-variables)) + (widget-delete widget)) + +;;; Theme faces + +(defun custom-theme-add-face (symbol) + (interactive (list (read-face-name "Face name" nil nil))) + (cond ((assq symbol custom-theme-faces) + (message "%s is already in the theme" (symbol-name symbol))) + ((not (facep symbol)) + (message "%s is not defined as a face" (symbol-name symbol))) + (t + (save-excursion + (goto-char custom-theme-insert-face-marker) + (widget-insert "\n") + (let ((widget (widget-create 'custom-face + :tag (custom-unlispify-tag-name symbol) + :custom-level 0 + :action 'custom-theme-face-action + :custom-state 'unknown + :value symbol))) + (push (cons symbol widget) custom-theme-faces) + (custom-magic-reset widget) + (widget-setup)))))) + +(defvar custom-theme-face-menu + `(("Reset to Theme Value" custom-face-reset-theme + (lambda (widget) + (let ((theme (intern (widget-value custom-theme-name))) + (symbol (widget-value widget)) + found) + (and (custom-theme-p theme) + (dolist (setting (get theme 'theme-settings) found) + (if (and (eq (cadr setting) symbol) + (eq (car setting) 'theme-face)) + (setq found t))))))) + ("---" ignore ignore) + ("Delete" custom-theme-delete-face nil)) + "Alist of actions for the `custom-variable' widget in Custom Theme Mode. +See the documentation for `custom-variable'.") + +(defun custom-theme-face-action (widget &optional event) + "Show the Custom Theme Mode menu for a `custom-face' widget. +Optional EVENT is the location for the menu." + (let ((custom-face-menu custom-theme-face-menu)) + (custom-face-action widget event))) + +(defun custom-face-reset-theme (widget) + "Reset WIDGET to its value for the currently edited theme." + (let ((theme (intern (widget-value custom-theme-name))) + (symbol (widget-value widget)) + found) + (dolist (setting (get theme 'theme-settings)) + (if (and (eq (cadr setting) symbol) + (eq (car setting) 'theme-face)) + (setq found setting))) + (widget-value-set (car (widget-get widget :children)) + (nth 3 found))) + (widget-put widget :custom-state 'themed) + (custom-redraw-magic widget) + (widget-setup)) + +(defun custom-theme-delete-face (widget) + (setq custom-theme-faces + (assq-delete-all (widget-value widget) custom-theme-faces)) + (widget-delete widget)) + +;;; Reading and writing + +(defun custom-theme-visit-theme () + (interactive) + (when (or (null custom-theme-variables) + (if (y-or-n-p "Discard current changes?") + (progn (customize-create-theme) t))) + (let ((theme (call-interactively 'custom-theme-merge-theme))) + (unless (eq theme 'user) + (widget-value-set custom-theme-name (symbol-name theme))) + (widget-value-set custom-theme-description + (or (get theme 'theme-documentation) + (format-time-string "Created %Y-%m-%d."))) + (widget-setup)))) + +(defun custom-theme-merge-theme (theme) + (interactive "SCustom theme name: ") + (unless (eq theme 'user) + (load-theme theme)) + (let ((settings (get theme 'theme-settings))) + (dolist (setting settings) + (if (eq (car setting) 'theme-value) + (custom-theme-add-variable (cadr setting)) + (custom-theme-add-face (cadr setting))))) + (disable-theme theme) + theme) + (defun custom-theme-write (&rest ignore) - (let ((name (widget-value custom-theme-name)) - (doc (widget-value custom-theme-description)) - (variables (widget-value custom-theme-variables)) - (faces (widget-value custom-theme-faces))) - (switch-to-buffer (concat name "-theme.el")) - (setq buffer-file-name (expand-file-name (concat name "-theme.el"))) - (let ((inhibit-read-only t)) - (erase-buffer)) - (insert "(deftheme " name) - (when doc - (newline) - (insert " \"" doc "\"")) - (insert ")\n") - (custom-theme-write-variables name variables) - (custom-theme-write-faces name faces) - (insert "\n(provide-theme '" name ")\n"))) + (let* ((name (widget-value custom-theme-name)) + (filename (expand-file-name (concat name "-theme.el") + custom-theme-directory)) + (doc (widget-value custom-theme-description)) + (vars custom-theme-variables) + (faces custom-theme-faces)) + (cond ((or (string-equal name "") + (string-equal name "user") + (string-equal name "changed")) + (error "Custom themes cannot be named `%s'" name)) + ((string-match " " name) + (error "Custom theme names should not contain spaces")) + ((if (file-exists-p filename) + (not (y-or-n-p + (format "File %s exists. Overwrite? " filename)))) + (error "Aborted"))) + (with-temp-buffer + (emacs-lisp-mode) + (unless (file-exists-p custom-theme-directory) + (make-directory (file-name-as-directory custom-theme-directory) t)) + (setq buffer-file-name filename) + (erase-buffer) + (insert "(deftheme " name) + (if doc (insert "\n \"" doc "\"")) + (insert ")\n") + (custom-theme-write-variables name vars) + (custom-theme-write-faces name faces) + (insert "\n(provide-theme '" name ")\n") + (save-buffer)) + (dolist (var vars) + (widget-put (cdr var) :custom-state 'saved) + (custom-redraw-magic (cdr var))) + (dolist (face faces) + (widget-put (cdr face) :custom-state 'saved) + (custom-redraw-magic (cdr face))))) (defun custom-theme-write-variables (theme vars) "Write a `custom-theme-set-variables' command for THEME. It includes all variables in list VARS." - ;; Most code is stolen from `custom-save-variables'. (when vars (let ((standard-output (current-buffer))) (princ "\n(custom-theme-set-variables\n") (princ " '") (princ theme) (princ "\n") - (mapc (lambda (symbol) - (when (boundp symbol) - (unless (bolp) - (princ "\n")) - (princ " '(") - (prin1 symbol) - (princ " ") - (prin1 (symbol-value symbol)) - (princ ")"))) - vars) + (mapc (lambda (spec) + (let* ((symbol (car spec)) + (child (car-safe (widget-get (cdr spec) :children))) + (value (if child + (widget-value child) + ;; For hidden widgets, use the standard value + (get symbol 'standard-value)))) + (when (boundp symbol) + (unless (bolp) + (princ "\n")) + (princ " '(") + (prin1 symbol) + (princ " ") + (prin1 (custom-quote value)) + (princ ")")))) + vars) (if (bolp) (princ " ")) (princ ")") @@ -136,21 +389,24 @@ (princ " '") (princ theme) (princ "\n") - (mapc (lambda (symbol) - (when (facep symbol) - (unless (bolp) - (princ "\n")) - (princ " '(") - (prin1 symbol) - (princ " ") - (prin1 (or (get symbol 'customized-face) - (get symbol 'face-defface-spec))) - (princ ")"))) - faces) + (mapc (lambda (spec) + (let* ((symbol (car spec)) + (child (car-safe (widget-get (cdr spec) :children))) + (value (if child (widget-value child)))) + (when (and (facep symbol) child) + (unless (bolp) + (princ "\n")) + (princ " '(") + (prin1 symbol) + (princ " ") + (prin1 value) + (princ ")")))) + faces) (if (bolp) (princ " ")) (princ ")") (unless (looking-at "\n") (princ "\n"))))) +;;; arch-tag: cd6919bc-63af-410e-bae2-b6702e762344 ;;; cus-theme.el ends here