haiku/src/apps/deskbar/InlineScrollView.cpp

634 lines
12 KiB
C++

/*
* Copyright 2012, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marc Flerackers (mflerackers@androme.be)
* Stefano Ceccherini (stefano.ceccherini@gmail.com)
* John Scipione (jscipione@gmail.com)
*/
#include "InlineScrollView.h"
#include <ControlLook.h>
#include <Debug.h>
#include <InterfaceDefs.h>
#include <Menu.h>
#include <Point.h>
#include <Screen.h>
#include <Window.h>
const int kDefaultScrollStep = 19;
const int kScrollerDimension = 12;
class ScrollArrow : public BView {
public:
ScrollArrow(BRect frame);
virtual ~ScrollArrow();
bool IsEnabled() const { return fEnabled; };
void SetEnabled(bool enabled);
private:
bool fEnabled;
};
class UpScrollArrow : public ScrollArrow {
public:
UpScrollArrow(BRect frame);
virtual ~UpScrollArrow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
};
class DownScrollArrow : public ScrollArrow {
public:
DownScrollArrow(BRect frame);
virtual ~DownScrollArrow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
};
class LeftScrollArrow : public ScrollArrow {
public:
LeftScrollArrow(BRect frame);
virtual ~LeftScrollArrow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
};
class RightScrollArrow : public ScrollArrow {
public:
RightScrollArrow(BRect frame);
virtual ~RightScrollArrow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
};
// #pragma mark -
ScrollArrow::ScrollArrow(BRect frame)
:
BView(frame, "menu scroll arrow", B_FOLLOW_NONE, B_WILL_DRAW),
fEnabled(false)
{
SetViewUIColor(B_MENU_BACKGROUND_COLOR);
}
ScrollArrow::~ScrollArrow()
{
}
void
ScrollArrow::SetEnabled(bool enabled)
{
fEnabled = enabled;
Invalidate();
}
// #pragma mark -
UpScrollArrow::UpScrollArrow(BRect frame)
:
ScrollArrow(frame)
{
}
UpScrollArrow::~UpScrollArrow()
{
}
void
UpScrollArrow::Draw(BRect updateRect)
{
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_1_TINT));
if (IsEnabled())
SetHighColor(0, 0, 0);
else {
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_2_TINT));
}
FillRect(Bounds(), B_SOLID_LOW);
float middle = Bounds().right / 2;
FillTriangle(BPoint(middle, (kScrollerDimension / 2) - 3),
BPoint(middle + 5, (kScrollerDimension / 2) + 2),
BPoint(middle - 5, (kScrollerDimension / 2) + 2));
}
void
UpScrollArrow::MouseDown(BPoint where)
{
if (!IsEnabled())
return;
TInlineScrollView* parent = dynamic_cast<TInlineScrollView*>(Parent());
if (parent == NULL)
return;
float smallStep;
float largeStep;
parent->GetSteps(&smallStep, &largeStep);
BMessage* message = Window()->CurrentMessage();
int32 modifiers = 0;
message->FindInt32("modifiers", &modifiers);
// pressing the shift key scrolls faster
if ((modifiers & B_SHIFT_KEY) != 0)
parent->ScrollBy(-largeStep);
else
parent->ScrollBy(-smallStep);
snooze(5000);
}
// #pragma mark -
DownScrollArrow::DownScrollArrow(BRect frame)
:
ScrollArrow(frame)
{
}
DownScrollArrow::~DownScrollArrow()
{
}
void
DownScrollArrow::Draw(BRect updateRect)
{
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_1_TINT));
if (IsEnabled())
SetHighColor(0, 0, 0);
else {
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_2_TINT));
}
BRect frame = Bounds();
FillRect(frame, B_SOLID_LOW);
float middle = Bounds().right / 2;
FillTriangle(BPoint(middle, frame.bottom - (kScrollerDimension / 2) + 3),
BPoint(middle + 5, frame.bottom - (kScrollerDimension / 2) - 2),
BPoint(middle - 5, frame.bottom - (kScrollerDimension / 2) - 2));
}
void
DownScrollArrow::MouseDown(BPoint where)
{
if (!IsEnabled())
return;
TInlineScrollView* grandparent
= dynamic_cast<TInlineScrollView*>(Parent()->Parent());
if (grandparent == NULL)
return;
float smallStep;
float largeStep;
grandparent->GetSteps(&smallStep, &largeStep);
BMessage* message = Window()->CurrentMessage();
int32 modifiers = 0;
message->FindInt32("modifiers", &modifiers);
// pressing the shift key scrolls faster
if ((modifiers & B_SHIFT_KEY) != 0)
grandparent->ScrollBy(largeStep);
else
grandparent->ScrollBy(smallStep);
snooze(5000);
}
// #pragma mark -
LeftScrollArrow::LeftScrollArrow(BRect frame)
:
ScrollArrow(frame)
{
}
LeftScrollArrow::~LeftScrollArrow()
{
}
void
LeftScrollArrow::Draw(BRect updateRect)
{
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
if (IsEnabled())
SetHighColor(0, 0, 0);
else {
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_2_TINT));
}
FillRect(Bounds(), B_SOLID_LOW);
float middle = Bounds().bottom / 2;
FillTriangle(BPoint((kScrollerDimension / 2) - 3, middle),
BPoint((kScrollerDimension / 2) + 2, middle + 5),
BPoint((kScrollerDimension / 2) + 2, middle - 5));
}
void
LeftScrollArrow::MouseDown(BPoint where)
{
if (!IsEnabled())
return;
TInlineScrollView* parent = dynamic_cast<TInlineScrollView*>(Parent());
if (parent == NULL)
return;
float smallStep;
float largeStep;
parent->GetSteps(&smallStep, &largeStep);
BMessage* message = Window()->CurrentMessage();
int32 modifiers = 0;
message->FindInt32("modifiers", &modifiers);
// pressing the shift key scrolls faster
if ((modifiers & B_SHIFT_KEY) != 0)
parent->ScrollBy(-largeStep);
else
parent->ScrollBy(-smallStep);
snooze(5000);
}
// #pragma mark -
RightScrollArrow::RightScrollArrow(BRect frame)
:
ScrollArrow(frame)
{
}
RightScrollArrow::~RightScrollArrow()
{
}
void
RightScrollArrow::Draw(BRect updateRect)
{
SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
if (IsEnabled())
SetHighColor(0, 0, 0);
else {
SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
B_DARKEN_2_TINT));
}
BRect frame = Bounds();
FillRect(frame, B_SOLID_LOW);
float middle = Bounds().bottom / 2;
FillTriangle(BPoint(kScrollerDimension / 2 + 3, middle),
BPoint(kScrollerDimension / 2 - 2, middle + 5),
BPoint(kScrollerDimension / 2 - 2, middle - 5));
}
void
RightScrollArrow::MouseDown(BPoint where)
{
if (!IsEnabled())
return;
TInlineScrollView* grandparent
= dynamic_cast<TInlineScrollView*>(Parent()->Parent());
if (grandparent == NULL)
return;
float smallStep;
float largeStep;
grandparent->GetSteps(&smallStep, &largeStep);
BMessage* message = Window()->CurrentMessage();
int32 modifiers = 0;
message->FindInt32("modifiers", &modifiers);
// pressing the shift key scrolls faster
if ((modifiers & B_SHIFT_KEY) != 0)
grandparent->ScrollBy(largeStep);
else
grandparent->ScrollBy(smallStep);
snooze(5000);
}
// #pragma mark -
TInlineScrollView::TInlineScrollView(BView* target,
enum orientation orientation)
:
BView(BRect(0, 0, 0, 0), "inline scroll view", B_FOLLOW_NONE, B_WILL_DRAW),
fTarget(target),
fBeginScrollArrow(NULL),
fEndScrollArrow(NULL),
fScrollStep(kDefaultScrollStep),
fScrollValue(0),
fScrollLimit(0),
fOrientation(orientation)
{
}
TInlineScrollView::~TInlineScrollView()
{
if (fBeginScrollArrow != NULL) {
fBeginScrollArrow->RemoveSelf();
delete fBeginScrollArrow;
fBeginScrollArrow = NULL;
}
if (fEndScrollArrow != NULL) {
fEndScrollArrow->RemoveSelf();
delete fEndScrollArrow;
fEndScrollArrow = NULL;
}
}
void
TInlineScrollView::AttachedToWindow()
{
BView::AttachedToWindow();
if (fTarget == NULL)
return;
AddChild(fTarget);
fTarget->MoveTo(0, 0);
}
void
TInlineScrollView::DetachedFromWindow()
{
BView::DetachedFromWindow();
if (fTarget != NULL)
fTarget->RemoveSelf();
if (fBeginScrollArrow != NULL)
fBeginScrollArrow->RemoveSelf();
if (fEndScrollArrow != NULL)
fEndScrollArrow->RemoveSelf();
}
void
TInlineScrollView::Draw(BRect updateRect)
{
BRect frame = Bounds();
be_control_look->DrawButtonBackground(this, frame, updateRect,
ui_color(B_MENU_BACKGROUND_COLOR));
}
// #pragma mark -
void
TInlineScrollView::AttachScrollers()
{
if (fTarget == NULL)
return;
BRect frame = Bounds();
if (HasScrollers()) {
if (fOrientation == B_VERTICAL) {
fScrollLimit = fTarget->Bounds().Height()
- (frame.Height() - 2 * kScrollerDimension);
} else {
fScrollLimit = fTarget->Bounds().Width()
- (frame.Width() - 2 * kScrollerDimension);
}
if (fScrollValue > fScrollLimit) {
// If scroll value is above limit scroll back
float delta = fScrollLimit - fScrollValue;
if (fOrientation == B_VERTICAL)
fTarget->ScrollBy(0, delta);
else
fTarget->ScrollBy(delta, 0);
fScrollValue = fScrollLimit;
}
return;
}
fTarget->MakeFocus(true);
if (fOrientation == B_VERTICAL) {
if (fBeginScrollArrow == NULL) {
fBeginScrollArrow = new UpScrollArrow(
BRect(frame.left, frame.top, frame.right,
kScrollerDimension - 1));
AddChild(fBeginScrollArrow);
}
if (fEndScrollArrow == NULL) {
fEndScrollArrow = new DownScrollArrow(
BRect(0, frame.bottom - 2 * kScrollerDimension + 1, frame.right,
frame.bottom - kScrollerDimension));
fTarget->AddChild(fEndScrollArrow);
}
fTarget->MoveBy(0, kScrollerDimension);
fScrollLimit = fTarget->Bounds().Height()
- (frame.Height() - 2 * kScrollerDimension);
} else {
if (fBeginScrollArrow == NULL) {
fBeginScrollArrow = new LeftScrollArrow(
BRect(frame.left, frame.top,
frame.left + kScrollerDimension - 1, frame.bottom));
AddChild(fBeginScrollArrow);
}
if (fEndScrollArrow == NULL) {
fEndScrollArrow = new RightScrollArrow(
BRect(frame.right - 2 * kScrollerDimension + 1, frame.top,
frame.right, frame.bottom));
fTarget->AddChild(fEndScrollArrow);
}
fTarget->MoveBy(kScrollerDimension, 0);
fScrollLimit = fTarget->Bounds().Width()
- (frame.Width() - 2 * kScrollerDimension);
}
fBeginScrollArrow->SetEnabled(false);
fEndScrollArrow->SetEnabled(true);
fScrollValue = 0;
}
void
TInlineScrollView::DetachScrollers()
{
if (!HasScrollers())
return;
if (fEndScrollArrow) {
fEndScrollArrow->RemoveSelf();
delete fEndScrollArrow;
fEndScrollArrow = NULL;
}
if (fBeginScrollArrow) {
fBeginScrollArrow->RemoveSelf();
delete fBeginScrollArrow;
fBeginScrollArrow = NULL;
}
if (fTarget) {
// We don't remember the position where the last scrolling
// ended, so scroll back to the beginning.
if (fOrientation == B_VERTICAL)
fTarget->MoveBy(0, -kScrollerDimension);
else
fTarget->MoveBy(-kScrollerDimension, 0);
fTarget->ScrollTo(0, 0);
fScrollValue = 0;
}
}
bool
TInlineScrollView::HasScrollers() const
{
return fTarget != NULL && fBeginScrollArrow != NULL
&& fEndScrollArrow != NULL;
}
void
TInlineScrollView::SetSmallStep(float step)
{
fScrollStep = step;
}
void
TInlineScrollView::GetSteps(float* _smallStep, float* _largeStep) const
{
if (_smallStep != NULL)
*_smallStep = fScrollStep;
if (_largeStep != NULL) {
*_largeStep = fScrollStep * 3;
}
}
void
TInlineScrollView::ScrollBy(const float& step)
{
if (!HasScrollers())
return;
if (step > 0) {
if (fScrollValue == 0)
fBeginScrollArrow->SetEnabled(true);
if (fScrollValue + step >= fScrollLimit) {
// If we reached the limit, only scroll to the end
if (fOrientation == B_VERTICAL) {
fTarget->ScrollBy(0, fScrollLimit - fScrollValue);
fEndScrollArrow->MoveBy(0, fScrollLimit - fScrollValue);
} else {
fTarget->ScrollBy(fScrollLimit - fScrollValue, 0);
fEndScrollArrow->MoveBy(fScrollLimit - fScrollValue, 0);
}
fEndScrollArrow->SetEnabled(false);
fScrollValue = fScrollLimit;
} else {
if (fOrientation == B_VERTICAL) {
fTarget->ScrollBy(0, step);
fEndScrollArrow->MoveBy(0, step);
} else {
fTarget->ScrollBy(step, 0);
fEndScrollArrow->MoveBy(step, 0);
}
fScrollValue += step;
}
} else if (step < 0) {
if (fScrollValue == fScrollLimit)
fEndScrollArrow->SetEnabled(true);
if (fScrollValue + step <= 0) {
if (fOrientation == B_VERTICAL) {
fTarget->ScrollBy(0, -fScrollValue);
fEndScrollArrow->MoveBy(0, -fScrollValue);
} else {
fTarget->ScrollBy(-fScrollValue, 0);
fEndScrollArrow->MoveBy(-fScrollValue, 0);
}
fBeginScrollArrow->SetEnabled(false);
fScrollValue = 0;
} else {
if (fOrientation == B_VERTICAL) {
fTarget->ScrollBy(0, step);
fEndScrollArrow->MoveBy(0, step);
} else {
fTarget->ScrollBy(step, 0);
fEndScrollArrow->MoveBy(step, 0);
}
fScrollValue += step;
}
}
//fTarget->Invalidate();
}