/*
* Copyright 2001-2009, Ingo Weinhold <ingo_weinhold@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "Scrollable.h"
#include <algorithm>
#include <stdio.h>
#include "Scroller.h"
// constructor
Scrollable::Scrollable()
: fDataRect(0.0, 0.0, 0.0, 0.0),
fScrollOffset(0.0, 0.0),
fVisibleWidth(0),
fVisibleHeight(0),
fScrollSource(NULL)
{
}
// destructor
Scrollable::~Scrollable()
{
if (fScrollSource)
fScrollSource->SetScrollTarget(NULL);
}
// SetScrollSource
//
// Sets a new scroll source. Notifies the old and the new source
// of the change if necessary .
void
Scrollable::SetScrollSource(Scroller* source)
{
Scroller* oldSource = fScrollSource;
if (oldSource != source) {
fScrollSource = NULL;
// Notify the old source, if it doesn't know about the change.
if (oldSource && oldSource->ScrollTarget() == this)
fScrollSource->SetScrollTarget(NULL);
fScrollSource = source;
// Notify the new source, if it doesn't know about the change.
if (source && source->ScrollTarget() != this)
source->SetScrollTarget(this);
// Notify ourselves.
ScrollSourceChanged(oldSource, fScrollSource);
}
}
// ScrollSource
//
// Returns the current scroll source. May be NULL, if we don't have any.
Scroller*
Scrollable::ScrollSource() const
{
return fScrollSource;
}
// SetDataRect
//
// Sets the data rect.
void
Scrollable::SetDataRect(BRect dataRect, bool validateScrollOffset)
{
if (fDataRect != dataRect && dataRect.IsValid()) {
BRect oldDataRect = fDataRect;
fDataRect = dataRect;
// notify ourselves
DataRectChanged(oldDataRect, fDataRect);
// notify scroller
if (fScrollSource)
fScrollSource->DataRectChanged(oldDataRect, fDataRect);
// adjust the scroll offset, if necessary
if (validateScrollOffset) {
BPoint offset = ValidScrollOffsetFor(fScrollOffset);
if (offset != fScrollOffset)
SetScrollOffset(offset);
}
}
}
// DataRect
//
// Returns the current data rect.
BRect
Scrollable::DataRect() const
{
return fDataRect;
}
// SetScrollOffset
//
// Sets the scroll offset.
void
Scrollable::SetScrollOffset(BPoint offset)
{
// adjust the supplied offset to be valid
offset = ValidScrollOffsetFor(offset);
if (fScrollOffset != offset) {
BPoint oldOffset = fScrollOffset;
fScrollOffset = offset;
// notify ourselves
ScrollOffsetChanged(oldOffset, fScrollOffset);
// notify scroller
if (fScrollSource)
fScrollSource->ScrollOffsetChanged(oldOffset, fScrollOffset);
}
}
// ScrollOffset
//
// Returns the current scroll offset.
BPoint
Scrollable::ScrollOffset() const
{
return fScrollOffset;
}
// SetDataRect
//
// Sets the data rect.
void
Scrollable::SetDataRectAndScrollOffset(BRect dataRect, BPoint offset)
{
if (fDataRect != dataRect && dataRect.IsValid()) {
BRect oldDataRect = fDataRect;
fDataRect = dataRect;
// notify ourselves
DataRectChanged(oldDataRect, fDataRect);
// notify scroller
if (fScrollSource) {
fScrollSource->SetScrollingEnabled(false);
fScrollSource->DataRectChanged(oldDataRect, fDataRect);
}
// adjust the scroll offset, if necessary
offset = ValidScrollOffsetFor(offset);
if (offset != fScrollOffset)
SetScrollOffset(offset);
if (fScrollSource)
fScrollSource->SetScrollingEnabled(true);
}
}
// ValidScrollOffsetFor
//
// Returns the valid scroll offset next to the supplied offset.
BPoint
Scrollable::ValidScrollOffsetFor(BPoint offset) const
{
return ValidScrollOffsetFor(offset, fDataRect);
}
// ValidScrollOffsetFor
//
// Returns the valid scroll offset next to the supplied offset.
BPoint
Scrollable::ValidScrollOffsetFor(BPoint offset, const BRect& dataRect) const
{
float maxX = max_c(dataRect.left, dataRect.right - fVisibleWidth);
float maxY = max_c(dataRect.top, dataRect.bottom - fVisibleHeight);
// adjust the offset to be valid
if (offset.x < dataRect.left)
offset.x = dataRect.left;
else if (offset.x > maxX)
offset.x = maxX;
if (offset.y < dataRect.top)
offset.y = dataRect.top;
else if (offset.y > maxY)
offset.y = maxY;
return offset;
}
// SetVisibleSize
//
// Sets the visible size.
void
Scrollable::SetVisibleSize(float width, float height)
{
if ((fVisibleWidth != width || fVisibleHeight != height) &&
width >= 0 && height >= 0) {
float oldWidth = fVisibleWidth;
float oldHeight = fVisibleHeight;
fVisibleWidth = width;
fVisibleHeight = height;
// notify ourselves
VisibleSizeChanged(oldWidth, oldHeight, fVisibleWidth, fVisibleHeight);
// notify scroller
if (fScrollSource) {
fScrollSource->VisibleSizeChanged(oldWidth, oldHeight,
fVisibleWidth, fVisibleHeight);
}
// adjust the scroll offset, if necessary
BPoint offset = ValidScrollOffsetFor(fScrollOffset);
if (offset != fScrollOffset)
SetScrollOffset(offset);
}
}
// VisibleBounds
//
// Returns the visible bounds, i.e. a rectangle of the visible size
// located at (0.0, 0.0).
BRect
Scrollable::VisibleBounds() const
{
return BRect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
}
// VisibleRect
//
// Returns the visible rect, i.e. a rectangle of the visible size located
// at the scroll offset.
BRect
Scrollable::VisibleRect() const
{
BRect rect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
rect.OffsetBy(fScrollOffset);
return rect;
}
// DataRectChanged
//
// Hook function. Implemented by derived classes to get notified when
// the data rect has changed.
void
Scrollable::DataRectChanged(BRect /*oldDataRect*/, BRect /*newDataRect*/)
{
}
// ScrollOffsetChanged
//
// Hook function. Implemented by derived classes to get notified when
// the scroll offset has changed.
void
Scrollable::ScrollOffsetChanged(BPoint /*oldOffset*/, BPoint /*newOffset*/)
{
}
// VisibleSizeChanged
//
// Hook function. Implemented by derived classes to get notified when
// the visible size has changed.
void
Scrollable::VisibleSizeChanged(float /*oldWidth*/, float /*oldHeight*/,
float /*newWidth*/, float /*newHeight*/)
{
}
// ScrollSourceChanged
//
// Hook function. Implemented by derived classes to get notified when
// the scroll source has changed.
void
Scrollable::ScrollSourceChanged(Scroller* /*oldSource*/,
Scroller* /*newSource*/)
{
}
↑ V522 Dereferencing of the null pointer 'fScrollSource' might take place.