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