#include "BeDecorator.h"
#include <algorithm>
#include <cmath>
#include <new>
#include <stdio.h>
#include <WindowPrivate.h>
#include <Autolock.h>
#include <Debug.h>
#include <GradientLinear.h>
#include <Rect.h>
#include <Region.h>
#include <View.h>
#include "BitmapDrawingEngine.h"
#include "Desktop.h"
#include "DesktopSettings.h"
#include "DrawingEngine.h"
#include "DrawState.h"
#include "FontManager.h"
#include "PatternHandler.h"
#include "RGBColor.h"
#include "ServerBitmap.h"
#ifdef DEBUG_DECORATOR
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
static const float kBorderResizeLength = 22.0;
static const float kResizeKnobSize = 18.0;
static const unsigned char f = 0xff;
static const unsigned char kInnerShadowBits[] = {
f, f, f, f, f, f, f, f, f, 0,
f, f, f, f, f, f, 0, f, 0, f,
f, f, f, f, f, 0, f, 0, f, 0,
f, f, f, f, 0, f, 0, 0, 0, 0,
f, f, f, 0, f, 0, 0, 0, 0, 0,
f, f, 0, f, 0, 0, 0, 0, 0, 0,
f, 0, f, 0, 0, 0, 0, 0, 0, 0,
f, f, 0, 0, 0, 0, 0, 0, 0, 0,
f, 0, f, 0, 0, 0, 0, 0, 0, 0,
0, f, 0, 0, 0, 0, 0, 0, 0, 0
};
static const unsigned char kOuterShadowBits[] = {
f, f, f, f, f, f, f, f, f, f,
f, f, f, f, f, f, f, f, f, f,
f, f, f, f, f, f, f, f, f, f,
f, f, f, f, f, f, f, f, f, f,
f, f, f, f, f, f, f, f, f, 0,
f, f, f, f, f, f, f, 0, 0, 0,
f, f, f, f, f, f, 0, f, 0, 0,
f, f, f, f, f, 0, f, 0, 0, 0,
f, f, f, f, f, 0, 0, 0, 0, 0,
f, f, f, f, 0, 0, 0, 0, 0, 0
};
static const unsigned char kBigInnerShadowBits[] = {
f, f, f, f, f, f, f,
f, f, f, f, f, f, 0,
f, f, f, f, f, 0, 0,
f, f, f, f, 0, f, 0,
f, f, f, 0, f, 0, 0,
f, f, 0, f, 0, 0, 0,
f, 0, 0, 0, 0, 0, 0
};
static const unsigned char kBigOuterShadowBits[] = {
f, f, f, f, f, f, f,
f, f, f, f, f, f, 0,
f, f, f, f, f, f, 0,
f, f, f, f, f, f, 0,
f, f, f, f, f, f, 0,
f, f, f, f, f, f, 0,
f, 0, 0, 0, 0, 0, 0
};
static const unsigned char kSmallInnerShadowBits[] = {
f, f, f, 0, 0,
f, f, 0, f, 0,
f, 0, f, 0, 0,
0, f, 0, 0, 0,
0, 0, 0, 0, 0
};
static const unsigned char kSmallOuterShadowBits[] = {
f, f, f, f, f,
f, f, f, f, f,
f, f, f, f, f,
f, f, f, f, 0,
f, f, 0, 0, 0
};
static const unsigned char kGlintBits[] = {
0, f, 0,
f, 0, f,
0, f, f
};
BeDecorAddOn::BeDecorAddOn(image_id id, const char* name)
:
DecorAddOn(id, name)
{
}
Decorator*
BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
Desktop* desktop)
{
return new (std::nothrow)BeDecorator(settings, rect, desktop);
}
BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect,
Desktop* desktop)
:
SATDecorator(settings, rect, desktop),
fCStatus(B_NO_INIT)
{
STRACE(("BeDecorator:\n"));
STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
rect.left, rect.top, rect.right, rect.bottom));
fCloseBitmap = _CreateTemporaryBitmap(BRect(0, 0, 9, 9));
fBigZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 6, 6));
fSmallZoomBitmap = _CreateTemporaryBitmap(BRect(0, 0, 4, 4));
fGlintBitmap = _CreateTemporaryBitmap(BRect(0, 0, 2, 2));
if (fCloseBitmap == NULL || fBigZoomBitmap == NULL
|| fSmallZoomBitmap == NULL || fGlintBitmap == NULL) {
fCStatus = B_NO_MEMORY;
} else
fCStatus = B_OK;
}
BeDecorator::~BeDecorator()
{
STRACE(("BeDecorator: ~BeDecorator()\n"));
if (fCloseBitmap != NULL)
fCloseBitmap->ReleaseReference();
if (fBigZoomBitmap != NULL)
fBigZoomBitmap->ReleaseReference();
if (fSmallZoomBitmap != NULL)
fSmallZoomBitmap->ReleaseReference();
if (fGlintBitmap != NULL)
fGlintBitmap->ReleaseReference();
}
void
BeDecorator::GetComponentColors(Component component, uint8 highlight,
ComponentColors _colors, Decorator::Tab* _tab)
{
Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
switch (component) {
case COMPONENT_TAB:
if (highlight == HIGHLIGHT_STACK_AND_TILE) {
_colors[COLOR_TAB_FRAME_LIGHT]
= tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
_colors[COLOR_TAB_FRAME_DARK]
= tint_color(fFocusFrameColor, B_DARKEN_4_TINT);
_colors[COLOR_TAB] = tint_color(fFocusTabColor,
B_DARKEN_1_TINT);
_colors[COLOR_TAB_LIGHT] = tint_color(fFocusTabColorLight,
B_DARKEN_1_TINT);
_colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel;
_colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow;
_colors[COLOR_TAB_TEXT] = fFocusTextColor;
} else if (tab && tab->buttonFocus) {
_colors[COLOR_TAB_FRAME_LIGHT]
= tint_color(fFocusFrameColor, B_DARKEN_2_TINT);
_colors[COLOR_TAB_FRAME_DARK]
= tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
_colors[COLOR_TAB] = fFocusTabColor;
_colors[COLOR_TAB_LIGHT] = fFocusTabColorLight;
_colors[COLOR_TAB_BEVEL] = fFocusTabColorBevel;
_colors[COLOR_TAB_SHADOW] = fFocusTabColorShadow;
_colors[COLOR_TAB_TEXT] = fFocusTextColor;
} else {
_colors[COLOR_TAB_FRAME_LIGHT]
= tint_color(fNonFocusFrameColor, B_DARKEN_2_TINT);
_colors[COLOR_TAB_FRAME_DARK]
= tint_color(fNonFocusFrameColor, B_DARKEN_3_TINT);
_colors[COLOR_TAB] = fNonFocusTabColor;
_colors[COLOR_TAB_LIGHT] = fNonFocusTabColorLight;
_colors[COLOR_TAB_BEVEL] = fNonFocusTabColorBevel;
_colors[COLOR_TAB_SHADOW] = fNonFocusTabColorShadow;
_colors[COLOR_TAB_TEXT] = fNonFocusTextColor;
}
break;
case COMPONENT_CLOSE_BUTTON:
case COMPONENT_ZOOM_BUTTON:
if (highlight == HIGHLIGHT_STACK_AND_TILE) {
_colors[COLOR_BUTTON] = tint_color(fFocusTabColor,
B_DARKEN_1_TINT);
_colors[COLOR_BUTTON_LIGHT] = tint_color(fFocusTabColorLight,
B_DARKEN_1_TINT);
} else if (tab && tab->buttonFocus) {
_colors[COLOR_BUTTON] = fFocusTabColor;
_colors[COLOR_BUTTON_LIGHT] = fFocusTabColorLight;
} else {
_colors[COLOR_BUTTON] = fNonFocusTabColor;
_colors[COLOR_BUTTON_LIGHT] = fNonFocusTabColorLight;
}
break;
case COMPONENT_LEFT_BORDER:
case COMPONENT_RIGHT_BORDER:
case COMPONENT_TOP_BORDER:
case COMPONENT_BOTTOM_BORDER:
case COMPONENT_RESIZE_CORNER:
default:
{
rgb_color base;
if (highlight == HIGHLIGHT_STACK_AND_TILE)
base = tint_color(fFocusFrameColor, B_DARKEN_3_TINT);
else if (tab && tab->buttonFocus)
base = fFocusFrameColor;
else
base = fNonFocusFrameColor;
_colors[0].red = std::max(0, base.red - 72);
_colors[0].green = std::max(0, base.green - 72);
_colors[0].blue = std::max(0, base.blue - 72);
_colors[0].alpha = 255;
_colors[1].red = std::min(255, base.red + 64);
_colors[1].green = std::min(255, base.green + 64);
_colors[1].blue = std::min(255, base.blue + 64);
_colors[1].alpha = 255;
_colors[2].red = std::max(0, base.red - 8);
_colors[2].green = std::max(0, base.green - 8);
_colors[2].blue = std::max(0, base.blue - 8);
_colors[2].alpha = 255;
_colors[3].red = std::max(0, base.red - 88);
_colors[3].green = std::max(0, base.green - 88);
_colors[3].blue = std::max(0, base.blue - 88);
_colors[3].alpha = 255;
_colors[4].red = std::max(0, base.red - 72);
_colors[4].green = std::max(0, base.green - 72);
_colors[4].blue = std::max(0, base.blue - 72);
_colors[4].alpha = 255;
_colors[5].red = std::max(0, base.red - 128);
_colors[5].green = std::max(0, base.green - 128);
_colors[5].blue = std::max(0, base.blue - 128);
_colors[5].alpha = 255;
if (highlight == HIGHLIGHT_RESIZE_BORDER) {
for (int32 i = 0; i < 6; i++) {
_colors[i].red = std::max((int)_colors[i].red - 80, 0);
_colors[i].green = std::max((int)_colors[i].green - 80, 0);
_colors[i].blue = 255;
}
}
break;
}
}
}
void
BeDecorator::_DrawFrame(BRect invalid)
{
STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top,
invalid.right, invalid.bottom));
if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
return;
if (fBorderWidth <= 0)
return;
BRect r = BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom());
switch ((int)fTopTab->look) {
case B_TITLED_WINDOW_LOOK:
case B_DOCUMENT_WINDOW_LOOK:
case B_MODAL_WINDOW_LOOK:
{
if (invalid.Intersects(fTopBorder)) {
ComponentColors colors;
_GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab);
for (int8 i = 0; i < 5; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
BPoint(r.right - i, r.top + i), colors[i]);
}
if (fTitleBarRect.IsValid()) {
fDrawingEngine->StrokeLine(
BPoint(fTitleBarRect.left + 2,
fTitleBarRect.bottom + 1),
BPoint(fTitleBarRect.right - 2,
fTitleBarRect.bottom + 1),
colors[2]);
}
}
if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
ComponentColors colors;
_GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
for (int8 i = 0; i < 5; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
BPoint(r.left + i, r.bottom - i), colors[i]);
}
}
if (invalid.Intersects(fBottomBorder)) {
ComponentColors colors;
_GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab);
for (int8 i = 0; i < 5; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i),
BPoint(r.right - i, r.bottom - i),
colors[(4 - i) == 4 ? 5 : (4 - i)]);
}
}
if (invalid.Intersects(
fRightBorder.InsetByCopy(0, -fBorderWidth))) {
ComponentColors colors;
_GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab);
for (int8 i = 0; i < 5; i++) {
fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i),
BPoint(r.right - i, r.bottom - i),
colors[(4 - i) == 4 ? 5 : (4 - i)]);
}
}
break;
}
case B_FLOATING_WINDOW_LOOK:
case kLeftTitledWindowLook:
{
if (invalid.Intersects(fTopBorder)) {
ComponentColors colors;
_GetComponentColors(COMPONENT_TOP_BORDER, colors, fTopTab);
for (int8 i = 0; i < 3; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
BPoint(r.right - i, r.top + i), colors[i * 2]);
}
if (fTitleBarRect.IsValid()
&& fTopTab->look != kLeftTitledWindowLook) {
fDrawingEngine->StrokeLine(
BPoint(fTitleBarRect.left + 2,
fTitleBarRect.bottom + 1),
BPoint(fTitleBarRect.right - 2,
fTitleBarRect.bottom + 1), colors[2]);
}
}
if (invalid.Intersects(fLeftBorder.InsetByCopy(0, -fBorderWidth))) {
ComponentColors colors;
_GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
for (int8 i = 0; i < 3; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i),
BPoint(r.left + i, r.bottom - i), colors[i * 2]);
}
if (fTopTab->look == kLeftTitledWindowLook
&& fTitleBarRect.IsValid()) {
fDrawingEngine->StrokeLine(
BPoint(fTitleBarRect.right + 1,
fTitleBarRect.top + 2),
BPoint(fTitleBarRect.right + 1,
fTitleBarRect.bottom - 2), colors[2]);
}
}
if (invalid.Intersects(fBottomBorder)) {
ComponentColors colors;
_GetComponentColors(COMPONENT_BOTTOM_BORDER, colors, fTopTab);
for (int8 i = 0; i < 3; i++) {
fDrawingEngine->StrokeLine(BPoint(r.left + i, r.bottom - i),
BPoint(r.right - i, r.bottom - i),
colors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
}
}
if (invalid.Intersects(fRightBorder.InsetByCopy(0, -fBorderWidth))) {
ComponentColors colors;
_GetComponentColors(COMPONENT_RIGHT_BORDER, colors, fTopTab);
for (int8 i = 0; i < 3; i++) {
fDrawingEngine->StrokeLine(BPoint(r.right - i, r.top + i),
BPoint(r.right - i, r.bottom - i),
colors[(2 - i) == 2 ? 5 : (2 - i) * 2]);
}
}
break;
}
case B_BORDERED_WINDOW_LOOK:
{
ComponentColors colors;
_GetComponentColors(COMPONENT_LEFT_BORDER, colors, fTopTab);
fDrawingEngine->StrokeRect(r, colors[5]);
break;
}
default:
break;
}
if (!(fTopTab->flags & B_NOT_RESIZABLE)) {
r = fResizeRect;
ComponentColors colors;
_GetComponentColors(COMPONENT_RESIZE_CORNER, colors, fTopTab);
switch ((int)fTopTab->look) {
case B_DOCUMENT_WINDOW_LOOK:
{
if (!invalid.Intersects(r))
break;
float x = r.right - 3;
float y = r.bottom - 3;
BRect bg(x - 13, y - 13, x, y);
BGradientLinear gradient;
gradient.SetStart(bg.LeftTop());
gradient.SetEnd(bg.RightBottom());
gradient.AddColor(colors[1], 0);
gradient.AddColor(colors[2], 255);
fDrawingEngine->FillRect(bg, gradient);
fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15),
BPoint(x - 15, y - 2), colors[0]);
fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14),
BPoint(x - 14, y - 1), colors[1]);
fDrawingEngine->StrokeLine(BPoint(x - 15, y - 15),
BPoint(x - 2, y - 15), colors[0]);
fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14),
BPoint(x - 1, y - 14), colors[1]);
if (fTopTab && !IsFocus(fTopTab))
break;
static const rgb_color kWhite
= (rgb_color){ 255, 255, 255, 255 };
for (int8 i = 1; i <= 4; i++) {
for (int8 j = 1; j <= i; j++) {
BPoint pt1(x - (3 * j) + 1, y - (3 * (5 - i)) + 1);
BPoint pt2(x - (3 * j) + 2, y - (3 * (5 - i)) + 2);
fDrawingEngine->StrokePoint(pt1, colors[0]);
fDrawingEngine->StrokePoint(pt2, kWhite);
}
}
break;
}
case B_TITLED_WINDOW_LOOK:
case B_FLOATING_WINDOW_LOOK:
case B_MODAL_WINDOW_LOOK:
case kLeftTitledWindowLook:
{
if (!invalid.Intersects(BRect(fRightBorder.right
- kBorderResizeLength,
fBottomBorder.bottom - kBorderResizeLength,
fRightBorder.right - 1, fBottomBorder.bottom - 1))) {
break;
}
fDrawingEngine->StrokeLine(BPoint(fRightBorder.left,
fBottomBorder.bottom - kBorderResizeLength),
BPoint(fRightBorder.right - 1,
fBottomBorder.bottom - kBorderResizeLength),
colors[0]);
fDrawingEngine->StrokeLine(
BPoint(fRightBorder.right - kBorderResizeLength,
fBottomBorder.top),
BPoint(fRightBorder.right - kBorderResizeLength,
fBottomBorder.bottom - 1),
colors[0]);
break;
}
default:
break;
}
}
}
void
BeDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid)
{
STRACE(("_DrawTab(%.1f, %.1f, %.1f, %.1f)\n",
invalid.left, invalid.top, invalid.right, invalid.bottom));
const BRect& tabRect = tab->tabRect;
if (!tabRect.IsValid() || !invalid.Intersects(tabRect))
return;
ComponentColors colors;
_GetComponentColors(COMPONENT_TAB, colors, tab);
fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.LeftBottom(),
colors[COLOR_TAB_FRAME_LIGHT]);
fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.RightTop(),
colors[COLOR_TAB_FRAME_LIGHT]);
if (tab->look != kLeftTitledWindowLook) {
fDrawingEngine->StrokeLine(tabRect.RightTop(), tabRect.RightBottom(),
colors[COLOR_TAB_FRAME_DARK]);
} else {
fDrawingEngine->StrokeLine(tabRect.LeftBottom(),
tabRect.RightBottom(), colors[COLOR_TAB_FRAME_DARK]);
}
float tabBotton = tabRect.bottom;
if (fTopTab != tab)
tabBotton -= 1;
fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1),
BPoint(tabRect.left + 1,
tabBotton - (tab->look == kLeftTitledWindowLook ? 1 : 0)),
colors[COLOR_TAB_BEVEL]);
fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1),
BPoint(tabRect.right - (tab->look == kLeftTitledWindowLook ? 0 : 1),
tabRect.top + 1),
colors[COLOR_TAB_BEVEL]);
if (tab->look != kLeftTitledWindowLook) {
fDrawingEngine->StrokeLine(BPoint(tabRect.right - 1, tabRect.top + 2),
BPoint(tabRect.right - 1, tabBotton),
colors[COLOR_TAB_SHADOW]);
} else {
fDrawingEngine->StrokeLine(
BPoint(tabRect.left + 2, tabRect.bottom - 1),
BPoint(tabRect.right, tabRect.bottom - 1),
colors[COLOR_TAB_SHADOW]);
}
if (fTopTab->look != kLeftTitledWindowLook) {
fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2,
tabRect.right - 2, tabRect.bottom), colors[COLOR_TAB]);
} else {
fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2,
tabRect.right, tabRect.bottom - 2), colors[COLOR_TAB]);
}
_DrawTitle(tab, tabRect);
_DrawButtons(tab, invalid);
}
void
BeDecorator::_DrawTitle(Decorator::Tab* _tab, BRect r)
{
STRACE(("_DrawTitle(%f, %f, %f, %f)\n", r.left, r.top, r.right, r.bottom));
Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
const BRect& tabRect = tab->tabRect;
const BRect& closeRect = tab->closeRect;
const BRect& zoomRect = tab->zoomRect;
ComponentColors colors;
_GetComponentColors(COMPONENT_TAB, colors, tab);
fDrawingEngine->SetDrawingMode(B_OP_OVER);
fDrawingEngine->SetHighColor(colors[COLOR_TAB_TEXT]);
fDrawingEngine->SetLowColor(colors[COLOR_TAB]);
fDrawingEngine->SetFont(fDrawState.Font());
font_height fontHeight;
fDrawState.Font().GetHeight(fontHeight);
BPoint titlePos;
if (fTopTab->look != kLeftTitledWindowLook) {
titlePos.x = closeRect.IsValid() ? closeRect.right + tab->textOffset
: tabRect.left + tab->textOffset;
titlePos.y = floorf(((tabRect.top + 2.0) + tabRect.bottom
+ fontHeight.ascent + fontHeight.descent) / 2.0
- fontHeight.descent + 0.5);
} else {
titlePos.x = floorf(((tabRect.left + 2.0) + tabRect.right
+ fontHeight.ascent + fontHeight.descent) / 2.0
- fontHeight.descent + 0.5);
titlePos.y = zoomRect.IsValid() ? zoomRect.top - tab->textOffset
: tabRect.bottom - tab->textOffset;
}
fDrawingEngine->SetFont(fDrawState.Font());
fDrawingEngine->DrawString(tab->truncatedTitle.String(),
tab->truncatedTitleLength, titlePos);
fDrawingEngine->SetDrawingMode(B_OP_COPY);
}
void
BeDecorator::_DrawClose(Decorator::Tab* _tab, bool direct, BRect rect)
{
STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
rect.bottom));
Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
int32 index = (tab->buttonFocus ? 0 : 1) + (tab->closePressed ? 0 : 2);
ServerBitmap* bitmap = tab->closeBitmaps[index];
if (bitmap == NULL) {
bitmap = _GetBitmapForButton(tab, COMPONENT_CLOSE_BUTTON,
tab->closePressed, rect.IntegerWidth(), rect.IntegerHeight());
tab->closeBitmaps[index] = bitmap;
}
_DrawButtonBitmap(bitmap, direct, rect);
}
void
BeDecorator::_DrawZoom(Decorator::Tab* _tab, bool direct, BRect rect)
{
STRACE(("_DrawZoom(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right,
rect.bottom));
if (rect.IntegerWidth() < 1)
return;
Decorator::Tab* tab = static_cast<Decorator::Tab*>(_tab);
int32 index = (tab->buttonFocus ? 0 : 1) + (tab->zoomPressed ? 0 : 2);
ServerBitmap* bitmap = tab->zoomBitmaps[index];
if (bitmap == NULL) {
bitmap = _GetBitmapForButton(tab, COMPONENT_ZOOM_BUTTON,
tab->zoomPressed, rect.IntegerWidth(), rect.IntegerHeight());
tab->zoomBitmaps[index] = bitmap;
}
_DrawButtonBitmap(bitmap, direct, rect);
}
void
BeDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect)
{
}
void
BeDecorator::_GetButtonSizeAndOffset(const BRect& tabRect, float* _offset,
float* _size, float* _inset) const
{
float tabSize = fTopTab->look == kLeftTitledWindowLook ?
tabRect.Width() : tabRect.Height();
*_offset = 5.0f;
*_inset = 0.0f;
*_size = std::max(0.0f, tabSize - 7.0f);
}
void
BeDecorator::_DrawBevelRect(DrawingEngine* engine, const BRect rect, bool down,
rgb_color light, rgb_color shadow)
{
if (down) {
BRect inner(rect.InsetByCopy(1.0f, 1.0f));
engine->StrokeLine(rect.LeftBottom(), rect.LeftTop(), shadow);
engine->StrokeLine(rect.LeftTop(), rect.RightTop(), shadow);
engine->StrokeLine(inner.LeftBottom(), inner.LeftTop(), shadow);
engine->StrokeLine(inner.LeftTop(), inner.RightTop(), shadow);
engine->StrokeLine(rect.RightTop(), rect.RightBottom(), light);
engine->StrokeLine(rect.RightBottom(), rect.LeftBottom(), light);
engine->StrokeLine(inner.RightTop(), inner.RightBottom(), light);
engine->StrokeLine(inner.RightBottom(), inner.LeftBottom(), light);
} else {
BRect r1(rect);
r1.left += 1.0f;
r1.top += 1.0f;
BRect r2(rect);
r2.bottom -= 1.0f;
r2.right -= 1.0f;
engine->StrokeRect(r2, shadow);
engine->StrokeRect(rect, shadow);
engine->StrokeRect(r1, light);
}
}
void
BeDecorator::_DrawBlendedRect(DrawingEngine* engine, const BRect rect,
bool down, rgb_color colorA, rgb_color colorB, rgb_color colorC,
rgb_color colorD)
{
BRect fillRect(rect.InsetByCopy(1.0f, 1.0f));
BGradientLinear gradient;
if (down) {
gradient.SetStart(fillRect.RightBottom());
gradient.SetEnd(fillRect.LeftTop());
} else {
gradient.SetStart(fillRect.LeftTop());
gradient.SetEnd(fillRect.RightBottom());
}
gradient.AddColor(colorA, 0);
gradient.AddColor(colorB, 95);
gradient.AddColor(colorC, 159);
gradient.AddColor(colorD, 255);
engine->FillRect(fillRect, gradient);
}
void
BeDecorator::_DrawButtonBitmap(ServerBitmap* bitmap, bool direct, BRect rect)
{
if (bitmap == NULL)
return;
bool copyToFrontEnabled = fDrawingEngine->CopyToFrontEnabled();
fDrawingEngine->SetCopyToFrontEnabled(direct);
drawing_mode oldMode;
fDrawingEngine->SetDrawingMode(B_OP_OVER, oldMode);
fDrawingEngine->DrawBitmap(bitmap, rect.OffsetToCopy(0, 0), rect);
fDrawingEngine->SetDrawingMode(oldMode);
fDrawingEngine->SetCopyToFrontEnabled(copyToFrontEnabled);
}
ServerBitmap*
BeDecorator::_GetBitmapForButton(Decorator::Tab* tab, Component item,
bool down, int32 width, int32 height)
{
uint8* data;
size_t size;
size_t offset;
struct decorator_bitmap {
Component item;
bool down;
int32 width;
int32 height;
rgb_color baseColor;
rgb_color lightColor;
UtilityBitmap* bitmap;
decorator_bitmap* next;
};
static BLocker sBitmapListLock("decorator lock", true);
static decorator_bitmap* sBitmapList = NULL;
ComponentColors colors;
_GetComponentColors(item, colors, tab);
const rgb_color buttonColor(colors[COLOR_BUTTON]);
bool isGrayscale = buttonColor.red == buttonColor.green
&& buttonColor.green == buttonColor.blue;
rgb_color buttonColorLight1(buttonColor);
buttonColorLight1.red = std::min(255, buttonColor.red + 35),
buttonColorLight1.green = std::min(255, buttonColor.green + 35),
buttonColorLight1.blue = std::min(255, buttonColor.blue
+ (isGrayscale ? 35 : 0));
rgb_color buttonColorLight2(buttonColor);
buttonColorLight2.red = std::min(255, buttonColor.red + 52),
buttonColorLight2.green = std::min(255, buttonColor.green + 52),
buttonColorLight2.blue = std::min(255, buttonColor.blue + 26);
rgb_color buttonColorShadow1(buttonColor);
buttonColorShadow1.red = std::max(0, buttonColor.red - 21),
buttonColorShadow1.green = std::max(0, buttonColor.green - 21),
buttonColorShadow1.blue = std::max(0, buttonColor.blue - 21);
BAutolock locker(sBitmapListLock);
decorator_bitmap* current = sBitmapList;
while (current) {
if (current->item == item && current->down == down
&& current->width == width && current->height == height
&& current->baseColor == colors[COLOR_BUTTON]
&& current->lightColor == colors[COLOR_BUTTON_LIGHT]) {
return current->bitmap;
}
current = current->next;
}
static BitmapDrawingEngine* sBitmapDrawingEngine = NULL;
if (sBitmapDrawingEngine == NULL)
sBitmapDrawingEngine = new(std::nothrow) BitmapDrawingEngine();
if (sBitmapDrawingEngine == NULL
|| sBitmapDrawingEngine->SetSize(width, height) != B_OK) {
return NULL;
}
BRect rect(0, 0, width - 1, height - 1);
STRACE(("BeDecorator creating bitmap for %s %s at size %ldx%ld\n",
item == COMPONENT_CLOSE_BUTTON ? "close" : "zoom",
down ? "down" : "up", width, height));
switch (item) {
case COMPONENT_CLOSE_BUTTON:
{
rgb_color buttonColorShadow2(buttonColor);
buttonColorShadow2.red = std::max(0, buttonColor.red - 72),
buttonColorShadow2.green = std::max(0, buttonColor.green - 72),
buttonColorShadow2.blue = std::max(0, buttonColor.blue - 72);
sBitmapDrawingEngine->FillRect(rect, buttonColor);
_DrawBevelRect(sBitmapDrawingEngine, rect, tab->closePressed,
buttonColorLight2, buttonColorShadow2);
if (fCStatus != B_OK) {
rect.InsetBy(1, 1);
_DrawBlendedRect(sBitmapDrawingEngine, rect, tab->closePressed,
buttonColorLight2, buttonColorLight1, buttonColor,
buttonColorShadow1);
break;
}
rect.InsetBy(2, 2);
sBitmapDrawingEngine->FillRect(rect, buttonColorLight1);
sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
sBitmapDrawingEngine->SetLowColor(buttonColorLight1);
if (tab->closePressed) {
data = fGlintBitmap->Bits();
size = sizeof(kGlintBits);
for (size_t i = 0; i < size; i++) {
offset = (size - 1 - i) * 4;
if (kGlintBits[i] == 0) {
data[offset + 0] = buttonColorLight2.blue;
data[offset + 1] = buttonColorLight2.green;
data[offset + 2] = buttonColorLight2.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect rightBottom(BRect(rect.right - 2, rect.bottom - 2,
rect.right, rect.bottom));
sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
fGlintBitmap->Bounds(), rightBottom);
data = fCloseBitmap->Bits();
size = sizeof(kOuterShadowBits);
for (size_t i = 0; i < size; i++) {
offset = (size - 1 - i) * 4;
if (kOuterShadowBits[i] == 0) {
data[offset + 0] = buttonColorShadow1.blue;
data[offset + 1] = buttonColorShadow1.green;
data[offset + 2] = buttonColorShadow1.red;
} else if (kInnerShadowBits[i] == 0) {
data[offset + 0] = buttonColor.blue;
data[offset + 1] = buttonColor.green;
data[offset + 2] = buttonColor.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect leftTop(rect.left, rect.top,
rect.left + 9, rect.top + 9);
sBitmapDrawingEngine->DrawBitmap(fCloseBitmap,
fCloseBitmap->Bounds(), leftTop);
} else {
data = fGlintBitmap->Bits();
size = sizeof(kGlintBits);
for (size_t i = 0; i < size; i++) {
offset = i * 4 + 0;
if (kGlintBits[i] == 0) {
data[offset + 0] = buttonColorLight2.blue;
data[offset + 1] = buttonColorLight2.green;
data[offset + 2] = buttonColorLight2.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect leftTop(rect.left, rect.top,
rect.left + 2, rect.top + 2);
sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
fGlintBitmap->Bounds(), leftTop);
data = fCloseBitmap->Bits();
size = sizeof(kOuterShadowBits);
for (size_t i = 0; i < size; i++) {
offset = i * 4 + 0;
if (kOuterShadowBits[i] == 0) {
data[offset + 0] = buttonColorShadow1.blue;
data[offset + 1] = buttonColorShadow1.green;
data[offset + 2] = buttonColorShadow1.red;
} else if (kInnerShadowBits[i] == 0) {
data[offset + 0] = buttonColor.blue;
data[offset + 1] = buttonColor.green;
data[offset + 2] = buttonColor.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect rightBottom(BRect(rect.right - 9, rect.bottom - 9,
rect.right, rect.bottom));
sBitmapDrawingEngine->DrawBitmap(fCloseBitmap,
fCloseBitmap->Bounds(), rightBottom);
}
sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
break;
}
case COMPONENT_ZOOM_BUTTON:
{
rgb_color buttonColorShadow2(buttonColor);
buttonColorShadow2.red = std::max(0, buttonColor.red - 45),
buttonColorShadow2.green = std::max(0, buttonColor.green - 45),
buttonColorShadow2.blue = std::max(0, buttonColor.blue - 45);
sBitmapDrawingEngine->FillRect(rect, buttonColor);
BRect bigRect(rect);
bigRect.left += floorf(width * 3.0f / 14.0f);
bigRect.top += floorf(height * 3.0f / 14.0f);
BRect smallRect(rect);
smallRect.right -= floorf(width * 5.0f / 14.0f);
smallRect.bottom -= floorf(height * 5.0f / 14.0f);
_DrawBevelRect(sBitmapDrawingEngine, bigRect, tab->zoomPressed,
buttonColorLight2, buttonColorShadow2);
if (fCStatus != B_OK) {
bigRect.InsetBy(1, 1);
_DrawBlendedRect(sBitmapDrawingEngine, bigRect,
tab->zoomPressed, buttonColorLight2, buttonColorLight1,
buttonColor, buttonColorShadow1);
_DrawBevelRect(sBitmapDrawingEngine, smallRect,
tab->zoomPressed, buttonColorLight2, buttonColorShadow2);
if (!tab->zoomPressed) {
sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(),
buttonColor);
sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(),
buttonColor);
}
smallRect.InsetBy(1, 1);
_DrawBlendedRect(sBitmapDrawingEngine, smallRect,
tab->zoomPressed, buttonColorLight2, buttonColorLight1,
buttonColor, buttonColorShadow1);
break;
}
bigRect.InsetBy(2, 2);
sBitmapDrawingEngine->FillRect(bigRect, buttonColorLight1);
if (tab->zoomPressed) {
data = fGlintBitmap->Bits();
size = sizeof(kGlintBits);
for (size_t i = 0; i < sizeof(kGlintBits); i++) {
offset = (size - 1 - i) * 4;
if (kGlintBits[i] == 0) {
data[offset + 0] = buttonColorLight2.blue;
data[offset + 1] = buttonColorLight2.green;
data[offset + 2] = buttonColorLight2.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect rightBottom(BRect(bigRect.right - 2,
bigRect.bottom - 2, bigRect.right, bigRect.bottom));
sBitmapDrawingEngine->DrawBitmap(fGlintBitmap,
fGlintBitmap->Bounds(), rightBottom);
} else {
data = fBigZoomBitmap->Bits();
for (size_t i = 0; i < sizeof(kBigOuterShadowBits); i++) {
offset = i * 4;
if (kBigOuterShadowBits[i] == 0) {
data[offset + 0] = buttonColorShadow1.blue;
data[offset + 1] = buttonColorShadow1.green;
data[offset + 2] = buttonColorShadow1.red;
} else if (kBigInnerShadowBits[i] == 0) {
data[offset + 0] = buttonColor.blue;
data[offset + 1] = buttonColor.green;
data[offset + 2] = buttonColor.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect rightBottom(BRect(bigRect.right - 6,
bigRect.bottom - 6, bigRect.right, bigRect.bottom));
sBitmapDrawingEngine->DrawBitmap(fBigZoomBitmap,
fBigZoomBitmap->Bounds(), rightBottom);
}
sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
_DrawBevelRect(sBitmapDrawingEngine, smallRect, tab->zoomPressed,
buttonColorLight2, buttonColorShadow2);
if (!tab->zoomPressed) {
sBitmapDrawingEngine->StrokePoint(smallRect.LeftBottom(),
buttonColor);
sBitmapDrawingEngine->StrokePoint(smallRect.RightTop(),
buttonColor);
}
smallRect.InsetBy(2, 2);
sBitmapDrawingEngine->FillRect(smallRect, buttonColorLight1);
sBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
sBitmapDrawingEngine->SetLowColor(buttonColorLight1);
data = fSmallZoomBitmap->Bits();
size = sizeof(kSmallOuterShadowBits);
if (tab->zoomPressed) {
for (size_t i = 0; i < size; i++) {
offset = (size - 1 - i) * 4;
if (kSmallOuterShadowBits[i] == 0) {
data[offset + 0] = buttonColorShadow1.blue;
data[offset + 1] = buttonColorShadow1.green;
data[offset + 2] = buttonColorShadow1.red;
} else if (kSmallInnerShadowBits[i] == 0) {
data[offset + 0] = buttonColor.blue;
data[offset + 1] = buttonColor.green;
data[offset + 2] = buttonColor.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect smallLeftTop(BRect(smallRect.left,
smallRect.top, smallRect.left + 4, smallRect.top + 4));
sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap,
fSmallZoomBitmap->Bounds(), smallLeftTop);
} else {
for (size_t i = 0; i < size; i++) {
offset = i * 4;
if (kSmallOuterShadowBits[i] == 0) {
data[offset + 0] = buttonColorShadow1.blue;
data[offset + 1] = buttonColorShadow1.green;
data[offset + 2] = buttonColorShadow1.red;
} else if (kSmallInnerShadowBits[i] == 0) {
data[offset + 0] = buttonColor.blue;
data[offset + 1] = buttonColor.green;
data[offset + 2] = buttonColor.red;
} else {
data[offset + 0] = buttonColorLight1.blue;
data[offset + 1] = buttonColorLight1.green;
data[offset + 2] = buttonColorLight1.red;
}
}
const BRect smallRightBottom(BRect(smallRect.right - 4,
smallRect.bottom - 4, smallRect.right, smallRect.bottom));
sBitmapDrawingEngine->DrawBitmap(fSmallZoomBitmap,
fSmallZoomBitmap->Bounds(), smallRightBottom);
}
sBitmapDrawingEngine->StrokePoint(tab->zoomPressed
? smallRect.RightBottom() : smallRect.LeftTop(),
buttonColorLight2);
sBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
break;
}
default:
break;
}
UtilityBitmap* bitmap = sBitmapDrawingEngine->ExportToBitmap(width, height,
B_RGB32);
if (bitmap == NULL)
return NULL;
decorator_bitmap* entry = new(std::nothrow) decorator_bitmap;
if (entry == NULL) {
delete bitmap;
return NULL;
}
entry->item = item;
entry->down = down;
entry->width = width;
entry->height = height;
entry->bitmap = bitmap;
entry->baseColor = colors[COLOR_BUTTON];
entry->lightColor = colors[COLOR_BUTTON_LIGHT];
entry->next = sBitmapList;
sBitmapList = entry;
return bitmap;
}
ServerBitmap*
BeDecorator::_CreateTemporaryBitmap(BRect bounds) const
{
UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds,
B_RGB32, 0);
if (bitmap == NULL)
return NULL;
if (!bitmap->IsValid()) {
delete bitmap;
return NULL;
}
memset(bitmap->Bits(), 0, bitmap->BitsLength());
return bitmap;
}
void
BeDecorator::_GetComponentColors(Component component,
ComponentColors _colors, Decorator::Tab* tab)
{
Region region = REGION_NONE;
switch (component) {
case COMPONENT_TAB:
region = REGION_TAB;
break;
case COMPONENT_CLOSE_BUTTON:
region = REGION_CLOSE_BUTTON;
break;
case COMPONENT_ZOOM_BUTTON:
region = REGION_ZOOM_BUTTON;
break;
case COMPONENT_LEFT_BORDER:
region = REGION_LEFT_BORDER;
break;
case COMPONENT_RIGHT_BORDER:
region = REGION_RIGHT_BORDER;
break;
case COMPONENT_TOP_BORDER:
region = REGION_TOP_BORDER;
break;
case COMPONENT_BOTTOM_BORDER:
region = REGION_BOTTOM_BORDER;
break;
case COMPONENT_RESIZE_CORNER:
region = REGION_RIGHT_BOTTOM_CORNER;
break;
}
return GetComponentColors(component, RegionHighlight(region), _colors, tab);
}
extern "C" DecorAddOn* (instantiate_decor_addon)(image_id id, const char* name)
{
return new (std::nothrow)BeDecorAddOn(id, name);
}