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