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 14Scrollable::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 24Scrollable::~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 . 34void 35Scrollable::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. 55Scroller* 56Scrollable::ScrollSource() const 57{ 58 return fScrollSource; 59} 60 61// SetDataRect 62// 63// Sets the data rect. 64void 65Scrollable::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. 87BRect 88Scrollable::DataRect() const 89{ 90 return fDataRect; 91} 92 93// SetScrollOffset 94// 95// Sets the scroll offset. 96void 97Scrollable::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. 115BPoint 116Scrollable::ScrollOffset() const 117{ 118 return fScrollOffset; 119} 120 121// SetDataRect 122// 123// Sets the data rect. 124void 125Scrollable::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. 151BPoint 152Scrollable::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. 160BPoint 161Scrollable::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. 180void 181Scrollable::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). 207BRect 208Scrollable::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. 217BRect 218Scrollable::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. 229void 230Scrollable::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. 238void 239Scrollable::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. 247void 248Scrollable::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. 257void 258Scrollable::ScrollSourceChanged(Scroller* /*oldSource*/, 259 Scroller* /*newSource*/) 260{ 261} 262 263 264