diff --git a/headers/os/interface/ControlLook.h b/headers/os/interface/ControlLook.h index 2f7af32d19..8e2baae882 100644 --- a/headers/os/interface/ControlLook.h +++ b/headers/os/interface/ControlLook.h @@ -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, diff --git a/headers/os/interface/ScrollBar.h b/headers/os/interface/ScrollBar.h index 873ab84535..161575443e 100644 --- a/headers/os/interface/ScrollBar.h +++ b/headers/os/interface/ScrollBar.h @@ -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; diff --git a/headers/private/interface/HaikuControlLook.h b/headers/private/interface/HaikuControlLook.h index 09d8e69614..cbdf430e2e 100644 --- a/headers/private/interface/HaikuControlLook.h +++ b/headers/private/interface/HaikuControlLook.h @@ -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; }; diff --git a/headers/private/interface/ScrollBarPrivate.h b/headers/private/interface/ScrollBarPrivate.h new file mode 100644 index 0000000000..7392449d01 --- /dev/null +++ b/headers/private/interface/ScrollBarPrivate.h @@ -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 diff --git a/src/kits/interface/HaikuControlLook.cpp b/src/kits/interface/HaikuControlLook.cpp index cdbb1e1e30..8fd5c257f7 100644 --- a/src/kits/interface/HaikuControlLook.cpp +++ b/src/kits/interface/HaikuControlLook.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/src/kits/interface/ScrollBar.cpp b/src/kits/interface/ScrollBar.cpp index 8049b990c2..05bcbcfe0c 100644 --- a/src/kits/interface/ScrollBar.cpp +++ b/src/kits/interface/ScrollBar.cpp @@ -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 +#include + //#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 { diff --git a/src/preferences/appearance/FakeScrollBar.cpp b/src/preferences/appearance/FakeScrollBar.cpp index e8a792928e..f5230abb6b 100644 --- a/src/preferences/appearance/FakeScrollBar.cpp +++ b/src/preferences/appearance/FakeScrollBar.cpp @@ -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); }