* Copyright 2021-2025 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus, superstippi@gmx.de
* John Scipione, jscipione@gmail.com
* Nahuel Tello, ntello@unarix.com.ar
*/
#include "FlatControlLook.h"
#include <algorithm>
#include <cmath>
#include <new>
#include <stdio.h>
#include <GradientLinear.h>
#include <Rect.h>
#include <Region.h>
#include <View.h>
#include <WindowPrivate.h>
namespace BPrivate {
static const float kEdgeBevelLightTint = 1.0;
static const float kEdgeBevelShadowTint = 1.0;
static const float kHoverTintFactor = 0.55;
static const float kRadius = 3.0f;
static const float kButtonPopUpIndicatorWidth = 11;
FlatControlLook::FlatControlLook()
: HaikuControlLook()
{
}
FlatControlLook::~FlatControlLook()
{
}
void
FlatControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, const rgb_color& background, uint32 flags,
uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, background,
1.0, 1.0, flags, borders);
}
void
FlatControlLook::DrawButtonFrame(BView* view, BRect& rect, const BRect& updateRect,
float radius, const rgb_color& base, const rgb_color& background, uint32 flags,
uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, background,
1.0, 1.0, flags, borders);
}
void
FlatControlLook::DrawButtonFrame(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
const rgb_color& background, uint32 flags,
uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, background,
1.0, 1.0, flags, borders);
}
void
FlatControlLook::DrawButtonBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, false,
flags, borders, orientation);
}
void
FlatControlLook::DrawButtonBackground(BView* view, BRect& rect,
const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, false,
flags, borders, orientation);
}
void
FlatControlLook::DrawButtonBackground(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
uint32 flags, uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, false,
flags, borders, orientation);
}
void
FlatControlLook::DrawMenuBarBackground(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, uint32 flags, uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
float topTint = 1.0;
float bottomTint = 1.0;
rgb_color customColor = base;
bool isEnabled = (flags & B_DISABLED) != 0;
bool isFocused = (flags & B_FOCUSED) != 0;
if (isEnabled || isFocused) {
customColor = tint_color(ui_color(B_WINDOW_TAB_COLOR), 1.0);
rgb_color bevelColor1 = tint_color(customColor, 1.0);
rgb_color bevelColor2 = tint_color(customColor, 1.0);
topTint = 1.0;
bottomTint = 1.0;
_DrawFrame(view, rect,
bevelColor1, bevelColor1,
bevelColor2, bevelColor2,
borders & B_TOP_BORDER);
} else {
rgb_color cornerColor = tint_color(customColor, 1.0);
rgb_color bevelColorTop = tint_color(customColor, 1.0);
rgb_color bevelColorLeft = tint_color(customColor, 1.0);
rgb_color bevelColorRightBottom = tint_color(customColor, 1.0);
topTint = 1.0;
bottomTint = 1.0;
_DrawFrame(view, rect,
bevelColorLeft, bevelColorTop,
bevelColorRightBottom, bevelColorRightBottom,
cornerColor, cornerColor,
borders);
}
_FillGradient(view, rect, customColor, topTint, bottomTint);
}
void
FlatControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base,
const rgb_color& background, uint32 flags, uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, background,
1.0, 1.0, flags, borders);
}
void
FlatControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
const BRect& updateRect, float radius, const rgb_color& base,
const rgb_color& background, uint32 flags, uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, radius, radius, radius, radius, base, background, 1.0,
1.0, flags, borders);
}
void
FlatControlLook::DrawMenuFieldFrame(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius,
float rightTopRadius, float leftBottomRadius,
float rightBottomRadius, const rgb_color& base,
const rgb_color& background, uint32 flags, uint32 borders)
{
_DrawButtonFrame(view, rect, updateRect, leftTopRadius, rightTopRadius, leftBottomRadius,
rightBottomRadius, base, background, 1.0, 1.0, flags, borders);
}
void
FlatControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, bool popupIndicator,
uint32 flags)
{
_DrawMenuFieldBackgroundOutside(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius,
base, popupIndicator, flags);
}
void
FlatControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders)
{
_DrawMenuFieldBackgroundInside(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base,
flags, borders);
}
void
FlatControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
const BRect& updateRect, float radius, const rgb_color& base,
bool popupIndicator, uint32 flags)
{
_DrawMenuFieldBackgroundOutside(view, rect, updateRect, radius, radius,
radius, radius, base, popupIndicator, flags);
}
void
FlatControlLook::DrawMenuFieldBackground(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
bool popupIndicator, uint32 flags)
{
_DrawMenuFieldBackgroundOutside(view, rect, updateRect, leftTopRadius,
rightTopRadius, leftBottomRadius, rightBottomRadius, base,
popupIndicator, flags);
}
void
FlatControlLook::DrawMenuBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rgb_color background = tint_color(base, 1.05);
rgb_color bevelColor;
bevelColor = tint_color(background, 1.1);
_DrawFrame(view, rect,
bevelColor, bevelColor,
bevelColor, bevelColor,
borders);
view->SetHighColor(background);
view->FillRect(rect);
}
void
FlatControlLook::DrawMenuItemBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
float topTint;
float bottomTint;
rgb_color selectedColor = base;
if ((flags & B_ACTIVATED) != 0) {
topTint = 0.9;
bottomTint = 0.95;
} else if ((flags & B_DISABLED) != 0) {
topTint = 1.0;
bottomTint = 1.0;
} else {
topTint = 0.9;
bottomTint = 0.95;
}
rgb_color bevelShadowColor = (base.IsDark()) ? tint_color(selectedColor, 0.8) : tint_color(selectedColor, 1.2);
_DrawFrame(view, rect,
base, bevelShadowColor,
base, bevelShadowColor,
borders);
view->SetLowColor(selectedColor);
_FillGradient(view, rect, selectedColor, topTint, bottomTint);
}
void
FlatControlLook::DrawScrollBarBorder(BView* view, BRect rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
view->PushState();
view->ClipToRect(rect);
bool isEnabled = (flags & B_DISABLED) == 0;
bool isFocused = (flags & B_FOCUSED) != 0;
view->SetHighColor(tint_color(base, 1.2));
if (isEnabled && isFocused) {
rgb_color borderColor = tint_color(base, 1.2);
rgb_color highlightColor = tint_color(base, 1.2);
view->BeginLineArray(4);
view->AddLine(BPoint(rect.left + 1, rect.bottom),
BPoint(rect.right, rect.bottom), borderColor);
view->AddLine(BPoint(rect.right, rect.top + 1),
BPoint(rect.right, rect.bottom - 1), borderColor);
if (orientation == B_HORIZONTAL) {
view->AddLine(BPoint(rect.left, rect.top + 1),
BPoint(rect.left, rect.bottom), borderColor);
} else {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.left, rect.bottom), highlightColor);
}
if (orientation == B_HORIZONTAL) {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.right, rect.top), highlightColor);
} else {
view->AddLine(BPoint(rect.left + 1, rect.top),
BPoint(rect.right, rect.top), borderColor);
}
view->EndLineArray();
} else
view->StrokeRect(rect);
view->PopState();
}
void
FlatControlLook::DrawScrollBarButton(BView* view, BRect rect,
const BRect& updateRect, const rgb_color& base, const rgb_color& text,
uint32 flags, int32 direction, orientation orientation, bool down)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rgb_color arrowColor;
bool isEnabled = (flags & B_DISABLED) == 0;
if (isEnabled) {
arrowColor = tint_color(text, 0.6);
if (base.IsDark()) {
arrowColor = tint_color(text, 1.3);
}
} else {
arrowColor = tint_color(text, 0.4);
if (base.IsDark()) {
arrowColor = tint_color(text, 1.5);
}
}
view->PushState();
view->ClipToRect(rect);
flags &= ~B_FLAT;
DrawScrollBarBackground(view, rect, updateRect, base, flags, orientation);
rect.InsetBy(1, 1);
DrawArrowShape(view, rect, updateRect, arrowColor, direction, flags, 1.0f);
view->PopState();
}
void
FlatControlLook::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
FlatControlLook::DrawScrollBarBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
view->PushState();
view->ClipToRect(rect);
bool isEnabled = (flags & B_DISABLED) == 0;
view->SetDrawingMode(B_OP_COPY);
float gradient1Tint = 1.08;
float gradient2Tint = 0.95;
if (orientation == B_HORIZONTAL) {
if (rect.Width() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
}
} else {
if (rect.Height() >= 0) {
_FillGradient(view, rect, base, gradient1Tint, gradient2Tint,
orientation);
}
}
view->PopState();
}
void
FlatControlLook::DrawScrollBarThumb(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
orientation orientation, uint32 knobStyle)
{
if (!ShouldDraw(view, rect, updateRect))
return;
view->PushState();
view->ClipToRect(rect);
bool isEnabled = (flags & B_DISABLED) == 0;
rgb_color thumbColor = tint_color(ui_color(B_SCROLL_BAR_THUMB_COLOR), 1.09);
rgb_color base_panel = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color light, dark, dark1, dark2;
light = tint_color(base_panel, B_DARKEN_1_TINT);
dark = tint_color(base_panel, B_DARKEN_1_TINT);
dark1 = tint_color(base_panel, B_DARKEN_1_TINT);
dark2 = tint_color(base_panel, B_DARKEN_1_TINT);
view->SetDrawingMode(B_OP_OVER);
view->SetHighColor(dark1);
if (isEnabled) {
BRegion clipping(updateRect);
DrawScrollBarBackground(view, rect, updateRect, base_panel, flags, orientation);
if (orientation == B_HORIZONTAL)
rect.InsetBy(0, 2);
else
rect.InsetBy(2, 0);
view->SetHighColor(base_panel);
view->FillRect(rect);
_DrawNonFlatButtonBackground(view, rect, updateRect, clipping, kRadius + 1, kRadius + 1,
kRadius + 1, kRadius + 1, thumbColor, false, flags, B_ALL_BORDERS, orientation);
} else {
DrawScrollBarBackground(view, rect, updateRect, base_panel, flags, orientation);
}
knobStyle = B_KNOB_LINES;
if (knobStyle != B_KNOB_NONE && isEnabled) {
rgb_color knobLight = isEnabled
? tint_color(thumbColor, 0.4)
: tint_color(base_panel, 1.1);
rgb_color knobDark = isEnabled
? tint_color(thumbColor, 1.6)
: tint_color(base_panel, 1.2);
if (knobStyle == B_KNOB_DOTS) {
float hcenter = rect.left + rect.Width() / 2;
float vmiddle = rect.top + rect.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 = rect.Height();
if (rect.left + 3 < hcenter - spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(-spacer, 0));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(-spacer + 1, 1));
}
if (rect.right - 3 > hcenter + spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(spacer, 0));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(spacer + 1, 1));
}
} else {
view->SetHighColor(knobDark);
view->FillRect(knob);
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, 1));
float spacer = rect.Width();
if (rect.top + 3 < vmiddle - spacer) {
view->SetHighColor(knobDark);
view->FillRect(knob.OffsetByCopy(0, -spacer));
view->SetHighColor(knobLight);
view->FillRect(knob.OffsetByCopy(1, -spacer + 1));
}
if (rect.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 == B_KNOB_LINES && isEnabled) {
if (orientation == B_HORIZONTAL) {
float middle = rect.Width() / 2;
view->BeginLineArray(6);
view->AddLine(
BPoint(rect.left + middle - 3, rect.top + 2),
BPoint(rect.left + middle - 3, rect.bottom - 2),
knobDark);
view->AddLine(
BPoint(rect.left + middle, rect.top + 2),
BPoint(rect.left + middle, rect.bottom - 2),
knobDark);
view->AddLine(
BPoint(rect.left + middle + 3, rect.top + 2),
BPoint(rect.left + middle + 3, rect.bottom - 2),
knobDark);
view->AddLine(
BPoint(rect.left + middle - 2, rect.top + 2),
BPoint(rect.left + middle - 2, rect.bottom - 2),
knobLight);
view->AddLine(
BPoint(rect.left + middle + 1, rect.top + 2),
BPoint(rect.left + middle + 1, rect.bottom - 2),
knobLight);
view->AddLine(
BPoint(rect.left + middle + 4, rect.top + 2),
BPoint(rect.left + middle + 4, rect.bottom - 2),
knobLight);
view->EndLineArray();
} else {
float middle = rect.Height() / 2;
view->BeginLineArray(6);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle - 3),
BPoint(rect.right - 2, rect.top + middle - 3),
knobDark);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle),
BPoint(rect.right - 2, rect.top + middle),
knobDark);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle + 3),
BPoint(rect.right - 2, rect.top + middle + 3),
knobDark);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle - 2),
BPoint(rect.right - 2, rect.top + middle - 2),
knobLight);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle + 1),
BPoint(rect.right - 2, rect.top + middle + 1),
knobLight);
view->AddLine(
BPoint(rect.left + 2, rect.top + middle + 4),
BPoint(rect.right - 2, rect.top + middle + 4),
knobLight);
view->EndLineArray();
}
}
}
view->PopState();
}
void
FlatControlLook::DrawScrollViewFrame(BView* view, BRect& rect,
const BRect& updateRect, BRect verticalScrollBarFrame,
BRect horizontalScrollBarFrame, const rgb_color& base,
border_style borderStyle, uint32 flags, uint32 _borders)
{
BRect scrollCornerFillRect(rect.right, rect.bottom,
rect.right, rect.bottom);
if (horizontalScrollBarFrame.IsValid())
scrollCornerFillRect.left = horizontalScrollBarFrame.right + 1;
if (verticalScrollBarFrame.IsValid())
scrollCornerFillRect.top = verticalScrollBarFrame.bottom + 1;
if (borderStyle == B_NO_BORDER) {
if (scrollCornerFillRect.IsValid()) {
view->SetHighColor(base);
view->FillRect(scrollCornerFillRect);
}
return;
}
bool excludeScrollCorner = borderStyle == B_FANCY_BORDER
&& horizontalScrollBarFrame.IsValid()
&& verticalScrollBarFrame.IsValid();
uint32 borders = _borders;
if (excludeScrollCorner) {
rect.bottom = horizontalScrollBarFrame.top;
rect.right = verticalScrollBarFrame.left;
borders &= ~(B_RIGHT_BORDER | B_BOTTOM_BORDER);
}
rgb_color scrollbarFrameColor = tint_color(base, 1.2);
if (borderStyle == B_FANCY_BORDER)
_DrawOuterResessedFrame(view, rect, base, 1.0, 1.0, flags, borders);
if ((flags & B_FOCUSED) != 0) {
_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
scrollbarFrameColor, scrollbarFrameColor, borders);
} else {
_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
scrollbarFrameColor, scrollbarFrameColor, borders);
}
if (excludeScrollCorner) {
horizontalScrollBarFrame.InsetBy(-1, -1);
horizontalScrollBarFrame.top += 2;
borders = _borders;
borders &= ~B_TOP_BORDER;
_DrawOuterResessedFrame(view, horizontalScrollBarFrame, base,
1.0, 1.0, flags, borders);
_DrawFrame(view, horizontalScrollBarFrame, scrollbarFrameColor,
scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
borders);
verticalScrollBarFrame.InsetBy(-1, -1);
verticalScrollBarFrame.left += 2;
borders = _borders;
borders &= ~B_LEFT_BORDER;
_DrawOuterResessedFrame(view, verticalScrollBarFrame, base,
1.0, 1.0, flags, borders);
_DrawFrame(view, verticalScrollBarFrame, scrollbarFrameColor,
scrollbarFrameColor, scrollbarFrameColor, scrollbarFrameColor,
borders);
scrollCornerFillRect.top++;
scrollCornerFillRect.left++;
}
if (scrollCornerFillRect.IsValid()) {
view->SetHighColor(base);
view->FillRect(scrollCornerFillRect);
}
}
rgb_color
FlatControlLook::SliderBarColor(const rgb_color& base)
{
return base.IsLight() ? tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 1.05) :
tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 0.95);
}
void
FlatControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
const rgb_color& base, rgb_color leftFillColor, rgb_color rightFillColor,
float sliderScale, uint32 flags, orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
float sliderPosition;
BRect leftBarSide = rect;
BRect rightBarSide = rect;
if (orientation == B_HORIZONTAL) {
sliderPosition = floorf(rect.left + 2 + (rect.Width() - 2)
* sliderScale);
leftBarSide.right = sliderPosition - 1;
rightBarSide.left = sliderPosition;
} else {
sliderPosition = floorf(rect.top + 2 + (rect.Height() - 2)
* (1.0 - sliderScale));
leftBarSide.top = sliderPosition;
rightBarSide.bottom = sliderPosition - 1;
}
view->PushState();
view->ClipToRect(rightBarSide);
DrawSliderBar(view, rect, updateRect, base, leftFillColor, flags, orientation);
view->PopState();
view->PushState();
view->ClipToRect(leftBarSide);
DrawSliderBar(view, rect, updateRect, base, rightFillColor, flags,
orientation);
view->PopState();
}
void
FlatControlLook::DrawSliderBar(BView* view, BRect rect, const BRect& updateRect,
const rgb_color& base, rgb_color fillColor, uint32 flags,
orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
BRect leftCorner(rect);
BRect rightCorner(rect);
BRect barRect(rect);
if (orientation == B_HORIZONTAL) {
leftCorner.right = leftCorner.left + leftCorner.Height();
rightCorner.left = rightCorner.right - rightCorner.Height();
barRect.left += ceilf(barRect.Height() / 2);
barRect.right -= ceilf(barRect.Height() / 2);
} else {
leftCorner.bottom = leftCorner.top + leftCorner.Width();
rightCorner.top = rightCorner.bottom - rightCorner.Width();
barRect.top += ceilf(barRect.Width() / 2);
barRect.bottom -= ceilf(barRect.Width() / 2);
}
view->PushState();
view->ClipToRect(rect);
view->ClipToInverseRect(barRect);
if ((flags & B_BLEND_FRAME) == 0) {
view->SetHighColor(base);
view->FillRect(rect);
}
float edgeLightTint;
float edgeShadowTint;
float frameLightTint;
float frameShadowTint;
float fillLightTint;
float fillShadowTint;
uint8 edgeLightAlpha;
uint8 edgeShadowAlpha;
uint8 frameLightAlpha;
uint8 frameShadowAlpha;
if ((flags & B_DISABLED) != 0) {
edgeLightTint = 1.0;
edgeShadowTint = 1.0;
frameLightTint = 1.05;
frameShadowTint = 1.05;
fillLightTint = 0.8;
fillShadowTint = 0.8;
edgeLightAlpha = 12;
edgeShadowAlpha = 12;
frameLightAlpha = 40;
frameShadowAlpha = 45;
fillColor.red = uint8(fillColor.red * 0.4 + base.red * 0.6);
fillColor.green = uint8(fillColor.green * 0.4 + base.green * 0.6);
fillColor.blue = uint8(fillColor.blue * 0.4 + base.blue * 0.6);
} else {
edgeLightTint = 1.1;
edgeShadowTint = 1.1;
if (base.IsDark()) {
frameLightTint = 0.8;
frameShadowTint = 0.8;
} else {
frameLightTint = 1.2;
frameShadowTint = 1.2;
}
fillLightTint = 0.85;
fillShadowTint = 0.9;
edgeLightAlpha = 15;
edgeShadowAlpha = 15;
frameLightAlpha = 102;
frameShadowAlpha = 117;
}
rgb_color edgeLightColor;
rgb_color edgeShadowColor;
rgb_color frameLightColor;
rgb_color frameShadowColor;
rgb_color fillLightColor = tint_color(fillColor, fillLightTint);
rgb_color fillShadowColor = tint_color(fillColor, fillShadowTint);
drawing_mode oldMode = view->DrawingMode();
if ((flags & B_BLEND_FRAME) != 0) {
edgeLightColor = (rgb_color){ 255, 255, 255, edgeLightAlpha };
edgeShadowColor = (rgb_color){ 0, 0, 0, edgeShadowAlpha };
frameLightColor = (rgb_color){ 0, 0, 0, frameLightAlpha };
frameShadowColor = (rgb_color){ 0, 0, 0, frameShadowAlpha };
view->SetDrawingMode(B_OP_ALPHA);
} else {
edgeLightColor = tint_color(base, edgeLightTint);
edgeShadowColor = tint_color(base, edgeShadowTint);
frameLightColor = tint_color(fillColor, frameLightTint);
frameShadowColor = tint_color(fillColor, frameShadowTint);
}
if (orientation == B_HORIZONTAL) {
_DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
fillShadowColor, 1.0, 1.0, 0.0, -1.0, orientation);
_DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
fillShadowColor, 0.0, 1.0, -1.0, -1.0, orientation);
} else {
_DrawRoundBarCorner(view, leftCorner, updateRect, edgeLightColor,
edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
fillShadowColor, 1.0, 1.0, -1.0, 0.0, orientation);
_DrawRoundBarCorner(view, rightCorner, updateRect, edgeLightColor,
edgeShadowColor, frameLightColor, frameShadowColor, fillLightColor,
fillShadowColor, 1.0, 0.0, -1.0, -1.0, orientation);
}
view->PopState();
view->BeginLineArray(4);
if (orientation == B_HORIZONTAL) {
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.LeftBottom(), barRect.RightBottom(),
frameLightColor);
barRect.InsetBy(0, 1);
} else {
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.RightTop(), barRect.RightBottom(),
frameLightColor);
barRect.InsetBy(1, 0);
}
view->EndLineArray();
view->SetDrawingMode(oldMode);
_FillGradient(view, barRect, fillColor, fillShadowTint, fillLightTint,
orientation);
}
void
FlatControlLook::DrawSliderThumb(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, uint32 flags, orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rgb_color thumbColor = tint_color(ui_color(B_SCROLL_BAR_THUMB_COLOR), 1.0);
rgb_color frameLightColor;
rgb_color frameShadowColor;
rgb_color shadowColor;
if (base.IsLight())
shadowColor = tint_color(ui_color(B_CONTROL_TEXT_COLOR), 0.5);
else
shadowColor = tint_color(ui_color(B_CONTROL_TEXT_COLOR), 1.55);
if ((flags & B_FOCUSED) != 0) {
frameLightColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
frameShadowColor = frameLightColor;
} else {
float frameLightTint;
float frameShadowTint;
if ((flags & B_DISABLED) != 0) {
frameLightTint = 1.30;
frameShadowTint = 1.35;
shadowColor.alpha = 30;
} else {
frameLightTint = 1.6;
frameShadowTint = 1.65;
}
frameLightColor = tint_color(base, frameLightTint);
frameShadowColor = tint_color(base, frameShadowTint);
}
BRect originalRect(rect);
rect.right--;
rect.bottom--;
_DrawFrame(view, rect, shadowColor, shadowColor, shadowColor, shadowColor);
flags &= ~B_ACTIVATED;
flags &= ~B_FLAT;
DrawScrollBarBackground(view, rect, updateRect, base, flags, orientation);
if (orientation == B_HORIZONTAL) {
rect.InsetBy(0, floorf(rect.Height() / 4));
rect.left = floorf((rect.left + rect.right) / 2);
rect.right = rect.left;
shadowColor = tint_color(thumbColor, 1.5);
view->SetHighColor(shadowColor);
view->StrokeLine(rect.LeftTop(), rect.LeftBottom());
rgb_color lightColor = tint_color(thumbColor, 1.0);
view->SetHighColor(lightColor);
view->StrokeLine(rect.RightTop(), rect.RightBottom());
} else {
rect.InsetBy(floorf(rect.Width() / 4), 0);
rect.top = floorf((rect.top + rect.bottom) / 2);
rect.bottom = rect.top + 1;
shadowColor = tint_color(thumbColor, 1.5);
view->SetHighColor(shadowColor);
view->StrokeLine(rect.LeftTop(), rect.RightTop());
rgb_color lightColor = tint_color(thumbColor, 1.0);
view->SetHighColor(lightColor);
view->StrokeLine(rect.LeftBottom(), rect.RightBottom());
}
view->SetDrawingMode(B_OP_COPY);
}
void
FlatControlLook::DrawActiveTab(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders, uint32 side, int32, int32, int32, int32)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rect.left = floorf(rect.left);
rect.right = floorf(rect.right);
rect.top = floorf(rect.top);
rect.bottom = floorf(rect.bottom);
view->PushState();
view->ClipToRect(rect);
rgb_color edgeShadowColor;
rgb_color edgeLightColor;
rgb_color frameShadowColor;
rgb_color frameLightColor;
rgb_color bevelShadowColor;
rgb_color bevelLightColor;
float tint = (base.IsDark()) ? 0.8 : 1.3;
BGradientLinear fillGradient;
fillGradient.SetStart(rect.LeftTop() + BPoint(3, 3));
fillGradient.SetEnd(rect.LeftBottom() + BPoint(3, -3));
if ((flags & B_DISABLED) != 0) {
edgeLightColor = base;
edgeShadowColor = base;
frameLightColor = tint_color(base, 1.0);
frameShadowColor = tint_color(base, 1.30);
bevelLightColor = tint_color(base, 0.8);
bevelShadowColor = tint_color(base, 1.07);
fillGradient.AddColor(tint_color(base, 0.85), 0);
fillGradient.AddColor(base, 255);
} else {
edgeLightColor = tint_color(base, 0.95);
edgeShadowColor = tint_color(base, 1.03);
frameLightColor = tint_color(base, tint);
frameShadowColor = tint_color(base, tint);
bevelLightColor = tint_color(base, 1.0);
bevelShadowColor = tint_color(base, 1.0);
fillGradient.AddColor(tint_color(base, 0.95), 0);
fillGradient.AddColor(tint_color(base, 1.0), 155);
}
static const float kRoundCornerRadius = kRadius;
BRect leftTopCorner(rect);
leftTopCorner.right = floorf(leftTopCorner.left + kRoundCornerRadius);
leftTopCorner.bottom = floorf(rect.top + kRoundCornerRadius);
BRect rightTopCorner(rect);
rightTopCorner.left = floorf(rightTopCorner.right - kRoundCornerRadius);
rightTopCorner.bottom = floorf(rect.top + kRoundCornerRadius);
BRect leftBottomCorner(rect);
leftBottomCorner.right = floorf(leftBottomCorner.left + kRoundCornerRadius);
leftBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius);
BRect rightBottomCorner(rect);
rightBottomCorner.left = floorf(rightBottomCorner.right
- kRoundCornerRadius);
rightBottomCorner.top = floorf(rect.bottom - kRoundCornerRadius);
BRect roundCorner[2];
switch (side) {
case B_TOP_BORDER:
roundCorner[0] = leftTopCorner;
roundCorner[1] = rightTopCorner;
_DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base,
edgeShadowColor, frameLightColor, bevelLightColor,
fillGradient);
_DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base,
edgeShadowColor, edgeLightColor, frameLightColor,
frameShadowColor, bevelLightColor, bevelShadowColor,
fillGradient);
break;
case B_BOTTOM_BORDER:
roundCorner[0] = leftBottomCorner;
roundCorner[1] = rightBottomCorner;
_DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base,
edgeShadowColor, edgeLightColor, frameLightColor,
frameShadowColor, bevelLightColor, bevelShadowColor,
fillGradient);
_DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect,
base, edgeLightColor, frameShadowColor, bevelShadowColor,
fillGradient);
break;
case B_LEFT_BORDER:
roundCorner[0] = leftTopCorner;
roundCorner[1] = leftBottomCorner;
_DrawRoundCornerLeftTop(view, leftTopCorner, updateRect, base,
edgeShadowColor, frameLightColor, bevelLightColor,
fillGradient);
_DrawRoundCornerLeftBottom(view, leftBottomCorner, updateRect, base,
edgeShadowColor, edgeLightColor, frameLightColor,
frameShadowColor, bevelLightColor, bevelShadowColor,
fillGradient);
break;
case B_RIGHT_BORDER:
roundCorner[0] = rightTopCorner;
roundCorner[1] = rightBottomCorner;
_DrawRoundCornerRightTop(view, rightTopCorner, updateRect, base,
edgeShadowColor, edgeLightColor, frameLightColor,
frameShadowColor, bevelLightColor, bevelShadowColor,
fillGradient);
_DrawRoundCornerRightBottom(view, rightBottomCorner, updateRect,
base, edgeLightColor, frameShadowColor, bevelShadowColor,
fillGradient);
break;
}
view->ClipToInverseRect(roundCorner[0]);
view->ClipToInverseRect(roundCorner[1]);
uint32 bordersToDraw = 0;
switch (side) {
case B_TOP_BORDER:
bordersToDraw = (B_LEFT_BORDER | B_TOP_BORDER | B_RIGHT_BORDER);
break;
case B_BOTTOM_BORDER:
bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_RIGHT_BORDER);
break;
case B_LEFT_BORDER:
bordersToDraw = (B_LEFT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER);
break;
case B_RIGHT_BORDER:
bordersToDraw = (B_RIGHT_BORDER | B_BOTTOM_BORDER | B_TOP_BORDER);
break;
}
_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor,
edgeLightColor, borders);
if (side == B_TOP_BORDER || side == B_BOTTOM_BORDER) {
if ((borders & B_LEFT_BORDER) == 0)
rect.left++;
if ((borders & B_RIGHT_BORDER) == 0)
rect.right--;
} else if (side == B_LEFT_BORDER || side == B_RIGHT_BORDER) {
if ((borders & B_TOP_BORDER) == 0)
rect.top++;
if ((borders & B_BOTTOM_BORDER) == 0)
rect.bottom--;
}
_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor,
frameShadowColor, bordersToDraw);
_DrawFrame(view, rect, bevelLightColor, bevelLightColor, bevelShadowColor,
bevelShadowColor);
view->FillRect(rect, fillGradient);
view->PopState();
}
void
FlatControlLook::DrawSplitter(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, orientation orientation, uint32 flags,
uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rgb_color background;
if ((flags & (B_CLICKED | B_ACTIVATED)) != 0)
background = tint_color(base, B_DARKEN_1_TINT);
else
background = base;
rgb_color light = tint_color(background, 1.9);
rgb_color shadow = tint_color(background, 1.9);
if (borders != 0 && rect.Width() > 3 && rect.Height() > 3)
DrawRaisedBorder(view, rect, updateRect, background, flags, borders);
if (orientation == B_HORIZONTAL) {
if (rect.Width() > 2) {
BRegion region(rect);
rect.left = floorf((rect.left + rect.right) / 2.0 - 0.5);
rect.right = rect.left + 1;
region.Exclude(rect);
view->SetHighColor(background);
view->FillRegion(®ion);
}
BPoint dot = rect.LeftTop();
BPoint stop = rect.LeftBottom();
int32 num = 1;
while (dot.y <= stop.y) {
rgb_color col1;
rgb_color col2;
switch (num) {
case 1:
col1 = background;
col2 = background;
break;
case 2:
col1 = shadow;
col2 = background;
break;
case 3:
default:
col1 = background;
col2 = light;
num = 0;
break;
}
view->SetHighColor(col1);
view->StrokeLine(dot, dot, B_SOLID_LOW);
view->SetHighColor(col2);
dot.x++;
view->StrokeLine(dot, dot, B_SOLID_LOW);
dot.x -= 1.0;
num++;
dot.y++;
}
} else {
if (rect.Height() > 2) {
BRegion region(rect);
rect.top = floorf((rect.top + rect.bottom) / 2.0 - 0.5);
rect.bottom = rect.top + 1;
region.Exclude(rect);
view->SetHighColor(background);
view->FillRegion(®ion);
}
BPoint dot = rect.LeftTop();
BPoint stop = rect.RightTop();
int32 num = 1;
while (dot.x <= stop.x) {
rgb_color col1;
rgb_color col2;
switch (num) {
case 1:
col1 = background;
col2 = background;
break;
case 2:
col1 = shadow;
col2 = background;
break;
case 3:
default:
col1 = background;
col2 = light;
num = 0;
break;
}
view->SetHighColor(col1);
view->StrokeLine(dot, dot, B_SOLID_LOW);
view->SetHighColor(col2);
dot.y++;
view->StrokeLine(dot, dot, B_SOLID_LOW);
dot.y -= 1.0;
num++;
dot.x++;
}
}
}
void
FlatControlLook::DrawBorder(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, border_style borderStyle, uint32 flags,
uint32 borders)
{
if (borderStyle == B_NO_BORDER)
return;
rgb_color scrollbarFrameColor = tint_color(base, 1.0);
_DrawFrame(view, rect, scrollbarFrameColor, scrollbarFrameColor,
scrollbarFrameColor, scrollbarFrameColor, borders);
}
void
FlatControlLook::DrawRaisedBorder(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders)
{
_DrawFrame(view, rect, base, base, base, base, borders);
}
void
FlatControlLook::DrawTextControlBorder(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
rgb_color invalidColor = ui_color(B_FAILURE_COLOR);
rgb_color documentBackground = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
if ((flags & B_DISABLED) == 0 && (flags & B_FOCUSED) != 0) {
if (base.IsDark())
documentBackground = tint_color(documentBackground, 0.9);
else
documentBackground = tint_color(documentBackground, 1.5);
}
if ((flags & B_DISABLED) == 0 && (flags & B_INVALID) != 0)
documentBackground = tint_color(invalidColor, 0.5);
if ((flags & B_BLEND_FRAME) != 0) {
drawing_mode oldMode = view->DrawingMode();
view->SetDrawingMode(B_OP_ALPHA);
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius,
documentBackground, base, false, false, flags, borders);
view->SetDrawingMode(oldMode);
} else {
_DrawButtonFrame(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius,
documentBackground, base, false, false, flags, borders);
}
}
void
FlatControlLook::DrawGroupFrame(BView* view, BRect& rect, const BRect& updateRect,
const rgb_color& base, uint32 borders)
{
rgb_color frameColor = tint_color(base, 1.1);
if (base.IsDark())
frameColor = tint_color(base, 0.9);
_DrawFrame(view, rect, frameColor, frameColor, frameColor, frameColor, borders);
}
void
FlatControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
const BRect& updateRect, const rgb_color& base, uint32 flags,
uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, kRadius, kRadius, kRadius, kRadius, base, true,
flags, borders, orientation);
}
void
FlatControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
const BRect& updateRect, float radius, const rgb_color& base, uint32 flags,
uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, radius, radius, radius,
radius, base, true, flags, borders, orientation);
}
void
FlatControlLook::DrawButtonWithPopUpBackground(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
uint32 flags, uint32 borders, orientation orientation)
{
_DrawButtonBackground(view, rect, updateRect, leftTopRadius,
rightTopRadius, leftBottomRadius, rightBottomRadius, base, true, flags,
borders, orientation);
}
void
FlatControlLook::_DrawButtonFrame(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
const rgb_color& background, float contrast, float brightness,
uint32 flags, uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
const rgb_color customColor = background;
rgb_color customColor2 = tint_color(ui_color(B_CONTROL_TEXT_COLOR), 0.55);
if (customColor.IsDark())
customColor2 = tint_color(ui_color(B_CONTROL_TEXT_COLOR), 1.55);
view->PushState();
view->ClipToRect(rect);
if ((flags & B_FLAT) != 0 && (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
&& ((flags & (B_HOVER | B_FOCUSED)) == 0 || (flags & B_DISABLED) != 0)) {
_DrawFrame(view, rect, background, background, background, background, borders);
_DrawFrame(view, rect, background, background, background, background, borders);
view->PopState();
return;
}
rgb_color edgeLightColor = background;
rgb_color edgeShadowColor = background;
rgb_color cornerBgColor = background;
drawing_mode oldMode = view->DrawingMode();
if ((flags & B_DEFAULT_BUTTON) != 0) {
float tint = (base.IsDark()) ? 1.4 : 0.8;
rect.InsetBy(1, 1);
rect.InsetBy(1, 1);
cornerBgColor = tint_color(ui_color(B_WINDOW_TAB_COLOR), tint);
view->SetHighColor(tint_color(ui_color(B_WINDOW_TAB_COLOR), tint));
view->StrokeRoundRect(rect, leftTopRadius, leftTopRadius);
rect.InsetBy(1, 1);
} else {
if ((flags & B_BLEND_FRAME) != 0) {
cornerBgColor.alpha = 0;
view->SetDrawingMode(B_OP_ALPHA);
}
}
rgb_color frameLightColor = customColor2;
rgb_color frameShadowColor = customColor2;
if ((flags & B_DISABLED) != 0) {
float tint = (base.IsDark()) ? 1.1 : 0.9;
frameLightColor = tint_color(customColor2, tint);
frameShadowColor = tint_color(customColor2, tint);
}
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
&& leftTopRadius > 0) {
BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
floorf(rect.left + leftTopRadius),
floorf(rect.top + leftTopRadius));
BRect cornerRect(leftTopCorner);
_DrawRoundCornerFrameLeftTop(view, leftTopCorner, updateRect,
cornerBgColor, edgeShadowColor, frameLightColor);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
&& rightTopRadius > 0) {
BRect rightTopCorner(floorf(rect.right - rightTopRadius),
floorf(rect.top), floorf(rect.right),
floorf(rect.top + rightTopRadius));
BRect cornerRect(rightTopCorner);
_DrawRoundCornerFrameRightTop(view, rightTopCorner, updateRect,
cornerBgColor, edgeShadowColor, edgeLightColor,
frameLightColor, frameShadowColor);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& leftBottomRadius > 0) {
BRect leftBottomCorner(floorf(rect.left),
floorf(rect.bottom - leftBottomRadius),
floorf(rect.left + leftBottomRadius), floorf(rect.bottom));
BRect cornerRect(leftBottomCorner);
_DrawRoundCornerFrameLeftBottom(view, leftBottomCorner, updateRect,
cornerBgColor, edgeShadowColor, edgeLightColor,
frameLightColor, frameShadowColor);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& rightBottomRadius > 0) {
BRect rightBottomCorner(floorf(rect.right - rightBottomRadius),
floorf(rect.bottom - rightBottomRadius), floorf(rect.right),
floorf(rect.bottom));
BRect cornerRect(rightBottomCorner);
_DrawRoundCornerFrameRightBottom(view, rightBottomCorner,
updateRect, cornerBgColor, edgeLightColor, frameShadowColor);
view->ClipToInverseRect(cornerRect);
}
if ((flags & B_DEFAULT_BUTTON) != 0) {
_DrawOuterResessedFrame(view, rect, background, 0, 0, flags, borders);
} else {
if ((flags & B_FOCUSED) != 0)
_DrawOuterResessedFrame(view, rect, tint_color(background, 1.15), 0, 0);
else
_DrawOuterResessedFrame(view, rect, background, 0, 0, flags, borders);
}
view->SetDrawingMode(oldMode);
if ((flags & B_BLEND_FRAME) != 0) {
drawing_mode oldDrawingMode = view->DrawingMode();
view->SetDrawingMode(B_OP_ALPHA);
_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor, frameShadowColor,
borders);
view->SetDrawingMode(oldDrawingMode);
} else {
_DrawFrame(view, rect, frameLightColor, frameLightColor, frameShadowColor, frameShadowColor,
borders);
}
view->PopState();
}
void
FlatControlLook::_DrawOuterResessedFrame(BView* view, BRect& rect,
const rgb_color& base, float contrast, float brightness, uint32 flags,
uint32 borders)
{
rgb_color edgeLightColor = base;
rgb_color edgeShadowColor = base;
if ((flags & B_BLEND_FRAME) != 0) {
drawing_mode oldDrawingMode = view->DrawingMode();
view->SetDrawingMode(B_OP_ALPHA);
_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor, edgeLightColor,
borders);
view->SetDrawingMode(oldDrawingMode);
} else {
_DrawFrame(view, rect, edgeShadowColor, edgeShadowColor, edgeLightColor, edgeLightColor,
borders);
}
}
void
FlatControlLook::_DrawButtonBackground(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
bool popupIndicator, uint32 flags, uint32 borders, orientation orientation)
{
if (!ShouldDraw(view, rect, updateRect))
return;
view->PushState();
view->ClipToRect(rect);
if ((flags & B_FLAT) != 0
&& (flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED)) == 0
&& ((flags & (B_HOVER | B_FOCUSED)) == 0
|| (flags & B_DISABLED) != 0)) {
rgb_color flatBase = base;
if (view->Parent() != NULL)
flatBase = view->Parent()->LowColor();
_DrawFlatButtonBackground(view, rect, updateRect, flatBase, popupIndicator,
flags, borders, orientation);
} else {
BRegion clipping(rect);
_DrawNonFlatButtonBackground(view, rect, updateRect, clipping,
leftTopRadius, rightTopRadius, leftBottomRadius, rightBottomRadius,
base, popupIndicator, flags, borders, orientation);
}
view->PopState();
}
void
FlatControlLook::_DrawNonFlatButtonBackground(BView* view, BRect& rect,
const BRect& updateRect, BRegion& clipping, float leftTopRadius,
float rightTopRadius, float leftBottomRadius, float rightBottomRadius,
const rgb_color& base, bool popupIndicator, uint32 flags, uint32 borders,
orientation orientation)
{
rgb_color bevelLightColor = _BevelLightColor(base, flags);
rgb_color bevelShadowColor = _BevelShadowColor(base, flags);
rgb_color buttonBgColor = base;
BGradientLinear fillGradient;
_MakeButtonGradient(fillGradient, rect, base, flags, orientation);
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
&& leftTopRadius > 0) {
BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
floorf(rect.left + leftTopRadius - 2.0),
floorf(rect.top + leftTopRadius - 2.0));
clipping.Exclude(leftTopCorner);
BRect cornerRect(leftTopCorner);
_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
bevelLightColor, fillGradient);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
&& rightTopRadius > 0) {
BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
floorf(rect.top), floorf(rect.right),
floorf(rect.top + rightTopRadius - 2.0));
clipping.Exclude(rightTopCorner);
BRect cornerRect(rightTopCorner);
_DrawRoundCornerBackgroundRightTop(view, rightTopCorner,
updateRect, bevelLightColor, bevelShadowColor, fillGradient);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& leftBottomRadius > 0) {
BRect leftBottomCorner(floorf(rect.left),
floorf(rect.bottom - leftBottomRadius + 2.0),
floorf(rect.left + leftBottomRadius - 2.0),
floorf(rect.bottom));
clipping.Exclude(leftBottomCorner);
BRect cornerRect(leftBottomCorner);
_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
updateRect, bevelLightColor, bevelShadowColor, fillGradient);
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& rightBottomRadius > 0) {
BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
floorf(rect.bottom));
clipping.Exclude(rightBottomCorner);
BRect cornerRect(rightBottomCorner);
_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
updateRect, bevelShadowColor, fillGradient);
view->ClipToInverseRect(cornerRect);
}
if ((flags & B_ACTIVATED) != 0) {
view->BeginLineArray(4);
if (borders & B_LEFT_BORDER) {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.left, rect.bottom), buttonBgColor);
rect.left++;
}
if (borders & B_TOP_BORDER) {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.right, rect.top), buttonBgColor);
rect.top++;
}
if (borders & B_LEFT_BORDER) {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.left, rect.bottom), buttonBgColor);
rect.left++;
}
if (borders & B_TOP_BORDER) {
view->AddLine(BPoint(rect.left, rect.top),
BPoint(rect.right, rect.top), buttonBgColor);
rect.top++;
}
view->EndLineArray();
} else {
_DrawFrame(view, rect,
buttonBgColor, buttonBgColor,
buttonBgColor, buttonBgColor,
buttonBgColor, buttonBgColor, borders);
}
if (popupIndicator) {
BRect indicatorRect(rect);
rect.right -= kButtonPopUpIndicatorWidth;
indicatorRect.left = rect.right + 3;
if ((flags & B_ACTIVATED) != 0)
indicatorRect.top--;
rgb_color separatorBaseColor = base;
if ((flags & B_ACTIVATED) != 0)
separatorBaseColor = tint_color(base, B_DARKEN_1_TINT);
rgb_color separatorShadowColor = tint_color(base, B_DARKEN_1_TINT);
view->BeginLineArray(2);
view->AddLine(BPoint(indicatorRect.left - 2, indicatorRect.top),
BPoint(indicatorRect.left - 2, indicatorRect.bottom),
separatorShadowColor);
view->AddLine(BPoint(indicatorRect.left - 1, indicatorRect.top),
BPoint(indicatorRect.left - 1, indicatorRect.bottom),
separatorShadowColor);
view->EndLineArray();
_DrawMenuFieldBackgroundInside(view, indicatorRect, updateRect, kRadius, rightTopRadius,
kRadius, rightBottomRadius, base, flags, 0);
if ((flags & B_ACTIVATED) != 0)
indicatorRect.top++;
_DrawPopUpMarker(view, indicatorRect, ui_color(B_MENU_ITEM_TEXT_COLOR), flags);
}
view->FillRect(rect, fillGradient);
}
void
FlatControlLook::_DrawPopUpMarker(BView* view, const BRect& rect,
const rgb_color& base, uint32 flags)
{
BPoint center(roundf((rect.left + rect.right) / 2.0),
roundf((rect.top + rect.bottom) / 2.0));
BPoint triangle[3];
triangle[0] = center + BPoint(-2.5, -0.5);
triangle[1] = center + BPoint(2.5, -0.5);
triangle[2] = center + BPoint(0.0, 2.0);
uint32 viewFlags = view->Flags();
view->SetFlags(viewFlags | B_SUBPIXEL_PRECISE);
rgb_color markColor;
if ((flags & B_DISABLED) != 0)
markColor = tint_color(base, 1.0);
else
markColor = tint_color(base, 1.0);
view->SetHighColor(markColor);
view->FillTriangle(triangle[0], triangle[1], triangle[2]);
view->SetFlags(viewFlags);
}
void
FlatControlLook::_DrawMenuFieldBackgroundOutside(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
bool popupIndicator, uint32 flags)
{
if (!ShouldDraw(view, rect, updateRect))
return;
if (popupIndicator) {
rgb_color indicatorColor;
if (base.IsDark())
indicatorColor = tint_color(base, 0.95);
else
indicatorColor = tint_color(base, 1.05);
const float indicatorWidth = ComposeSpacing(kButtonPopUpIndicatorWidth);
const float spacing = (indicatorWidth <= 11.0f) ? 1.0f : roundf(indicatorWidth / 11.0f);
BRect leftRect(rect);
leftRect.right -= indicatorWidth - spacing;
BRect rightRect(rect);
rightRect.left = rightRect.right - (indicatorWidth - spacing * 2);
_DrawMenuFieldBackgroundInside(view, leftRect, updateRect, leftTopRadius, 0.0f,
leftBottomRadius, 0.0f, base, flags, B_LEFT_BORDER | B_TOP_BORDER | B_BOTTOM_BORDER);
_DrawMenuFieldBackgroundInside(view, rightRect, updateRect, 0.0f, rightTopRadius, 0.0f,
rightBottomRadius, indicatorColor, flags,
B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
_DrawPopUpMarker(view, rightRect, ui_color(B_MENU_ITEM_TEXT_COLOR), flags);
rgb_color bevelShadowColor = tint_color(indicatorColor, 1.3);
if (base.IsDark())
bevelShadowColor = tint_color(indicatorColor, 0.9);
view->SetHighColor(bevelShadowColor);
BPoint leftTopCorner(floorf(rightRect.left - spacing), floorf(rightRect.top - spacing));
BPoint leftBottomCorner(floorf(rightRect.left - spacing),
floorf(rightRect.bottom + spacing));
for (float i = 0; i < spacing; i++)
view->StrokeLine(leftTopCorner + BPoint(i, 0), leftBottomCorner + BPoint(i, 0));
rect = leftRect;
} else {
_DrawMenuFieldBackgroundInside(view, rect, updateRect, leftTopRadius,
rightTopRadius, leftBottomRadius, rightBottomRadius, base, flags,
B_TOP_BORDER | B_RIGHT_BORDER | B_BOTTOM_BORDER);
}
}
void
FlatControlLook::_DrawMenuFieldBackgroundInside(BView* view, BRect& rect,
const BRect& updateRect, float leftTopRadius, float rightTopRadius,
float leftBottomRadius, float rightBottomRadius, const rgb_color& base,
uint32 flags, uint32 borders)
{
if (!ShouldDraw(view, rect, updateRect))
return;
view->PushState();
view->ClipToRect(rect);
rgb_color frameLightColor = base;
rgb_color frameShadowColor = base;
rgb_color indicatorBase;
if ((borders & B_LEFT_BORDER) != 0)
indicatorBase = base;
else {
if ((flags & B_DISABLED) != 0)
indicatorBase = tint_color(base, 1.05);
else
indicatorBase = tint_color(base, 1.12);
}
rgb_color cornerColor = tint_color(indicatorBase, 0.85);
rgb_color bevelColor1 = tint_color(indicatorBase, 0.3);
rgb_color bevelColor2 = tint_color(indicatorBase, 0.5);
rgb_color bevelColor3 = tint_color(indicatorBase, 1.03);
if ((flags & B_DISABLED) != 0) {
cornerColor = tint_color(indicatorBase, 1.0);
bevelColor1 = tint_color(indicatorBase, 1.0);
bevelColor2 = tint_color(indicatorBase, 1.0);
bevelColor3 = tint_color(indicatorBase, 1.0);
} else {
cornerColor = tint_color(indicatorBase, 1.0);
bevelColor1 = tint_color(indicatorBase, 1.0);
bevelColor2 = tint_color(indicatorBase, 1.0);
bevelColor3 = tint_color(indicatorBase, 1.0);
}
BGradientLinear fillGradient;
_MakeButtonGradient(fillGradient, rect, indicatorBase, flags);
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_TOP_BORDER) != 0
&& leftTopRadius > 0) {
BRect leftTopCorner(floorf(rect.left), floorf(rect.top),
floorf(rect.left + leftTopRadius - 2.0),
floorf(rect.top + leftTopRadius - 2.0));
BRect cornerRect(leftTopCorner);
view->PushState();
view->ClipToRect(cornerRect);
BRect ellipseRect(leftTopCorner);
ellipseRect.InsetBy(-1.0, -1.0);
ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
view->SetHighColor(frameLightColor);
view->FillEllipse(ellipseRect);
_DrawRoundCornerBackgroundLeftTop(view, leftTopCorner, updateRect,
bevelColor1, fillGradient);
view->PopState();
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_TOP_BORDER) != 0 && (borders & B_RIGHT_BORDER) != 0
&& rightTopRadius > 0) {
BRect rightTopCorner(floorf(rect.right - rightTopRadius + 2.0),
floorf(rect.top), floorf(rect.right),
floorf(rect.top + rightTopRadius - 2.0));
BRect cornerRect(rightTopCorner);
view->PushState();
view->ClipToRect(cornerRect);
BRect ellipseRect(rightTopCorner);
ellipseRect.InsetBy(-1.0, -1.0);
ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
ellipseRect.bottom = ellipseRect.top + ellipseRect.Height() * 2;
if (frameLightColor == frameShadowColor) {
view->SetHighColor(frameLightColor);
view->FillEllipse(ellipseRect);
} else {
BGradientLinear gradient;
gradient.AddColor(frameLightColor, 0);
gradient.AddColor(frameShadowColor, 255);
gradient.SetStart(rightTopCorner.LeftTop());
gradient.SetEnd(rightTopCorner.RightBottom());
view->FillEllipse(ellipseRect, gradient);
}
_DrawRoundCornerBackgroundRightTop(view, rightTopCorner, updateRect,
bevelColor1, bevelColor3, fillGradient);
view->PopState();
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_LEFT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& leftBottomRadius > 0) {
BRect leftBottomCorner(floorf(rect.left),
floorf(rect.bottom - leftBottomRadius + 2.0),
floorf(rect.left + leftBottomRadius - 2.0),
floorf(rect.bottom));
BRect cornerRect(leftBottomCorner);
view->PushState();
view->ClipToRect(cornerRect);
BRect ellipseRect(leftBottomCorner);
ellipseRect.InsetBy(-1.0, -1.0);
ellipseRect.right = ellipseRect.left + ellipseRect.Width() * 2;
ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
if (frameLightColor == frameShadowColor) {
view->SetHighColor(frameLightColor);
view->FillEllipse(ellipseRect);
} else {
BGradientLinear gradient;
gradient.AddColor(frameLightColor, 0);
gradient.AddColor(frameShadowColor, 255);
gradient.SetStart(leftBottomCorner.LeftTop());
gradient.SetEnd(leftBottomCorner.RightBottom());
view->FillEllipse(ellipseRect, gradient);
}
_DrawRoundCornerBackgroundLeftBottom(view, leftBottomCorner,
updateRect, bevelColor2, bevelColor3, fillGradient);
view->PopState();
view->ClipToInverseRect(cornerRect);
}
if ((borders & B_RIGHT_BORDER) != 0 && (borders & B_BOTTOM_BORDER) != 0
&& rightBottomRadius > 0) {
BRect rightBottomCorner(floorf(rect.right - rightBottomRadius + 2.0),
floorf(rect.bottom - rightBottomRadius + 2.0), floorf(rect.right),
floorf(rect.bottom));
BRect cornerRect(rightBottomCorner);
view->PushState();
view->ClipToRect(cornerRect);
BRect ellipseRect(rightBottomCorner);
ellipseRect.InsetBy(-1.0, -1.0);
ellipseRect.left = ellipseRect.right - ellipseRect.Width() * 2;
ellipseRect.top = ellipseRect.bottom - ellipseRect.Height() * 2;
view->SetHighColor(frameShadowColor);
view->FillEllipse(ellipseRect);
_DrawRoundCornerBackgroundRightBottom(view, rightBottomCorner,
updateRect, bevelColor3, fillGradient);
view->PopState();
view->ClipToInverseRect(cornerRect);
}
_DrawFrame(view, rect,
bevelColor2, bevelColor1,
bevelColor3, bevelColor3,
cornerColor, cornerColor,
borders);
view->FillRect(rect, fillGradient);
view->PopState();
}
rgb_color
FlatControlLook::_EdgeLightColor(const rgb_color& base, float contrast,
float brightness, uint32 flags)
{
return base;
}
rgb_color
FlatControlLook::_EdgeShadowColor(const rgb_color& base, float contrast,
float brightness, uint32 flags)
{
return base;
}
rgb_color
FlatControlLook::_BevelLightColor(const rgb_color& base, uint32 flags)
{
rgb_color bevelLightColor = tint_color(base, 1.0);
return bevelLightColor;
}
rgb_color
FlatControlLook::_BevelShadowColor(const rgb_color& base, uint32 flags)
{
rgb_color bevelShadowColor = tint_color(base, 1.0);
return bevelShadowColor;
}
void
FlatControlLook::_MakeGradient(BGradientLinear& gradient, const BRect& rect,
const rgb_color& base, float topTint, float bottomTint,
orientation orientation) const
{
gradient.AddColor(tint_color(base, 0.97), 0);
gradient.AddColor(tint_color(base, 1.0), 255);
gradient.SetStart(rect.LeftTop());
if (orientation == B_HORIZONTAL)
gradient.SetEnd(rect.LeftBottom());
else
gradient.SetEnd(rect.RightTop());
}
void
FlatControlLook::_MakeGlossyGradient(BGradientLinear& gradient, const BRect& rect,
const rgb_color& base, float topTint, float middle1Tint,
float middle2Tint, float bottomTint,
orientation orientation) const
{
gradient.AddColor(tint_color(base, topTint), 0);
gradient.AddColor(tint_color(base, bottomTint), 255);
gradient.SetStart(rect.LeftTop());
if (orientation == B_HORIZONTAL)
gradient.SetEnd(rect.LeftBottom());
else
gradient.SetEnd(rect.RightTop());
}
void
FlatControlLook::_MakeButtonGradient(BGradientLinear& gradient, BRect& rect,
const rgb_color& base, uint32 flags, orientation orientation) const
{
float topTint = 0.99;
float middleTint1 = 1.0;
float middleTint2 = 1.0;
float bottomTint = 1.1;
if ((flags & B_ACTIVATED) != 0) {
topTint = 1.1;
bottomTint = 1.1;
}
if ((flags & B_DISABLED) != 0) {
topTint = (topTint + B_NO_TINT) / 2;
middleTint1 = (middleTint1 + B_NO_TINT) / 2;
middleTint2 = (middleTint2 + B_NO_TINT) / 2;
bottomTint = (bottomTint + B_NO_TINT) / 2;
} else if ((flags & B_HOVER) != 0) {
topTint = 1.0;
middleTint1 = 1.0;
middleTint2 = 1.0;
bottomTint = 1.0;
}
if ((flags & B_ACTIVATED) != 0) {
_MakeGradient(gradient, rect, base, topTint, bottomTint, orientation);
} else {
_MakeGlossyGradient(gradient, rect, base, topTint, middleTint1,
middleTint2, bottomTint, orientation);
}
}
}
extern "C" BControlLook* (instantiate_control_look)(image_id id)
{
return new (std::nothrow)BPrivate::FlatControlLook();
}