1 ;;; cus-face.el --- customization support for faces
3 ;; Copyright (C) 1996-1997, 1999-2017 Free Software Foundation, Inc.
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
6 ;; Keywords: help, faces
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
30 (defalias 'custom-facep
'facep
)
34 (defun custom-declare-face (face spec doc
&rest args
)
35 "Like `defface', but with FACE evaluated as a normal argument."
36 (unless (get face
'face-defface-spec
)
37 (face-spec-set face
(purecopy spec
) 'face-defface-spec
)
38 (push (cons 'defface face
) current-load-list
)
40 (set-face-documentation face
(purecopy doc
)))
41 (custom-handle-all-keywords face args
'custom-face
)
42 (run-hooks 'custom-define-hook
))
47 (defconst custom-face-attributes
49 (string :tag
"Font Family"
50 :help-echo
"Font family or fontset alias name."))
53 (string :tag
"Font Foundry"
54 :help-echo
"Font foundry name."))
58 :help-echo
"Font width."
59 :value normal
; default
60 (const :tag
"compressed" condensed
)
61 (const :tag
"condensed" condensed
)
62 (const :tag
"demiexpanded" semi-expanded
)
63 (const :tag
"expanded" expanded
)
64 (const :tag
"extracondensed" extra-condensed
)
65 (const :tag
"extraexpanded" extra-expanded
)
66 (const :tag
"medium" normal
)
67 (const :tag
"narrow" condensed
)
68 (const :tag
"normal" normal
)
69 (const :tag
"regular" normal
)
70 (const :tag
"semicondensed" semi-condensed
)
71 (const :tag
"semiexpanded" semi-expanded
)
72 (const :tag
"ultracondensed" ultra-condensed
)
73 (const :tag
"ultraexpanded" ultra-expanded
)
74 (const :tag
"wide" extra-expanded
)))
78 :help-echo
"Face's font height."
80 (integer :tag
"Height in 1/10 pt")
81 (number :tag
"Scale" 1.0)))
85 :help-echo
"Font weight."
86 :value normal
; default
87 (const :tag
"black" ultra-bold
)
88 (const :tag
"bold" bold
)
89 (const :tag
"book" semi-light
)
90 (const :tag
"demibold" semi-bold
)
91 (const :tag
"extralight" extra-light
)
92 (const :tag
"extrabold" extra-bold
)
93 (const :tag
"heavy" extra-bold
)
94 (const :tag
"light" light
)
95 (const :tag
"medium" normal
)
96 (const :tag
"normal" normal
)
97 (const :tag
"regular" normal
)
98 (const :tag
"semibold" semi-bold
)
99 (const :tag
"semilight" semi-light
)
100 (const :tag
"ultralight" ultra-light
)
101 (const :tag
"ultrabold" ultra-bold
)
102 (const :tag
"thin" thin
)))
106 :help-echo
"Font slant."
107 :value normal
; default
108 (const :tag
"italic" italic
)
109 (const :tag
"oblique" oblique
)
110 (const :tag
"normal" normal
)
111 (const :tag
"roman" roman
)))
114 (choice :tag
"Underline"
115 :help-echo
"Control text underlining."
116 (const :tag
"Off" nil
)
118 :value
(:color foreground-color
:style line
)
119 (const :format
"" :value
:color
)
121 (const :tag
"Foreground Color" foreground-color
)
123 (const :format
"" :value
:style
)
125 (const :tag
"Line" line
)
126 (const :tag
"Wave" wave
))))
127 ;; filter to make value suitable for customize
131 (or (and (consp real-value
) (plist-get real-value
:color
))
132 (and (stringp real-value
) real-value
)
135 (or (and (consp real-value
) (plist-get real-value
:style
))
137 (list :color color
:style style
))))
138 ;; filter to make customized-value suitable for storing
141 (let ((color (plist-get cus-value
:color
))
142 (style (plist-get cus-value
:style
)))
143 (cond ((eq style
'line
)
144 ;; Use simple value for default style
145 (if (eq color
'foreground-color
) t color
))
147 `(:color
,color
:style
,style
)))))))
150 (choice :tag
"Overline"
151 :help-echo
"Control text overlining."
152 (const :tag
"Off" nil
)
154 (color :tag
"Colored")))
157 (choice :tag
"Strike-through"
158 :help-echo
"Control text strike-through."
159 (const :tag
"Off" nil
)
161 (color :tag
"Colored")))
164 ;; Fixme: this can probably be done better.
165 (choice :tag
"Box around text"
166 :help-echo
"Control box around text."
167 (const :tag
"Off" nil
)
169 :value
(:line-width
2 :color
"grey75" :style released-button
)
170 (const :format
"" :value
:line-width
)
171 (integer :tag
"Width")
172 (const :format
"" :value
:color
)
173 (choice :tag
"Color" (const :tag
"*" nil
) color
)
174 (const :format
"" :value
:style
)
176 (const :tag
"Raised" released-button
)
177 (const :tag
"Sunken" pressed-button
)
178 (const :tag
"None" nil
))))
179 ;; filter to make value suitable for customize
183 (or (and (consp real-value
)
184 (plist-get real-value
:line-width
))
185 (and (integerp real-value
) real-value
)
188 (or (and (consp real-value
) (plist-get real-value
:color
))
189 (and (stringp real-value
) real-value
)
192 (and (consp real-value
) (plist-get real-value
:style
))))
193 (list :line-width lwidth
:color color
:style style
))))
194 ;; filter to make customized-value suitable for storing
197 (let ((lwidth (plist-get cus-value
:line-width
))
198 (color (plist-get cus-value
:color
))
199 (style (plist-get cus-value
:style
)))
200 (cond ((and (null color
) (null style
))
202 ((and (null lwidth
) (null style
))
203 ;; actually can't happen, because LWIDTH is always an int
206 ;; Keep as a plist, but remove null entries
207 (nconc (and lwidth
`(:line-width
,lwidth
))
208 (and color
`(:color
,color
))
209 (and style
`(:style
,style
)))))))))
212 (choice :tag
"Inverse-video"
213 :help-echo
"Control whether text should be in inverse-video."
214 (const :tag
"Off" nil
)
215 (const :tag
"On" t
)))
218 (color :tag
"Foreground"
219 :help-echo
"Set foreground color (name or #RRGGBB hex spec)."))
222 (color :tag
"Distant Foreground"
223 :help-echo
"Set distant foreground color (name or #RRGGBB hex spec)."))
226 (color :tag
"Background"
227 :help-echo
"Set background color (name or #RRGGBB hex spec)."))
230 (choice :tag
"Stipple"
231 :help-echo
"Background bit-mask"
232 (const :tag
"None" nil
)
234 :help-echo
"Name of bitmap file."
238 (repeat :tag
"Inherit"
239 :help-echo
"List of faces to inherit attributes from."
240 (face :Tag
"Face" default
))
241 ;; filter to make value suitable for customize
243 (cond ((or (null real-value
) (eq real-value
'unspecified
))
245 ((symbolp real-value
)
249 ;; filter to make customized-value suitable for storing
251 (if (and (consp cus-value
) (null (cdr cus-value
)))
255 "Alist of face attributes.
257 The elements are of the form (KEY TYPE PRE-FILTER POST-FILTER),
258 where KEY is the name of the attribute, TYPE is a widget type for
259 editing the attribute, PRE-FILTER is a function to make the attribute's
260 value suitable for the customization widget, and POST-FILTER is a
261 function to make the customized value suitable for storing. PRE-FILTER
262 and POST-FILTER are optional.
264 The PRE-FILTER should take a single argument, the attribute value as
265 stored, and should return a value for customization (using the
266 customization type TYPE).
268 The POST-FILTER should also take a single argument, the value after
269 being customized, and should return a value suitable for setting the
270 given face attribute.")
272 (defun custom-face-attributes-get (face frame
)
273 "For FACE on FRAME, return an alternating list describing its attributes.
274 The list has the form (KEYWORD VALUE KEYWORD VALUE...).
275 Each keyword should be listed in `custom-face-attributes'.
277 If FRAME is nil, use the global defaults for FACE."
278 (let ((attrs custom-face-attributes
)
281 (let* ((attribute (car (car attrs
)))
282 (value (face-attribute face attribute frame
)))
283 (setq attrs
(cdr attrs
))
284 (unless (or (eq value
'unspecified
)
285 (and (null value
) (memq attribute
'(:inherit
))))
286 (setq plist
(cons attribute
(cons value plist
))))))
291 (defun custom-set-faces (&rest args
)
292 "Apply a list of face specs for user customizations.
293 This works by calling `custom-theme-set-faces' for the `user'
294 theme, a special theme referring to settings made via Customize.
295 The arguments should be a list where each entry has the form:
297 (FACE SPEC [NOW [COMMENT]])
299 See the documentation of `custom-theme-set-faces' for details."
300 (apply 'custom-theme-set-faces
'user args
))
302 (defun custom-theme-set-faces (theme &rest args
)
303 "Apply a list of face specs associated with theme THEME.
304 THEME should be a theme name (a symbol). The special theme named
305 `user' refers to user settings applied via Customize.
307 The remaining ARGS should be a list where each entry is a list of
310 (FACE SPEC [NOW [COMMENT]])
312 FACE should be a face name (a symbol). If FACE is a face alias,
313 the setting refers to the parent face.
315 SPEC should be a face spec. For details, see `defface'.
317 NOW, if present and non-nil, forces the face settings to take
318 immediate effect in the Emacs display; in particular, FACE is
319 initialized as a face if it is not yet one. If NOW is omitted or
320 nil, the caller is responsible for making the settings take
321 effect later, by calling `custom-theme-recalc-face' or
324 COMMENT is a string comment about FACE.
326 This function works by calling `custom-push-theme' to record each
327 SPEC in each FACE's `theme-face' property, and in THEME's
328 `theme-settings' property. If FACE has not already been
329 customized, it also stores SPEC in the `saved-face' property.
331 If THEME has a non-nil `theme-immediate' property, this is
332 equivalent to providing the NOW argument to all faces in the
334 (custom-check-theme theme
)
335 (let ((immediate (get theme
'theme-immediate
)))
337 (unless (listp entry
)
338 (error "Incompatible Custom theme spec"))
339 (let ((face (car entry
))
340 (spec (nth 1 entry
)))
341 ;; If FACE is actually an alias, customize the face it
343 (if (get face
'face-alias
)
344 (setq face
(get face
'face-alias
)))
345 (if custom--inhibit-theme-enable
346 ;; Just update theme settings.
347 (custom-push-theme 'theme-face face theme
'set spec
)
348 ;; Update theme settings and set the face spec.
349 (let ((now (nth 2 entry
))
350 (comment (nth 3 entry
))
351 (oldspec (get face
'theme-face
)))
352 (when (not (and oldspec
(eq 'user
(caar oldspec
))))
353 (put face
'saved-face spec
)
354 (put face
'saved-face-comment comment
))
355 (custom-push-theme 'theme-face face theme
'set spec
)
356 (when (or now immediate
)
357 (put face
'force-face
(if now
'rogue
'immediate
)))
358 (when (or now immediate
(facep face
))
359 (put face
'face-comment comment
)
360 (face-spec-set face spec t
))))))))
362 ;; XEmacs compatibility function. In XEmacs, when you reset a Custom
363 ;; Theme, you have to specify the theme to reset it to. We just apply
365 (defun custom-theme-reset-faces (theme &rest args
)
366 "Reset the specs in THEME of some faces to their specs in other themes.
367 Each of the arguments ARGS has this form:
371 This means reset FACE. The argument IGNORED is ignored."
372 (custom-check-theme theme
)
374 (custom-push-theme 'theme-face
(car arg
) theme
'reset
)))
376 (defun custom-reset-faces (&rest args
)
377 "Reset the specs of some faces to their specs in specified themes.
378 This creates settings in the `user' theme.
380 Each of the arguments ARGS has this form:
384 This means reset FACE to its value in FROM-THEME."
385 (apply 'custom-theme-reset-faces
'user args
))
391 ;;; cus-face.el ends here