0
|
1 // Written in the D programming language
|
|
2 // www.digitalmars.com/d/
|
|
3
|
|
4 /*
|
|
5 * The contents of this file are subject to the Mozilla Public License Version
|
|
6 * 1.1 (the "License"); you may not use this file except in compliance with
|
|
7 * the License. You may obtain a copy of the License at
|
|
8 * http://www.mozilla.org/MPL/
|
|
9 *
|
|
10 * Software distributed under the License is distributed on an "AS IS" basis,
|
|
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
12 * for the specific language governing rights and limitations under the
|
|
13 * License.
|
|
14 *
|
|
15 * The Original Code is the Dynamin library.
|
|
16 *
|
|
17 * The Initial Developer of the Original Code is Jordan Miner.
|
|
18 * Portions created by the Initial Developer are Copyright (C) 2007-2009
|
|
19 * the Initial Developer. All Rights Reserved.
|
|
20 *
|
|
21 * Contributor(s):
|
|
22 * Jordan Miner <jminer7@gmail.com>
|
|
23 *
|
|
24 */
|
|
25
|
|
26 module dynamin.gui.scroll_bar;
|
|
27
|
|
28 import dynamin.all_core;
|
|
29 import dynamin.all_gui;
|
|
30 import dynamin.all_painting;
|
|
31 import tango.io.Stdout;
|
|
32
|
|
33 enum ArrowDirection {
|
|
34 Left, Right, Up, Down
|
|
35 }
|
|
36 class ArrowButton : Button {
|
|
37 ArrowDirection _direction;
|
|
38 ArrowDirection direction() { return _direction; }
|
|
39 void direction(ArrowDirection dir) { _direction = dir; }
|
|
40 override void whenPainting(PaintingEventArgs e) {
|
|
41 Theme.current.ArrowButton_paint(this, e.graphics);
|
|
42 }
|
|
43 }
|
|
44 class ScrollBarTrack : Button {
|
|
45 override void whenPainting(PaintingEventArgs e) {
|
|
46 Theme.current.ScrollBarTrack_paint(this, e.graphics);
|
|
47 }
|
|
48 }
|
|
49 class ScrollBarThumb : Button {
|
|
50 override void whenMouseDown(MouseEventArgs e) {
|
|
51 }
|
|
52 override void whenMouseDragged(MouseEventArgs e) {
|
|
53 }
|
|
54 override void whenPainting(PaintingEventArgs e) {
|
|
55 Theme.current.ScrollBarThumb_paint(this, e.graphics);
|
|
56 }
|
|
57 }
|
|
58 //debug=ScrollBar;
|
|
59
|
|
60 ///
|
|
61 abstract class ScrollBar : Container {
|
|
62 protected:
|
|
63 ScrollBarTrack _track1, _track2;
|
|
64 ScrollBarThumb _thumb;
|
|
65 ArrowButton _button1, _button2;
|
|
66 int _value = 0, _maxValue = 100;
|
|
67 real _visibleValue = 0.5;
|
|
68 real _thumbDragLoc = -1;
|
|
69 // stores the location of the thumb as a percentage of the track
|
|
70 real _thumbPos;
|
|
71 this() {
|
|
72 valueChanged = new Event!()(&whenValueChanged);
|
|
73
|
|
74 _track1 = new ScrollBarTrack;
|
|
75 _track2 = new ScrollBarTrack;
|
|
76 _thumb = new ScrollBarThumb;
|
|
77 _button1 = new ArrowButton;
|
|
78 _button2 = new ArrowButton;
|
|
79 _track1.mouseDown += &whenTrack1MouseDown;
|
|
80 _track2.mouseDown += &whenTrack2MouseDown;
|
|
81 _thumb.mouseDown += &whenThumbMouseDown;
|
|
82 _thumb.mouseUp += &whenThumbMouseUp;
|
|
83 _thumb.mouseDragged += &whenThumbMouseDragged;
|
|
84 _button1.mouseDown += &whenButton1MouseDown;
|
|
85 _button2.mouseDown += &whenButton2MouseDown;
|
|
86 add(_track1);
|
|
87 add(_track2);
|
|
88 add(_thumb);
|
|
89 add(_button1);
|
|
90 add(_button2);
|
|
91 size = _size;
|
|
92 }
|
|
93 void whenThumbMouseDown(MouseEventArgs e);
|
|
94 void whenThumbMouseDragged(MouseEventArgs e);
|
|
95 void whenThumbMouseUp(MouseEventArgs e) {
|
|
96 // This gives the behavior of the thumb jumping when MaxValue
|
|
97 // is smaller than the track to exactly represent where
|
|
98 // Value is, as jEdit and some of Windows' controls do.
|
|
99 _thumbPos = 0;
|
|
100 updateControls();
|
|
101 }
|
|
102 void whenTrack1MouseDown(MouseEventArgs e) {
|
|
103 value = value - 100;
|
|
104 }
|
|
105 void whenTrack2MouseDown(MouseEventArgs e) {
|
|
106 value = value + 100;
|
|
107 }
|
|
108 void whenButton1MouseDown(MouseEventArgs e) {
|
|
109 value = value - 10;
|
|
110 }
|
|
111 void whenButton2MouseDown(MouseEventArgs e) {
|
|
112 value = value + 10;
|
|
113 }
|
|
114 void putControl(Control c, real location, real size);
|
|
115 real breadth();
|
|
116 real length();
|
|
117 override void whenResized(EventArgs e) {
|
|
118 updateControls();
|
|
119 }
|
|
120 void layoutControls(Control[] controls, real[] sizes) {
|
|
121 assert(controls.length == sizes.length);
|
|
122 real loc = 0;
|
|
123 for(int i = 0; i < controls.length; ++i) {
|
|
124 putControl(controls[i], loc, sizes[i]);
|
|
125 loc += sizes[i];
|
|
126 }
|
|
127 }
|
|
128 // updates controls based on what value, visible value, and max value are
|
|
129 void updateControls() {
|
|
130 if(breadth*2 > length) {
|
|
131 return;
|
|
132 // no track or thumb
|
|
133 }
|
|
134 // if thumbPos does not represent the current value
|
|
135 if(cast(int)(_thumbPos * _maxValue) != _value)
|
|
136 _thumbPos = _value / cast(real)_maxValue;
|
|
137 auto totalSz = length;
|
|
138 auto buttonSz = breadth;
|
|
139 auto totalTrackSz = totalSz - buttonSz*2;
|
|
140 auto thumbSz = round(totalTrackSz*_visibleValue);
|
|
141 auto thumbLoc = buttonSz+(totalTrackSz-thumbSz)*_thumbPos;
|
|
142 if(thumbSz < 8)
|
|
143 thumbSz = 8;
|
|
144 auto track1Sz = thumbLoc-buttonSz;
|
|
145 auto track2Sz = totalTrackSz-track1Sz-thumbSz;
|
|
146 if(track1Sz < 0) track1Sz = 0;
|
|
147 if(track2Sz < 0) track2Sz = 0;
|
|
148 debug(ScrollBar) {
|
|
149 Stdout.format("value={}", value).newline;
|
|
150 Stdout.format("visibleValue={}", visibleValue).newline;
|
|
151 Stdout.format("maxValue={}", maxValue).newline;
|
|
152 Stdout.format("totalSz={}", totalSz).newline;
|
|
153 Stdout.format("buttonSz={}", buttonSz).newline;
|
|
154 Stdout.format("totalTrackSz={}", totalTrackSz).newline;
|
|
155 Stdout.format("thumbSz={}", thumbSz).newline;
|
|
156 Stdout.format("track1Sz={}", track1Sz).newline;
|
|
157 Stdout.format("track2Sz={}", track2Sz).newline;
|
|
158 Stdout("********").newline;
|
|
159 assert(2*buttonSz+track1Sz+thumbSz+track2Sz <= totalSz + 0.01);
|
|
160 }
|
|
161 layoutControls([cast(Control)
|
|
162 _button1, _track1, _thumb, _track2, _button2],
|
|
163 [buttonSz, track1Sz, thumbSz, track2Sz, buttonSz]);
|
|
164 }
|
|
165 public:
|
|
166 /// This event occurs after Value has been changed.
|
|
167 Event!() valueChanged;
|
|
168 /// Override this method in a subclass to handle the ValueChanged event.
|
|
169 protected void whenValueChanged(EventArgs e) { }
|
|
170
|
|
171 override Size bestSize() {
|
|
172 if(cast(VScrollBar)this)
|
|
173 return Size(Theme.current.ScrollBar_size(), 100);
|
|
174 else
|
|
175 return Size(100, Theme.current.ScrollBar_size());
|
|
176 }
|
|
177 ///
|
|
178 real thumbLocation();
|
|
179 /// ditto
|
|
180 void thumbLocation(real loc) {
|
|
181 // TODO: return if no thumb (too small for one)
|
|
182 if(loc < trackStart)
|
|
183 loc = trackStart;
|
|
184 if(loc > trackEnd - thumbSize)
|
|
185 loc = trackEnd - thumbSize;
|
|
186 if(floatsEqual(loc, thumbLocation, 0.1))
|
|
187 return;
|
|
188
|
|
189 _thumbPos = (loc - trackStart) / (trackSize - thumbSize);
|
|
190 value = cast(int)(_thumbPos * _maxValue);
|
|
191 updateControls();
|
|
192 }
|
|
193 ///
|
|
194 real thumbSize();
|
|
195 ///
|
|
196 real trackStart();
|
|
197 ///
|
|
198 real trackEnd();
|
|
199 ///
|
|
200 real trackSize() { return trackEnd-trackStart; }
|
|
201 ///
|
|
202 int value() { return _value; }
|
|
203 /// ditto
|
|
204 void value(int val) {
|
|
205 if(val < 0)
|
|
206 val = 0;
|
|
207 else if(val > _maxValue)
|
|
208 val = _maxValue;
|
|
209 if(val == _value)
|
|
210 return;
|
|
211 _value = val;
|
|
212 updateControls();
|
|
213 valueChanged(new EventArgs);
|
|
214 }
|
|
215 ///
|
|
216 int maxValue() { return _maxValue; }
|
|
217 /// ditto
|
|
218 void maxValue(int val) {
|
|
219 if(val < 1)
|
|
220 val = 1;
|
|
221 if(val == _maxValue)
|
|
222 return;
|
|
223 _maxValue = val;
|
|
224 if(_value > _maxValue)
|
|
225 _value = _maxValue;
|
|
226 if(_visibleValue > _maxValue)
|
|
227 _visibleValue = _maxValue;
|
|
228 updateControls();
|
|
229 }
|
|
230 /**
|
|
231 * A floating-point number between 0 and 1 that specifies how large the
|
|
232 * thumb should be compared to the track. A value of 0 makes the thumb its
|
|
233 * minimum size, and a value of 1 makes the thumb take up all of the track.
|
|
234 * The default is 0.5.
|
|
235 */
|
|
236 real visibleValue() { return _visibleValue; }
|
|
237 /// ditto
|
|
238 void visibleValue(real val) {
|
|
239 if(val < 0)
|
|
240 val = 0;
|
|
241 else if(val > 1)
|
|
242 val = 1;
|
|
243 if(val == _visibleValue)
|
|
244 return;
|
|
245 _visibleValue = val;
|
|
246 updateControls();
|
|
247 }
|
|
248 }
|
|
249 ///
|
|
250 class HScrollBar : ScrollBar {
|
|
251 this() {
|
|
252 _button1.direction = ArrowDirection.Left;
|
|
253 _button2.direction = ArrowDirection.Right;
|
|
254 }
|
|
255 protected:
|
|
256 void whenThumbMouseDown(MouseEventArgs e) {
|
|
257 _thumbDragLoc = e.location.x;
|
|
258 }
|
|
259 void whenThumbMouseDragged(MouseEventArgs e) {
|
|
260 _thumb.state = ButtonState.Pressed;
|
|
261 thumbLocation = e.location.x + _thumb.location.x - _thumbDragLoc;
|
|
262 }
|
|
263 void putControl(Control c, real location, real size) {
|
|
264 c.location = [location, 0.0];
|
|
265 c.size = [size, height];
|
|
266 }
|
|
267 real breadth() { return height; }
|
|
268 real length() { return width; }
|
|
269 alias ScrollBar.thumbLocation thumbLocation;
|
|
270 real thumbLocation() { return _thumb.x; }
|
|
271 real thumbSize() { return _thumb.width; }
|
|
272 real trackStart() { return _track1.x; }
|
|
273 real trackEnd() { return _track2.x+_track2.width; }
|
|
274 }
|
|
275 ///
|
|
276 class VScrollBar : ScrollBar {
|
|
277 this() {
|
|
278 _button1.direction = ArrowDirection.Up;
|
|
279 _button2.direction = ArrowDirection.Down;
|
|
280 }
|
|
281 protected:
|
|
282 void whenThumbMouseDown(MouseEventArgs e) {
|
|
283 _thumbDragLoc = e.location.y;
|
|
284 }
|
|
285 void whenThumbMouseDragged(MouseEventArgs e) {
|
|
286 _thumb.state = ButtonState.Pressed;
|
|
287 thumbLocation = e.location.y + _thumb.location.y - _thumbDragLoc;
|
|
288 }
|
|
289 void putControl(Control c, real location, real size) {
|
|
290 c.location = [0.0, location];
|
|
291 c.size = [width, size];
|
|
292 }
|
|
293 real breadth() { return width; }
|
|
294 real length() { return height; }
|
|
295 alias ScrollBar.thumbLocation thumbLocation;
|
|
296 real thumbLocation() { return _thumb.y; }
|
|
297 real thumbSize() { return _thumb.height; }
|
|
298 real trackStart() { return _track1.y; }
|
|
299 real trackEnd() { return _track2.y+_track2.height; }
|
|
300 }
|
|
301
|