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-16 16:11:46 +00:00
committed by waddlesplash
parent 70f1070b6f
commit ec1b18c58a
7 changed files with 734 additions and 544 deletions
+9 -6
View File
@@ -86,6 +86,7 @@ public:
B_FLAT = 1 << 8, // flat look (e.g. button background) B_FLAT = 1 << 8, // flat look (e.g. button background)
B_INVALID = 1 << 9, // invalid value, use B_FAILURE_COLOR B_INVALID = 1 << 9, // invalid value, use B_FAILURE_COLOR
B_IS_CONTROL = 1 << 10, // use control colors B_IS_CONTROL = 1 << 10, // use control colors
B_SCROLLABLE = 1 << 11, // scroll bar within bounds
B_BLEND_FRAME = 1 << 16, B_BLEND_FRAME = 1 << 16,
}; };
@@ -224,15 +225,17 @@ public:
const rgb_color& base, const rgb_color& base,
uint32 flags = 0) = 0; uint32 flags = 0) = 0;
virtual void DrawScrollBarBackground(BView* view, virtual void DrawScrollBar(BView* view, BRect& rect,
BRect& rect1, BRect& rect2,
const BRect& updateRect, const BRect& updateRect,
const rgb_color& base, uint32 flags, const rgb_color& base, uint32 flags,
orientation orientation) = 0; orientation orientation,
virtual void DrawScrollBarBackground(BView* view, bool doubleArrows = false,
BRect& rect, const BRect& updateRect, int32 buttonDown = -1) = 0;
virtual void DrawScrollBarThumb(BView* view, BRect& rect,
BRect& thumbRect, const BRect& updateRect,
const rgb_color& base, uint32 flags, const rgb_color& base, uint32 flags,
orientation orientation) = 0; orientation orientation,
uint32 knobStyle = 0) = 0;
virtual void DrawScrollViewFrame(BView* view, virtual void DrawScrollViewFrame(BView* view,
BRect& rect, const BRect& updateRect, BRect& rect, const BRect& updateRect,
+1 -8
View File
@@ -114,6 +114,7 @@ private:
// disabled // disabled
BScrollBar& operator=(const BScrollBar& other); BScrollBar& operator=(const BScrollBar& other);
bool _ScrollingEnabled() const;
bool _DoubleArrows() const; bool _DoubleArrows() const;
void _UpdateThumbFrame(); void _UpdateThumbFrame();
float _ValueFor(BPoint where) const; float _ValueFor(BPoint where) const;
@@ -121,14 +122,6 @@ private:
BRect _ButtonRectFor(int32 button) const; BRect _ButtonRectFor(int32 button) const;
void _UpdateTargetValue(BPoint where); void _UpdateTargetValue(BPoint where);
void _UpdateArrowButtons(); 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; BSize _MinSize() const;
+28 -6
View File
@@ -157,15 +157,17 @@ public:
const rgb_color& base, const rgb_color& base,
uint32 flags = 0); uint32 flags = 0);
virtual void DrawScrollBarBackground(BView* view, virtual void DrawScrollBar(BView* view, BRect& rect,
BRect& rect1, BRect& rect2,
const BRect& updateRect, const BRect& updateRect,
const rgb_color& base, uint32 flags, const rgb_color& base, uint32 flags,
orientation orientation); orientation orientation,
virtual void DrawScrollBarBackground(BView* view, bool doubleArrows = false,
BRect& rect, const BRect& updateRect, int32 buttonDown = -1);
virtual void DrawScrollBarThumb(BView* view, BRect& rect,
BRect& thumbRect, const BRect& updateRect,
const rgb_color& base, uint32 flags, const rgb_color& base, uint32 flags,
orientation orientation); orientation orientation,
uint32 knobStyle = 0);
virtual void DrawScrollViewFrame(BView* view, virtual void DrawScrollViewFrame(BView* view,
BRect& rect, const BRect& updateRect, BRect& rect, const BRect& updateRect,
@@ -559,6 +561,26 @@ protected:
const rgb_color& base, rgb_color& color, const rgb_color& base, rgb_color& color,
uint32 flags) const; 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: private:
bool fCachedOutline; bool fCachedOutline;
}; };
@@ -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
+549 -80
View File
@@ -18,6 +18,7 @@
#include <GradientLinear.h> #include <GradientLinear.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
#include <Region.h> #include <Region.h>
#include <ScrollBarPrivate.h>
#include <Shape.h> #include <Shape.h>
#include <String.h> #include <String.h>
#include <View.h> #include <View.h>
@@ -562,96 +563,359 @@ HaikuControlLook::DrawRadioButton(BView* view, BRect& rect, const BRect& updateR
void void
HaikuControlLook::DrawScrollBarBackground(BView* view, BRect& rect1, BRect& rect2, HaikuControlLook::DrawScrollBar(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags, const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation) orientation orientation, bool doubleArrows, int32 buttonDown)
{
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)) if (!rect.IsValid() || !rect.Intersects(updateRect))
return; return;
float gradient1Tint; // save the clipping constraints of the view
float gradient2Tint; view->PushState();
float darkEdge1Tint;
float darkEdge2Tint;
float shadowTint;
if ((flags & B_DISABLED) != 0) { // set clipping constraints to updateRect
gradient1Tint = 0.9; BRegion clipping(updateRect);
gradient2Tint = 0.8; view->ConstrainClippingRegion(&clipping);
darkEdge1Tint = B_DARKEN_2_TINT;
darkEdge2Tint = B_DARKEN_2_TINT; // flags
shadowTint = gradient1Tint; 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 { } else {
gradient1Tint = 1.10; light = tint_color(base, B_LIGHTEN_MAX_TINT);
gradient2Tint = 1.05; dark = tint_color(base, B_DARKEN_2_TINT);
darkEdge1Tint = B_DARKEN_3_TINT; dark1 = tint_color(base, B_LIGHTEN_2_TINT);
darkEdge2Tint = B_DARKEN_2_TINT; dark2 = tint_color(base, B_LIGHTEN_1_TINT);
shadowTint = gradient1Tint;
} }
rgb_color darkEdge1 = tint_color(base, darkEdge1Tint); // Stroke a dark frame around the scroll bar background independent of
rgb_color darkEdge2 = tint_color(base, darkEdge2Tint); // enabled state, also handle focus highlighting.
rgb_color shadow = tint_color(base, shadowTint); 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) { if (orientation == B_HORIZONTAL) {
// dark vertical line on left edge buttonFrame1.Set(rect.left, rect.top,
if (rect.Width() > 0) { rect.left + rect.Height(), rect.bottom);
view->SetHighColor(darkEdge1); if (doubleArrows) {
view->StrokeLine(rect.LeftTop(), rect.LeftBottom()); buttonFrame2 = buttonFrame1.OffsetByCopy(rect.Height() + 1, 0);
rect.left++; buttonFrame3 = buttonFrame2.OffsetToCopy(
} rect.right - (rect.Height() * 2 + 1), rect.top);
// 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);
} }
buttonFrame4 = buttonFrame1.OffsetToCopy(rect.right - rect.Height(),
rect.top);
} else { } else {
// dark vertical line on top edge buttonFrame1.Set(rect.left, rect.top, rect.right,
if (rect.Height() > 0) { rect.top + rect.Width());
view->SetHighColor(darkEdge1); if (doubleArrows) {
view->StrokeLine(rect.LeftTop(), rect.RightTop()); buttonFrame2 = buttonFrame1.OffsetByCopy(0, rect.Width() + 1);
rect.top++; buttonFrame3 = buttonFrame2.OffsetToCopy(rect.left, rect.bottom
- ((rect.Width() * 2) + 1));
} }
// dark vertical line on bottom edge buttonFrame4 = buttonFrame1.OffsetToCopy(rect.left,
if (rect.Height() >= 0) { rect.bottom - rect.Width());
view->SetHighColor(darkEdge2); }
view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
rect.bottom--; // add to clipping region
} buttonRegion.Include(buttonFrame1);
// horizontal shadow line after top edge if (doubleArrows) {
if (rect.Height() >= 0) { buttonRegion.Include(buttonFrame2);
view->SetHighColor(shadow); buttonRegion.Include(buttonFrame3);
view->StrokeLine(rect.LeftTop(), rect.RightTop()); }
rect.top++; buttonRegion.Include(buttonFrame4);
}
// fill // clip to button region
if (rect.Height() >= 0) { view->ConstrainClippingRegion(&buttonRegion);
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation); // 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 void
HaikuControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect, HaikuControlLook::DrawArrowShape(BView* view, BRect& rect,
const rgb_color& base, uint32 direction, uint32 flags, float tint) const BRect& updateRect, const rgb_color& base, uint32 direction,
uint32 flags, float tint)
{ {
BPoint tri1, tri2, tri3; BPoint tri1, tri2, tri3;
float hInset = rect.Width() / 3; float hInset = rect.Width() / 3;
@@ -1004,20 +1269,24 @@ HaikuControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect
view->BeginLineArray(4); view->BeginLineArray(4);
if (orientation == B_HORIZONTAL) { if (orientation == B_HORIZONTAL) {
view->AddLine(barRect.LeftTop(), barRect.RightTop(), edgeShadowColor); view->AddLine(barRect.LeftTop(), barRect.RightTop(),
edgeShadowColor);
view->AddLine(barRect.LeftBottom(), barRect.RightBottom(), view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
edgeLightColor); edgeLightColor);
barRect.InsetBy(0, 1); barRect.InsetBy(0, 1);
view->AddLine(barRect.LeftTop(), barRect.RightTop(), frameShadowColor); view->AddLine(barRect.LeftTop(), barRect.RightTop(),
frameShadowColor);
view->AddLine(barRect.LeftBottom(), barRect.RightBottom(), view->AddLine(barRect.LeftBottom(), barRect.RightBottom(),
frameLightColor); frameLightColor);
barRect.InsetBy(0, 1); barRect.InsetBy(0, 1);
} else { } else {
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), edgeShadowColor); view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
edgeShadowColor);
view->AddLine(barRect.RightTop(), barRect.RightBottom(), view->AddLine(barRect.RightTop(), barRect.RightBottom(),
edgeLightColor); edgeLightColor);
barRect.InsetBy(1, 0); barRect.InsetBy(1, 0);
view->AddLine(barRect.LeftTop(), barRect.LeftBottom(), frameShadowColor); view->AddLine(barRect.LeftTop(), barRect.LeftBottom(),
frameShadowColor);
view->AddLine(barRect.RightTop(), barRect.RightBottom(), view->AddLine(barRect.RightTop(), barRect.RightBottom(),
frameLightColor); frameLightColor);
barRect.InsetBy(1, 0); 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 } // namespace BPrivate
+82 -356
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. * Distributed under the terms of the MIT license.
* *
* Authors: * Authors:
@@ -27,6 +27,8 @@
#include <binary_compatibility/Interface.h> #include <binary_compatibility/Interface.h>
#include <ScrollBarPrivate.h>
//#define TRACE_SCROLLBAR //#define TRACE_SCROLLBAR
#ifdef TRACE_SCROLLBAR #ifdef TRACE_SCROLLBAR
@@ -36,31 +38,11 @@
#endif #endif
typedef enum {
ARROW_LEFT = 0,
ARROW_RIGHT,
ARROW_UP,
ARROW_DOWN,
ARROW_NONE
} arrow_direction;
#define SBC_SCROLLBYVALUE 0 #define SBC_SCROLLBYVALUE 0
#define SBC_SETDOUBLE 1 #define SBC_SETDOUBLE 1
#define SBC_SETPROPORTIONAL 2 #define SBC_SETPROPORTIONAL 2
#define SBC_SETSTYLE 3 #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; static const bigtime_t kRepeatDelay = 300000;
@@ -84,7 +66,7 @@ public:
fUpArrowsEnabled(true), fUpArrowsEnabled(true),
fDownArrowsEnabled(true), fDownArrowsEnabled(true),
fBorderHighlighted(false), fBorderHighlighted(false),
fButtonDown(NOARROW) fButtonDown(SCROLL_NO_ARROW)
{ {
#ifdef TEST_MODE #ifdef TEST_MODE
fScrollBarInfo.proportional = true; 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, void DrawScrollBarButton(BScrollBar* owner, arrow_direction direction,
BRect frame, bool down = false); BRect frame, bool down = false);
@@ -166,7 +156,7 @@ BScrollBar::Private::ButtonRepeaterThread()
if (fScrollBar->LockLooper()) { if (fScrollBar->LockLooper()) {
if (fDoRepeat) { if (fDoRepeat) {
float value = fScrollBar->Value() + fThumbInc; 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 // in this case we want to stop when we're under the mouse
if (fThumbInc > 0.0 && value <= fStopValue) if (fThumbInc > 0.0 && value <= fStopValue)
fScrollBar->SetValue(value); fScrollBar->SetValue(value);
@@ -378,205 +368,28 @@ BScrollBar::DetachedFromWindow()
void void
BScrollBar::Draw(BRect updateRect) 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; 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; flags |= BControlLook::B_DISABLED;
// fill background besides the thumb bool isFocused = fPrivateData->fBorderHighlighted;
if (fOrientation == B_HORIZONTAL) { if (isFocused)
BRect leftOfThumb(thumbBG.left, thumbBG.top, rect.left - 1, flags |= BControlLook::B_FOCUSED;
thumbBG.bottom);
BRect rightOfThumb(rect.right + 1, thumbBG.top, thumbBG.right,
thumbBG.bottom);
be_control_look->DrawScrollBarBackground(this, leftOfThumb, rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
rightOfThumb, updateRect, normal, flags, fOrientation);
} else {
BRect topOfThumb(thumbBG.left, thumbBG.top,
thumbBG.right, rect.top - 1);
BRect bottomOfThumb(thumbBG.left, rect.bottom + 1, BRect rect(Bounds());
thumbBG.right, thumbBG.bottom); BRect thumbRect(fPrivateData->fThumbFrame);
be_control_look->DrawScrollBarBackground(this, topOfThumb, be_control_look->DrawScrollBar(this, rect, updateRect, base,
bottomOfThumb, updateRect, normal, flags, fOrientation); flags, fOrientation, _DoubleArrows(), fPrivateData->fButtonDown);
} be_control_look->DrawScrollBarThumb(this, rect, thumbRect, updateRect, base,
flags, fOrientation, fPrivateData->fScrollBarInfo.knob);
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);
}
}
} }
@@ -647,12 +460,16 @@ BScrollBar::MouseDown(BPoint where)
if (buttons & B_SECONDARY_MOUSE_BUTTON) { if (buttons & B_SECONDARY_MOUSE_BUTTON) {
// special absolute scrolling: move thumb to where we clicked // special absolute scrolling: move thumb to where we clicked
fPrivateData->fButtonDown = THUMB; fPrivateData->fButtonDown = SCROLL_THUMB;
fPrivateData->fClickOffset = fPrivateData->fThumbFrame.LeftTop() - where; fPrivateData->fClickOffset
if (Orientation() == B_HORIZONTAL) = fPrivateData->fThumbFrame.LeftTop() - where;
fPrivateData->fClickOffset.x = -fPrivateData->fThumbFrame.Width() / 2; if (Orientation() == B_HORIZONTAL) {
else fPrivateData->fClickOffset.x
fPrivateData->fClickOffset.y = -fPrivateData->fThumbFrame.Height() / 2; = -fPrivateData->fThumbFrame.Width() / 2;
} else {
fPrivateData->fClickOffset.y
= -fPrivateData->fThumbFrame.Height() / 2;
}
SetValue(_ValueFor(where + fPrivateData->fClickOffset)); SetValue(_ValueFor(where + fPrivateData->fClickOffset));
return; return;
@@ -660,8 +477,9 @@ BScrollBar::MouseDown(BPoint where)
// hit test for the thumb // hit test for the thumb
if (fPrivateData->fThumbFrame.Contains(where)) { if (fPrivateData->fThumbFrame.Contains(where)) {
fPrivateData->fButtonDown = THUMB; fPrivateData->fButtonDown = SCROLL_THUMB;
fPrivateData->fClickOffset = fPrivateData->fThumbFrame.LeftTop() - where; fPrivateData->fClickOffset
= fPrivateData->fThumbFrame.LeftTop() - where;
Invalidate(fPrivateData->fThumbFrame); Invalidate(fPrivateData->fThumbFrame);
return; return;
} }
@@ -675,23 +493,23 @@ BScrollBar::MouseDown(BPoint where)
fPrivateData->fButtonDown = _ButtonFor(where); fPrivateData->fButtonDown = _ButtonFor(where);
switch (fPrivateData->fButtonDown) { switch (fPrivateData->fButtonDown) {
case ARROW1: case SCROLL_ARROW_1:
scrollValue = -buttonStepSize; scrollValue = -buttonStepSize;
break; break;
case ARROW2: case SCROLL_ARROW_2:
scrollValue = buttonStepSize; scrollValue = buttonStepSize;
break; break;
case ARROW3: case SCROLL_ARROW_3:
scrollValue = -buttonStepSize; scrollValue = -buttonStepSize;
break; break;
case ARROW4: case SCROLL_ARROW_4:
scrollValue = buttonStepSize; scrollValue = buttonStepSize;
break; break;
case NOARROW: case SCROLL_NO_ARROW:
// we hit the empty area, figure out which side of the thumb // we hit the empty area, figure out which side of the thumb
if (fOrientation == B_VERTICAL) { if (fOrientation == B_VERTICAL) {
if (where.y < fPrivateData->fThumbFrame.top) if (where.y < fPrivateData->fThumbFrame.top)
@@ -733,13 +551,11 @@ BScrollBar::MouseDown(BPoint where)
void void
BScrollBar::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) BScrollBar::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
{ {
if (!fPrivateData->fEnabled || fMin >= fMax || fProportion >= 1.0f if (!fPrivateData->fEnabled || !_ScrollingEnabled())
|| fProportion < 0.0f) {
return; return;
}
if (fPrivateData->fButtonDown != NOARROW) { if (fPrivateData->fButtonDown != SCROLL_NO_ARROW) {
if (fPrivateData->fButtonDown == THUMB) { if (fPrivateData->fButtonDown == SCROLL_THUMB) {
SetValue(_ValueFor(where + fPrivateData->fClickOffset)); SetValue(_ValueFor(where + fPrivateData->fClickOffset));
} else { } else {
// suspend the repeating if the mouse is not over the button // 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 void
BScrollBar::MouseUp(BPoint where) BScrollBar::MouseUp(BPoint where)
{ {
if (fPrivateData->fButtonDown == THUMB) if (fPrivateData->fButtonDown == SCROLL_THUMB)
Invalidate(fPrivateData->fThumbFrame); Invalidate(fPrivateData->fThumbFrame);
else else
Invalidate(_ButtonRectFor(fPrivateData->fButtonDown)); Invalidate(_ButtonRectFor(fPrivateData->fButtonDown));
fPrivateData->fButtonDown = NOARROW; fPrivateData->fButtonDown = SCROLL_NO_ARROW;
fPrivateData->fExitRepeater = true; fPrivateData->fExitRepeater = true;
fPrivateData->fDoRepeat = false; fPrivateData->fDoRepeat = false;
} }
@@ -858,13 +674,11 @@ BScrollBar::SetProportion(float value)
TRACE("BScrollBar(%s)::SetProportion(%.1f)\n", Name(), value); TRACE("BScrollBar(%s)::SetProportion(%.1f)\n", Name(), value);
bool oldEnabled = fPrivateData->fEnabled && fMin < fMax bool oldEnabled = fPrivateData->fEnabled && _ScrollingEnabled();
&& fProportion < 1.0f && fProportion >= 0.0f;
fProportion = value; fProportion = value;
bool newEnabled = fPrivateData->fEnabled && fMin < fMax bool newEnabled = fPrivateData->fEnabled && _ScrollingEnabled();
&& fProportion < 1.0f && fProportion >= 0.0f;
_UpdateThumbFrame(); _UpdateThumbFrame();
@@ -1216,6 +1030,13 @@ BScrollBar::operator=(const BScrollBar&)
} }
bool
BScrollBar::_ScrollingEnabled() const
{
return fMin < fMax && fProportion >= 0.0f && fProportion < 1.0f;
}
bool bool
BScrollBar::_DoubleArrows() const BScrollBar::_DoubleArrows() const
{ {
@@ -1387,39 +1208,39 @@ BScrollBar::_ButtonFor(BPoint where) const
if (fOrientation == B_VERTICAL) { if (fOrientation == B_VERTICAL) {
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW1; return SCROLL_ARROW_1;
if (_DoubleArrows()) { if (_DoubleArrows()) {
rect.OffsetBy(0.0, buttonSize); rect.OffsetBy(0.0, buttonSize);
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW2; return SCROLL_ARROW_2;
rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize); rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize);
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW3; return SCROLL_ARROW_3;
} }
rect.OffsetTo(bounds.left, bounds.bottom - buttonSize); rect.OffsetTo(bounds.left, bounds.bottom - buttonSize);
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW4; return SCROLL_ARROW_4;
} else { } else {
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW1; return SCROLL_ARROW_1;
if (_DoubleArrows()) { if (_DoubleArrows()) {
rect.OffsetBy(buttonSize, 0.0); rect.OffsetBy(buttonSize, 0.0);
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW2; return SCROLL_ARROW_2;
rect.OffsetTo(bounds.right - 2 * buttonSize, bounds.top); rect.OffsetTo(bounds.right - 2 * buttonSize, bounds.top);
if (rect.Contains(where)) if (rect.Contains(where))
return ARROW3; return SCROLL_ARROW_3;
} }
rect.OffsetTo(bounds.right - buttonSize, bounds.top); rect.OffsetTo(bounds.right - buttonSize, bounds.top);
if (rect.Contains(where)) 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) { if (fOrientation == B_VERTICAL) {
switch (button) { switch (button) {
case ARROW1: case SCROLL_ARROW_1:
break; break;
case ARROW2: case SCROLL_ARROW_2:
rect.OffsetBy(0.0, buttonSize); rect.OffsetBy(0.0, buttonSize);
break; break;
case ARROW3: case SCROLL_ARROW_3:
rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize + 1); rect.OffsetTo(bounds.left, bounds.bottom - 2 * buttonSize + 1);
break; break;
case ARROW4: case SCROLL_ARROW_4:
rect.OffsetTo(bounds.left, bounds.bottom - buttonSize + 1); rect.OffsetTo(bounds.left, bounds.bottom - buttonSize + 1);
break; break;
} }
} else { } else {
switch (button) { switch (button) {
case ARROW1: case SCROLL_ARROW_1:
break; break;
case ARROW2: case SCROLL_ARROW_2:
rect.OffsetBy(buttonSize, 0.0); rect.OffsetBy(buttonSize, 0.0);
break; break;
case ARROW3: case SCROLL_ARROW_3:
rect.OffsetTo(bounds.right - 2 * buttonSize + 1, bounds.top); rect.OffsetTo(bounds.right - 2 * buttonSize + 1, bounds.top);
break; break;
case ARROW4: case SCROLL_ARROW_4:
rect.OffsetTo(bounds.right - buttonSize + 1, bounds.top); rect.OffsetTo(bounds.right - buttonSize + 1, bounds.top);
break; break;
} }
@@ -1495,17 +1316,17 @@ BScrollBar::_UpdateArrowButtons()
bool upEnabled = fValue > fMin; bool upEnabled = fValue > fMin;
if (fPrivateData->fUpArrowsEnabled != upEnabled) { if (fPrivateData->fUpArrowsEnabled != upEnabled) {
fPrivateData->fUpArrowsEnabled = upEnabled; fPrivateData->fUpArrowsEnabled = upEnabled;
Invalidate(_ButtonRectFor(ARROW1)); Invalidate(_ButtonRectFor(SCROLL_ARROW_1));
if (_DoubleArrows()) if (_DoubleArrows())
Invalidate(_ButtonRectFor(ARROW3)); Invalidate(_ButtonRectFor(SCROLL_ARROW_3));
} }
bool downEnabled = fValue < fMax; bool downEnabled = fValue < fMax;
if (fPrivateData->fDownArrowsEnabled != downEnabled) { if (fPrivateData->fDownArrowsEnabled != downEnabled) {
fPrivateData->fDownArrowsEnabled = downEnabled; fPrivateData->fDownArrowsEnabled = downEnabled;
Invalidate(_ButtonRectFor(ARROW4)); Invalidate(_ButtonRectFor(SCROLL_ARROW_4));
if (_DoubleArrows()) 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 BSize
BScrollBar::_MinSize() const BScrollBar::_MinSize() const
{ {
+33 -88
View File
@@ -35,8 +35,10 @@ FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows,
fDrawArrows(drawArrows), fDrawArrows(drawArrows),
fDoubleArrows(doubleArrows) fDoubleArrows(doubleArrows)
{ {
SetExplicitMinSize(BSize(160, 20)); // add some height to draw the ring around the scroll bar
SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20)); 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 void
FakeScrollBar::Draw(BRect updateRect) 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()) { uint32 flags = BControlLook::B_SCROLLABLE;
// draw the focus indicator if (IsFocus())
SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR)); flags |= BControlLook::B_FOCUSED;
StrokeRect(bounds);
bounds.InsetBy(1.0, 1.0);
// Draw the selected border (1px) if (Value() == B_CONTROL_ON)
if (Value() == B_CONTROL_ON) SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
SetHighColor(ui_color(B_CONTROL_MARK_COLOR)); else
else SetHighColor(base);
SetHighColor(normal);
StrokeRect(bounds); // Draw the selected border (2px)
bounds.InsetBy(1.0, 1.0); StrokeRect(rect);
} else { rect.InsetBy(1, 1);
// Draw the selected border (2px) StrokeRect(rect);
if (Value() == B_CONTROL_ON) rect.InsetBy(1, 1);
SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
else
SetHighColor(normal);
StrokeRect(bounds); // draw a 1px gap
bounds.InsetBy(1.0, 1.0); SetHighColor(base);
StrokeRect(bounds); StrokeRect(rect);
bounds.InsetBy(1.0, 1.0); rect.InsetBy(1, 1);
}
// draw a gap (1px) // draw a 1px border around control
SetHighColor(normal); SetHighColor(tint_color(base, B_DARKEN_1_TINT));
StrokeRect(bounds); StrokeRect(rect);
bounds.InsetBy(1.0, 1.0); rect.InsetBy(1, 1);
SetHighColor(base);
// draw a border around control (1px) be_control_look->DrawScrollBar(this, rect, updateRect, base,
SetHighColor(tint_color(normal, B_DARKEN_1_TINT)); flags, B_HORIZONTAL, fDoubleArrows);
StrokeRect(bounds); float less = floorf(rect.Width() / 3); // thumb takes up 1/3 full width
bounds.InsetBy(1.0, 1.0); BRect thumbRect(rect.left + less, rect.top, rect.right - less, rect.bottom);
be_control_look->DrawScrollBarThumb(this, rect, thumbRect, updateRect, base,
BRect thumbBG = bounds; flags, B_HORIZONTAL, fKnobStyle);
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);
} }