#include "WinDecorator.h"
#include <new>
#include <stdio.h>
#include <Point.h>
#include <Rect.h>
#include <View.h>
#include "DesktopSettings.h"
#include "DrawingEngine.h"
#include "PatternHandler.h"
#include "RGBColor.h"
#ifdef DEBUG_DECORATOR
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
WinDecorAddOn::WinDecorAddOn(image_id id, const char* name)
:
DecorAddOn(id, name)
{
}
Decorator*
WinDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
Desktop* desktop)
{
return new (std::nothrow)WinDecorator(settings, rect, desktop);
}
WinDecorator::WinDecorator(DesktopSettings& settings, BRect frame,
Desktop* desktop)
:
SATDecorator(settings, frame, desktop),
fFrameHighColor((rgb_color){ 255, 255, 255, 255 }),
fFrameMidColor((rgb_color){ 216, 216, 216, 255 }),
fFrameLowColor((rgb_color){ 110, 110, 110, 255 }),
fFrameLowerColor((rgb_color){ 0, 0, 0, 255 }),
fFocusTabColor(settings.UIColor(B_WINDOW_TAB_COLOR)),
fFocusTextColor(settings.UIColor(B_WINDOW_TEXT_COLOR)),
fNonFocusTabColor(settings.UIColor(B_WINDOW_INACTIVE_TAB_COLOR)),
fNonFocusTextColor(settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR))
{
STRACE(("WinDecorator:\n"));
STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",
frame.left, frame.top, frame.right, frame.bottom));
}
WinDecorator::~WinDecorator()
{
STRACE(("~WinDecorator()\n"));
}
void
WinDecorator::Draw(BRect updateRect)
{
STRACE(("WinDecorator::Draw(BRect updateRect): "));
updateRect.PrintToStream();
fDrawingEngine->SetDrawState(&fDrawState);
_DrawFrame(updateRect & fBorderRect);
_DrawTabs(updateRect & fTitleBarRect);
}
void
WinDecorator::Draw()
{
STRACE(("WinDecorator: Draw()"));
fDrawingEngine->SetDrawState(&fDrawState);
_DrawFrame(fBorderRect);
_DrawTabs(fTitleBarRect);
}
Decorator::Region
WinDecorator::RegionAt(BPoint where, int32& tabIndex) const
{
tabIndex = -1;
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
if (tab->minimizeRect.Contains(where)) {
tabIndex = i;
return REGION_MINIMIZE_BUTTON;
}
}
Region region = Decorator::RegionAt(where, tabIndex);
if (region != REGION_NONE)
return region;
if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where))
return REGION_RIGHT_BOTTOM_CORNER;
if (!(fTopTab->flags & B_NOT_RESIZABLE)
&& (fTopTab->look == B_TITLED_WINDOW_LOOK
|| fTopTab->look == B_FLOATING_WINDOW_LOOK
|| fTopTab->look == B_MODAL_WINDOW_LOOK)
&& fBorderRect.Contains(where) && !fFrame.Contains(where)) {
return REGION_BOTTOM_BORDER;
}
return REGION_NONE;
}
bool
WinDecorator::SetRegionHighlight(Region region, uint8 highlight,
BRegion* dirty, int32 tabIndex)
{
Decorator::Tab* tab
= static_cast<Decorator::Tab*>(_TabAt(tabIndex));
if (tab != NULL) {
tab->isHighlighted = highlight != 0;
switch (region) {
case REGION_CLOSE_BUTTON:
if (highlight != RegionHighlight(region))
memset(&tab->closeBitmaps, 0, sizeof(tab->closeBitmaps));
break;
case REGION_MINIMIZE_BUTTON:
if (highlight != RegionHighlight(region)) {
memset(&tab->minimizeBitmaps, 0,
sizeof(tab->minimizeBitmaps));
}
break;
case REGION_ZOOM_BUTTON:
if (highlight != RegionHighlight(region))
memset(&tab->zoomBitmaps, 0, sizeof(tab->zoomBitmaps));
break;
default:
break;
}
}
return Decorator::SetRegionHighlight(region, highlight, dirty, tabIndex);
}
void
WinDecorator::_DoLayout()
{
STRACE(("WinDecorator()::_DoLayout()\n"));
bool hasTab = false;
fBorderRect = fFrame;
switch ((int)fTopTab->look) {
case B_MODAL_WINDOW_LOOK:
fBorderWidth = 4;
break;
case B_TITLED_WINDOW_LOOK:
case B_DOCUMENT_WINDOW_LOOK:
hasTab = true;
fBorderWidth = 4;
break;
case B_FLOATING_WINDOW_LOOK:
fBorderWidth = 0;
hasTab = true;
break;
case B_BORDERED_WINDOW_LOOK:
fBorderWidth = 1;
break;
default:
fBorderWidth = 0;
break;
}
fBorderRect.InsetBy(-fBorderWidth, -fBorderWidth);
if (hasTab) {
font_height fontHeight;
fDrawState.Font().GetHeight(fontHeight);
float tabSize = ceilf(fontHeight.ascent + fontHeight.descent + 4.0);
if (tabSize < 20)
tabSize = 20;
fBorderRect.top -= tabSize;
fTitleBarRect.Set(fFrame.left - 1,
fFrame.top - tabSize,
((fFrame.right - fFrame.left) < 32.0 ?
fFrame.left + 32.0 : fFrame.right) + 1,
fFrame.top - 1);
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
tab->tabRect = fTitleBarRect;
const float buttonsInset = 3;
tab->zoomRect = tab->tabRect;
tab->zoomRect.top += buttonsInset;
tab->zoomRect.right -= buttonsInset;
tab->zoomRect.bottom -= buttonsInset;
tab->zoomRect.left = tab->zoomRect.right - tabSize + buttonsInset;
tab->closeRect = tab->zoomRect;
tab->zoomRect.OffsetBy(0 - tab->zoomRect.Width() - 3, 0);
tab->minimizeRect = tab->zoomRect;
tab->minimizeRect.OffsetBy(0 - tab->zoomRect.Width() - 1, 0);
}
} else {
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
tab->tabRect.Set(0.0, 0.0, -1.0, -1.0);
tab->closeRect.Set(0.0, 0.0, -1.0, -1.0);
tab->zoomRect.Set(0.0, 0.0, -1.0, -1.0);
tab->minimizeRect.Set(0.0, 0.0, -1.0, -1.0);
}
}
}
void
WinDecorator::_DrawFrame(BRect rect)
{
if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
return;
if (fBorderRect == fFrame)
return;
BRect r = fBorderRect;
fDrawingEngine->SetHighColor(fFrameLowerColor);
fDrawingEngine->StrokeRect(r);
if (fTopTab->look == B_BORDERED_WINDOW_LOOK)
return;
BPoint pt;
pt = r.RightTop();
pt.x--;
fDrawingEngine->StrokeLine(r.LeftTop(), pt, fFrameMidColor);
pt = r.LeftBottom();
pt.y--;
fDrawingEngine->StrokeLine(r.LeftTop(), pt, fFrameMidColor);
fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), fFrameLowerColor);
fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), fFrameLowerColor);
r.InsetBy(1, 1);
pt = r.RightTop();
pt.x--;
fDrawingEngine->StrokeLine(r.LeftTop(),pt,fFrameHighColor);
pt = r.LeftBottom();
pt.y--;
fDrawingEngine->StrokeLine(r.LeftTop(),pt,fFrameHighColor);
fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), fFrameLowColor);
fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), fFrameLowColor);
r.InsetBy(1, 1);
fDrawingEngine->StrokeRect(r, fFrameMidColor);
r.InsetBy(1, 1);
fDrawingEngine->StrokeRect(r, fFrameMidColor);
}
void
WinDecorator::_DrawTab(Decorator::Tab* tab, BRect rect)
{
const BRect& tabRect = tab->tabRect;
if (!tabRect.IsValid() || !rect.Intersects(tabRect)
|| fTopTab->look == B_NO_BORDER_WINDOW_LOOK) {
return;
}
fDrawingEngine->FillRect(tabRect & rect, fTabColor);
_DrawTitle(tab, tabRect);
_DrawButtons(tab, rect);
}
void
WinDecorator::_DrawTitle(Decorator::Tab* tab, BRect rect)
{
const BRect& tabRect = tab->tabRect;
const BRect& minimizeRect = tab->minimizeRect;
const BRect& zoomRect = tab->zoomRect;
const BRect& closeRect = tab->closeRect;
fDrawingEngine->SetHighColor(fTextColor);
fDrawingEngine->SetLowColor(IsFocus(tab)
? fFocusTabColor : fNonFocusTabColor);
tab->truncatedTitle = Title(tab);
fDrawState.Font().TruncateString(&tab->truncatedTitle, B_TRUNCATE_END,
((minimizeRect.IsValid() ? minimizeRect.left :
zoomRect.IsValid() ? zoomRect.left :
closeRect.IsValid() ? closeRect.left : tabRect.right) - 5)
- (tabRect.left + 5));
tab->truncatedTitleLength = tab->truncatedTitle.Length();
fDrawingEngine->SetFont(fDrawState.Font());
font_height fontHeight;
fDrawState.Font().GetHeight(fontHeight);
BPoint titlePos;
titlePos.x = tabRect.left + 5;
titlePos.y = floorf(((tabRect.top + 2.0) + tabRect.bottom
+ fontHeight.ascent + fontHeight.descent) / 2.0
- fontHeight.descent + 0.5);
fDrawingEngine->DrawString(tab->truncatedTitle, tab->truncatedTitleLength,
titlePos);
}
void
WinDecorator::_DrawButtons(Decorator::Tab* tab, const BRect& invalid)
{
if ((tab->flags & B_NOT_MINIMIZABLE) == 0
&& invalid.Intersects(tab->minimizeRect)) {
_DrawMinimize(tab, false, tab->minimizeRect);
}
if ((tab->flags & B_NOT_ZOOMABLE) == 0
&& invalid.Intersects(tab->zoomRect)) {
_DrawZoom(tab, false, tab->zoomRect);
}
if ((tab->flags & B_NOT_CLOSABLE) == 0
&& invalid.Intersects(tab->closeRect)) {
_DrawClose(tab, false, tab->closeRect);
}
}
void
WinDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect)
{
_DrawBeveledRect(rect, tab->minimizePressed);
fDrawingEngine->SetHighColor(fTextColor);
BRect minimizeBox(rect.left + 5, rect.bottom - 4, rect.right - 5,
rect.bottom - 3);
if (true)
minimizeBox.OffsetBy(1, 1);
fDrawingEngine->SetHighColor(RGBColor(0, 0, 0));
fDrawingEngine->StrokeRect(minimizeBox);
}
void
WinDecorator::_DrawZoom(Decorator::Tab* tab, bool direct, BRect rect)
{
_DrawBeveledRect(rect, tab->zoomPressed);
BRect zoomBox(rect);
zoomBox.InsetBy(2, 2);
zoomBox.InsetBy(1, 0);
zoomBox.bottom--;
zoomBox.right--;
if (true)
zoomBox.OffsetBy(1, 1);
fDrawingEngine->SetHighColor(RGBColor(0,0,0));
fDrawingEngine->StrokeRect(zoomBox);
zoomBox.InsetBy(1, 1);
fDrawingEngine->StrokeLine(zoomBox.LeftTop(), zoomBox.RightTop());
}
void
WinDecorator::_DrawClose(Decorator::Tab* tab, bool direct, BRect rect)
{
STRACE(("_DrawClose(%f, %f, %f, %f)\n", rect.left, rect.top, rect.right,
rect.bottom));
_DrawBeveledRect(rect, tab->closePressed);
BRect closeBox(rect);
closeBox.InsetBy(4, 4);
closeBox.right--;
closeBox.top--;
if (true)
closeBox.OffsetBy(1, 1);
fDrawingEngine->SetHighColor(RGBColor(0, 0, 0));
fDrawingEngine->StrokeLine(closeBox.LeftTop(), closeBox.RightBottom());
fDrawingEngine->StrokeLine(closeBox.RightTop(), closeBox.LeftBottom());
closeBox.OffsetBy(1, 0);
fDrawingEngine->StrokeLine(closeBox.LeftTop(), closeBox.RightBottom());
fDrawingEngine->StrokeLine(closeBox.RightTop(), closeBox.LeftBottom());
}
void
WinDecorator::_SetTitle(Decorator::Tab* tab, const char* string,
BRegion* updateRegion)
{
BRect rect = TabRect(tab);
if (updateRegion == NULL)
return;
BRect updatedRect = TabRect(tab);
if (rect.left > updatedRect.left)
rect.left = updatedRect.left;
if (rect.right < updatedRect.right)
rect.right = updatedRect.right;
updateRegion->Include(rect);
}
void
WinDecorator::_SetFocus(Decorator::Tab* tab)
{
if (IsFocus(tab)) {
fTabColor = fFocusTabColor;
fTextColor = fFocusTextColor;
} else {
fTabColor = fNonFocusTabColor;
fTextColor = fNonFocusTextColor;
}
}
void
WinDecorator::_MoveBy(BPoint offset)
{
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
tab->zoomRect.OffsetBy(offset);
tab->closeRect.OffsetBy(offset);
tab->minimizeRect.OffsetBy(offset);
tab->tabRect.OffsetBy(offset);
}
fFrame.OffsetBy(offset);
fTitleBarRect.OffsetBy(offset);
fResizeRect.OffsetBy(offset);
fBorderRect.OffsetBy(offset);
}
void
WinDecorator::_ResizeBy(BPoint offset, BRegion* dirty)
{
fFrame.right += offset.x;
fFrame.bottom += offset.y;
fTitleBarRect.right += offset.x;
fTitleBarRect.bottom += offset.y;
fResizeRect.OffsetBy(offset);
fBorderRect.right += offset.x;
fBorderRect.bottom += offset.y;
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
tab->tabRect.right += offset.x;
if (dirty != NULL)
dirty->Include(tab->tabRect);
}
if (dirty != NULL)
dirty->Include(fBorderRect);
_DoLayout();
}
Decorator::Tab*
WinDecorator::_AllocateNewTab()
{
Decorator::Tab* tab = new(std::nothrow) Decorator::Tab;
if (tab == NULL)
return NULL;
_SetFocus(tab);
return tab;
}
bool
WinDecorator::_AddTab(DesktopSettings& settings, int32 index,
BRegion* updateRegion)
{
_UpdateFont(settings);
_DoLayout();
if (updateRegion != NULL)
updateRegion->Include(fTitleBarRect);
return true;
}
bool
WinDecorator::_RemoveTab(int32 index, BRegion* updateRegion)
{
BRect oldTitle = fTitleBarRect;
_DoLayout();
if (updateRegion != NULL) {
updateRegion->Include(oldTitle);
updateRegion->Include(fTitleBarRect);
}
return true;
}
bool
WinDecorator::_MoveTab(int32 from, int32 to, bool isMoving,
BRegion* updateRegion)
{
return false;
}
void
WinDecorator::_GetFootprint(BRegion* region)
{
if (region == NULL)
return;
region->MakeEmpty();
if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK)
return;
region->Set(fBorderRect);
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
region->Include(tab->tabRect);
}
region->Exclude(fFrame);
}
void
WinDecorator::_UpdateFont(DesktopSettings& settings)
{
ServerFont font;
if (fTopTab->look == B_FLOATING_WINDOW_LOOK)
settings.GetDefaultPlainFont(font);
else
settings.GetDefaultBoldFont(font);
font.SetFlags(B_FORCE_ANTIALIASING);
font.SetSpacing(B_STRING_SPACING);
fDrawState.SetFont(font);
}
void
WinDecorator::_DrawBeveledRect(BRect r, bool down)
{
RGBColor higher;
RGBColor high;
RGBColor mid;
RGBColor low;
RGBColor lower;
if (down) {
lower.SetColor(255,255,255);
low.SetColor(216,216,216);
mid.SetColor(192,192,192);
high.SetColor(128,128,128);
higher.SetColor(0,0,0);
} else {
higher.SetColor(255,255,255);
high.SetColor(216,216,216);
mid.SetColor(192,192,192);
low.SetColor(128,128,128);
lower.SetColor(0,0,0);
}
BRect rect(r);
BPoint point;
fDrawingEngine->SetHighColor(higher);
fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop());
fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom());
point = rect.RightTop();
point.y++;
fDrawingEngine->StrokeLine(point, rect.RightBottom(), lower);
point = rect.LeftBottom();
point.x++;
fDrawingEngine->StrokeLine(point, rect.RightBottom(), lower);
rect.InsetBy(1,1);
fDrawingEngine->SetHighColor(high);
fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop());
fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom());
point = rect.RightTop();
point.y++;
fDrawingEngine->StrokeLine(point, rect.RightBottom(), low);
point = rect.LeftBottom();
point.x++;
fDrawingEngine->StrokeLine(point, rect.RightBottom(), low);
rect.InsetBy(1,1);
fDrawingEngine->FillRect(rect, mid);
}
extern "C" DecorAddOn*
instantiate_decor_addon(image_id id, const char* name)
{
return new (std::nothrow)WinDecorAddOn(id, name);
}