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