summaryrefslogtreecommitdiff
path: root/ipl/gprocs/slider.icn
blob: 39c0dba23dc8bc8dd81eaa9d0943261fce400655 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
############################################################################
#
#	File:     slider.icn
#
#	Subject:  Procedures for slider sensors
#
#	Author:   Gregg M. Townsend
#
#	Date:     August 14, 1996
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#	These procedures implement slider using the "evmux" event
#	multiplexor instead of the usual vidget library.
#
#	slider(win, proc, arg, x, y, w, h, lb, iv, ub)  creates a slider.
#
#	slidervalue(h, v)			modifies a slider's value.
#
############################################################################
#
#  slider(win, proc, arg, x, y, w, h, lb, iv, ub)
#
#	establishes a slider and returns a handle for use with slidervalue().
#
#	x,y,w,h give the dimensions of the slider.  The slider runs vertically
#	or horizontally depending on which of w and h is larger.  20 makes a
#	nice width (or height).
#
#	lb and ub give the range of real values represented by the slider;
#	lb is the left or bottom end.  iv is the initial value.
#	proc(win, arg, value) is called as the slider is dragged to different
#	positions.
#
#  slidervalue(h, v)
#
#	changes the position of the slider h to reflect value v.
#	The underlying action procedure is not called.
#
############################################################################
#
#  Example:  A simple color picker
#
#	record color(red, green, blue)
#	global win, spot
#
#		...
#	    Fg(win, spot := NewColor(win))
#	    Color(win, spot, "gray50")
#	    FillArc(win, 10, 10, 100, 100)
#	    Fg(win, "black")
#	    h1 := slider(win, setcolor, 1, 110, 10, 20, 100, 0, 32767, 65535)
#	    h2 := slider(win, setcolor, 2, 140, 10, 20, 100, 0, 32767, 65535)
#	    h3 := slider(win, setcolor, 3, 170, 10, 20, 100, 0, 32767, 65535)
#		...
#
#	procedure setcolor(win, n, v)
#	    static fg
#	    initial fg := color(32767, 32767, 32767)
#	    fg[n] := v
#	    Color(win, spot, fg.red || "," || fg.green || "," || fg.blue)
#	end
#
#	Draw a filled circle in a mutable color that is initially gray.
#	Draw three parallel, vertical sliders of size 20 x 100.  Their values
#	run from 0 to 65535 and they are each initialized at the midpoint.
#	(The values are only used internally; the sliders are unlabeled.)
#
#	When one of the sliders is moved, call setcolor(win, n, v).
#	n, from the "arg" value when it was built, identifies the slider.
#	v is the new value of the slider.   Setcolor uses the resulting
#	color triple to set the color of the mutable color "spot".
#
#	Additional calls
#	    every slidervalue(h1 | h2 | h3, 32767)
#	    every setcolor(win, 1 to 3, 32767)
#	would reset the original gray color.  Note that explicit calls to
# 	setcolor are needed because slidervalue does not call it.
#
############################################################################
#
#  Links: evmux, graphics
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################
#
#  See also:  evmux.icn
#
############################################################################

link evmux
link graphics

$define MARGIN 10

record Slider_Rec(win, proc, arg, x, y, w, h, lb, ub, n)

procedure slider(win, proc, arg, x, y, w, h, lb, iv, ub)
   local r

   r := Slider_Rec(win, proc, arg, x, y, w, h, lb, ub)
   slidervalue(r, iv)
   if h > w then 	# vertical slider
      sensor(win, &lpress, Exec_Vert_Slider, r, x, y - MARGIN, w, h + 2*MARGIN)
   else			# horizontal slider
      sensor(win, &lpress, Exec_Horiz_Slider, r, x - MARGIN, y, w + 2*MARGIN, h)
   return r
end

procedure slidervalue(r, v)
   local n

   Erase_Slider_Bar(r)			# erase old handle
   if r.lb ~= r.ub then
      v := real(v - r.lb) / (r.ub - r.lb)
   else
      v := 0.0
   v <:= 0.0
   v >:= 1.0
   if r.h > r.w then			# if vertical
      n := r.y + integer((1.0 - v) * (r.h - 1) + 0.5)
   else
      n := r.x + integer(v * (r.w - 1) + 0.5)
   Set_Slider_Posn(r, n)		# redraw track and handle
   return
end

procedure Set_Slider_Posn(r, n)
   local c

   r.n := n
   if r.h > r.w then {
      c := r.x + r.w / 2
      BevelRectangle(r.win, c - 2, r.y, 4, r.h, -2)	# vertical track
      BevelRectangle(r.win, r.x, r.n - 3, r.w, 6)	# horizontal bar
      FillRectangle(r.win, r.x + 2, r.n - 1, r.w - 4, 2)
      }
   else {
      c := r.y + r.h / 2
      BevelRectangle(r.win, r.x, c - 2, r.w, 4, -2)	# horizontal track
      BevelRectangle(r.win, r.n - 3, r.y, 6, r.h)	# vertical bar
      FillRectangle(r.win, r.n - 1, r.y + 2, 2, r.h - 4)
      }
   return
end

procedure Erase_Slider_Bar(r)
   if r.h > r.w then
      EraseArea(r.win, r.x, \r.n - 3, r.w, 6)	# horizontal bar on vert. track
   else
      EraseArea(r.win, \r.n - 3, r.y, 6, r.h)	# vertical bar on horiz. track
   return
end

procedure Exec_Vert_Slider(win, r, x, y)
   local e, h, u, args, a, v

   e := &lpress
   repeat {
      if type(e) == "integer" then {	# if a mouse event
         y <:= r.y
         y >:= r.y + r.h - 1
         if y ~= r.n then {
            Erase_Slider_Bar(r)
            Set_Slider_Posn(r, y)
            flush(r.win)
            v := real(r.y + r.h - y - 1) / real(r.h - 1)	# 0.0 to 1.0
            v := v * (r.ub - r.lb) + r.lb			# user range
            r.proc(win, r.arg, v)
            }
         if e = &lrelease then
            return
         }
      e := Event(win)
      y := &y
      }
   return
end

procedure Exec_Horiz_Slider(win, r, x, y)
   local e, h, u, args, a, v

   e := &lpress
   repeat {
      if type(e) == "integer" then {	# if a mouse event
         x <:= r.x
         x >:= r.x + r.w - 1
         if x ~= r.n then {
            Erase_Slider_Bar(r)
            Set_Slider_Posn(r, x)
            flush(r.win)
            v := real(x - r.x) / real(r.w - 1)		# 0.0 to 1.0
            v := v * (r.ub - r.lb) + r.lb		# user range
            r.proc(win, r.arg, v)
            }
         if e = &lrelease then
            return
         }
      e := Event(win)
      x := &x
      }
   return
end