1 /*
2 * Copyright 2001-2009, Ingo Weinhold <ingo_weinhold@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT license.
4 */
5
6 #include "Scrollable.h"
7
8 #include <algorithm>
9 #include <stdio.h>
10
11 #include "Scroller.h"
12
13 // constructor
Scrollable()14 Scrollable::Scrollable()
15 : fDataRect(0.0, 0.0, 0.0, 0.0),
16 fScrollOffset(0.0, 0.0),
17 fVisibleWidth(0),
18 fVisibleHeight(0),
19 fScrollSource(NULL)
20 {
21 }
22
23 // destructor
~Scrollable()24 Scrollable::~Scrollable()
25 {
26 if (fScrollSource)
27 fScrollSource->SetScrollTarget(NULL);
28 }
29
30 // SetScrollSource
31 //
32 // Sets a new scroll source. Notifies the old and the new source
33 // of the change if necessary .
34 void
SetScrollSource(Scroller * source)35 Scrollable::SetScrollSource(Scroller* source)
36 {
37 Scroller* oldSource = fScrollSource;
38 if (oldSource != source) {
39 fScrollSource = NULL;
40 // Notify the old source, if it doesn't know about the change.
41 if (oldSource && oldSource->ScrollTarget() == this)
42 oldSource->SetScrollTarget(NULL);
43 fScrollSource = source;
44 // Notify the new source, if it doesn't know about the change.
45 if (source && source->ScrollTarget() != this)
46 source->SetScrollTarget(this);
47 // Notify ourselves.
48 ScrollSourceChanged(oldSource, fScrollSource);
49 }
50 }
51
52 // ScrollSource
53 //
54 // Returns the current scroll source. May be NULL, if we don't have any.
55 Scroller*
ScrollSource() const56 Scrollable::ScrollSource() const
57 {
58 return fScrollSource;
59 }
60
61 // SetDataRect
62 //
63 // Sets the data rect.
64 void
SetDataRect(BRect dataRect,bool validateScrollOffset)65 Scrollable::SetDataRect(BRect dataRect, bool validateScrollOffset)
66 {
67 if (fDataRect != dataRect && dataRect.IsValid()) {
68 BRect oldDataRect = fDataRect;
69 fDataRect = dataRect;
70 // notify ourselves
71 DataRectChanged(oldDataRect, fDataRect);
72 // notify scroller
73 if (fScrollSource)
74 fScrollSource->DataRectChanged(oldDataRect, fDataRect);
75 // adjust the scroll offset, if necessary
76 if (validateScrollOffset) {
77 BPoint offset = ValidScrollOffsetFor(fScrollOffset);
78 if (offset != fScrollOffset)
79 SetScrollOffset(offset);
80 }
81 }
82 }
83
84 // DataRect
85 //
86 // Returns the current data rect.
87 BRect
DataRect() const88 Scrollable::DataRect() const
89 {
90 return fDataRect;
91 }
92
93 // SetScrollOffset
94 //
95 // Sets the scroll offset.
96 void
SetScrollOffset(BPoint offset)97 Scrollable::SetScrollOffset(BPoint offset)
98 {
99 // adjust the supplied offset to be valid
100 offset = ValidScrollOffsetFor(offset);
101 if (fScrollOffset != offset) {
102 BPoint oldOffset = fScrollOffset;
103 fScrollOffset = offset;
104 // notify ourselves
105 ScrollOffsetChanged(oldOffset, fScrollOffset);
106 // notify scroller
107 if (fScrollSource)
108 fScrollSource->ScrollOffsetChanged(oldOffset, fScrollOffset);
109 }
110 }
111
112 // ScrollOffset
113 //
114 // Returns the current scroll offset.
115 BPoint
ScrollOffset() const116 Scrollable::ScrollOffset() const
117 {
118 return fScrollOffset;
119 }
120
121 // SetDataRect
122 //
123 // Sets the data rect.
124 void
SetDataRectAndScrollOffset(BRect dataRect,BPoint offset)125 Scrollable::SetDataRectAndScrollOffset(BRect dataRect, BPoint offset)
126 {
127 if (fDataRect != dataRect && dataRect.IsValid()) {
128
129 BRect oldDataRect = fDataRect;
130 fDataRect = dataRect;
131 // notify ourselves
132 DataRectChanged(oldDataRect, fDataRect);
133 // notify scroller
134 if (fScrollSource) {
135 fScrollSource->SetScrollingEnabled(false);
136 fScrollSource->DataRectChanged(oldDataRect, fDataRect);
137 }
138 // adjust the scroll offset, if necessary
139 offset = ValidScrollOffsetFor(offset);
140 if (offset != fScrollOffset)
141 SetScrollOffset(offset);
142
143 if (fScrollSource)
144 fScrollSource->SetScrollingEnabled(true);
145 }
146 }
147
148 // ValidScrollOffsetFor
149 //
150 // Returns the valid scroll offset next to the supplied offset.
151 BPoint
ValidScrollOffsetFor(BPoint offset) const152 Scrollable::ValidScrollOffsetFor(BPoint offset) const
153 {
154 return ValidScrollOffsetFor(offset, fDataRect);
155 }
156
157 // ValidScrollOffsetFor
158 //
159 // Returns the valid scroll offset next to the supplied offset.
160 BPoint
ValidScrollOffsetFor(BPoint offset,const BRect & dataRect) const161 Scrollable::ValidScrollOffsetFor(BPoint offset, const BRect& dataRect) const
162 {
163 float maxX = max_c(dataRect.left, dataRect.right - fVisibleWidth);
164 float maxY = max_c(dataRect.top, dataRect.bottom - fVisibleHeight);
165 // adjust the offset to be valid
166 if (offset.x < dataRect.left)
167 offset.x = dataRect.left;
168 else if (offset.x > maxX)
169 offset.x = maxX;
170 if (offset.y < dataRect.top)
171 offset.y = dataRect.top;
172 else if (offset.y > maxY)
173 offset.y = maxY;
174 return offset;
175 }
176
177 // SetVisibleSize
178 //
179 // Sets the visible size.
180 void
SetVisibleSize(float width,float height)181 Scrollable::SetVisibleSize(float width, float height)
182 {
183 if ((fVisibleWidth != width || fVisibleHeight != height) &&
184 width >= 0 && height >= 0) {
185 float oldWidth = fVisibleWidth;
186 float oldHeight = fVisibleHeight;
187 fVisibleWidth = width;
188 fVisibleHeight = height;
189 // notify ourselves
190 VisibleSizeChanged(oldWidth, oldHeight, fVisibleWidth, fVisibleHeight);
191 // notify scroller
192 if (fScrollSource) {
193 fScrollSource->VisibleSizeChanged(oldWidth, oldHeight,
194 fVisibleWidth, fVisibleHeight);
195 }
196 // adjust the scroll offset, if necessary
197 BPoint offset = ValidScrollOffsetFor(fScrollOffset);
198 if (offset != fScrollOffset)
199 SetScrollOffset(offset);
200 }
201 }
202
203 // VisibleBounds
204 //
205 // Returns the visible bounds, i.e. a rectangle of the visible size
206 // located at (0.0, 0.0).
207 BRect
VisibleBounds() const208 Scrollable::VisibleBounds() const
209 {
210 return BRect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
211 }
212
213 // VisibleRect
214 //
215 // Returns the visible rect, i.e. a rectangle of the visible size located
216 // at the scroll offset.
217 BRect
VisibleRect() const218 Scrollable::VisibleRect() const
219 {
220 BRect rect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
221 rect.OffsetBy(fScrollOffset);
222 return rect;
223 }
224
225 // DataRectChanged
226 //
227 // Hook function. Implemented by derived classes to get notified when
228 // the data rect has changed.
229 void
DataRectChanged(BRect,BRect)230 Scrollable::DataRectChanged(BRect /*oldDataRect*/, BRect /*newDataRect*/)
231 {
232 }
233
234 // ScrollOffsetChanged
235 //
236 // Hook function. Implemented by derived classes to get notified when
237 // the scroll offset has changed.
238 void
ScrollOffsetChanged(BPoint,BPoint)239 Scrollable::ScrollOffsetChanged(BPoint /*oldOffset*/, BPoint /*newOffset*/)
240 {
241 }
242
243 // VisibleSizeChanged
244 //
245 // Hook function. Implemented by derived classes to get notified when
246 // the visible size has changed.
247 void
VisibleSizeChanged(float,float,float,float)248 Scrollable::VisibleSizeChanged(float /*oldWidth*/, float /*oldHeight*/,
249 float /*newWidth*/, float /*newHeight*/)
250 {
251 }
252
253 // ScrollSourceChanged
254 //
255 // Hook function. Implemented by derived classes to get notified when
256 // the scroll source has changed.
257 void
ScrollSourceChanged(Scroller *,Scroller *)258 Scrollable::ScrollSourceChanged(Scroller* /*oldSource*/,
259 Scroller* /*newSource*/)
260 {
261 }
262
263
264