1 ;;; sliders.el --- graphical sliders for XEmacs. (c) 1997
3 ;; Author: Jens Lautenbacher <jens@tellux.de>
7 ;; This file is not (yet?) part of XEmacs.
9 ;; XEmacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; XEmacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with XEmacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
28 ;; There is a bug in XEmacs extents where the order of extent glyphs
29 ;; can get messed up when you have zero-length extents. SXEmacs has
30 ;; this fixed, but because it is such a long-standing bug code like
31 ;; this was written against the "buggy" extent api and so "breaks"
32 ;; when used with non-buggy extents. Hence this compatibility snippet
35 (if (featurep 'sxemacs)
37 (fset #'slider-set-glyph #'set-extent-end-glyph)
38 (fset #'slider-glyph #'extent-end-glyph))
39 (fset #'slider-set-glyph #'set-extent-begin-glyph)
40 (fset #'slider-glyph #'extent-begin-glyph)))
42 ;;; First of all we'll define the needed variables.
45 (defconst slider-bar-elem-width 4)
47 (defvar slider-pixmap-dir (locate-data-directory "slider"))
49 (defvar slider-bar-keymap nil)
50 (if slider-bar-keymap ()
51 (setq slider-bar-keymap (make-keymap 'slider-bar-keymap))
52 (suppress-keymap slider-bar-keymap)
53 (define-key slider-bar-keymap "+" 'slider-one-right-this)
54 (define-key slider-bar-keymap "-" 'slider-one-left-this)
55 (define-key slider-bar-keymap 'button1 'slider-activate-arrow-or-bar))
57 (defvar slider-knob-keymap nil)
58 (if slider-knob-keymap ()
59 (setq slider-knob-keymap (make-keymap 'slider-knob-keymap))
60 (suppress-keymap slider-knob-keymap)
61 (define-key slider-knob-keymap 'button1 'slider-activate-knob))
64 ;;; Add the correct path here!
65 (defvar slider-left-up (make-glyph (concat slider-pixmap-dir "left-up.xpm")))
66 (defvar slider-left-down (make-glyph (concat slider-pixmap-dir "left-down.xpm")))
67 (defvar slider-right-up (make-glyph (concat slider-pixmap-dir "right-up.xpm")))
68 (defvar slider-right-down (make-glyph (concat slider-pixmap-dir "right-down.xpm")))
69 (defvar slider-element (make-glyph (concat slider-pixmap-dir "bar.xpm")))
70 (defvar slider-knob (make-glyph (concat slider-pixmap-dir "knob.xpm")))
72 (defun slider-new (visible-size min-val max-val stepsize
73 &optional callback callback-data read-only)
74 (let* ((number-of-bars (/ visible-size slider-bar-elem-width))
75 (left-vector (make-vector (1+ number-of-bars) nil))
76 (right-vector (make-vector (1+ number-of-bars) nil))
78 ;; creating the extents....
79 ;; the left part: left-vector[0] is the left arrow.
81 (goto-char (1- (point)))
83 (setq slider (make-extent (point) (point)))
84 (set-extent-property slider 'keymap slider-bar-keymap)
85 (set-extent-property slider 'read-only read-only)
86 (set-extent-property slider 'start-open t)
87 (set-extent-property slider 'slider t)
88 (set-extent-property slider 'slider-stepsize stepsize)
89 (set-extent-property slider 'slider-left left-vector)
90 (set-extent-property slider 'slider-right right-vector)
91 (set-extent-property slider 'slider-max max-val)
92 (set-extent-property slider 'slider-min min-val)
93 (set-extent-property slider 'slider-callback callback)
94 (set-extent-property slider 'slider-data callback-data)
95 (set-extent-property slider 'slider-value min-val)
96 (set-extent-property slider 'slider-value-int 0)
97 (set-extent-property slider 'slider-number-of-bars number-of-bars)
98 (set-extent-face slider 'bold)
99 (setq tmp (make-extent (point) (point)))
100 (aset left-vector 0 tmp)
101 (set-extent-keymap tmp slider-bar-keymap)
102 (set-extent-property tmp 'slider-action 'slider-one-left)
103 (set-extent-property tmp 'slider-down slider-left-down)
104 ;; from 1 to number-of-bars: the slider bar to the left.
106 (while (<= count number-of-bars) ; <= to get length + 1 elements
107 (setq tmp (make-extent (point) (point)))
108 (aset left-vector count tmp)
109 (set-extent-keymap tmp slider-bar-keymap)
110 (set-extent-property tmp 'slider-action 'slider-left-action)
111 (setq count (1+ count))))
112 ;; now the sliders "knob"
113 (setq knob (make-extent (point) (point)))
114 (set-extent-property knob 'slider-this slider)
116 ;; from 0 to (1- number-of-bars): the slider bar to the right
118 (while (< count number-of-bars) ; < to get length elements
119 (setq tmp (make-extent (point) (point)))
120 (aset right-vector count tmp)
121 (set-extent-keymap tmp slider-bar-keymap)
122 (set-extent-property tmp 'slider-action 'slider-right-action)
123 (setq count (1+ count))))
125 (aset right-vector number-of-bars
126 (setq tmp (make-extent (point) (point))))
127 (set-extent-keymap tmp slider-bar-keymap)
128 (set-extent-property tmp 'slider-action 'slider-one-right)
129 (set-extent-property tmp 'slider-down slider-right-down)
130 ;; initializing the display:
132 (slider-set-glyph (aref left-vector 0) slider-left-up)
133 ;; the left bar is invisible, so make the knob glyph:
134 (slider-set-glyph knob slider-knob)
135 ;; the right part of the bar is fully visible
137 (while (< count number-of-bars)
138 (slider-set-glyph (aref right-vector count) slider-element)
139 (setq count (1+ count))))
140 ;; the right arrow glyph
141 (slider-set-glyph (aref right-vector number-of-bars) slider-right-up)
142 ;; put some needed information into the knob's properties.
143 (set-extent-property knob 'slider-action 'slider-drag-knob)
144 (set-extent-keymap knob slider-knob-keymap)
145 ;; loop oer the whole left and right side and fill in needed properties
147 (while (<= count number-of-bars)
148 (set-extent-property (setq tmp (aref right-vector count))
150 (set-extent-property tmp 'slider-bar-number (+ 1 count))
151 (set-extent-property (setq tmp (aref left-vector count))
153 (set-extent-property tmp 'slider-bar-number count)
154 (setq count (1+ count))))
156 (goto-char (1+ (point)))
159 (defun slider-set (slider abs-value)
160 (let* ((max (extent-property slider 'slider-max))
161 (min (extent-property slider 'slider-min))
162 (func (extent-property slider 'slider-callback))
163 (length (extent-property slider 'slider-number-of-bars))
164 (step (floor (* (/ (float length) (float (- max min)))
165 (- abs-value min)))))
166 (if (not (sliderp slider))
167 (error "No slider: %s" slider))
168 (if (or (< abs-value min) (> abs-value max))
169 (error "Value %s not in allowed range [%s...%s]"
172 (while (<= count step)
174 (aref (extent-property slider 'slider-left)
177 (setq count (1+ count)))
178 (while (<= count length)
180 (aref (extent-property slider 'slider-left)
183 (setq count (1+ count))))
185 (while (< count step)
187 (aref (extent-property slider 'slider-right)
190 (setq count (1+ count)))
191 (while (< count length)
193 (aref (extent-property slider 'slider-right)
196 (setq count (1+ count))))
197 (set-extent-property slider 'slider-value abs-value)
198 (set-extent-property slider 'slider-value-int step)
199 (if func (funcall func slider (extent-property slider 'slider-data)))
202 (defun slider-set-data (slider data)
203 (cond ((sliderp slider)
204 (set-extent-property slider 'slider-data data))
206 (error "No slider: %s" slider))))
208 (defun slider-get (slider)
209 (cond ((sliderp slider)
210 (extent-property slider 'slider-value))
212 (error "No slider: %s" slider))))
214 (defun slider-destroy (slider)
215 (let ((start (extent-start-position slider))
216 (end (extent-end-position slider)))
217 (cond ((sliderp slider)
218 (set-extent-property slider 'read-only nil)
219 (delete-region start end))
221 (error "No slider: %s" slider)))))
224 ;;; Internal functions below...
228 (extent-property obj 'slider)))
230 (defun slider-one-right (slider)
231 (let ((val (slider-get slider))
232 (max (extent-property slider 'slider-max)))
233 (if (< val max) (slider-set slider (1+ val)))))
235 (defun slider-one-left (slider)
236 (let ((val (slider-get slider))
237 (min (extent-property slider 'slider-min)))
238 (if (> val min) (slider-set slider (1- val)))))
240 (defun slider-right-action (slider)
241 (let ((val (slider-get slider))
242 (stepsize (extent-property slider 'slider-stepsize))
243 (max (extent-property slider 'slider-max)))
244 (if (< val max) (slider-set slider (min max (+ stepsize val))))))
246 (defun slider-left-action (slider)
247 (let ((val (slider-get slider))
248 (stepsize (extent-property slider 'slider-stepsize))
249 (min (extent-property slider 'slider-min)))
250 (if (> val min) (slider-set slider (max min (- val stepsize))))))
252 (defun slider-one-right-this ()
254 (let ((slider (extent-at (point) (current-buffer) 'slider nil 'at)))
255 (slider-one-right slider)
258 (defun slider-one-left-this ()
260 (let ((slider (extent-at (point) (current-buffer) 'slider nil 'at)))
261 (slider-one-left slider)
264 (defun slider-activate-arrow-or-bar (event)
266 (let* ((extent (event-glyph-extent event))
268 (action (extent-property extent 'slider-action))
270 ;; make the glyph look pressed
271 (cond ((setq down-glyph (extent-property extent 'slider-down))
272 (setq up-glyph (slider-glyph extent))
273 (slider-set-glyph extent down-glyph)))
275 (if (input-pending-p)
276 (setq event (next-event event))
277 (if action (funcall action (extent-property extent 'slider-this)))
279 (if (button-release-event-p event)
280 (setq mouse-down nil)))
281 ;; make the glyph look released
282 (if down-glyph (slider-set-glyph extent up-glyph))))
284 (defun slider-activate-knob (event)
286 (let* ((extent (event-glyph-extent event))
287 (X (event-x-pixel event))
288 (bar (extent-property (extent-property extent 'slider-this)
290 (max-bar (extent-property (extent-property extent 'slider-this)
291 'slider-number-of-bars))
293 (action (extent-property extent 'slider-action))
294 X-new X-diff new-bar)
296 (setq event (next-event event))
297 (cond ((mouse-event-p event)
298 (setq X-new (event-x-pixel event))
299 (setq X-diff (- X-new X))
300 (setq new-bar (max (min (+ bar (/ X-diff slider-bar-elem-width))
302 (cond ((not (= bar new-bar))
303 (funcall action (extent-property extent 'slider-this)
305 (setq X (+ X (* slider-bar-elem-width (- new-bar bar))))
307 (if (button-release-event-p event)
308 (setq mouse-down nil)))))))
310 (defun slider-drag-knob (extent bar)
311 (let* ((range (- (extent-property extent 'slider-max)
312 (extent-property extent 'slider-min)))
313 (offset (extent-property extent 'slider-min))
314 (slider-length (length (extent-property extent 'slider-left)))
315 (value (floor (* bar (/ (float range) (float slider-length))))))
316 (slider-set extent (+ offset value))))