Mercurial > projects > dynamin
annotate dynamin/gui/scrollable.d @ 113:4636a64afabc default tip
Add reverse() function.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 19 Jan 2013 21:08:52 -0600 |
parents | acdbb30fee7e |
children |
rev | line source |
---|---|
0 | 1 |
2 /* | |
103
73060bc3f004
Change license to Boost 1.0 and MPL 2.0.
Jordan Miner <jminer7@gmail.com>
parents:
14
diff
changeset
|
3 * Copyright Jordan Miner |
0 | 4 * |
103
73060bc3f004
Change license to Boost 1.0 and MPL 2.0.
Jordan Miner <jminer7@gmail.com>
parents:
14
diff
changeset
|
5 * This Source Code Form is subject to the terms of the Mozilla Public |
73060bc3f004
Change license to Boost 1.0 and MPL 2.0.
Jordan Miner <jminer7@gmail.com>
parents:
14
diff
changeset
|
6 * License, v. 2.0. If a copy of the MPL was not distributed with this |
73060bc3f004
Change license to Boost 1.0 and MPL 2.0.
Jordan Miner <jminer7@gmail.com>
parents:
14
diff
changeset
|
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
0 | 8 * |
9 */ | |
10 | |
11 module dynamin.gui.scrollable; | |
12 | |
13 import dynamin.all_core; | |
14 import dynamin.all_painting; | |
15 import dynamin.all_gui; | |
16 import tango.io.Stdout; | |
17 | |
18 /// | |
19 enum VisibleScrollBars { | |
20 /** | |
21 * Shows a vertical scroll bar when it is needed. A horizontal scroll bar | |
22 * is never shown. A text box with line wrap turned on could use this | |
23 * option. | |
24 */ | |
25 Vertical, | |
26 /** | |
27 * Shows a horizontal scroll bar when it is needed. A vertical scroll bar | |
28 * is never shown. The list view in Windows Explorer could use this option. | |
29 */ | |
30 Horizontal, | |
31 /** | |
32 * Shows either scroll bar when it is needed. | |
33 * A control, such as the detail view in Windows Explorer, that changes its | |
34 * width when not being scrolled should use this option. | |
35 */ | |
36 Each, | |
37 /** | |
38 * Shows both scroll bars when both are needed. | |
39 * A control, such as a text box, that changes its width based upon | |
40 * where it is scrolled to should use this option. | |
41 */ | |
42 Both, | |
43 /** | |
44 * Does not show any scroll bars, even if they are needed. | |
45 * A single-line text box uses this option. | |
46 */ | |
47 None | |
48 } | |
49 | |
50 class ScrollableClipper : Control { | |
51 protected: | |
52 override void whenPainting(PaintingEventArgs e) { | |
53 auto par = cast(Scrollable)_parent; | |
54 e.graphics.fillRule = GraphicsFillRule.EvenOdd; | |
55 e.graphics.rectangle(Rect(0, 0, width, height)); | |
56 e.graphics.rectangle(par.contentVisibleRect); | |
57 e.graphics.clip(); | |
58 e.graphics.source = par.foreColor; | |
59 Theme.current.Scrollable_paint(par, e.graphics); | |
60 } | |
61 public: | |
62 override bool contains(Point pt) { | |
63 auto par = cast(Scrollable)_parent; | |
64 if(par is null) | |
65 return false; | |
66 return !par.contentVisibleRect.contains(pt); | |
67 } | |
68 } | |
69 | |
70 class ScrollableContent : Panel { | |
71 private: | |
72 Scrollable sc; | |
73 package this(Scrollable s) { | |
74 sc = s; | |
75 } | |
76 protected: | |
77 public override Size bestSize() { | |
78 return sc.contentBestSize; | |
79 } | |
80 override void whenMoved(EventArgs e) { | |
81 sc.whenContentMoved(e); | |
82 } | |
83 override void whenResized(EventArgs e) { | |
84 sc.whenContentResized(e); | |
85 } | |
86 override void whenMouseEntered(EventArgs e) { | |
87 sc.whenContentMouseEntered(e); | |
88 } | |
89 override void whenMouseLeft(EventArgs e) { | |
90 sc.whenContentMouseLeft(e); | |
91 } | |
92 override void whenMouseDown(MouseEventArgs e) { | |
93 sc.whenContentMouseDown(e); | |
94 } | |
95 override void whenMouseUp(MouseEventArgs e) { | |
96 sc.whenContentMouseUp(e); | |
97 } | |
98 override void whenMouseMoved(MouseEventArgs e) { | |
99 sc.whenContentMouseMoved(e); | |
100 } | |
101 override void whenMouseDragged(MouseEventArgs e) { | |
102 sc.whenContentMouseDragged(e); | |
103 } | |
104 override void whenPainting(PaintingEventArgs e) { | |
105 sc.whenContentPainting(e); | |
106 } | |
107 } | |
108 | |
109 /** | |
110 * Here is a skeleton implementation of a scrollable control: | |
111 * ----- | |
112 * class YourControl : Scrollable { | |
113 * protected override void whenContentPainting(PaintingEventArgs e) { | |
14
e6e201c3a439
Remove ANSI functions from Windows binding and convert inner tabs to spaces
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
114 * with(e.graphics) { |
e6e201c3a439
Remove ANSI functions from Windows binding and convert inner tabs to spaces
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
115 * drawText("Hello World", 5, 5); |
e6e201c3a439
Remove ANSI functions from Windows binding and convert inner tabs to spaces
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
116 * } |
0 | 117 * } |
118 * } | |
119 * ----- | |
120 */ | |
121 abstract class Scrollable : Container { | |
122 private: | |
123 Panel _content; | |
124 protected: | |
125 VisibleScrollBars _scrollBars; | |
126 ScrollBar _hScrollBar, _vScrollBar; | |
127 ScrollableClipper _clipper; | |
128 | |
104
5c8c1c2e12c0
Change from real to double.
Jordan Miner <jminer7@gmail.com>
parents:
103
diff
changeset
|
129 double _sbSize; |
5c8c1c2e12c0
Change from real to double.
Jordan Miner <jminer7@gmail.com>
parents:
103
diff
changeset
|
130 double _leftControlsWidth, _topControlsHeight; |
0 | 131 // the area the content could be shown if no scroll bars |
132 Rect _availableRect; | |
133 // the area the content is actually visible, after scroll bars are | |
134 // taken into account | |
135 Rect _visibleRect; | |
136 bool _hVisible, _vVisible; | |
137 override void whenMouseTurned(MouseTurnedEventArgs e) { | |
138 _vScrollBar.value = _vScrollBar.value + cast(int)(10*e.scrollAmount); | |
139 } | |
140 | |
141 Size contentBestSize() { return Size(0, 0); } /// | |
142 void whenContentMoved(EventArgs e) { } /// | |
143 void whenContentResized(EventArgs e) { } /// | |
144 void whenContentMouseEntered(EventArgs e) { } /// | |
145 void whenContentMouseLeft(EventArgs e) { } /// | |
146 void whenContentMouseDown(MouseEventArgs e) { } /// | |
147 void whenContentMouseUp(MouseEventArgs e) { } /// | |
148 void whenContentMouseMoved(MouseEventArgs e) { } /// | |
149 void whenContentMouseDragged(MouseEventArgs e) { } /// | |
150 void whenContentPainting(PaintingEventArgs e) { } /// | |
151 | |
152 this() { | |
153 _elasticX = true; | |
154 _elasticY = true; | |
155 | |
156 _scrollBars = VisibleScrollBars.Each; | |
157 //content = c; | |
158 _content = new ScrollableContent(this); | |
159 _content.location = [borderSize.left, borderSize.top]; | |
160 add(_content); | |
161 | |
162 _clipper = new ScrollableClipper; | |
163 add(_clipper); | |
164 | |
165 _vScrollBar = new VScrollBar; | |
166 _vScrollBar.valueChanged += &whenValueChanged; | |
167 _hScrollBar = new HScrollBar; | |
168 _hScrollBar.valueChanged += &whenValueChanged; | |
169 layout(); | |
170 } | |
171 void whenValueChanged(EventArgs e) { | |
172 _content.location = [_visibleRect.x-_hScrollBar.value, _visibleRect.y-_vScrollBar.value]; | |
173 } | |
174 public: | |
175 override void layout() { | |
176 _sbSize = Theme.current.ScrollBar_size; | |
177 _leftControlsWidth = 0; | |
178 //foreach(c; leftControls) | |
179 // total += c.bestSize.width; | |
180 _topControlsHeight = 0; | |
181 //foreach(c; topControls) | |
182 // total += c.bestSize.height; | |
183 _availableRect = Rect(0, 0, width, height) - borderSize - | |
184 BorderSize(_leftControlsWidth, _topControlsHeight, 0, 0); | |
185 _hVisible = HScrollBarVisible; | |
186 _vVisible = VScrollBarVisible; | |
187 _visibleRect = _availableRect; | |
188 if(_hVisible) | |
189 _visibleRect.height = _visibleRect.height - _sbSize; | |
190 if(_vVisible) | |
191 _visibleRect.width = _visibleRect.width - _sbSize; | |
192 | |
193 remove(_hScrollBar); | |
194 remove(_vScrollBar); | |
195 if(_hVisible) | |
196 add(_hScrollBar); | |
197 if(_vVisible) | |
198 add(_vScrollBar); | |
199 | |
200 _content.size = _content.bestSize; | |
201 if(_content.width < _visibleRect.width) | |
202 _content.size = Size(_visibleRect.width, _content.height); | |
203 if(_content.height < _visibleRect.height) | |
204 _content.size = Size(_content.width, _visibleRect.height); | |
205 _clipper.size = size; | |
206 | |
207 _vScrollBar.maxValue = cast(int)(_content.height-_visibleRect.height); | |
208 _vScrollBar.visibleValue = _visibleRect.height/_content.height; | |
209 _hScrollBar.maxValue = cast(int)(_content.width-_visibleRect.width); | |
210 _hScrollBar.visibleValue = _visibleRect.width/_content.width; | |
211 | |
212 _vScrollBar.location = [_visibleRect.right, _visibleRect.y]; | |
213 _vScrollBar.size = [_sbSize, _visibleRect.height]; | |
214 _hScrollBar.location = [_visibleRect.x, _visibleRect.bottom]; | |
215 _hScrollBar.size = [_visibleRect.width, _sbSize]; | |
216 | |
217 whenValueChanged(null); | |
218 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
219 |
0 | 220 /** |
221 * Gets or sets which scroll bars are shown. The default is Each. | |
222 */ | |
223 VisibleScrollBars visibleScrollBars() { return _scrollBars; } | |
224 /// ditto | |
225 void visibleScrollBars(VisibleScrollBars bars) { // TODO: rename? SBPolicy? | |
226 _scrollBars = bars; | |
227 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
228 |
0 | 229 /** |
230 * Gets whether the horizontal scroll bar is currently shown. | |
231 */ | |
232 bool HScrollBarVisible() { | |
106 | 233 final switch(_scrollBars) { |
0 | 234 case VisibleScrollBars.None: |
235 case VisibleScrollBars.Vertical: | |
236 return false; | |
237 case VisibleScrollBars.Horizontal: | |
238 return _content.bestSize.width > _availableRect.width; | |
239 case VisibleScrollBars.Each: | |
240 // if vertical scroll bar shown | |
241 if(_content.bestSize.height > _availableRect.height) | |
242 return _content.bestSize.width > _availableRect.width-_sbSize; | |
243 else | |
244 return _content.bestSize.width > _availableRect.width; | |
245 case VisibleScrollBars.Both: | |
246 return _content.bestSize.width > _availableRect.width || | |
247 _content.bestSize.height > _availableRect.height; | |
248 } | |
249 } | |
250 /** | |
251 * Gets whether the vertical scroll bar is currently shown. | |
252 */ | |
253 bool VScrollBarVisible() { | |
106 | 254 final switch(_scrollBars) { |
0 | 255 case VisibleScrollBars.None: |
256 case VisibleScrollBars.Horizontal: | |
257 return false; | |
258 case VisibleScrollBars.Vertical: | |
259 return _content.bestSize.height > _availableRect.height; | |
260 case VisibleScrollBars.Each: | |
261 // if horizontal scroll bar shown | |
262 if(_content.bestSize.width > _availableRect.width) | |
263 return _content.bestSize.height > _availableRect.height-_sbSize; | |
264 else | |
265 return _content.bestSize.height > _availableRect.height; | |
266 case VisibleScrollBars.Both: | |
267 return _content.bestSize.height > _availableRect.height || | |
268 _content.bestSize.width > _availableRect.width; | |
269 } | |
270 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
271 |
0 | 272 /** |
273 * Gets the combined width of all the controls docked on the left side of | |
274 * this scrollable. | |
275 */ | |
104
5c8c1c2e12c0
Change from real to double.
Jordan Miner <jminer7@gmail.com>
parents:
103
diff
changeset
|
276 double leftControlsWidth() { |
0 | 277 return _leftControlsWidth; |
278 } | |
279 /** | |
280 * Gets the combined height of all the controls docked on the top side of | |
281 * this scrollable. | |
282 */ | |
104
5c8c1c2e12c0
Change from real to double.
Jordan Miner <jminer7@gmail.com>
parents:
103
diff
changeset
|
283 double topControlsHeight() { |
0 | 284 return _topControlsHeight; |
285 } | |
286 | |
287 /// Returns the area inside the border, scroll bars, and any controls on the side. | |
288 Rect contentVisibleRect() { | |
289 return _visibleRect; | |
290 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
291 |
0 | 292 Panel content() { return _content; } |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
293 |
0 | 294 BorderSize borderSize() { |
295 return Theme.current.Scrollable_borderSize(this); | |
296 } | |
297 } | |
298 |