BScrollBar: Add lines and dots knob styles to scroll bar

Fixes #9137

Move scroll bar drawing into HaikuControlLook

Added B_SCROLLABLE flag to BControlLook

Update FakeScrollBar in Appearance to also draw using HaikuControlLook.

Focus works on scroll bars again, used by FakeScrollBar... and probably
nowhere else.

Added private _ScrollingEnabled() convenience method to BScrollBar and
use it in a few places making.

Create ScrollBarPrivate.h header to share a couple of scroll bar related
enums with HaikuControlLook that come from BeOS Scroll Bar prefs.

Stuff arrow_direction enum into BScrollBar::Private as it has been
succeeded by a similar enum already present in BControlLook and is only
around now for BScrollBar::Private::DrawScrollBarButton.

Change-Id: Idc31ee41de091ba45ded2f0315a004af00143803
This commit is contained in:
John Scipione 2018-07-14 17:26:47 -07:00 committed by waddlesplash
parent 70f1070b6f
commit ec1b18c58a
7 changed files with 734 additions and 544 deletions

View File

@ -86,6 +86,7 @@ public:
B_FLAT = 1 << 8, // flat look (e.g. button background)
B_INVALID = 1 << 9, // invalid value, use B_FAILURE_COLOR
B_IS_CONTROL = 1 << 10, // use control colors
B_SCROLLABLE = 1 << 11, // scroll bar within bounds
B_BLEND_FRAME = 1 << 16,
};
@ -224,15 +225,17 @@ public:
const rgb_color& base,
uint32 flags = 0) = 0;
virtual void DrawScrollBarBackground(BView* view,
BRect& rect1, BRect& rect2,
virtual void DrawScrollBar(BView* view, BRect& rect,
const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation) = 0;
virtual void DrawScrollBarBackground(BView* view,
BRect& rect, const BRect& updateRect,
orientation orientation,
bool doubleArrows = false,
int32 buttonDown = -1) = 0;
virtual void DrawScrollBarThumb(BView* view, BRect& rect,
BRect& thumbRect, const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation) = 0;
orientation orientation,
uint32 knobStyle = 0) = 0;
virtual void DrawScrollViewFrame(BView* view,
BRect& rect, const BRect& updateRect,

View File

@ -114,6 +114,7 @@ private:
// disabled
BScrollBar& operator=(const BScrollBar& other);
bool _ScrollingEnabled() const;
bool _DoubleArrows() const;
void _UpdateThumbFrame();
float _ValueFor(BPoint where) const;
@ -121,14 +122,6 @@ private:
BRect _ButtonRectFor(int32 button) const;
void _UpdateTargetValue(BPoint where);
void _UpdateArrowButtons();
void _DrawDisabledBackground(BRect area,
const rgb_color& light,
const rgb_color& dark,
const rgb_color& fill);
void _DrawArrowButton(int32 direction,
bool doubleArrows, BRect frame,
const BRect& updateRect,
bool enabled, bool down);
BSize _MinSize() const;

View File

@ -157,15 +157,17 @@ public:
const rgb_color& base,
uint32 flags = 0);
virtual void DrawScrollBarBackground(BView* view,
BRect& rect1, BRect& rect2,
virtual void DrawScrollBar(BView* view, BRect& rect,
const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation);
virtual void DrawScrollBarBackground(BView* view,
BRect& rect, const BRect& updateRect,
orientation orientation,
bool doubleArrows = false,
int32 buttonDown = -1);
virtual void DrawScrollBarThumb(BView* view, BRect& rect,
BRect& thumbRect, const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation);
orientation orientation,
uint32 knobStyle = 0);
virtual void DrawScrollViewFrame(BView* view,
BRect& rect, const BRect& updateRect,
@ -559,6 +561,26 @@ protected:
const rgb_color& base, rgb_color& color,
uint32 flags) const;
void _DrawScrollBarBackground(BView* view,
BRect& rect1, BRect& rect2,
const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation);
void _DrawScrollBarBackground(BView* view,
BRect& rect, const BRect& updateRect,
const rgb_color& base, uint32 flags,
orientation orientation);
void _DrawDisabledScrollBarBackground(BView* view,
BRect rect, orientation orientation,
const rgb_color& light,
const rgb_color& dark,
const rgb_color& fill);
void _DrawScrollBarArrowButton(BView* view,
BRect rect, const BRect& updateRect,
const rgb_color& base, uint32 flags,
int32 direction, orientation orientation,
bool doubleArrows, bool down);
private:
bool fCachedOutline;
};

View File

@ -0,0 +1,32 @@
/*
* Copyright 2018 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#ifndef _SCROLL_BAR_PRIVATE_H
#define _SCROLL_BAR_PRIVATE_H
// Constants for determining which arrow is down and are defined with respect
// to double arrow mode. ARROW_1 and ARROW_4 refer to the outer pair of arrows
// while ARROW_2 and ARROW_3 refer to the inner ones. ARROW_1 point left/up
// and ARROW_4 points right/down. THUMB is the scroll bar thumb.
enum {
SCROLL_NO_ARROW = -1,
SCROLL_ARROW_1,
SCROLL_ARROW_2,
SCROLL_ARROW_3,
SCROLL_ARROW_4,
SCROLL_THUMB
};
// constants for determining which knob style to draw on scroll bar
typedef enum {
KNOB_NONE = 0,
KNOB_DOTS,
KNOB_LINES
} knob_style;
#endif // _SCROLL_BAR_PRIVATE_H

View File

@ -18,6 +18,7 @@
#include <GradientLinear.h>
#include <LayoutUtils.h>
#include <Region.h>
#include <ScrollBarPrivate.h>
#include <Shape.h>
#include <String.h>
#include <View.h>
@ -562,96 +563,359 @@ HaikuControlLook::DrawRadioButton(BView* view, BRect& rect, const BRect& updateR
void
HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect1, BRect& rect2,
HaikuControlLook::DrawScrollBar(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
{
DrawScrollBarBackground(view, rect1, updateRect, base, flags, orientation);
DrawScrollBarBackground(view, rect2, updateRect, base, flags, orientation);
}
void
HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
orientation orientation, bool doubleArrows, int32 buttonDown)
{
if (!rect.IsValid() || !rect.Intersects(updateRect))
return;
float gradient1Tint;
float gradient2Tint;
float darkEdge1Tint;
float darkEdge2Tint;
float shadowTint;
// save the clipping constraints of the view
view->PushState();
if ((flags & B_DISABLED) != 0) {
gradient1Tint = 0.9;
gradient2Tint = 0.8;
darkEdge1Tint = B_DARKEN_2_TINT;
darkEdge2Tint = B_DARKEN_2_TINT;
shadowTint = gradient1Tint;
// set clipping constraints to updateRect
BRegion clipping(updateRect);
view->ConstrainClippingRegion(&clipping);
// flags
bool isEnabled = (flags & B_DISABLED) == 0;
bool isFocused = (flags & B_FOCUSED) != 0;
// colors
rgb_color borderColor = tint_color(base, B_DARKEN_2_TINT);
rgb_color navigation = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
rgb_color light, dark, dark1, dark2;
if (isEnabled) {
light = tint_color(base, B_LIGHTEN_MAX_TINT);
dark = tint_color(base, B_DARKEN_3_TINT);
dark1 = tint_color(base, B_DARKEN_1_TINT);
dark2 = tint_color(base, B_DARKEN_2_TINT);
} else {
gradient1Tint = 1.10;
gradient2Tint = 1.05;
darkEdge1Tint = B_DARKEN_3_TINT;
darkEdge2Tint = B_DARKEN_2_TINT;
shadowTint = gradient1Tint;
light = tint_color(base, B_LIGHTEN_MAX_TINT);
dark = tint_color(base, B_DARKEN_2_TINT);
dark1 = tint_color(base, B_LIGHTEN_2_TINT);
dark2 = tint_color(base, B_LIGHTEN_1_TINT);
}
rgb_color darkEdge1 = tint_color(base, darkEdge1Tint);
rgb_color darkEdge2 = tint_color(base, darkEdge2Tint);
rgb_color shadow = tint_color(base, shadowTint);
// Stroke a dark frame around the scroll bar background independent of
// enabled state, also handle focus highlighting.
view->SetHighColor(isEnabled && isFocused ? navigation : borderColor);
view->StrokeRect(rect);
// inset past border
rect.InsetBy(1, 1);
// clipping region of button rects
BRegion buttonRegion = BRegion();
BRect buttonFrame1(rect);
BRect buttonFrame2(rect);
BRect buttonFrame3(rect);
BRect buttonFrame4(rect);
// define arrow rects
if (orientation == B_HORIZONTAL) {
// dark vertical line on left edge
if (rect.Width() > 0) {
view->SetHighColor(darkEdge1);
view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
rect.left++;
}
// dark vertical line on right edge
if (rect.Width() >= 0) {
view->SetHighColor(darkEdge2);
view->StrokeLine(rect.RightTop(), rect.RightBottom());
rect.right--;
}
// vertical shadow line after left edge
if (rect.Width() >= 0) {
view->SetHighColor(shadow);
view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
rect.left++;
}
// fill
if (rect.Width() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
buttonFrame1.Set(rect.left, rect.top,
rect.left + rect.Height(), rect.bottom);
if (doubleArrows) {
buttonFrame2 = buttonFrame1.OffsetByCopy(rect.Height() + 1, 0);
buttonFrame3 = buttonFrame2.OffsetToCopy(
rect.right - (rect.Height() * 2 + 1), rect.top);
}
buttonFrame4 = buttonFrame1.OffsetToCopy(rect.right - rect.Height(),
rect.top);
} else {
// dark vertical line on top edge
if (rect.Height() > 0) {
view->SetHighColor(darkEdge1);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
rect.top++;
buttonFrame1.Set(rect.left, rect.top, rect.right,
rect.top + rect.Width());
if (doubleArrows) {
buttonFrame2 = buttonFrame1.OffsetByCopy(0, rect.Width() + 1);
buttonFrame3 = buttonFrame2.OffsetToCopy(rect.left, rect.bottom
- ((rect.Width() * 2) + 1));
}
// dark vertical line on bottom edge
if (rect.Height() >= 0) {
view->SetHighColor(darkEdge2);
view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
rect.bottom--;
}
// horizontal shadow line after top edge
if (rect.Height() >= 0) {
view->SetHighColor(shadow);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
rect.top++;
}
// fill
if (rect.Height() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
buttonFrame4 = buttonFrame1.OffsetToCopy(rect.left,
rect.bottom - rect.Width());
}
// add to clipping region
buttonRegion.Include(buttonFrame1);
if (doubleArrows) {
buttonRegion.Include(buttonFrame2);
buttonRegion.Include(buttonFrame3);
}
buttonRegion.Include(buttonFrame4);
// clip to button region
view->ConstrainClippingRegion(&buttonRegion);
// clear B_ACTIVATED flag if set, we set it on down button ourselves
flags &= ~B_ACTIVATED;
// draw arrow 1
buttonRegion.Include(buttonFrame1);
_DrawScrollBarArrowButton(view, buttonFrame1, updateRect, base,
buttonDown == SCROLL_ARROW_1 ? (flags | B_ACTIVATED) : flags,
orientation == B_HORIZONTAL ? B_LEFT_ARROW : B_UP_ARROW, orientation,
doubleArrows, buttonDown == SCROLL_ARROW_1);
if (doubleArrows) {
// draw arrow 2
_DrawScrollBarArrowButton(view, buttonFrame2, updateRect, base,
buttonDown == SCROLL_ARROW_2 ? (flags | B_ACTIVATED) : flags,
orientation == B_HORIZONTAL ? B_RIGHT_ARROW : B_DOWN_ARROW,
orientation, doubleArrows, buttonDown == SCROLL_ARROW_2);
// draw arrow 3
_DrawScrollBarArrowButton(view, buttonFrame3, updateRect, base,
buttonDown == SCROLL_ARROW_3 ? (flags | B_ACTIVATED) : flags,
orientation == B_HORIZONTAL ? B_LEFT_ARROW : B_UP_ARROW,
orientation, doubleArrows, buttonDown == SCROLL_ARROW_3);
}
// draw arrow 4
_DrawScrollBarArrowButton(view, buttonFrame4, updateRect, base,
buttonDown == SCROLL_ARROW_4 ? (flags | B_ACTIVATED) : flags,
orientation == B_HORIZONTAL ? B_RIGHT_ARROW : B_DOWN_ARROW,
orientation, doubleArrows, buttonDown == SCROLL_ARROW_4);
// set rect to background excluding arrows for thumb to draw on
BRegion background = BRegion(rect);
background.Exclude(&buttonRegion);
rect = background.Frame();
// restore the clipping constraints of the view
view->PopState();
}
void
HaikuControlLook::DrawScrollBarThumb(BView* view, BRect& rect, BRect& thumbRect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation, uint32 knobStyle)
{
if (!rect.IsValid() || !rect.Intersects(updateRect))
return;
// save the clipping constraints of the view
view->PushState();
// set clipping constraints to the thumb and background region
BRegion clipping(rect);
view->ConstrainClippingRegion(&clipping);
// flags
bool isEnabled = (flags & B_DISABLED) == 0;
bool isScrollable = (flags & B_SCROLLABLE) != 0;
// colors
rgb_color thumbColor = ui_color(B_SCROLL_BAR_THUMB_COLOR);
rgb_color light, dark, dark1, dark2;
if (isEnabled) {
light = tint_color(base, B_LIGHTEN_MAX_TINT);
dark = tint_color(base, B_DARKEN_3_TINT);
dark1 = tint_color(base, B_DARKEN_1_TINT);
dark2 = tint_color(base, B_DARKEN_2_TINT);
} else {
light = tint_color(base, B_LIGHTEN_MAX_TINT);
dark = tint_color(base, B_DARKEN_2_TINT);
dark1 = tint_color(base, B_LIGHTEN_2_TINT);
dark2 = tint_color(base, B_LIGHTEN_1_TINT);
}
BRect beforeThumb = BRect();
BRect afterThumb = BRect();
if (orientation == B_HORIZONTAL) {
// I'm only interested in the horizontal coordinates of thumbRect
thumbRect.top = rect.top;
thumbRect.bottom = rect.bottom;
beforeThumb.Set(rect.left, rect.top, thumbRect.left - 1, rect.bottom);
afterThumb.Set(thumbRect.right + 1, rect.top, rect.right, rect.bottom);
} else {
// I'm only interested in the vertical coordinates of thumbRect
thumbRect.left = rect.left;
thumbRect.right = rect.right;
beforeThumb.Set(rect.left, rect.top, rect.right, thumbRect.top - 1);
afterThumb.Set(rect.left, thumbRect.bottom + 1, rect.right,
rect.bottom);
}
if (beforeThumb.IsValid() && afterThumb.IsValid()) {
// clip to background region
BRegion besidesThumb = BRegion();
besidesThumb.Include(beforeThumb);
besidesThumb.Include(afterThumb);
view->ConstrainClippingRegion(&besidesThumb);
// draw background besides thumb
_DrawScrollBarBackground(view, beforeThumb, afterThumb, updateRect,
base, flags, orientation);
} else {
// before/after rects are invalid, draw thumb on whole rect
thumbRect = rect;
}
// clip to thumb
BRegion thumbRegion(thumbRect);
view->ConstrainClippingRegion(&thumbRegion);
// draw scroll bar thumb
if (isEnabled) {
// fill the clickable surface of the thumb
DrawButtonBackground(view, thumbRect, updateRect, thumbColor, 0,
B_ALL_BORDERS, orientation);
} else {
if (!isScrollable) {
// we cannot scroll at all, use rect here not thumbRect
_DrawDisabledScrollBarBackground(view, rect, orientation,
light, dark, dark1);
} else {
// we could scroll, but we're disabled
// thumb bevel
view->BeginLineArray(4);
view->AddLine(BPoint(thumbRect.left, thumbRect.bottom),
BPoint(thumbRect.left, thumbRect.top), light);
view->AddLine(BPoint(thumbRect.left + 1, thumbRect.top),
BPoint(thumbRect.right, thumbRect.top), light);
view->AddLine(BPoint(thumbRect.right, thumbRect.top + 1),
BPoint(thumbRect.right, thumbRect.bottom), dark2);
view->AddLine(BPoint(thumbRect.right - 1, thumbRect.bottom),
BPoint(thumbRect.left + 1, thumbRect.bottom), dark2);
view->EndLineArray();
// thumb fill
view->SetHighColor(dark1);
view->FillRect(thumbRect.InsetBySelf(1, 1));
// and inset past bevel
}
}
// draw knob style
if (knobStyle != KNOB_NONE) {
rgb_color knobLight = isEnabled
? tint_color(thumbColor, B_LIGHTEN_MAX_TINT)
: tint_color(dark1, B_LIGHTEN_1_TINT);
rgb_color knobDark = isEnabled
? tint_color(thumbColor, 1.22)
: tint_color(knobLight, B_DARKEN_1_TINT);
if (knobStyle == KNOB_DOTS) {
// draw dots on the scroll bar thumb
float hcenter = thumbRect.left + thumbRect.Width() / 2;
float vmiddle = thumbRect.top + thumbRect.Height() / 2;
BRect knob(hcenter, vmiddle, hcenter, vmiddle);
if (orientation == B_HORIZONTAL) {
view->SetHighColor(knobDark);
view->FillRect(knob);
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, 1));
float spacer = thumbRect.Height();
if (thumbRect.left + 3 < hcenter - spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(-spacer, 0));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(-spacer + 1, 1));
}
if (thumbRect.right - 3 > hcenter + spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(spacer, 0));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(spacer + 1, 1));
}
} else {
// B_VERTICAL
view->SetHighColor(knobDark);
view->FillRect(knob);
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, 1));
float spacer = thumbRect.Width();
if (thumbRect.top + 3 < vmiddle - spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(0, -spacer));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, -spacer + 1));
}
if (thumbRect.bottom - 3 > vmiddle + spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(0, spacer));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, spacer + 1));
}
}
} else if (knobStyle == KNOB_LINES) {
// draw lines on the scroll bar thumb
if (orientation == B_HORIZONTAL) {
float middle = thumbRect.Width() / 2;
view->BeginLineArray(6);
view->AddLine(
BPoint(thumbRect.left + middle - 3, thumbRect.top + 2),
BPoint(thumbRect.left + middle - 3, thumbRect.bottom - 2),
knobDark);
view->AddLine(
BPoint(thumbRect.left + middle, thumbRect.top + 2),
BPoint(thumbRect.left + middle, thumbRect.bottom - 2),
knobDark);
view->AddLine(
BPoint(thumbRect.left + middle + 3, thumbRect.top + 2),
BPoint(thumbRect.left + middle + 3, thumbRect.bottom - 2),
knobDark);
view->AddLine(
BPoint(thumbRect.left + middle - 2, thumbRect.top + 2),
BPoint(thumbRect.left + middle - 2, thumbRect.bottom - 2),
knobLight);
view->AddLine(
BPoint(thumbRect.left + middle + 1, thumbRect.top + 2),
BPoint(thumbRect.left + middle + 1, thumbRect.bottom - 2),
knobLight);
view->AddLine(
BPoint(thumbRect.left + middle + 4, thumbRect.top + 2),
BPoint(thumbRect.left + middle + 4, thumbRect.bottom - 2),
knobLight);
view->EndLineArray();
} else {
// B_VERTICAL
float middle = thumbRect.Height() / 2;
view->BeginLineArray(6);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle - 3),
BPoint(thumbRect.right - 2, thumbRect.top + middle - 3),
knobDark);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle),
BPoint(thumbRect.right - 2, thumbRect.top + middle),
knobDark);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle + 3),
BPoint(thumbRect.right - 2, thumbRect.top + middle + 3),
knobDark);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle - 2),
BPoint(thumbRect.right - 2, thumbRect.top + middle - 2),
knobLight);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle + 1),
BPoint(thumbRect.right - 2, thumbRect.top + middle + 1),
knobLight);
view->AddLine(
BPoint(thumbRect.left + 2, thumbRect.top + middle + 4),
BPoint(thumbRect.right - 2, thumbRect.top + middle + 4),
knobLight);
view->EndLineArray();
}
}
}
// set back to original rect clipping
view->ConstrainClippingRegion(&clipping);
// restore the clipping constraints of the view
view->PopState();
}
@ -740,8 +1004,9 @@ HaikuControlLook::DrawScrollViewFrame(BView* view, BRect& rect,
void
HaikuControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, uint32 direction, uint32 flags, float tint)
HaikuControlLook::DrawArrowShape(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 direction,
uint32 flags, float tint)
{
BPoint tri1, tri2, tri3;
float hInset = rect.Width() / 3;
@ -1004,20 +1269,24 @@ HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect
view->BeginLineArray(4);
if (orientation == B_HORIZONTAL) {
view->AddLine(barRect.LeftTop(), barRect.RightTop(), edgeShadowColor);
view->AddLine(barRect.LeftTop(), barRect.RightTop(),
edgeShadowColor);
view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
edgeLightColor);
barRect.InsetBy(0, 1);
view->AddLine(barRect.LeftTop(), barRect.RightTop(), frameShadowColor);
view->AddLine(barRect.LeftTop(), barRect.RightTop(),
frameShadowColor);
view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
frameLightColor);
barRect.InsetBy(0, 1);
} else {
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), edgeShadowColor);
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
edgeShadowColor);
view->AddLine(barRect.RightTop(), barRect.RightBottom(),
edgeLightColor);
barRect.InsetBy(1, 0);
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), frameShadowColor);
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
frameShadowColor);
view->AddLine(barRect.RightTop(), barRect.RightBottom(),
frameLightColor);
barRect.InsetBy(1, 0);
@ -3598,4 +3867,204 @@ HaikuControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base,
}
// #pragma mark - protected scroll bar methods
void
HaikuControlLook::_DrawScrollBarBackground(BView* view, BRect& rect1,
BRect& rect2, const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
{
_DrawScrollBarBackground(view, rect1, updateRect, base, flags, orientation);
_DrawScrollBarBackground(view, rect2, updateRect, base, flags, orientation);
}
void
HaikuControlLook::_DrawScrollBarBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
{
if (!rect.IsValid() || !rect.Intersects(updateRect))
return;
float gradient1Tint;
float gradient2Tint;
float darkEdge1Tint;
float darkEdge2Tint;
float shadowTint;
if ((flags & B_DISABLED) != 0) {
gradient1Tint = 0.9;
gradient2Tint = 0.8;
darkEdge1Tint = B_DARKEN_2_TINT;
darkEdge2Tint = B_DARKEN_2_TINT;
shadowTint = gradient1Tint;
} else {
gradient1Tint = 1.10;
gradient2Tint = 1.05;
darkEdge1Tint = B_DARKEN_3_TINT;
darkEdge2Tint = B_DARKEN_2_TINT;
shadowTint = gradient1Tint;
}
rgb_color darkEdge1 = tint_color(base, darkEdge1Tint);
rgb_color darkEdge2 = tint_color(base, darkEdge2Tint);
rgb_color shadow = tint_color(base, shadowTint);
if (orientation == B_HORIZONTAL) {
// dark vertical line on left edge
if (rect.Width() > 0) {
view->SetHighColor(darkEdge1);
view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
rect.left++;
}
// dark vertical line on right edge
if (rect.Width() >= 0) {
view->SetHighColor(darkEdge2);
view->StrokeLine(rect.RightTop(), rect.RightBottom());
rect.right--;
}
// vertical shadow line after left edge
if (rect.Width() >= 0) {
view->SetHighColor(shadow);
view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
rect.left++;
}
// fill
if (rect.Width() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
}
} else {
// dark vertical line on top edge
if (rect.Height() > 0) {
view->SetHighColor(darkEdge1);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
rect.top++;
}
// dark vertical line on bottom edge
if (rect.Height() >= 0) {
view->SetHighColor(darkEdge2);
view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
rect.bottom--;
}
// horizontal shadow line after top edge
if (rect.Height() >= 0) {
view->SetHighColor(shadow);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
rect.top++;
}
// fill
if (rect.Height() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
}
}
}
void
HaikuControlLook::_DrawDisabledScrollBarBackground(BView* view, BRect rect,
orientation orientation, const rgb_color& light, const rgb_color& dark,
const rgb_color& fill)
{
if (!rect.IsValid())
return;
if (orientation == B_VERTICAL) {
int32 height = rect.IntegerHeight();
if (height == 0) {
view->SetHighColor(dark);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
} else if (height == 1) {
view->SetHighColor(dark);
view->FillRect(rect);
} else {
view->BeginLineArray(4);
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.right, rect.top), dark);
view->AddLine(BPoint(rect.left, rect.bottom - 1),
BPoint(rect.left, rect.top + 1), light);
view->AddLine(BPoint(rect.left + 1, rect.top + 1),
BPoint(rect.right, rect.top + 1), light);
view->AddLine(BPoint(rect.right, rect.bottom),
BPoint(rect.left, rect.bottom), dark);
view->EndLineArray();
rect.left++;
rect.top += 2;
rect.bottom--;
if (rect.IsValid()) {
view->SetHighColor(fill);
view->FillRect(rect);
}
}
} else {
int32 width = rect.IntegerWidth();
if (width == 0) {
view->SetHighColor(dark);
view->StrokeLine(rect.LeftBottom(), rect.LeftTop());
} else if (width == 1) {
view->SetHighColor(dark);
view->FillRect(rect);
} else {
view->BeginLineArray(4);
view->AddLine(BPoint(rect.left, rect.bottom),
BPoint(rect.left, rect.top), dark);
view->AddLine(BPoint(rect.left + 1, rect.bottom),
BPoint(rect.left + 1, rect.top + 1), light);
view->AddLine(BPoint(rect.left + 1, rect.top),
BPoint(rect.right - 1, rect.top), light);
view->AddLine(BPoint(rect.right, rect.top),
BPoint(rect.right, rect.bottom), dark);
view->EndLineArray();
rect.left += 2;
rect.top ++;
rect.right--;
if (rect.IsValid()) {
view->SetHighColor(fill);
view->FillRect(rect);
}
}
}
}
void
HaikuControlLook::_DrawScrollBarArrowButton(BView* view, BRect rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
int32 direction, orientation orientation, bool doubleArrows, bool down)
{
if (!updateRect.Intersects(rect))
return;
// clip to button
BRegion buttonRegion(rect);
view->ConstrainClippingRegion(&buttonRegion);
// TODO: why do we need this for the scroll bar to draw right?
rgb_color arrowColor = tint_color(base, B_LIGHTEN_1_TINT);
// TODO: Why do we need this negative inset for the arrow to look right?
BRect arrowRect(rect.InsetByCopy(-1, -1));
// draw button and arrow
DrawButtonBackground(view, rect, updateRect, arrowColor, flags,
BControlLook::B_ALL_BORDERS, orientation);
DrawArrowShape(view, arrowRect, arrowRect, base, direction,
flags, B_DARKEN_4_TINT);
// revert clipping constratings back to updateRect for next guy
BRegion clipping(updateRect);
view->ConstrainClippingRegion(&clipping);
}
} // namespace BPrivate

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2014 Haiku, Inc. All rights reserved.
* Copyright 2001-2015 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
@ -27,6 +27,8 @@
#include <binary_compatibility/Interface.h>
#include <ScrollBarPrivate.h>
//#define TRACE_SCROLLBAR
#ifdef TRACE_SCROLLBAR
@ -36,31 +38,11 @@
#endif
typedef enum {
ARROW_LEFT = 0,
ARROW_RIGHT,
ARROW_UP,
ARROW_DOWN,
ARROW_NONE
} arrow_direction;
#define SBC_SCROLLBYVALUE 0
#define SBC_SETDOUBLE 1
#define SBC_SETPROPORTIONAL 2
#define SBC_SETSTYLE 3
// Quick constants for determining which arrow is down and are defined with
// respect to double arrow mode. ARROW1 and ARROW4 refer to the outer pair of
// arrows and ARROW2 and ARROW3 refer to the inner ones. ARROW1 points left/up
// and ARROW4 points right/down.
#define ARROW1 0
#define ARROW2 1
#define ARROW3 2
#define ARROW4 3
#define THUMB 4
#define NOARROW -1
static const bigtime_t kRepeatDelay = 300000;
@ -84,7 +66,7 @@ public:
fUpArrowsEnabled(true),
fDownArrowsEnabled(true),
fBorderHighlighted(false),
fButtonDown(NOARROW)
fButtonDown(SCROLL_NO_ARROW)
{
#ifdef TEST_MODE
fScrollBarInfo.proportional = true;
@ -105,6 +87,14 @@ public:
}
}
typedef enum {
ARROW_LEFT = 0,
ARROW_RIGHT,
ARROW_UP,
ARROW_DOWN,
ARROW_NONE
} arrow_direction;
void DrawScrollBarButton(BScrollBar* owner, arrow_direction direction,
BRect frame, bool down = false);
@ -166,7 +156,7 @@ BScrollBar::Private::ButtonRepeaterThread()
if (fScrollBar->LockLooper()) {
if (fDoRepeat) {
float value = fScrollBar->Value() + fThumbInc;
if (fButtonDown == NOARROW) {
if (fButtonDown == SCROLL_NO_ARROW) {
// in this case we want to stop when we're under the mouse
if (fThumbInc > 0.0 && value <= fStopValue)
fScrollBar->SetValue(value);
@ -378,205 +368,28 @@ BScrollBar::DetachedFromWindow()
void
BScrollBar::Draw(BRect updateRect)
{
BRect bounds = Bounds();
rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR);
// stroke a dark frame around the entire scrollbar
// (independent of enabled state)
// take care of border highlighting (scroll target is focus view)
SetHighColor(tint_color(normal, B_DARKEN_2_TINT));
if (fPrivateData->fBorderHighlighted && fPrivateData->fEnabled) {
rgb_color borderColor = HighColor();
rgb_color highlightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
BeginLineArray(4);
AddLine(BPoint(bounds.left + 1, bounds.bottom),
BPoint(bounds.right, bounds.bottom), borderColor);
AddLine(BPoint(bounds.right, bounds.top + 1),
BPoint(bounds.right, bounds.bottom - 1), borderColor);
if (fOrientation == B_HORIZONTAL) {
AddLine(BPoint(bounds.left, bounds.top + 1),
BPoint(bounds.left, bounds.bottom), borderColor);
} else {
AddLine(BPoint(bounds.left, bounds.top),
BPoint(bounds.left, bounds.bottom), highlightColor);
}
if (fOrientation == B_HORIZONTAL) {
AddLine(BPoint(bounds.left, bounds.top),
BPoint(bounds.right, bounds.top), highlightColor);
} else {
AddLine(BPoint(bounds.left + 1, bounds.top),
BPoint(bounds.right, bounds.top), borderColor);
}
EndLineArray();
} else
StrokeRect(bounds);
bounds.InsetBy(1.0f, 1.0f);
bool enabled = fPrivateData->fEnabled && fMin < fMax
&& fProportion < 1.0f && fProportion >= 0.0f;
rgb_color light, dark, dark1, dark2;
if (enabled) {
light = tint_color(normal, B_LIGHTEN_MAX_TINT);
dark = tint_color(normal, B_DARKEN_3_TINT);
dark1 = tint_color(normal, B_DARKEN_1_TINT);
dark2 = tint_color(normal, B_DARKEN_2_TINT);
} else {
light = tint_color(normal, B_LIGHTEN_MAX_TINT);
dark = tint_color(normal, B_DARKEN_2_TINT);
dark1 = tint_color(normal, B_LIGHTEN_2_TINT);
dark2 = tint_color(normal, B_LIGHTEN_1_TINT);
}
SetDrawingMode(B_OP_OVER);
BRect thumbBG = bounds;
bool doubleArrows = _DoubleArrows();
// Draw arrows
if (fOrientation == B_HORIZONTAL) {
BRect buttonFrame(bounds.left, bounds.top,
bounds.left + bounds.Height(), bounds.bottom);
_DrawArrowButton(ARROW_LEFT, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW1);
if (doubleArrows) {
buttonFrame.OffsetBy(bounds.Height() + 1, 0.0f);
_DrawArrowButton(ARROW_RIGHT, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW2);
buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1),
bounds.top);
_DrawArrowButton(ARROW_LEFT, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW3);
thumbBG.left += bounds.Height() * 2 + 2;
thumbBG.right -= bounds.Height() * 2 + 2;
} else {
thumbBG.left += bounds.Height() + 1;
thumbBG.right -= bounds.Height() + 1;
}
buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top);
_DrawArrowButton(ARROW_RIGHT, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW4);
} else {
BRect buttonFrame(bounds.left, bounds.top, bounds.right,
bounds.top + bounds.Width());
_DrawArrowButton(ARROW_UP, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW1);
if (doubleArrows) {
buttonFrame.OffsetBy(0.0f, bounds.Width() + 1);
_DrawArrowButton(ARROW_DOWN, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW2);
buttonFrame.OffsetTo(bounds.left, bounds.bottom
- ((bounds.Width() * 2) + 1));
_DrawArrowButton(ARROW_UP, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW3);
thumbBG.top += bounds.Width() * 2 + 2;
thumbBG.bottom -= bounds.Width() * 2 + 2;
} else {
thumbBG.top += bounds.Width() + 1;
thumbBG.bottom -= bounds.Width() + 1;
}
buttonFrame.OffsetTo(bounds.left, bounds.bottom - bounds.Width());
_DrawArrowButton(ARROW_DOWN, doubleArrows, buttonFrame, updateRect,
enabled, fPrivateData->fButtonDown == ARROW4);
}
SetDrawingMode(B_OP_COPY);
// background for thumb area
BRect rect(fPrivateData->fThumbFrame);
SetHighColor(dark1);
uint32 flags = 0;
if (!enabled)
bool scrollingEnabled = _ScrollingEnabled();
if (scrollingEnabled)
flags |= BControlLook::B_SCROLLABLE;
bool isEnabled = fPrivateData->fEnabled && scrollingEnabled;
if (!isEnabled)
flags |= BControlLook::B_DISABLED;
// fill background besides the thumb
if (fOrientation == B_HORIZONTAL) {
BRect leftOfThumb(thumbBG.left, thumbBG.top, rect.left - 1,
thumbBG.bottom);
BRect rightOfThumb(rect.right + 1, thumbBG.top, thumbBG.right,
thumbBG.bottom);
bool isFocused = fPrivateData->fBorderHighlighted;
if (isFocused)
flags |= BControlLook::B_FOCUSED;
be_control_look->DrawScrollBarBackground(this, leftOfThumb,
rightOfThumb, updateRect, normal, flags, fOrientation);
} else {
BRect topOfThumb(thumbBG.left, thumbBG.top,
thumbBG.right, rect.top - 1);
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
BRect bottomOfThumb(thumbBG.left, rect.bottom + 1,
thumbBG.right, thumbBG.bottom);
BRect rect(Bounds());
BRect thumbRect(fPrivateData->fThumbFrame);
be_control_look->DrawScrollBarBackground(this, topOfThumb,
bottomOfThumb, updateRect, normal, flags, fOrientation);
}
rgb_color thumbColor = ui_color(B_SCROLL_BAR_THUMB_COLOR);
// Draw scroll thumb
if (enabled) {
// fill the clickable surface of the thumb
be_control_look->DrawButtonBackground(this, rect, updateRect,
thumbColor, 0, BControlLook::B_ALL_BORDERS, fOrientation);
// TODO: Add the other thumb styles - dots and lines
} else {
if (fMin >= fMax || fProportion >= 1.0f || fProportion < 0.0f) {
// we cannot scroll at all
_DrawDisabledBackground(thumbBG, light, dark, dark1);
} else {
// we could scroll, but we're simply disabled
float bgTint = 1.06;
rgb_color bgLight = tint_color(light, bgTint * 3);
rgb_color bgShadow = tint_color(dark, bgTint);
rgb_color bgFill = tint_color(dark1, bgTint);
if (fOrientation == B_HORIZONTAL) {
// left of thumb
BRect besidesThumb(thumbBG);
besidesThumb.right = rect.left - 1;
_DrawDisabledBackground(besidesThumb, bgLight, bgShadow, bgFill);
// right of thumb
besidesThumb.left = rect.right + 1;
besidesThumb.right = thumbBG.right;
_DrawDisabledBackground(besidesThumb, bgLight, bgShadow, bgFill);
} else {
// above thumb
BRect besidesThumb(thumbBG);
besidesThumb.bottom = rect.top - 1;
_DrawDisabledBackground(besidesThumb, bgLight, bgShadow, bgFill);
// below thumb
besidesThumb.top = rect.bottom + 1;
besidesThumb.bottom = thumbBG.bottom;
_DrawDisabledBackground(besidesThumb, bgLight, bgShadow, bgFill);
}
// thumb bevel
BeginLineArray(4);
AddLine(BPoint(rect.left, rect.bottom),
BPoint(rect.left, rect.top), light);
AddLine(BPoint(rect.left + 1, rect.top),
BPoint(rect.right, rect.top), light);
AddLine(BPoint(rect.right, rect.top + 1),
BPoint(rect.right, rect.bottom), dark2);
AddLine(BPoint(rect.right - 1, rect.bottom),
BPoint(rect.left + 1, rect.bottom), dark2);
EndLineArray();
// thumb fill
rect.InsetBy(1.0, 1.0);
SetHighColor(dark1);
FillRect(rect);
}
}
be_control_look->DrawScrollBar(this, rect, updateRect, base,
flags, fOrientation, _DoubleArrows(), fPrivateData->fButtonDown);
be_control_look->DrawScrollBarThumb(this, rect, thumbRect, updateRect, base,
flags, fOrientation, fPrivateData->fScrollBarInfo.knob);
}
@ -647,12 +460,16 @@ BScrollBar::MouseDown(BPoint where)
if (buttons & B_SECONDARY_MOUSE_BUTTON) {
// special absolute scrolling: move thumb to where we clicked
fPrivateData->fButtonDown = THUMB;
fPrivateData->fClickOffset = fPrivateData->fThumbFrame.LeftTop() - where;
if (Orientation() == B_HORIZONTAL)
fPrivateData->fClickOffset.x = -fPrivateData->fThumbFrame.Width() / 2;
else
fPrivateData->fClickOffset.y = -fPrivateData->fThumbFrame.Height() / 2;
fPrivateData->fButtonDown = SCROLL_THUMB;
fPrivateData->fClickOffset
= fPrivateData->fThumbFrame.LeftTop() - where;
if (Orientation() == B_HORIZONTAL) {
fPrivateData->fClickOffset.x
= -fPrivateData->fThumbFrame.Width() / 2;
} else {
fPrivateData->fClickOffset.y
= -fPrivateData->fThumbFrame.Height() / 2;
}
SetValue(_ValueFor(where + fPrivateData->fClickOffset));
return;
@ -660,8 +477,9 @@ BScrollBar::MouseDown(BPoint where)
// hit test for the thumb
if (fPrivateData->fThumbFrame.Contains(where)) {
fPrivateData->fButtonDown = THUMB;
fPrivateData->fClickOffset = fPrivateData->fThumbFrame.LeftTop() - where;
fPrivateData->fButtonDown = SCROLL_THUMB;
fPrivateData->fClickOffset
= fPrivateData->fThumbFrame.LeftTop() - where;
Invalidate(fPrivateData->fThumbFrame);
return;
}
@ -675,23 +493,23 @@ BScrollBar::MouseDown(BPoint where)
fPrivateData->fButtonDown = _ButtonFor(where);
switch (fPrivateData->fButtonDown) {
case ARROW1:
case SCROLL_ARROW_1:
scrollValue = -buttonStepSize;
break;
case ARROW2:
case SCROLL_ARROW_2:
scrollValue = buttonStepSize;
break;
case ARROW3:
case SCROLL_ARROW_3:
scrollValue = -buttonStepSize;
break;
case ARROW4:
case SCROLL_ARROW_4:
scrollValue = buttonStepSize;
break;
case NOARROW:
case SCROLL_NO_ARROW:
// we hit the empty area, figure out which side of the thumb
if (fOrientation == B_VERTICAL) {
if (where.y < fPrivateData->fThumbFrame.top)
@ -733,13 +551,11 @@ BScrollBar::MouseDown(BPoint where)
void
BScrollBar::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
{
if (!fPrivateData->fEnabled || fMin >= fMax || fProportion >= 1.0f
|| fProportion < 0.0f) {
if (!fPrivateData->fEnabled || !_ScrollingEnabled())
return;
}
if (fPrivateData->fButtonDown != NOARROW) {
if (fPrivateData->fButtonDown == THUMB) {
if (fPrivateData->fButtonDown != SCROLL_NO_ARROW) {
if (fPrivateData->fButtonDown == SCROLL_THUMB) {
SetValue(_ValueFor(where + fPrivateData->fClickOffset));
} else {
// suspend the repeating if the mouse is not over the button
@ -769,12 +585,12 @@ BScrollBar::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
void
BScrollBar::MouseUp(BPoint where)
{
if (fPrivateData->fButtonDown == THUMB)
if (fPrivateData->fButtonDown == SCROLL_THUMB)
Invalidate(fPrivateData->fThumbFrame);
else
Invalidate(_ButtonRectFor(fPrivateData->fButtonDown));
fPrivateData->fButtonDown = NOARROW;
fPrivateData->fButtonDown = SCROLL_NO_ARROW;
fPrivateData->fExitRepeater = true;
fPrivateData->fDoRepeat = false;
}
@ -858,13 +674,11 @@ BScrollBar::SetProportion(float value)
TRACE("BScrollBar(%s)::SetProportion(%.1f)\n", Name(), value);
bool oldEnabled = fPrivateData->fEnabled && fMin < fMax
&& fProportion < 1.0f && fProportion >= 0.0f;
bool oldEnabled = fPrivateData->fEnabled && _ScrollingEnabled();
fProportion = value;
bool newEnabled = fPrivateData->fEnabled && fMin < fMax
&& fProportion < 1.0f && fProportion >= 0.0f;
bool newEnabled = fPrivateData->fEnabled && _ScrollingEnabled();
_UpdateThumbFrame();
@ -1216,6 +1030,13 @@ BScrollBar::operator=(const BScrollBar&)
}
bool
BScrollBar::_ScrollingEnabled() const
{
return fMin < fMax && fProportion >= 0.0f && fProportion < 1.0f;
}
bool
BScrollBar::_DoubleArrows() const
{
@ -1387,39 +1208,39 @@ BScrollBar::_ButtonFor(BPoint where) const
if (fOrientation == B_VERTICAL) {
if (rect.Contains(where))
return ARROW1;
return SCROLL_ARROW_1;
if (_DoubleArrows()) {
rect.OffsetBy(0.0, buttonSize);
if (rect.Contains(where))
return ARROW2;
return SCROLL_ARROW_2;
rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize);
if (rect.Contains(where))
return ARROW3;
return SCROLL_ARROW_3;
}
rect.OffsetTo(bounds.left, bounds.bottom - buttonSize);
if (rect.Contains(where))
return ARROW4;
return SCROLL_ARROW_4;
} else {
if (rect.Contains(where))
return ARROW1;
return SCROLL_ARROW_1;
if (_DoubleArrows()) {
rect.OffsetBy(buttonSize, 0.0);
if (rect.Contains(where))
return ARROW2;
return SCROLL_ARROW_2;
rect.OffsetTo(bounds.right - 2 * buttonSize, bounds.top);
if (rect.Contains(where))
return ARROW3;
return SCROLL_ARROW_3;
}
rect.OffsetTo(bounds.right - buttonSize, bounds.top);
if (rect.Contains(where))
return ARROW4;
return SCROLL_ARROW_4;
}
return NOARROW;
return SCROLL_NO_ARROW;
}
@ -1438,35 +1259,35 @@ BScrollBar::_ButtonRectFor(int32 button) const
if (fOrientation == B_VERTICAL) {
switch (button) {
case ARROW1:
case SCROLL_ARROW_1:
break;
case ARROW2:
case SCROLL_ARROW_2:
rect.OffsetBy(0.0, buttonSize);
break;
case ARROW3:
case SCROLL_ARROW_3:
rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize + 1);
break;
case ARROW4:
case SCROLL_ARROW_4:
rect.OffsetTo(bounds.left, bounds.bottom - buttonSize + 1);
break;
}
} else {
switch (button) {
case ARROW1:
case SCROLL_ARROW_1:
break;
case ARROW2:
case SCROLL_ARROW_2:
rect.OffsetBy(buttonSize, 0.0);
break;
case ARROW3:
case SCROLL_ARROW_3:
rect.OffsetTo(bounds.right - 2 * buttonSize + 1, bounds.top);
break;
case ARROW4:
case SCROLL_ARROW_4:
rect.OffsetTo(bounds.right - buttonSize + 1, bounds.top);
break;
}
@ -1495,17 +1316,17 @@ BScrollBar::_UpdateArrowButtons()
bool upEnabled = fValue > fMin;
if (fPrivateData->fUpArrowsEnabled != upEnabled) {
fPrivateData->fUpArrowsEnabled = upEnabled;
Invalidate(_ButtonRectFor(ARROW1));
Invalidate(_ButtonRectFor(SCROLL_ARROW_1));
if (_DoubleArrows())
Invalidate(_ButtonRectFor(ARROW3));
Invalidate(_ButtonRectFor(SCROLL_ARROW_3));
}
bool downEnabled = fValue < fMax;
if (fPrivateData->fDownArrowsEnabled != downEnabled) {
fPrivateData->fDownArrowsEnabled = downEnabled;
Invalidate(_ButtonRectFor(ARROW4));
Invalidate(_ButtonRectFor(SCROLL_ARROW_4));
if (_DoubleArrows())
Invalidate(_ButtonRectFor(ARROW2));
Invalidate(_ButtonRectFor(SCROLL_ARROW_2));
}
}
@ -1552,101 +1373,6 @@ control_scrollbar(scroll_bar_info* info, BScrollBar* bar)
}
void
BScrollBar::_DrawDisabledBackground(BRect area, const rgb_color& light,
const rgb_color& dark, const rgb_color& fill)
{
if (!area.IsValid())
return;
if (fOrientation == B_VERTICAL) {
int32 height = area.IntegerHeight();
if (height == 0) {
SetHighColor(dark);
StrokeLine(area.LeftTop(), area.RightTop());
} else if (height == 1) {
SetHighColor(dark);
FillRect(area);
} else {
BeginLineArray(4);
AddLine(BPoint(area.left, area.top),
BPoint(area.right, area.top), dark);
AddLine(BPoint(area.left, area.bottom - 1),
BPoint(area.left, area.top + 1), light);
AddLine(BPoint(area.left + 1, area.top + 1),
BPoint(area.right, area.top + 1), light);
AddLine(BPoint(area.right, area.bottom),
BPoint(area.left, area.bottom), dark);
EndLineArray();
area.left++;
area.top += 2;
area.bottom--;
if (area.IsValid()) {
SetHighColor(fill);
FillRect(area);
}
}
} else {
int32 width = area.IntegerWidth();
if (width == 0) {
SetHighColor(dark);
StrokeLine(area.LeftBottom(), area.LeftTop());
} else if (width == 1) {
SetHighColor(dark);
FillRect(area);
} else {
BeginLineArray(4);
AddLine(BPoint(area.left, area.bottom),
BPoint(area.left, area.top), dark);
AddLine(BPoint(area.left + 1, area.bottom),
BPoint(area.left + 1, area.top + 1), light);
AddLine(BPoint(area.left + 1, area.top),
BPoint(area.right - 1, area.top), light);
AddLine(BPoint(area.right, area.top),
BPoint(area.right, area.bottom), dark);
EndLineArray();
area.left += 2;
area.top ++;
area.right--;
if (area.IsValid()) {
SetHighColor(fill);
FillRect(area);
}
}
}
}
void
BScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect rect,
const BRect& updateRect, bool enabled, bool down)
{
if (!updateRect.Intersects(rect))
return;
uint32 flags = 0;
if (!enabled)
flags |= BControlLook::B_DISABLED;
if (down && fPrivateData->fDoRepeat)
flags |= BControlLook::B_ACTIVATED;
// TODO: Why does BControlLook need this as the base color for the
// scrollbar to look right?
rgb_color baseColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
B_LIGHTEN_1_TINT);
be_control_look->DrawButtonBackground(this, rect, updateRect, baseColor,
flags, BControlLook::B_ALL_BORDERS, fOrientation);
// TODO: Why does BControlLook need this negative inset for the arrow to
// look right?
rect.InsetBy(-1.0f, -1.0f);
be_control_look->DrawArrowShape(this, rect, updateRect,
baseColor, direction, flags, B_DARKEN_MAX_TINT);
}
BSize
BScrollBar::_MinSize() const
{

View File

@ -35,8 +35,10 @@ FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows,
fDrawArrows(drawArrows),
fDoubleArrows(doubleArrows)
{
SetExplicitMinSize(BSize(160, 20));
SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20));
// add some height to draw the ring around the scroll bar
float height = B_H_SCROLL_BAR_HEIGHT + 8;
SetExplicitMinSize(BSize(200, height));
SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, height));
}
@ -48,99 +50,42 @@ FakeScrollBar::~FakeScrollBar(void)
void
FakeScrollBar::Draw(BRect updateRect)
{
BRect bounds = Bounds();
BRect rect(Bounds());
rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
if (IsFocus()) {
// draw the focus indicator
SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR));
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
uint32 flags = BControlLook::B_SCROLLABLE;
if (IsFocus())
flags |= BControlLook::B_FOCUSED;
// Draw the selected border (1px)
if (Value() == B_CONTROL_ON)
SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
else
SetHighColor(normal);
if (Value() == B_CONTROL_ON)
SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
else
SetHighColor(base);
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
} else {
// Draw the selected border (2px)
if (Value() == B_CONTROL_ON)
SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
else
SetHighColor(normal);
// Draw the selected border (2px)
StrokeRect(rect);
rect.InsetBy(1, 1);
StrokeRect(rect);
rect.InsetBy(1, 1);
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
}
// draw a 1px gap
SetHighColor(base);
StrokeRect(rect);
rect.InsetBy(1, 1);
// draw a gap (1px)
SetHighColor(normal);
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
// draw a 1px border around control
SetHighColor(tint_color(base, B_DARKEN_1_TINT));
StrokeRect(rect);
rect.InsetBy(1, 1);
SetHighColor(base);
// draw a border around control (1px)
SetHighColor(tint_color(normal, B_DARKEN_1_TINT));
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
BRect thumbBG = bounds;
BRect bgRect = bounds;
if (fDrawArrows) {
// draw arrows
SetDrawingMode(B_OP_OVER);
BRect buttonFrame(bounds.left, bounds.top,
bounds.left + bounds.Height(), bounds.bottom);
_DrawArrowButton(ARROW_LEFT, buttonFrame, updateRect);
if (fDoubleArrows) {
buttonFrame.OffsetBy(bounds.Height() + 1, 0.0);
_DrawArrowButton(ARROW_RIGHT, buttonFrame,
updateRect);
buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1),
bounds.top);
_DrawArrowButton(ARROW_LEFT, buttonFrame,
updateRect);
thumbBG.left += bounds.Height() * 2 + 2;
thumbBG.right -= bounds.Height() * 2 + 2;
} else {
thumbBG.left += bounds.Height() + 1;
thumbBG.right -= bounds.Height() + 1;
}
buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top);
_DrawArrowButton(ARROW_RIGHT, buttonFrame, updateRect);
SetDrawingMode(B_OP_COPY);
bgRect = bounds.InsetByCopy(48, 0);
} else
bgRect = bounds.InsetByCopy(16, 0);
// fill background besides the thumb
BRect leftOfThumb(thumbBG.left, thumbBG.top, bgRect.left - 1,
thumbBG.bottom);
BRect rightOfThumb(bgRect.right + 1, thumbBG.top, thumbBG.right,
thumbBG.bottom);
be_control_look->DrawScrollBarBackground(this, leftOfThumb,
rightOfThumb, updateRect, normal, 0, B_HORIZONTAL);
// Draw scroll thumb
// fill the clickable surface of the thumb
be_control_look->DrawButtonBackground(this, bgRect, updateRect,
normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
be_control_look->DrawScrollBar(this, rect, updateRect, base,
flags, B_HORIZONTAL, fDoubleArrows);
float less = floorf(rect.Width() / 3); // thumb takes up 1/3 full width
BRect thumbRect(rect.left + less, rect.top, rect.right - less, rect.bottom);
be_control_look->DrawScrollBarThumb(this, rect, thumbRect, updateRect, base,
flags, B_HORIZONTAL, fKnobStyle);
}