/* * Copyright 2009-2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm, bpmagic@columbus.rr.com * Adrien Destugues, pulkomandy@gmail.com * John Scipione, jscipione@gmail.com */ /*! Decorator resembling Mac OS 8 and 9 */ #include "MacDecorator.h" #include #include #include #include #include #include "DesktopSettings.h" #include "DrawingEngine.h" #include "PatternHandler.h" #include "RGBColor.h" //#define DEBUG_DECORATOR #ifdef DEBUG_DECORATOR # define STRACE(x) printf x #else # define STRACE(x) ; #endif MacDecorAddOn::MacDecorAddOn(image_id id, const char* name) : DecorAddOn(id, name) { } Decorator* MacDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, Desktop* desktop) { return new (std::nothrow)MacDecorator(settings, rect, desktop); } MacDecorator::MacDecorator(DesktopSettings& settings, BRect frame, Desktop* desktop) : SATDecorator(settings, frame, desktop), fButtonHighColor((rgb_color) { 232, 232, 232, 255 }), fButtonLowColor((rgb_color) { 128, 128, 128, 255 }), fFrameHighColor((rgb_color) { 255, 255, 255, 255 }), fFrameMidColor((rgb_color) { 216, 216, 216, 255 }), fFrameLowColor((rgb_color) { 156, 156, 156, 255 }), fFrameLowerColor((rgb_color) { 0, 0, 0, 255 }), fFocusTextColor(settings.UIColor(B_WINDOW_TEXT_COLOR)), fNonFocusTextColor(settings.UIColor(B_WINDOW_INACTIVE_TEXT_COLOR)) { STRACE(("MacDecorator()\n")); STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n", frame.left, frame.top, frame.right, frame.bottom)); } MacDecorator::~MacDecorator() { STRACE(("~MacDecorator()\n")); } // TODO : Add GetSettings void MacDecorator::Draw(BRect updateRect) { STRACE(("MacDecorator: Draw(BRect updateRect): ")); updateRect.PrintToStream(); // We need to draw a few things: the tab, the borders, // and the buttons fDrawingEngine->SetDrawState(&fDrawState); _DrawFrame(updateRect & fBorderRect); _DrawTabs(updateRect & fTitleBarRect); } void MacDecorator::Draw() { STRACE("MacDecorator::Draw()\n"); fDrawingEngine->SetDrawState(&fDrawState); _DrawFrame(fBorderRect); _DrawTabs(fTitleBarRect); } // TODO : add GetSizeLimits Decorator::Region MacDecorator::RegionAt(BPoint where, int32& tab) const { // Let the base class version identify hits of the buttons and the tab. Region region = Decorator::RegionAt(where, tab); if (region != REGION_NONE) return region; // check the resize corner if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) return REGION_RIGHT_BOTTOM_CORNER; // hit-test the borders 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; // TODO: Determine the actual border! } return REGION_NONE; } bool MacDecorator::SetRegionHighlight(Region region, uint8 highlight, BRegion* dirty, int32 tabIndex) { Decorator::Tab* tab = static_cast(_TabAt(tabIndex)); if (tab != NULL) { tab->isHighlighted = highlight != 0; // Invalidate the bitmap caches for the close/minimize/zoom button // when the highlight changes. 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 MacDecorator::_DoLayout() { STRACE(("MacDecorator: Do Layout\n")); // Here we determine the size of every rectangle that we use // internally when we are given the size of the client rectangle. const int32 kDefaultBorderWidth = 6; bool hasTab = false; if (fTopTab) { switch (fTopTab->look) { case B_MODAL_WINDOW_LOOK: fBorderWidth = kDefaultBorderWidth; break; case B_TITLED_WINDOW_LOOK: case B_DOCUMENT_WINDOW_LOOK: hasTab = true; fBorderWidth = kDefaultBorderWidth; break; case B_FLOATING_WINDOW_LOOK: hasTab = true; fBorderWidth = 3; break; case B_BORDERED_WINDOW_LOOK: fBorderWidth = 1; break; default: fBorderWidth = 0; } } else fBorderWidth = 0; fBorderRect = fFrame.InsetByCopy(-fBorderWidth, -fBorderWidth); // calculate our tab rect if (hasTab) { fBorderRect.top += 3; font_height fontHeight; fDrawState.Font().GetHeight(fontHeight); // TODO the tab is drawn in a fixed height for now fTitleBarRect.Set(fFrame.left - fBorderWidth, fFrame.top - 22, ((fFrame.right - fFrame.left) < 32.0 ? fFrame.left + 32.0 : fFrame.right) + fBorderWidth, fFrame.top - 3); for (int32 i = 0; i < fTabList.CountItems(); i++) { Decorator::Tab* tab = fTabList.ItemAt(i); tab->tabRect = fTitleBarRect; // TODO actually handle multiple tabs tab->zoomRect = fTitleBarRect; tab->zoomRect.left = tab->zoomRect.right - 12; tab->zoomRect.bottom = tab->zoomRect.top + 12; tab->zoomRect.OffsetBy(-4, 4); tab->closeRect = tab->zoomRect; tab->minimizeRect = tab->zoomRect; tab->closeRect.OffsetTo(fTitleBarRect.left + 4, fTitleBarRect.top + 4); tab->zoomRect.OffsetBy(0 - (tab->zoomRect.Width() + 4), 0); if (Title(tab) != NULL && fDrawingEngine != NULL) { tab->truncatedTitle = Title(tab); fDrawingEngine->SetFont(fDrawState.Font()); tab->truncatedTitleLength = (int32)fDrawingEngine->StringWidth(Title(tab), strlen(Title(tab))); if (tab->truncatedTitleLength < (tab->zoomRect.left - tab->closeRect.right - 10)) { // start with offset from closerect.right tab->textOffset = int(((tab->zoomRect.left - 5) - (tab->closeRect.right + 5)) / 2); tab->textOffset -= int(tab->truncatedTitleLength / 2); // now make it the offset from fTabRect.left tab->textOffset += int(tab->closeRect.right + 5 - fTitleBarRect.left); } else tab->textOffset = int(tab->closeRect.right) + 5; } else tab->textOffset = 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 MacDecorator::_DrawFrame(BRect invalid) { if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) return; if (fBorderWidth <= 0) return; BRect r = fBorderRect; switch (fTopTab->look) { case B_TITLED_WINDOW_LOOK: case B_DOCUMENT_WINDOW_LOOK: case B_MODAL_WINDOW_LOOK: { if (IsFocus(fTopTab)) { BPoint offset = r.LeftTop(); BPoint pt2 = r.LeftBottom(); // Draw the left side of the frame fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.x++; pt2.x++; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); offset.x++; pt2.x++; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; pt2.x++; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; pt2.x++; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); offset.x++; offset.y += 2; BPoint topleftpt = offset; pt2.x++; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset = r.RightTop(); pt2 = r.RightBottom(); // Draw the right side of the frame fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.x--; pt2.x--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); offset.x--; pt2.x--; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x--; pt2.x--; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x--; pt2.x--; fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); offset.x--; offset.y += 2; BPoint toprightpt = offset; pt2.x--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); // Draw the top side of the frame that is not in the tab if (fTopTab->look == B_MODAL_WINDOW_LOOK) { offset = r.LeftTop(); pt2 = r.RightTop(); fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.x++; offset.y++; pt2.x--; pt2.y++; fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); offset.x++; offset.y++; pt2.x--; pt2.y++; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; offset.y++; pt2.x--; pt2.y++; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; offset.y++; pt2.x--; pt2.y++; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); offset.x++; offset.y++; pt2.x--; pt2.y++; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); } else { // Some odd stuff here where the title bar is melded into the // window border so that the sides are drawn into the title // so we draw this bottom up offset = topleftpt; pt2 = toprightpt; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.y--; offset.x++; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); } // Draw the bottom side of the frame offset = r.LeftBottom(); pt2 = r.RightBottom(); fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.x++; offset.y--; pt2.x--; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowColor); offset.x++; offset.y--; pt2.x--; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; offset.y--; pt2.x--; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameMidColor); offset.x++; offset.y--; pt2.x--; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameHighColor); offset.x += 2; offset.y--; pt2.x--; pt2.y--; fDrawingEngine->StrokeLine(offset, pt2, fFrameLowerColor); offset.y--; pt2.x--; pt2.y--; } else { r.top -= 3; RGBColor inactive(82, 82, 82); fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), inactive); fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), inactive); fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), inactive); for (int i = 0; i < 4; i++) { r.InsetBy(1, 1); fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), fFrameMidColor); fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), fFrameMidColor); fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), fFrameMidColor); fDrawingEngine->StrokeLine(r.LeftTop(), r.RightTop(), fFrameMidColor); } r.InsetBy(1, 1); fDrawingEngine->StrokeLine(r.LeftTop(), r.LeftBottom(), inactive); fDrawingEngine->StrokeLine(r.RightTop(), r.RightBottom(), inactive); fDrawingEngine->StrokeLine(r.LeftBottom(), r.RightBottom(), inactive); fDrawingEngine->StrokeLine(r.LeftTop(), r.RightTop(), inactive); } break; } case B_BORDERED_WINDOW_LOOK: fDrawingEngine->StrokeRect(r, fFrameMidColor); break; default: // don't draw a border frame break; } } void MacDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid) { // If a window has a tab, this will draw it and any buttons which are // in it. if (!tab->tabRect.IsValid() || !invalid.Intersects(tab->tabRect)) return; BRect rect(tab->tabRect); fDrawingEngine->SetHighColor(RGBColor(fFrameMidColor)); fDrawingEngine->FillRect(rect, fFrameMidColor); if (IsFocus(tab)) { fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), fFrameLowerColor); fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), fFrameLowerColor); fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), fFrameLowerColor); rect.InsetBy(1, 1); rect.bottom++; fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), fFrameHighColor); fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), fFrameHighColor); fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), fFrameLowColor); // Draw the neat little lines on either side of the title if there's // room float left; if ((tab->flags & B_NOT_CLOSABLE) == 0) left = tab->closeRect.right; else left = tab->tabRect.left; float right; if ((tab->flags & B_NOT_ZOOMABLE) == 0) right = tab->zoomRect.left; else if ((tab->flags & B_NOT_MINIMIZABLE) == 0) right = tab->minimizeRect.left; else right = tab->tabRect.right; if (tab->tabRect.left + tab->textOffset > left + 5) { RGBColor dark(115, 115, 115); // Left side BPoint offset(left + 5, tab->closeRect.top); BPoint pt2(tab->tabRect.left + tab->textOffset - 5, tab->closeRect.top); fDrawState.SetHighColor(RGBColor(fFrameHighColor)); for (int32 i = 0; i < 6; i++) { fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor()); offset.y += 2; pt2.y += 2; } offset.Set(left + 6, tab->closeRect.top + 1); pt2.Set(tab->tabRect.left + tab->textOffset - 4, tab->closeRect.top + 1); fDrawState.SetHighColor(dark); for (int32 i = 0; i < 6; i++) { fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor()); offset.y += 2; pt2.y += 2; } // Right side offset.Set(tab->tabRect.left + tab->textOffset + tab->truncatedTitleLength + 3, tab->zoomRect.top); pt2.Set(right - 8, tab->zoomRect.top); if (offset.x < pt2.x) { fDrawState.SetHighColor(RGBColor(fFrameHighColor)); for (int32 i = 0; i < 6; i++) { fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor()); offset.y += 2; pt2.y += 2; } offset.Set(tab->tabRect.left + tab->textOffset + tab->truncatedTitleLength + 4, tab->zoomRect.top + 1); pt2.Set(right - 7, tab->zoomRect.top + 1); fDrawState.SetHighColor(dark); for(int32 i = 0; i < 6; i++) { fDrawingEngine->StrokeLine(offset, pt2, fDrawState.HighColor()); offset.y += 2; pt2.y += 2; } } } _DrawButtons(tab, rect); } else { RGBColor inactive(82, 82, 82); // Not focused - Just draw a plain light grey area with the title // in the middle fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop(), inactive); fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftBottom(), inactive); fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop(), inactive); } _DrawTitle(tab, tab->tabRect); } void MacDecorator::_DrawButtons(Decorator::Tab* tab, const BRect& invalid) { if ((tab->flags & B_NOT_CLOSABLE) == 0 && invalid.Intersects(tab->closeRect)) { _DrawClose(tab, false, tab->closeRect); } 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); } } void MacDecorator::_DrawTitle(Decorator::Tab* tab, BRect rect) { fDrawingEngine->SetHighColor(IsFocus(tab) ? fFocusTextColor : fNonFocusTextColor); fDrawingEngine->SetLowColor(fFrameMidColor); tab->truncatedTitle = Title(tab); fDrawState.Font().TruncateString(&tab->truncatedTitle, B_TRUNCATE_END, (tab->zoomRect.left - 5) - (tab->closeRect.right + 5)); fDrawingEngine->SetFont(fDrawState.Font()); fDrawingEngine->DrawString(tab->truncatedTitle, tab->truncatedTitle.Length(), BPoint(fTitleBarRect.left + tab->textOffset, tab->closeRect.bottom - 1)); } void MacDecorator::_DrawClose(Decorator::Tab* tab, bool direct, BRect r) { _DrawButton(tab, direct, r, tab->closePressed); } void MacDecorator::_DrawZoom(Decorator::Tab* tab, bool direct, BRect rect) { _DrawButton(tab, direct, rect, tab->zoomPressed); rect.top++; rect.left++; rect.bottom = rect.top + 6; rect.right = rect.left + 6; fDrawState.SetHighColor(RGBColor(33, 33, 33)); fDrawingEngine->StrokeRect(rect, fDrawState.HighColor()); } void MacDecorator::_DrawMinimize(Decorator::Tab* tab, bool direct, BRect rect) { _DrawButton(tab, direct, rect, tab->minimizePressed); rect.InsetBy(1, 5); fDrawState.SetHighColor(RGBColor(33, 33, 33)); fDrawingEngine->StrokeRect(rect, fDrawState.HighColor()); } void MacDecorator::_SetTitle(Tab* tab, const char* string, BRegion* updateRegion) { // TODO: we could be much smarter about the update region // TODO may this change the other tabs too ? (to make space for a longer // title ?) BRect rect = TabRect(tab); _DoLayout(); if (updateRegion == NULL) return; rect = rect | TabRect(tab); rect.bottom++; // the border will look differently when the title is adjacent updateRegion->Include(rect); } // TODO : _SetFocus void MacDecorator::_MoveBy(BPoint offset) { // Move all internal rectangles the appropriate amount for (int32 i = 0; i < fTabList.CountItems(); i++) { Decorator::Tab* tab = fTabList.ItemAt(i); tab->zoomRect.OffsetBy(offset); tab->minimizeRect.OffsetBy(offset); tab->closeRect.OffsetBy(offset); tab->tabRect.OffsetBy(offset); } fFrame.OffsetBy(offset); fTitleBarRect.OffsetBy(offset); fResizeRect.OffsetBy(offset); fBorderRect.OffsetBy(offset); } void MacDecorator::_ResizeBy(BPoint offset, BRegion* dirty) { // Move all internal rectangles the appropriate amount fFrame.right += offset.x; fFrame.bottom += offset.y; fTitleBarRect.right += offset.x; fBorderRect.right += offset.x; fBorderRect.bottom += offset.y; // fZoomRect.OffsetBy(offset.x, 0); // fMinimizeRect.OffsetBy(offset.x, 0); if (dirty) { dirty->Include(fTitleBarRect); dirty->Include(fBorderRect); } // TODO probably some other layouting stuff here _DoLayout(); } // TODO : _SetSettings Decorator::Tab* MacDecorator::_AllocateNewTab() { Decorator::Tab* tab = new(std::nothrow) Decorator::Tab; if (tab == NULL) return NULL; // Set appropriate colors based on the current focus value. In this case, // each decorator defaults to not having the focus. _SetFocus(tab); return tab; } bool MacDecorator::_AddTab(DesktopSettings& settings, int32 index, BRegion* updateRegion) { _UpdateFont(settings); _DoLayout(); if (updateRegion != NULL) updateRegion->Include(fTitleBarRect); return true; } bool MacDecorator::_RemoveTab(int32 index, BRegion* updateRegion) { BRect oldTitle = fTitleBarRect; _DoLayout(); if (updateRegion != NULL) { updateRegion->Include(oldTitle); updateRegion->Include(fTitleBarRect); } return true; } bool MacDecorator::_MoveTab(int32 from, int32 to, bool isMoving, BRegion* updateRegion) { return false; #if 0 MacDecorator::Tab* toTab = _TabAt(to); if (toTab == NULL) return false; if (from < to) { fOldMovingTab.OffsetBy(toTab->tabRect.Width(), 0); toTab->tabRect.OffsetBy(-fOldMovingTab.Width(), 0); } else { fOldMovingTab.OffsetBy(-toTab->tabRect.Width(), 0); toTab->tabRect.OffsetBy(fOldMovingTab.Width(), 0); } toTab->tabOffset = uint32(toTab->tabRect.left - fLeftBorder.left); _LayoutTabItems(toTab, toTab->tabRect); _CalculateTabsRegion(); if (updateRegion != NULL) updateRegion->Include(fTitleBarRect); return true; #endif } void MacDecorator::_GetFootprint(BRegion* region) { // This function calculates the decorator's footprint in coordinates // relative to the view. This is most often used to set a Window // object's visible region. if (!region) return; region->MakeEmpty(); if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) return; region->Set(fBorderRect); region->Exclude(fFrame); if (fTopTab->look == B_BORDERED_WINDOW_LOOK) return; region->Include(fTitleBarRect); } void MacDecorator::_UpdateFont(DesktopSettings& settings) { ServerFont font; if (fTopTab && 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); } // #pragma mark - Private methods // Draw a mac-style button void MacDecorator::_DrawButton(Decorator::Tab* tab, bool direct, BRect r, bool down) { BRect rect(r); BPoint offset(r.LeftTop()), pt2(r.RightTop()); // Topleft dark grey border pt2.x--; fDrawingEngine->SetHighColor(RGBColor(136, 136, 136)); fDrawingEngine->StrokeLine(offset, pt2); pt2 = r.LeftBottom(); pt2.y--; fDrawingEngine->StrokeLine(offset, pt2); // Bottomright white border offset = r.RightBottom(); pt2 = r.RightTop(); pt2.y++; fDrawingEngine->SetHighColor(RGBColor(255, 255, 255)); fDrawingEngine->StrokeLine(offset, pt2); pt2 = r.LeftBottom(); pt2.x++; fDrawingEngine->StrokeLine(offset, pt2); // Black outline rect.InsetBy(1, 1); fDrawingEngine->SetHighColor(RGBColor(33, 33, 33)); fDrawingEngine->StrokeRect(rect); // Double-shaded button rect.InsetBy(1, 1); fDrawingEngine->SetHighColor(RGBColor(140, 140, 140)); fDrawingEngine->StrokeLine(rect.RightBottom(), rect.RightTop()); fDrawingEngine->StrokeLine(rect.RightBottom(), rect.LeftBottom()); fDrawingEngine->SetHighColor(RGBColor(206, 206, 206)); fDrawingEngine->StrokeLine(rect.LeftBottom(), rect.LeftTop()); fDrawingEngine->StrokeLine(rect.LeftTop(), rect.RightTop()); fDrawingEngine->SetHighColor(RGBColor(255, 255, 255)); fDrawingEngine->StrokeLine(rect.LeftTop(), rect.LeftTop()); rect.InsetBy(1, 1); _DrawBlendedRect(fDrawingEngine, rect, !down); } /*! \brief Draws a rectangle with a gradient. \param down The rectangle should be drawn recessed or not */ void MacDecorator::_DrawBlendedRect(DrawingEngine* engine, BRect rect, bool down/*, bool focus*/) { // figure out which colors to use rgb_color startColor, endColor; if (down) { startColor = fButtonLowColor; endColor = fFrameHighColor; } else { startColor = fButtonHighColor; endColor = fFrameLowerColor; } // fill BGradientLinear gradient; gradient.SetStart(rect.LeftTop()); gradient.SetEnd(rect.RightBottom()); gradient.AddColor(startColor, 0); gradient.AddColor(endColor, 255); engine->FillRect(rect, gradient); } // #pragma mark - DecorAddOn extern "C" DecorAddOn* instantiate_decor_addon(image_id id, const char* name) { return new (std::nothrow)MacDecorAddOn(id, name); }