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