xref: /haiku/src/apps/icon-o-matic/generic/gui/scrollview/Scrollable.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
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
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
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
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 			fScrollSource->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*
56 Scrollable::ScrollSource() const
57 {
58 	return fScrollSource;
59 }
60 
61 // SetDataRect
62 //
63 // Sets the data rect.
64 void
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
88 Scrollable::DataRect() const
89 {
90 	return fDataRect;
91 }
92 
93 // SetScrollOffset
94 //
95 // Sets the scroll offset.
96 void
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
116 Scrollable::ScrollOffset() const
117 {
118 	return fScrollOffset;
119 }
120 
121 // SetDataRect
122 //
123 // Sets the data rect.
124 void
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
152 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
161 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
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
208 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
218 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
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
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
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
258 Scrollable::ScrollSourceChanged(Scroller* /*oldSource*/,
259 								Scroller* /*newSource*/)
260 {
261 }
262 
263 
264