1 ;;; hui-em19-b.el --- GNU Emacs V19 button highlighting and flashing support.
3 ;; Copyright (C) 1992-1995, 2005, 2006 Free Software Foundation, Inc.
4 ;; Developed with support from Motorola Inc.
6 ;; Author: Bob Weiner, Brown U.
7 ;; Maintainer: Mats Lidell <matsl@contactor.se>
8 ;; Keywords: faces, hypermedia
10 ;; This file is part of GNU Hyperbole.
12 ;; GNU Hyperbole is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 3, or (at
15 ;; your option) any later version.
17 ;; GNU Hyperbole is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ;; General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
29 ;; This is truly prototype code.
31 ;; Can't use read-only buttons here because then outline-mode
37 (if (and hyperb:emacs19-p (or noninteractive hyperb:window-system))
39 (error "(hui-em19-b.el): Load only when running GNU Emacs V19 under a window system."))
42 ;;; Other required Elisp libraries
48 (defun hproperty:background ()
49 "Returns default background color for current frame."
50 (or (face-background (make-face 'default))
51 (cdr (assq 'background-color (frame-parameters)))
54 (defun hproperty:foreground ()
55 "Returns default foreground color for current frame."
56 (or (face-foreground (make-face 'default))
57 (cdr (assq 'foreground-color (frame-parameters)))
64 (defvar hproperty:but-emphasize-p nil
65 "*Non-nil means visually emphasize that button under mouse cursor is selectable.")
67 (defvar hproperty:but-flash-time 1000
68 "*Machine specific value for empty loop counter, Emacs 19 button flash delay.")
70 (defvar hproperty:item-highlight-color (hproperty:foreground)
71 "Color with which to highlight list/menu selections.
72 Call (hproperty:set-item-highlight <color>) to change value.")
78 ;; Support NEXTSTEP and X window systems.
79 (and (not (fboundp 'display-color-p))
80 (fboundp 'x-display-color-p)
81 (fset 'display-color-p 'x-display-color-p))
83 (defun hproperty:but-add (start end face)
84 "Add between START and END a button using FACE in current buffer.
85 If 'hproperty:but-emphasize-p' is non-nil when this is called, emphasize that
86 button is selectable whenever the mouse cursor moves over it."
87 (let ((but (make-overlay start end)))
88 (overlay-put but 'face face)
89 (if hproperty:but-emphasize-p (overlay-put but 'mouse-face 'highlight))))
91 (defun hproperty:but-color ()
92 "Return current color of buffer's buttons."
93 (if hproperty:color-ptr
94 (car hproperty:color-ptr)
95 (hproperty:foreground)))
97 (defun hproperty:but-clear ()
98 "Delete all Hyperbole buttons from current buffer."
100 (let ((start (point-min)))
101 (while (< start (point-max))
102 (mapcar (function (lambda (props)
103 (if (eq (overlay-get props 'face) hproperty:but-face)
104 (delete-overlay props))))
106 (setq start (next-overlay-change start)))))
108 (defun hproperty:but-create (&optional start-delim end-delim regexp-match)
109 "Highlight all hyper-buttons in buffer.
110 Will use optional strings START-DELIM and END-DELIM instead of default values.
111 If END-DELIM is a symbol, e.g. t, then START-DELIM is taken as a regular
112 expression which matches an entire button string.
113 If REGEXP-MATCH is non-nil, only buttons matching this argument are
116 If 'hproperty:but-emphasize-p' is non-nil when this is called, emphasize that
117 button is selectable whenever the mouse cursor moves over it."
119 (hproperty:but-clear)
120 (hproperty:but-create-all start-delim end-delim regexp-match))
122 (defun hproperty:but-create-all (&optional start-delim end-delim regexp-match)
123 "Mark all hyper-buttons in buffer for later highlighting.
124 Will use optional strings START-DELIM and END-DELIM instead of default values.
125 If END-DELIM is a symbol, e.g. t, then START-DELIM is taken as a regular
126 expression which matches an entire button string.
127 If REGEXP-MATCH is non-nil, only buttons matching this argument are
129 (ebut:map (function (lambda (lbl start end)
130 (hproperty:but-add start end hproperty:but-face)))
131 start-delim end-delim regexp-match 'include-delims))
133 (defun hproperty:but-delete (&optional pos)
134 (let ((but (hproperty:but-get pos)))
135 (if but (delete-overlay but))))
138 ;;; Private functions
141 (defun hproperty:but-get (&optional pos)
143 (mapcar (function (lambda (props)
144 (if (memq (overlay-get props 'face)
145 (list hproperty:but-face
146 hproperty:flash-face))
148 (overlays-at (or pos (point)))))))
150 (defmacro hproperty:list-cycle (list-ptr list)
151 "Move LIST-PTR to next element in LIST or when at end to first element."
152 (` (or (and (, list-ptr)
153 (setq (, list-ptr) (cdr (, list-ptr))))
154 (setq (, list-ptr) (, list)))))
157 ;;; Private variables
160 (defconst hproperty:color-list
161 (if (memq window-system '(x gtk))
162 '( "red" "blue" "paleturquoise4" "mediumpurple2"
163 "lightskyblue3" "springgreen2" "salmon" "yellowgreen" "darkorchid2"
164 "aquamarine4" "slateblue4" "slateblue1" "olivedrab1" "goldenrod4"
165 "goldenrod3" "cadetblue2" "burlywood1" "slategrey" "mistyrose"
166 "limegreen" "lightcyan" "goldenrod" "gainsboro" "skyblue1" "honeydew"
167 "yellow2" "tomato3" "skyblue" "purple4" "orange3" "bisque3" "bisque2"
168 "grey34" "gray99" "gray63" "gray44" "gray37" "gray33" "gray26" "azure1"
169 "snow4" "peru" "red" "lightgoldenrod4" "mediumseagreen" "blush"
170 "mediumorchid2" "lightskyblue1" "darkslateblue" "midnightblue"
171 "lightsalmon1" "lemonchiffon" "yellow" "lightsalmon" "coral"
172 "dodgerblue3" "darkorange4" "blue" "royalblue4" "red" "green" "cyan"
173 "darkviolet" "darksalmon" "darkorange" "blue" "pink" "magenta2"
174 "sienna4" "khaki2" "grey75" "grey74" "grey73" "grey69" "grey68" "grey35"
175 "grey13" "gray90" "gray81" "gray55" "gray51" "gray31" "snow2" "pink3"
176 "grey7" "gray1" "red4" "red3" "tan" "red" "yellow" "mediumvioletred"
177 "lightslategrey" "lavenderblush4" "turquoise" "darkturquoise"
178 "darkslategrey" "lightskyblue" "lightsalmon4" "lightsalmon3"
179 "forestgreen" "dodgerblue4" "orchid" "rosybrown4" "brown" "peachpuff3"
180 "palegreen3" "orangered2" "rose" "lightcyan4" "indianred4" "indianred3"
181 "seagreen2" "indianred" "deeppink1" "navyblue" "lavender" "grey"
182 "deeppink" "salmon4" "salmon3" "oldlace" "grey78" "grey77" "grey54"
183 "grey45" "grey21" "gray97" "gray96" "gray95" "gray88" "gray87" "gray86"
184 "gray70" "gray57" "gray38" "gray12" "gray11" "plum3" "linen" "gray9"
185 "gray8" "blue4" "beige" "turquoise" "blue" "lemonchiffon4"
186 "darkseagreen1" "antiquewhite3" "mediumorchid" "springgreen"
187 "turquoise4" "steelblue3" "mistyrose2" "lightcyan2" "red" "firebrick2"
188 "royalblue" "cadetblue" "skyblue3" "yellow3" "salmon1" "orange4"
189 "hotpink" "grey90" "gray56" "gray39" "gray18" "gray14" "plum4" "grey6"
190 "gray6" "gold3" "gold1" "blue2" "tan2" "cyan" "mediumspringgreen"
191 "darkolivegreen2" "goldenrod" "lightsteelblue" "brown" "whip"
192 "chartreuse3" "violetred4" "royalblue2" "royalblue1" "papayawhip"
193 "mistyrose3" "lightcyan1" "aquamarine" "skyblue4" "hotpink4" "hotpink3"
194 "hotpink2" "dimgray" "tomato" "grey66" "grey65" "grey64" "grey33"
195 "grey27" "gray76" "gray69" "gray68" "grey0" "azure" "green"
196 "darkgoldenrod4" "darkgoldenrod3" "darkgoldenrod2" "darkgoldenrod"
197 "brown" "lightsalmon2" "deepskyblue4" "deepskyblue3" "deepskyblue2"
198 "deepskyblue" "darkorange1" "violetred3" "violetred2" "violetred1"
199 "slateblue3" "slateblue2" "drab" "indianred1" "firebrick1" "cadetblue4"
200 "violetred" "rosybrown" "blue" "firebrick" "grey100" "wheat4" "grey79"
201 "grey76" "grey61" "gray93" "gray84" "gray65" "gray36" "gray32" "gray13"
202 "gray10" "azure3" "snow1" "tan1" "gray" "darkolivegreen1" "blue"
203 "almond" "lavenderblush3" "lavenderblush2" "lavenderblush1"
204 "darkolivegreen" "lavenderblush" "aquamarine2" "red" "olivedrab2"
205 "mistyrose4" "mistyrose1" "lightcyan3" "lightcoral" "chartreuse"
206 "peachpuff" "palegreen" "mintcream" "skyblue2" "moccasin" "tomato1"
207 "orchid3" "maroon3" "salmon" "grey81" "grey62" "grey39" "grey38"
208 "grey37" "gray92" "gray83" "gray66" "gray54" "gray50" "gray30" "gray19"
209 "gray15" "azure4" "grey3" "tan3" "pink" "gray" "blue" "lightsteelblue2"
210 "lightsteelblue1" "green" "lightslategray" "lemonchiffon2"
211 "springgreen1" "greenyellow" "chartreuse2" "grey" "royalblue3"
212 "powderblue" "peachpuff2" "palegreen2" "cream" "slateblue" "seashell2"
213 "deeppink2" "darkkhaki" "maroon4" "sienna" "grey71" "grey67" "grey18"
214 "gray59" "gray43" "gray25" "bisque" "red1" "mediumslateblue"
215 "lightgoldenrod1" "goldenrod" "paleturquoise3" "lightskyblue4" "green"
216 "yellow" "smoke" "blue" "white" "steelblue4" "rosybrown3" "peachpuff1"
217 "palegreen1" "blueviolet" "seashell4" "sienna3" "grey40" "gray91"
218 "gray82" "gray5" "cyan2" "cyan1" "blue1" "snow" "lightgoldenrod2"
219 "lightslateblue" "mediumorchid3" "darkseagreen4" "springgreen3" "green"
220 "slategray4" "slategray3" "slategray2" "blue" "peachpuff4" "palegreen4"
221 "green" "orangered3" "goldenrod1" "ghostwhite" "firebrick4" "firebrick3"
222 "cadetblue3" "slategray" "seashell3" "honeydew3" "cornsilk4" "cornsilk2"
223 "purple1" "dimgrey" "khaki1" "ivory3" "grey70" "grey60" "grey32"
224 "grey22" "grey12" "gray98" "gray89" "gray71" "gray64" "gray60" "gray49"
225 "azure2" "gray3" "paleturquoise1" "mediumpurple1" "purple"
226 "lemonchiffon1" "blue" "navajowhite3" "darkorchid1" "orange"
227 "goldenrod2" "khaki" "chocolate2" "burlywood2" "honeydew1" "darkgreen"
228 "thistle3" "thistle2" "thistle1" "thistle" "maroon2" "maroon1" "grey53"
229 "grey44" "grey25" "gray74" "gray45" "gray41" "gray35" "gray27" "gray23"
230 "gray16" "brown4" "wheat" "coral" "tan4" "lightgoldenrodyellow" "blue"
231 "green" "gray" "palevioletred3" "mediumpurple4" "mediumpurple3"
232 "saddlebrown" "blue" "darkorchid4" "darkorchid3" "puff" "olivedrab4"
233 "lightblue4" "lightpink" "lightgray" "honeydew2" "cornsilk1" "lace"
234 "sienna1" "bisque4" "orchid" "khaki3" "grey84" "grey83" "grey82"
235 "grey72" "grey52" "grey43" "grey26" "grey14" "grey10" "gray75" "gray53"
236 "gray21" "gray20" "brown3" "grey8" "red2" "navy" "grey" "gold"
237 "mediumaquamarine" "lightgoldenrod" "darkslategray4" "darkseagreen3"
238 "darkseagreen2" "antiquewhite4" "white" "springgreen4" "lightyellow4"
239 "white" "aquamarine1" "turquoise3" "steelblue2" "rosybrown2" "pink"
240 "gray" "indianred2" "dodgerblue" "green" "seagreen1" "deeppink4"
241 "aliceblue" "magenta1" "pink" "sienna2" "orchid1" "gray100" "grey97"
242 "grey94" "grey87" "grey86" "grey51" "grey42" "grey19" "gray94" "gray85"
243 "gray61" "brown2" "khaki" "grey1" "gold4" "blue" "green" "grey"
244 "turquoise" "paleturquoise" "mediumorchid4" "antiquewhite2"
245 "lightyellow2" "violet" "salmon" "chartreuse1" "turquoise1" "sandybrown"
246 "orangered1" "lightpink1" "lightblue2" "lightblue1" "grey" "seagreen4"
247 "seagreen3" "lightblue" "deeppink3" "burlywood" "seashell" "hotpink1"
248 "gray" "yellow4" "yellow" "purple" "orange" "ivory4" "grey99" "grey89"
249 "grey63" "grey58" "grey49" "grey31" "grey24" "grey20" "green4" "green1"
250 "gray73" "gray67" "coral3" "coral2" "plum2" "pink4" "ivory" "gray4"
251 "gray2" "gold2" "aquamarine" "grey" "lightgoldenrod3" "darkolivegreen3"
252 "darkgoldenrod1" "goldenrod" "orchid" "chiffon" "navajowhite4"
253 "deepskyblue1" "lightyellow" "floralwhite" "blue" "mediumblue"
254 "chocolate4" "chocolate3" "burlywood4" "turquoise" "steelblue" "green"
255 "lawngreen" "honeydew4" "seagreen" "orchid4" "wheat1" "violet" "ivory1"
256 "grey88" "grey85" "grey57" "grey56" "grey55" "grey48" "grey47" "grey46"
257 "grey30" "grey17" "gray47" "gray29" "pink2" "grey5" "grey4" "green"
258 "gray0" "brown" "lightsteelblue4" "darkolivegreen4" "palevioletred4"
259 "blue" "darkslategray3" "darkslategray2" "darkslategray1"
260 "blanchedalmond" "palegoldenrod" "blue" "lightseagreen" "lemonchiffon3"
261 "darkslategray" "green" "darkseagreen" "antiquewhite" "darkorange2"
262 "chartreuse4" "blue" "rosybrown1" "olivedrab3" "lightpink2" "orangered"
263 "thistle4" "blue" "cornsilk" "salmon2" "orchid2" "ivory2" "grey93"
264 "grey92" "grey91" "grey36" "grey29" "grey28" "grey16" "gray79" "gray78"
265 "gray77" "gray48" "gray17" "coral4" "coral1" "plum1" "pink1" "grey9"
266 "grey2" "gray7" "cyan4" "blue3" "plum" "cornflowerblue" "lightskyblue2"
267 "antiquewhite1" "navajowhite2" "navajowhite1" "lightyellow3"
268 "navajowhite" "darkorange3" "whitesmoke" "turquoise2" "steelblue1"
269 "lightpink4" "lightblue3" "green" "chocolate1" "blue" "olivedrab"
270 "lightgrey" "chocolate" "magenta4" "magenta3" "yellow1" "purple3"
271 "purple2" "orange2" "orange1" "magenta" "bisque1" "wheat2" "maroon"
272 "khaki4" "grey96" "grey95" "grey80" "grey50" "grey41" "grey15" "grey11"
273 "gray80" "gray58" "gray40" "gray34" "gray22" "brown1" "snow3"
274 "mediumturquoise" "lightsteelblue3" "palevioletred2" "palevioletred1"
275 "paleturquoise2" "green" "palevioletred" "mediumorchid1" "white"
276 "mediumpurple" "lightyellow1" "dodgerblue2" "dodgerblue1" "violet"
277 "aquamarine3" "slategray1" "gray" "orangered4" "lightpink3" "blue"
278 "darkorchid" "cadetblue1" "burlywood3" "seashell1" "cornsilk3" "tomato4"
279 "tomato2" "wheat3" "grey98" "grey59" "grey23" "green3" "green2" "gray72"
280 "gray62" "gray52" "gray46" "gray42" "gray28" "gray24" "white" "cyan3"
282 '("Red" "Blue" "Purple" "Magenta" "Orange" "Yellow" "Green" "Brown"
283 "Dark Gray" "Light Gray" "Black" "Cyan")
287 (defvar hproperty:color-ptr nil
288 "Pointer to current color name table to use for Hyperbole buttons.")
290 (defconst hproperty:good-colors
291 (if (memq window-system '(x gtk))
293 "medium violet red" "indianred4" "firebrick1" "DarkGoldenrod"
294 "NavyBlue" "darkorchid" "tomato3" "mediumseagreen" "deeppink"
295 "forestgreen" "mistyrose4" "slategrey" "purple4" "dodgerblue3"
296 "mediumvioletred" "lightsalmon3" "orangered2" "turquoise4" "Gray55"
298 hproperty:color-list)
299 "Good colors for contrast against wheat background and black foreground.")
306 (defun hproperty:cycle-but-color (&optional color)
307 "Switches button color to optional COLOR name or next item referenced by hproperty:color-ptr."
308 (interactive "sHyperbole button color: ")
309 (if (not (display-color-p))
311 (if color (setq hproperty:color-ptr nil))
313 hproperty:but-face (or color (car (hproperty:list-cycle hproperty:color-ptr hproperty:good-colors))))
314 (hproperty:set-flash-color)
315 (sit-for 0) ;; Force display update
318 (defun hproperty:set-flash-color ()
319 "Set button flashing colors based upon current color set."
320 (if (not (display-color-p))
322 (set-face-background hproperty:flash-face (hproperty:but-color))
323 (set-face-foreground hproperty:flash-face (hproperty:background))))
325 (defun hproperty:but-p (&optional pos)
326 "Return non-nil at point or optional POS iff face is eq to hproperty:but-face."
327 (memq t (mapcar (function (lambda (props)
328 (eq (overlay-get props 'face) hproperty:but-face)))
329 (overlays-at (or pos (point))))))
331 (defun hproperty:set-but-face (pos face)
332 (let ((but (hproperty:but-get pos)))
333 (if but (overlay-put but 'face face))))
335 (defun hproperty:but-flash ()
336 "Flash a Hyperbole button at or near point to indicate selection."
339 (start (hattr:get 'hbut:current 'lbl-start))
340 (end (hattr:get 'hbut:current 'lbl-end))
342 (if (and start end (setq prev (hproperty:but-p start)
344 (if (not prev) (hproperty:but-add start end hproperty:but-face))
345 (setq start (point)))
346 (setq b (and (hproperty:but-p start) hproperty:but-face))
349 (hproperty:set-but-face start hproperty:flash-face)
350 (sit-for 0) ;; Force display update
351 ;; Delay before redraw button
352 (let ((i 0)) (while (< i hproperty:but-flash-time) (setq i (1+ i))))
353 (hproperty:set-but-face start a)
354 (sit-for 0);; Force display update
356 (if (and ibut (not prev)) (hproperty:but-delete start))
359 (defun hproperty:set-item-highlight (&optional background foreground)
360 "Setup or reset item highlight face using optional BACKGROUND and FOREGROUND."
361 (make-local-variable 'hproperty:item-face)
362 (if (stringp background) (setq hproperty:item-highlight-color background))
363 (if (not hproperty:highlight-face)
365 (setq hproperty:highlight-face (make-face 'hproperty:highlight-face))
366 (set-face-foreground hproperty:highlight-face (or foreground
367 (hproperty:background)))
368 (set-face-underline-p hproperty:highlight-face nil)))
370 (let ((update-rolo-highlight-flag
371 (and (boundp 'rolo-highlight-face)
372 (facep rolo-highlight-face)
373 (or (null (face-foreground rolo-highlight-face))
374 (face-equal hproperty:highlight-face rolo-highlight-face)))))
375 (if (not (equal (face-background hproperty:highlight-face)
376 hproperty:item-highlight-color))
377 (set-face-background hproperty:highlight-face
378 hproperty:item-highlight-color))
379 (and background (not (equal (face-background
380 hproperty:highlight-face) background))
381 (set-face-background hproperty:highlight-face background))
382 (and foreground (not (equal (face-foreground
383 hproperty:highlight-face) foreground))
384 (set-face-foreground hproperty:highlight-face foreground))
385 (setq hproperty:item-face hproperty:highlight-face)
386 (if update-rolo-highlight-flag
387 (copy-face hproperty:highlight-face rolo-highlight-face))))
389 (defun hproperty:select-item (&optional pnt)
390 "Select item in current buffer at optional position PNT using hproperty:item-face."
391 (if pnt (goto-char pnt))
392 (skip-chars-forward " \t")
393 (skip-chars-backward "^ \t\n")
394 (let ((start (point)))
396 (skip-chars-forward "^ \t\n")
397 (hproperty:but-add start (point) hproperty:item-face)
399 (sit-for 0) ;; Force display update
402 (defun hproperty:select-line (&optional pnt)
403 "Select line in current buffer at optional position PNT using hproperty:item-face."
404 (if pnt (goto-char pnt))
407 (hproperty:but-add (point) (progn (end-of-line) (point)) hproperty:item-face))
408 (sit-for 0) ;; Force display update
412 ;;; Private variables
415 (defvar hproperty:but-face (progn (make-face 'hbut) 'hbut) "Face for hyper-buttons.")
416 (setq hproperty:but hproperty:but-face)
417 (set-face-foreground hproperty:but-face (hproperty:but-color))
418 (set-face-background hproperty:but-face (hproperty:background))
420 (defvar hproperty:flash-face (progn (make-face 'hbut-flash) 'hbut-flash)
421 "Face for flashing hyper-buttons.")
422 (hproperty:set-flash-color)
424 (defvar hproperty:item-button nil
425 "Button used to highlight an item in a listing buffer.")
426 (make-variable-buffer-local 'hproperty:item-button)
427 (defvar hproperty:item-face nil "Item marking face.")
428 (defvar hproperty:highlight-face nil
429 "Item highlighting face. Use (hproperty:set-item-highlight) to set.")
430 (if hproperty:highlight-face
432 ;; Reverse foreground and background colors for default block-style highlighting.
433 (hproperty:set-item-highlight (hproperty:foreground) (hproperty:background)))
435 (provide 'hui-em19-b)
437 ;;; hui-em19-b.el ends here