From db9c24a6513b99e48be51d9833c9ce3f9c6f73e3 Mon Sep 17 00:00:00 2001 From: John Scipione Date: Fri, 19 Jul 2013 19:58:43 -0400 Subject: [PATCH] BeDecorator: make it compile, use tabs. Crashes spectacularly like WinDecorator. --- .../decorators/BeDecorator/BeDecorator.cpp | 1105 +++++++++++------ .../decorators/BeDecorator/BeDecorator.h | 123 +- 2 files changed, 823 insertions(+), 405 deletions(-) diff --git a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp index 87828d1407..80fb9c0687 100644 --- a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp +++ b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp @@ -14,20 +14,27 @@ #include "BeDecorator.h" +#include +#include #include #include +#include + +#include +#include +#include +#include +#include + +#include "BitmapDrawingEngine.h" #include "DesktopSettings.h" #include "DrawingEngine.h" #include "DrawState.h" #include "FontManager.h" #include "PatternHandler.h" #include "RGBColor.h" - -#include "WindowPrivate.h" - -#include -#include +#include "ServerBitmap.h" //#define DEBUG_DECORATOR @@ -38,6 +45,18 @@ #endif +BeDecorator::Tab::Tab() + : + tabOffset(0), + tabLocation(0.0), + isHighlighted(false) +{ + closeBitmaps[0] = closeBitmaps[1] = closeBitmaps[2] = closeBitmaps[3] + = zoomBitmaps[0] = zoomBitmaps[1] = zoomBitmaps[2] = zoomBitmaps[3] + = NULL; +} + + static const float kBorderResizeLength = 22.0; static const float kResizeKnobSize = 18.0; @@ -94,26 +113,23 @@ BeDecorAddOn::BeDecorAddOn(image_id id, const char* name) Decorator* -BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, - window_look look, uint32 flags) +BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect) { - return new (std::nothrow)BeDecorator(settings, rect, look, flags); + return new (std::nothrow)BeDecorator(settings, rect); } // TODO: get rid of DesktopSettings here, and introduce private accessor // methods to the Decorator base class -BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect, - window_look look, uint32 flags) +BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect) : - Decorator(settings, rect, look, flags), + Decorator(settings, rect), fTabOffset(0), - fTabLocation(0.0), fWasDoubleClick(false) { _UpdateFont(settings); - SetLook(settings, look); + //SetLook(settings, look); fFrameColors = new RGBColor[6]; fFrameColors[0].SetColor(152, 152, 152); @@ -123,9 +139,11 @@ BeDecorator::BeDecorator(DesktopSettings& settings, BRect rect, fFrameColors[4].SetColor(152, 152, 152); fFrameColors[5].SetColor(96, 96, 96); + fTabList.AddItem(_AllocateNewTab()); + // Set appropriate colors based on the current focus value. In this case, // each decorator defaults to not having the focus. - _SetFocus(); + _SetFocus(_TabAt(0)); // Do initial decorator setup _DoLayout(); @@ -146,37 +164,60 @@ BeDecorator::~BeDecorator() } +float +BeDecorator::TabLocation(int32 tab) const +{ + BeDecorator::Tab* decoratorTab = _TabAt(tab); + if (decoratorTab == NULL) + return 0.0f; + + return (float)decoratorTab->tabOffset; +} + + bool BeDecorator::GetSettings(BMessage* settings) const { - if (!fTabRect.IsValid()) + if (!fTitleBarRect.IsValid()) return false; - if (settings->AddRect("tab frame", fTabRect) != B_OK) + if (settings->AddRect("tab frame", fTitleBarRect) != B_OK) return false; if (settings->AddFloat("border width", fBorderWidth) != B_OK) return false; - return settings->AddFloat("tab location", (float)fTabOffset) == B_OK; + // TODO: only add the location of the tab of the window who requested the + // settings + for (int32 i = 0; i < fTabList.CountItems(); i++) { + BeDecorator::Tab* tab = _TabAt(i); + if (settings->AddFloat("tab location", (float)tab->tabOffset) != B_OK) + return false; + } + + return true; } // #pragma mark - -void -BeDecorator::Draw(BRect update) -{ - STRACE(("BeDecorator: Draw(%.1f,%.1f,%.1f,%.1f)\n", - update.left, update.top, update.right, update.bottom)); +/*! \brief Updates the decorator in the rectangular area \a updateRect. + + The default version updates all areas which intersect the frame and tab. + + \param updateRect The rectangular area to update. +*/ +void +BeDecorator::Draw(BRect updateRect) +{ + STRACE(("BeDecorator::Draw(BRect updateRect): ")); + updateRect.PrintToStream(); - // We need to draw a few things: the tab, the resize knob, the borders, - // and the buttons fDrawingEngine->SetDrawState(&fDrawState); - _DrawFrame(update); - _DrawTab(update); + _DrawFrame(updateRect & fFrame); + _DrawTabs(updateRect & fTitleBarRect); } @@ -187,8 +228,8 @@ BeDecorator::Draw() // things fDrawingEngine->SetDrawState(&fDrawState); - _DrawFrame(BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom())); - _DrawTab(fTabRect); + _DrawFrame(fFrame); + _DrawTabs(fTitleBarRect); } @@ -196,9 +237,12 @@ void BeDecorator::GetSizeLimits(int32* minWidth, int32* minHeight, int32* maxWidth, int32* maxHeight) const { - if (fTabRect.IsValid()) { + float minTabSize = 0; + if (CountTabs() > 0) + minTabSize = _TabAt(0)->minTabSize; + if (fTitleBarRect.IsValid()) { *minWidth = (int32)roundf(max_c(*minWidth, - fMinTabSize - 2 * fBorderWidth)); + minTabSize - 2 * fBorderWidth)); } if (fResizeRect.IsValid()) { *minHeight = (int32)roundf(max_c(*minHeight, @@ -208,15 +252,15 @@ BeDecorator::GetSizeLimits(int32* minWidth, int32* minHeight, Decorator::Region -BeDecorator::RegionAt(BPoint where) const +BeDecorator::RegionAt(BPoint where, int32& tab) const { // Let the base class version identify hits of the buttons and the tab. - Region region = Decorator::RegionAt(where); + Region region = Decorator::RegionAt(where, tab); if (region != REGION_NONE) return region; // check the resize corner - if (fLook == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) + if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK && fResizeRect.Contains(where)) return REGION_RIGHT_BOTTOM_CORNER; // hit-test the borders @@ -235,11 +279,11 @@ BeDecorator::RegionAt(BPoint where) const return REGION_NONE; // check resize area - if ((fFlags & B_NOT_RESIZABLE) == 0 - && (fLook == B_TITLED_WINDOW_LOOK - || fLook == B_FLOATING_WINDOW_LOOK - || fLook == B_MODAL_WINDOW_LOOK - || fLook == kLeftTitledWindowLook)) { + if ((fTopTab->flags & B_NOT_RESIZABLE) == 0 + && (fTopTab->look == B_TITLED_WINDOW_LOOK + || fTopTab->look == B_FLOATING_WINDOW_LOOK + || fTopTab->look == B_MODAL_WINDOW_LOOK + || fTopTab->look == kLeftTitledWindowLook)) { BRect resizeRect(BPoint(fBottomBorder.right - kBorderResizeLength, fBottomBorder.bottom - kBorderResizeLength), fBottomBorder.RightBottom()); @@ -260,7 +304,7 @@ BeDecorator::_DoLayout() bool hasTab = false; - switch ((int)Look()) { + switch ((int)fTopTab->look) { case B_MODAL_WINDOW_LOOK: fBorderWidth = 5; break; @@ -284,76 +328,6 @@ BeDecorator::_DoLayout() fBorderWidth = 0; } - // calculate our tab rect - if (hasTab) { - // distance from one item of the tab bar to another. - // In this case the text and close/zoom rects - fTextOffset = (fLook == B_FLOATING_WINDOW_LOOK - || fLook == kLeftTitledWindowLook) ? 10 : 18; - - font_height fontHeight; - fDrawState.Font().GetHeight(fontHeight); - - if (fLook != kLeftTitledWindowLook) { - fTabRect.Set(fFrame.left - fBorderWidth, - fFrame.top - fBorderWidth - - ceilf(fontHeight.ascent + fontHeight.descent + 7.0), - ((fFrame.right - fFrame.left) < 35.0 ? - fFrame.left + 35.0 : fFrame.right) + fBorderWidth, - fFrame.top - fBorderWidth); - } else { - fTabRect.Set(fFrame.left - fBorderWidth - - ceilf(fontHeight.ascent + fontHeight.descent + 5.0), - fFrame.top - fBorderWidth, fFrame.left - fBorderWidth, - fFrame.bottom + fBorderWidth); - } - - // format tab rect for a floating window - make the rect smaller - if (fLook == B_FLOATING_WINDOW_LOOK) { - fTabRect.InsetBy(0, 2); - fTabRect.OffsetBy(0, 2); - } - - float offset; - float size; - _GetButtonSizeAndOffset(fTabRect, &offset, &size); - - // fMinTabSize contains just the room for the buttons - fMinTabSize = 4.0 + fTextOffset; - if ((fFlags & B_NOT_CLOSABLE) == 0) - fMinTabSize += offset + size; - if ((fFlags & B_NOT_ZOOMABLE) == 0) - fMinTabSize += offset + size; - - // fMaxTabSize contains fMinWidth + the width required for the title - fMaxTabSize = fDrawingEngine - ? ceilf(fDrawingEngine->StringWidth(Title(), strlen(Title()), - fDrawState.Font())) : 0.0; - if (fMaxTabSize > 0.0) - fMaxTabSize += fTextOffset; - fMaxTabSize += fMinTabSize; - - float tabSize = (fLook != kLeftTitledWindowLook - ? fFrame.Width() : fFrame.Height()) + fBorderWidth * 2; - if (tabSize < fMinTabSize) - tabSize = fMinTabSize; - if (tabSize > fMaxTabSize) - tabSize = fMaxTabSize; - - // layout buttons and truncate text - if (fLook != kLeftTitledWindowLook) - fTabRect.right = fTabRect.left + tabSize; - else - fTabRect.bottom = fTabRect.top + tabSize; - } else { - // no tab - fMinTabSize = 0.0; - fMaxTabSize = 0.0; - fTabRect.Set(0.0, 0.0, -1.0, -1.0); - fCloseRect.Set(0.0, 0.0, -1.0, -1.0); - fZoomRect.Set(0.0, 0.0, -1.0, -1.0); - } - // calculate left/top/right/bottom borders if (fBorderWidth > 0) { // NOTE: no overlapping, the left and right border rects @@ -388,23 +362,213 @@ BeDecorator::_DoLayout() } if (hasTab) { - // make sure fTabOffset is within limits and apply it to - // the fTabRect - if (fTabOffset < 0) - fTabOffset = 0; - if (fTabLocation != 0.0 - && fTabOffset > (fRightBorder.right - fLeftBorder.left - - fTabRect.Width())) - fTabOffset = uint32(fRightBorder.right - fLeftBorder.left - - fTabRect.Width()); - fTabRect.OffsetBy(fTabOffset, 0); - - // finally, layout the buttons and text within the tab rect - _LayoutTabItems(fTabRect); + _DoTabLayout(); + return; + } else { + // no tab + 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); + } + fTabsRegion.MakeEmpty(); + fTitleBarRect.Set(0.0, 0.0, -1.0, -1.0); } } +void +BeDecorator::_DoTabLayout() +{ + float tabOffset = 0; + if (fTabList.CountItems() == 1) { + float tabSize; + tabOffset = _SingleTabOffsetAndSize(tabSize); + } + + float sumTabWidth = 0; + // calculate our tab rect + for (int32 i = 0; i < fTabList.CountItems(); i++) { + BeDecorator::Tab* tab = _TabAt(i); + + BRect& tabRect = tab->tabRect; + // distance from one item of the tab bar to another. + // In this case the text and close/zoom rects + tab->textOffset = _DefaultTextOffset(); + + font_height fontHeight; + fDrawState.Font().GetHeight(fontHeight); + + if (tab->look != kLeftTitledWindowLook) { + tabRect.Set(fFrame.left - fBorderWidth, + fFrame.top - fBorderWidth + - ceilf(fontHeight.ascent + fontHeight.descent + 7.0), + ((fFrame.right - fFrame.left) < 35.0 ? + fFrame.left + 35.0 : fFrame.right) + fBorderWidth, + fFrame.top - fBorderWidth); + } else { + tabRect.Set(fFrame.left - fBorderWidth + - ceilf(fontHeight.ascent + fontHeight.descent + 5.0), + fFrame.top - fBorderWidth, fFrame.left - fBorderWidth, + fFrame.bottom + fBorderWidth); + } + + // format tab rect for a floating window - make the rect smaller + if (tab->look == B_FLOATING_WINDOW_LOOK) { + tabRect.InsetBy(0, 2); + tabRect.OffsetBy(0, 2); + } + + float offset; + float size; + float inset; + _GetButtonSizeAndOffset(tabRect, &offset, &size, &inset); + + // tab->minTabSize contains just the room for the buttons + tab->minTabSize = inset * 2 + tab->textOffset; + if ((tab->flags & B_NOT_CLOSABLE) == 0) + tab->minTabSize += offset + size; + if ((tab->flags & B_NOT_ZOOMABLE) == 0) + tab->minTabSize += offset + size; + + // tab->maxTabSize contains tab->minTabSize + the width required for the + // title + tab->maxTabSize = fDrawingEngine + ? ceilf(fDrawingEngine->StringWidth(Title(tab), strlen(Title(tab)), + fDrawState.Font())) : 0.0; + if (tab->maxTabSize > 0.0) + tab->maxTabSize += tab->textOffset; + tab->maxTabSize += tab->minTabSize; + + float tabSize = (tab->look != kLeftTitledWindowLook + ? fFrame.Width() : fFrame.Height()) + fBorderWidth * 2; + if (tabSize < tab->minTabSize) + tabSize = tab->minTabSize; + if (tabSize > tab->maxTabSize) + tabSize = tab->maxTabSize; + + // layout buttons and truncate text + if (tab->look != kLeftTitledWindowLook) + tabRect.right = tabRect.left + tabSize; + else + tabRect.bottom = tabRect.top + tabSize; + + // make sure fTabOffset is within limits and apply it to + // the tabRect + tab->tabOffset = (uint32)tabOffset; + if (tab->tabLocation != 0.0 && fTabList.CountItems() == 1 + && tab->tabOffset > (fRightBorder.right - fLeftBorder.left + - tabRect.Width())) { + tab->tabOffset = uint32(fRightBorder.right - fLeftBorder.left + - tabRect.Width()); + } + tabRect.OffsetBy(tab->tabOffset, 0); + tabOffset += tabRect.Width(); + + sumTabWidth += tabRect.Width(); + } + + float windowWidth = fFrame.Width() + 2 * fBorderWidth; + if (CountTabs() > 1 && sumTabWidth > windowWidth) + _DistributeTabSize(sumTabWidth - windowWidth); + + // finally, layout the buttons and text within the tab rect + for (int32 i = 0; i < fTabList.CountItems(); i++) { + Decorator::Tab* tab = fTabList.ItemAt(i); + + if (i == 0) + fTitleBarRect = tab->tabRect; + else + fTitleBarRect = fTitleBarRect | tab->tabRect; + + _LayoutTabItems(tab, tab->tabRect); + } + fTabsRegion = fTitleBarRect; +} + + +static bool +int_equal(float x, float y) +{ + return abs(x - y) <= 1; +} + + +void +BeDecorator::_DistributeTabSize(float delta) +{ + ASSERT(CountTabs() > 1); + + float maxTabSize = 0; + float secMaxTabSize = 0; + int32 nTabsWithMaxSize = 0; + for (int32 i = 0; i < fTabList.CountItems(); i++) { + Decorator::Tab* tab = fTabList.ItemAt(i); + float tabWidth = tab->tabRect.Width(); + if (int_equal(maxTabSize, tabWidth)) { + nTabsWithMaxSize++; + continue; + } + if (maxTabSize < tabWidth) { + secMaxTabSize = maxTabSize; + maxTabSize = tabWidth; + nTabsWithMaxSize = 1; + } else if (secMaxTabSize <= tabWidth) + secMaxTabSize = tabWidth; + } + + float minus = ceil(std::min(maxTabSize - secMaxTabSize, delta)); + delta -= minus; + minus /= nTabsWithMaxSize; + + Decorator::Tab* prevTab = NULL; + for (int32 i = 0; i < fTabList.CountItems(); i++) { + Decorator::Tab* tab = fTabList.ItemAt(i); + if (int_equal(maxTabSize, tab->tabRect.Width())) + tab->tabRect.right -= minus; + + if (prevTab) { + tab->tabRect.OffsetBy(prevTab->tabRect.right - tab->tabRect.left, + 0); + } + + prevTab = tab; + } + + if (delta > 0) { + _DistributeTabSize(delta); + return; + } + + // done + prevTab->tabRect.right = floor(fFrame.right + fBorderWidth); + + for (int32 i = 0; i < fTabList.CountItems(); i++) { + BeDecorator::Tab* tab = _TabAt(i); + tab->tabOffset = uint32(tab->tabRect.left - fLeftBorder.left); + } +} + + +Decorator::Tab* +BeDecorator::_AllocateNewTab() +{ + Decorator::Tab* tab = new(std::nothrow) BeDecorator::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; +} + + +BeDecorator::Tab* +BeDecorator::_TabAt(int32 index) const +{ + return static_cast(fTabList.ItemAt(index)); +} + + void BeDecorator::_DrawFrame(BRect invalid) { @@ -414,7 +578,7 @@ BeDecorator::_DrawFrame(BRect invalid) // NOTE: the DrawingEngine needs to be locked for the entire // time for the clipping to stay valid for this decorator - if (fLook == B_NO_BORDER_WINDOW_LOOK) + if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) return; if (fBorderWidth <= 0) @@ -422,7 +586,7 @@ BeDecorator::_DrawFrame(BRect invalid) // Draw the border frame BRect r = BRect(fTopBorder.LeftTop(), fBottomBorder.RightBottom()); - switch ((int)fLook) { + switch ((int)fTopTab->look) { case B_TITLED_WINDOW_LOOK: case B_DOCUMENT_WINDOW_LOOK: case B_MODAL_WINDOW_LOOK: @@ -433,12 +597,14 @@ BeDecorator::_DrawFrame(BRect invalid) fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), BPoint(r.right - i, r.top + i), fFrameColors[i]); } - if (fTabRect.IsValid()) { + if (fTitleBarRect.IsValid()) { // grey along the bottom of the tab // (overwrites "white" from frame) fDrawingEngine->StrokeLine( - BPoint(fTabRect.left + 2, fTabRect.bottom + 1), - BPoint(fTabRect.right - 2, fTabRect.bottom + 1), + BPoint(fTitleBarRect.left + 2, + fTitleBarRect.bottom + 1), + BPoint(fTitleBarRect.right - 2, + fTitleBarRect.bottom + 1), fFrameColors[2]); } } @@ -477,13 +643,14 @@ BeDecorator::_DrawFrame(BRect invalid) fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), BPoint(r.right - i, r.top + i), fFrameColors[i * 2]); } - if (fTabRect.IsValid() && fLook != kLeftTitledWindowLook) { + if (fTitleBarRect.IsValid() && fTopTab->look != kLeftTitledWindowLook) { // grey along the bottom of the tab // (overwrites "white" from frame) fDrawingEngine->StrokeLine( - BPoint(fTabRect.left + 2, fTabRect.bottom + 1), - BPoint(fTabRect.right - 2, fTabRect.bottom + 1), - fFrameColors[2]); + BPoint(fTitleBarRect.left + 2, + fTitleBarRect.bottom + 1), + BPoint(fTitleBarRect.right - 2, + fTitleBarRect.bottom + 1), fFrameColors[2]); } } // left @@ -492,13 +659,15 @@ BeDecorator::_DrawFrame(BRect invalid) fDrawingEngine->StrokeLine(BPoint(r.left + i, r.top + i), BPoint(r.left + i, r.bottom - i), fFrameColors[i * 2]); } - if (fLook == kLeftTitledWindowLook && fTabRect.IsValid()) { + if (fTopTab->look == kLeftTitledWindowLook + && fTitleBarRect.IsValid()) { // grey along the right side of the tab // (overwrites "white" from frame) fDrawingEngine->StrokeLine( - BPoint(fTabRect.right + 1, fTabRect.top + 2), - BPoint(fTabRect.right + 1, fTabRect.bottom - 2), - fFrameColors[2]); + BPoint(fTitleBarRect.right + 1, + fTitleBarRect.top + 2), + BPoint(fTitleBarRect.right + 1, + fTitleBarRect.bottom - 2), fFrameColors[2]); } } // bottom @@ -521,8 +690,11 @@ BeDecorator::_DrawFrame(BRect invalid) } case B_BORDERED_WINDOW_LOOK: + { + // TODO: Draw the borders individually! fDrawingEngine->StrokeRect(r, fFrameColors[5]); break; + } default: // don't draw a border frame @@ -530,10 +702,10 @@ BeDecorator::_DrawFrame(BRect invalid) } // Draw the resize knob if we're supposed to - if (!(fFlags & B_NOT_RESIZABLE)) { + if (!(fTopTab->flags & B_NOT_RESIZABLE)) { r = fResizeRect; - switch ((int)fLook) { + switch ((int)fTopTab->look) { case B_DOCUMENT_WINDOW_LOOK: { if (!invalid.Intersects(r)) @@ -554,7 +726,7 @@ BeDecorator::_DrawFrame(BRect invalid) fDrawingEngine->StrokeLine(BPoint(x - 14, y - 14), BPoint(x - 1, y - 14), fFrameColors[1]); - if (!IsFocus()) + if (!IsFocus(fTopTab)) break; for (int8 i = 1; i <= 4; i++) { @@ -598,13 +770,17 @@ BeDecorator::_DrawFrame(BRect invalid) void -BeDecorator::_DrawTab(BRect invalid) +BeDecorator::_DrawTab(Decorator::Tab* tab, BRect invalid) { - STRACE(("_DrawTab(%.1f,%.1f,%.1f,%.1f)\n", + STRACE(("_DrawTab(%.1f, %.1f, %.1f, %.1f)\n", invalid.left, invalid.top, invalid.right, invalid.bottom)); + const BRect& tabRect = tab->tabRect; // If a window has a tab, this will draw it and any buttons which are // in it. - if (!fTabRect.IsValid() || !invalid.Intersects(fTabRect)) + if (!tabRect.IsValid() || !invalid.Intersects(tabRect)) + return; + + if (fBorderWidth <= 0) return; // TODO: cache these @@ -614,70 +790,56 @@ BeDecorator::_DrawTab(BRect invalid) B_DARKEN_2_TINT)); // outer frame - fDrawingEngine->StrokeLine(fTabRect.LeftTop(), fTabRect.LeftBottom(), + fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.LeftBottom(), fFrameColors[0]); - fDrawingEngine->StrokeLine(fTabRect.LeftTop(), fTabRect.RightTop(), + fDrawingEngine->StrokeLine(tabRect.LeftTop(), tabRect.RightTop(), fFrameColors[0]); - if (fLook != kLeftTitledWindowLook) { - fDrawingEngine->StrokeLine(fTabRect.RightTop(), fTabRect.RightBottom(), + if (fTopTab->look != kLeftTitledWindowLook) { + fDrawingEngine->StrokeLine(tabRect.RightTop(), tabRect.RightBottom(), fFrameColors[5]); } else { - fDrawingEngine->StrokeLine(fTabRect.LeftBottom(), - fTabRect.RightBottom(), fFrameColors[5]); + fDrawingEngine->StrokeLine(tabRect.LeftBottom(), + tabRect.RightBottom(), fFrameColors[5]); } // bevel - fDrawingEngine->StrokeLine(BPoint(fTabRect.left + 1, fTabRect.top + 1), - BPoint(fTabRect.left + 1, - fTabRect.bottom - (fLook == kLeftTitledWindowLook ? 1 : 0)), + fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1), + BPoint(tabRect.left + 1, + tabRect.bottom - (fTopTab->look == kLeftTitledWindowLook ? 1 : 0)), tabColorLight); - fDrawingEngine->StrokeLine(BPoint(fTabRect.left + 1, fTabRect.top + 1), - BPoint(fTabRect.right - (fLook == kLeftTitledWindowLook ? 0 : 1), - fTabRect.top + 1), + fDrawingEngine->StrokeLine(BPoint(tabRect.left + 1, tabRect.top + 1), + BPoint(tabRect.right - (fTopTab->look == kLeftTitledWindowLook ? 0 : 1), + tabRect.top + 1), tabColorLight); - if (fLook != kLeftTitledWindowLook) { - fDrawingEngine->StrokeLine(BPoint(fTabRect.right - 1, fTabRect.top + 2), - BPoint(fTabRect.right - 1, fTabRect.bottom), tabColorShadow); + if (fTopTab->look != kLeftTitledWindowLook) { + fDrawingEngine->StrokeLine(BPoint(tabRect.right - 1, tabRect.top + 2), + BPoint(tabRect.right - 1, tabRect.bottom), tabColorShadow); } else { fDrawingEngine->StrokeLine( - BPoint(fTabRect.left + 2, fTabRect.bottom - 1), - BPoint(fTabRect.right, fTabRect.bottom - 1), tabColorShadow); + BPoint(tabRect.left + 2, tabRect.bottom - 1), + BPoint(tabRect.right, tabRect.bottom - 1), tabColorShadow); } // fill - if (fLook != kLeftTitledWindowLook) { - fDrawingEngine->FillRect(BRect(fTabRect.left + 2, fTabRect.top + 2, - fTabRect.right - 2, fTabRect.bottom), fTabColor); + if (fTopTab->look != kLeftTitledWindowLook) { + fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2, + tabRect.right - 2, tabRect.bottom), fTabColor); } else { - fDrawingEngine->FillRect(BRect(fTabRect.left + 2, fTabRect.top + 2, - fTabRect.right, fTabRect.bottom - 2), fTabColor); + fDrawingEngine->FillRect(BRect(tabRect.left + 2, tabRect.top + 2, + tabRect.right, tabRect.bottom - 2), fTabColor); } - _DrawTitle(fTabRect); + _DrawTitle(tab, tabRect); - // Draw the buttons if we're supposed to - if (!(fFlags & B_NOT_CLOSABLE) && invalid.Intersects(fCloseRect)) - _DrawClose(fCloseRect); - if (!(fFlags & B_NOT_ZOOMABLE) && invalid.Intersects(fZoomRect)) - _DrawZoom(fZoomRect); + DrawButtons(tab, invalid); } void -BeDecorator::_DrawClose(BRect rect) +BeDecorator::_DrawTitle(Decorator::Tab* tab, BRect r) { - STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right, - rect.bottom)); - // Just like DrawZoom, but for a close button - _DrawBlendedRect(rect, GetClose()); -} - - -void -BeDecorator::_DrawTitle(BRect r) -{ - STRACE(("_DrawTitle(%f,%f,%f,%f)\n", r.left, r.top, r.right, r.bottom)); + STRACE(("_DrawTitle(%f, %f, %f, %f)\n", r.left, r.top, r.right, r.bottom)); fDrawingEngine->SetDrawingMode(B_OP_OVER); fDrawingEngine->SetHighColor(fTextColor); @@ -689,18 +851,18 @@ BeDecorator::_DrawTitle(BRect r) fDrawState.Font().GetHeight(fontHeight); BPoint titlePos; - if (fLook != kLeftTitledWindowLook) { - titlePos.x = fCloseRect.IsValid() ? fCloseRect.right + fTextOffset - : fTabRect.left + fTextOffset; - titlePos.y = floorf(((fTabRect.top + 2.0) + fTabRect.bottom + if (fTopTab->look != kLeftTitledWindowLook) { + titlePos.x = tab->closeRect.IsValid() ? tab->closeRect.right + fTextOffset + : tab->tabRect.left + fTextOffset; + titlePos.y = floorf(((tab->tabRect.top + 2.0) + tab->tabRect.bottom + fontHeight.ascent + fontHeight.descent) / 2.0 - fontHeight.descent + 0.5); } else { - titlePos.x = floorf(((fTabRect.left + 2.0) + fTabRect.right + titlePos.x = floorf(((tab->tabRect.left + 2.0) + tab->tabRect.right + fontHeight.ascent + fontHeight.descent) / 2.0 - fontHeight.descent + 0.5); - titlePos.y = fZoomRect.IsValid() ? fZoomRect.top - fTextOffset - : fTabRect.bottom - fTextOffset; + titlePos.y = tab->zoomRect.IsValid() ? tab->zoomRect.top - fTextOffset + : tab->tabRect.bottom - fTextOffset; } fDrawingEngine->DrawString(fTruncatedTitle.String(), fTruncatedTitleLength, @@ -711,7 +873,17 @@ BeDecorator::_DrawTitle(BRect r) void -BeDecorator::_DrawZoom(BRect rect) +BeDecorator::_DrawClose(Decorator::Tab* tab, bool direct, BRect rect) +{ + STRACE(("_DrawClose(%f,%f,%f,%f)\n", rect.left, rect.top, rect.right, + rect.bottom)); + // Just like DrawZoom, but for a close button + _DrawBlendedRect(rect, true); +} + + +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)); @@ -721,28 +893,29 @@ BeDecorator::_DrawZoom(BRect rect) BRect zr(rect); zr.left += 3.0; zr.top += 3.0; - _DrawBlendedRect(zr, GetZoom()); + _DrawBlendedRect(zr, true); zr = rect; zr.right -= 5.0; zr.bottom -= 5.0; - _DrawBlendedRect(zr, GetZoom()); + _DrawBlendedRect(zr, true); } void -BeDecorator::_SetTitle(const char* string, BRegion* updateRegion) +BeDecorator::_SetTitle(Decorator::Tab* tab, const char* string, + BRegion* updateRegion) { // TODO: we could be much smarter about the update region - BRect rect = TabRect(); + BRect rect = TabRect(tab); _DoLayout(); if (updateRegion == NULL) return; - rect = rect | TabRect(); + rect = rect | TabRect(tab); rect.bottom++; // the border will look differently when the title is adjacent @@ -769,7 +942,29 @@ BeDecorator::_FontsChanged(DesktopSettings& settings, void -BeDecorator::_SetLook(DesktopSettings& settings, window_look look, +BeDecorator::_SetLook(Decorator::Tab* tab, DesktopSettings& settings, + window_look look, BRegion* updateRegion) +{ + // TODO: we could be much smarter about the update region + + // get previous extent + if (updateRegion != NULL) + updateRegion->Include(&GetFootprint()); + + tab->look = look; + + _UpdateFont(settings); + _InvalidateBitmaps(); + _DoLayout(); + + _InvalidateFootprint(); + if (updateRegion != NULL) + updateRegion->Include(&GetFootprint()); +} + + +void +BeDecorator::_SetFlags(Decorator::Tab* tab, uint32 flags, BRegion* updateRegion) { // TODO: we could be much smarter about the update region @@ -778,9 +973,7 @@ BeDecorator::_SetLook(DesktopSettings& settings, window_look look, if (updateRegion != NULL) updateRegion->Include(&GetFootprint()); - fLook = look; - - _UpdateFont(settings); + tab->flags = flags; _DoLayout(); _InvalidateFootprint(); @@ -790,99 +983,60 @@ BeDecorator::_SetLook(DesktopSettings& settings, window_look look, void -BeDecorator::_SetFlags(uint32 flags, BRegion* updateRegion) +BeDecorator::_SetFocus(Decorator::Tab* _tab) { - // TODO: we could be much smarter about the update region - - // get previous extent - if (updateRegion != NULL) - updateRegion->Include(&GetFootprint()); - - fFlags = flags; - _DoLayout(); - - _InvalidateFootprint(); - if (updateRegion != NULL) - updateRegion->Include(&GetFootprint()); + BeDecorator::Tab* tab = static_cast(_tab); + tab->buttonFocus = IsFocus(tab) + || ((tab->look == B_FLOATING_WINDOW_LOOK + || tab->look == kLeftTitledWindowLook) + && (tab->flags & B_AVOID_FOCUS) != 0); + if (CountTabs() > 1) + _LayoutTabItems(tab, tab->tabRect); } void -BeDecorator::_SetFocus() +BeDecorator::_MoveBy(BPoint offset) { - // SetFocus() performs necessary duties for color swapping and - // other things when a window is deactivated or activated. + STRACE(("BeDecorator: Move By (%.1f, %.1f)\n", offset.x, offset.y)); + // Move all internal rectangles the appropriate amount + for (int32 i = 0; i < fTabList.CountItems(); i++) { + Decorator::Tab* tab = fTabList.ItemAt(i); - if (IsFocus() - || ((fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook) - && (fFlags & B_AVOID_FOCUS) != 0)) { - fTabColor = UIColor(B_WINDOW_TAB_COLOR); - fTextColor = UIColor(B_WINDOW_TEXT_COLOR); - fButtonHighColor.SetColor(tint_color(fTabColor.GetColor32(), - B_LIGHTEN_2_TINT)); - fButtonLowColor.SetColor(tint_color(fTabColor.GetColor32(), - B_DARKEN_1_TINT)); - -// fFrameColors[0].SetColor(152, 152, 152); -// fFrameColors[1].SetColor(255, 255, 255); - fFrameColors[2].SetColor(216, 216, 216); - fFrameColors[3].SetColor(136, 136, 136); -// fFrameColors[4].SetColor(152, 152, 152); -// fFrameColors[5].SetColor(96, 96, 96); - } else { - fTabColor = UIColor(B_WINDOW_INACTIVE_TAB_COLOR); - fTextColor = UIColor(B_WINDOW_INACTIVE_TEXT_COLOR); - fButtonHighColor.SetColor(tint_color(fTabColor.GetColor32(), - B_LIGHTEN_2_TINT)); - fButtonLowColor.SetColor(tint_color(fTabColor.GetColor32(), - B_DARKEN_1_TINT)); - -// fFrameColors[0].SetColor(152, 152, 152); -// fFrameColors[1].SetColor(255, 255, 255); - fFrameColors[2].SetColor(232, 232, 232); - fFrameColors[3].SetColor(148, 148, 148); -// fFrameColors[4].SetColor(152, 152, 152); -// fFrameColors[5].SetColor(96, 96, 96); + tab->zoomRect.OffsetBy(offset); + tab->closeRect.OffsetBy(offset); + tab->tabRect.OffsetBy(offset); } + fFrame.OffsetBy(offset); + fTitleBarRect.OffsetBy(offset); + fTabsRegion.OffsetBy(offset); + fResizeRect.OffsetBy(offset); + fBorderRect.OffsetBy(offset); + + fLeftBorder.OffsetBy(offset); + fRightBorder.OffsetBy(offset); + fTopBorder.OffsetBy(offset); + fBottomBorder.OffsetBy(offset); } void -BeDecorator::_MoveBy(BPoint pt) +BeDecorator::_ResizeBy(BPoint offset, BRegion* dirty) { - STRACE(("BeDecorator: Move By (%.1f, %.1f)\n", pt.x, pt.y)); + STRACE(("BeDecorator: Resize By (%.1f, %.1f)\n", offset.x, offset.y)); // Move all internal rectangles the appropriate amount - fFrame.OffsetBy(pt); - fCloseRect.OffsetBy(pt); - fTabRect.OffsetBy(pt); - fResizeRect.OffsetBy(pt); - fZoomRect.OffsetBy(pt); - fBorderRect.OffsetBy(pt); - - fLeftBorder.OffsetBy(pt); - fRightBorder.OffsetBy(pt); - fTopBorder.OffsetBy(pt); - fBottomBorder.OffsetBy(pt); -} - - -void -BeDecorator::_ResizeBy(BPoint pt, BRegion* dirty) -{ - STRACE(("BeDecorator: Resize By (%.1f, %.1f)\n", pt.x, pt.y)); - // Move all internal rectangles the appropriate amount - fFrame.right += pt.x; - fFrame.bottom += pt.y; + fFrame.right += offset.x; + fFrame.bottom += offset.y; // Handle invalidation of resize rect - if (dirty && !(fFlags & B_NOT_RESIZABLE)) { + if (dirty && !(fTopTab->flags & B_NOT_RESIZABLE)) { BRect realResizeRect; - switch ((int)fLook) { + switch ((int)fTopTab->look) { case B_DOCUMENT_WINDOW_LOOK: realResizeRect = fResizeRect; // Resize rect at old location dirty->Include(realResizeRect); - realResizeRect.OffsetBy(pt); + realResizeRect.OffsetBy(offset); // Resize rect at new location dirty->Include(realResizeRect); break; @@ -891,21 +1045,23 @@ BeDecorator::_ResizeBy(BPoint pt, BRegion* dirty) case B_MODAL_WINDOW_LOOK: case kLeftTitledWindowLook: // The bottom border resize line - realResizeRect.Set(fRightBorder.right - kBorderResizeLength, fBottomBorder.top, - fRightBorder.right - kBorderResizeLength, fBottomBorder.bottom - 1); - // resize rect at old location + realResizeRect.Set(fRightBorder.right - kBorderResizeLength, + fBottomBorder.top, fRightBorder.right - kBorderResizeLength, + fBottomBorder.bottom - 1); + // Old location dirty->Include(realResizeRect); - realResizeRect.OffsetBy(pt); - // resize rect at new location + realResizeRect.OffsetBy(offset); + // New location dirty->Include(realResizeRect); // The right border resize line - realResizeRect.Set(fRightBorder.left, fBottomBorder.bottom - 22, - fRightBorder.right - 1, fBottomBorder.bottom - 22); - // resize rect at old location + realResizeRect.Set(fRightBorder.left, + fBottomBorder.bottom - kBorderResizeLength, fRightBorder.right - 1, + fBottomBorder.bottom - kBorderResizeLength); + // Old location dirty->Include(realResizeRect); - realResizeRect.OffsetBy(pt); - // resize rect at new location + realResizeRect.OffsetBy(offset); + // New location dirty->Include(realResizeRect); break; default: @@ -913,93 +1069,94 @@ BeDecorator::_ResizeBy(BPoint pt, BRegion* dirty) } } - fResizeRect.OffsetBy(pt); + fResizeRect.OffsetBy(offset); - fBorderRect.right += pt.x; - fBorderRect.bottom += pt.y; + fBorderRect.right += offset.x; + fBorderRect.bottom += offset.y; - fLeftBorder.bottom += pt.y; - fTopBorder.right += pt.x; + fLeftBorder.bottom += offset.y; + fTopBorder.right += offset.x; - fRightBorder.OffsetBy(pt.x, 0.0); - fRightBorder.bottom += pt.y; + fRightBorder.OffsetBy(offset.x, 0.0); + fRightBorder.bottom += offset.y; - fBottomBorder.OffsetBy(0.0, pt.y); - fBottomBorder.right += pt.x; + fBottomBorder.OffsetBy(0.0, offset.y); + fBottomBorder.right += offset.x; if (dirty) { - if (pt.x > 0.0) { - BRect t(fRightBorder.left - pt.x, fTopBorder.top, + if (offset.x > 0.0) { + BRect t(fRightBorder.left - offset.x, fTopBorder.top, fRightBorder.right, fTopBorder.bottom); dirty->Include(t); - t.Set(fRightBorder.left - pt.x, fBottomBorder.top, + t.Set(fRightBorder.left - offset.x, fBottomBorder.top, fRightBorder.right, fBottomBorder.bottom); dirty->Include(t); dirty->Include(fRightBorder); - } else if (pt.x < 0.0) { + } else if (offset.x < 0.0) { dirty->Include(BRect(fRightBorder.left, fTopBorder.top, fRightBorder.right, fBottomBorder.bottom)); } - if (pt.y > 0.0) { - BRect t(fLeftBorder.left, fLeftBorder.bottom - pt.y, + if (offset.y > 0.0) { + BRect t(fLeftBorder.left, fLeftBorder.bottom - offset.y, fLeftBorder.right, fLeftBorder.bottom); dirty->Include(t); - t.Set(fRightBorder.left, fRightBorder.bottom - pt.y, + t.Set(fRightBorder.left, fRightBorder.bottom - offset.y, fRightBorder.right, fRightBorder.bottom); dirty->Include(t); dirty->Include(fBottomBorder); - } else if (pt.y < 0.0) { + } else if (offset.y < 0.0) { dirty->Include(fBottomBorder); } } // resize tab and layout tab items - if (fTabRect.IsValid()) { - BRect oldTabRect(fTabRect); + if (fTitleBarRect.IsValid()) { + if (fTabList.CountItems() > 1) { + _DoTabLayout(); + if (dirty != NULL) + dirty->Include(fTitleBarRect); + return; + } + + BeDecorator::Tab* tab = _TabAt(0); + BRect& tabRect = tab->tabRect; + BRect oldTabRect(tabRect); float tabSize; - float maxLocation; - if (fLook != kLeftTitledWindowLook) { - tabSize = fRightBorder.right - fLeftBorder.left; - } else { - tabSize = fBottomBorder.bottom - fTopBorder.top; - } - maxLocation = tabSize - fMaxTabSize; - if (maxLocation < 0) - maxLocation = 0; + float tabOffset = _SingleTabOffsetAndSize(tabSize); - float tabOffset = floorf(fTabLocation * maxLocation); - float delta = tabOffset - fTabOffset; - fTabOffset = (uint32)tabOffset; - if (fLook != kLeftTitledWindowLook) - fTabRect.OffsetBy(delta, 0.0); + float delta = tabOffset - tab->tabOffset; + tab->tabOffset = (uint32)tabOffset; + if (fTopTab->look != kLeftTitledWindowLook) + tabRect.OffsetBy(delta, 0.0); else - fTabRect.OffsetBy(0.0, delta); + tabRect.OffsetBy(0.0, delta); - if (tabSize < fMinTabSize) - tabSize = fMinTabSize; - if (tabSize > fMaxTabSize) - tabSize = fMaxTabSize; + if (tabSize < tab->minTabSize) + tabSize = tab->minTabSize; + if (tabSize > tab->maxTabSize) + tabSize = tab->maxTabSize; - if (fLook != kLeftTitledWindowLook && tabSize != fTabRect.Width()) { - fTabRect.right = fTabRect.left + tabSize; - } else if (fLook == kLeftTitledWindowLook - && tabSize != fTabRect.Height()) { - fTabRect.bottom = fTabRect.top + tabSize; + if (fTopTab->look != kLeftTitledWindowLook + && tabSize != tabRect.Width()) { + tabRect.right = tabRect.left + tabSize; + } else if (fTopTab->look == kLeftTitledWindowLook + && tabSize != tabRect.Height()) { + tabRect.bottom = tabRect.top + tabSize; } - if (oldTabRect != fTabRect) { - _LayoutTabItems(fTabRect); + if (oldTabRect != tabRect) { + _LayoutTabItems(tab, tabRect); if (dirty) { // NOTE: the tab rect becoming smaller only would // handled be the Desktop anyways, so it is sufficient // to include it into the dirty region in it's // final state - BRect redraw(fTabRect); + BRect redraw(tabRect); if (delta != 0.0) { redraw = redraw | oldTabRect; - if (fLook != kLeftTitledWindowLook) + if (fTopTab->look != kLeftTitledWindowLook) redraw.bottom++; else redraw.right++; @@ -1007,44 +1164,72 @@ BeDecorator::_ResizeBy(BPoint pt, BRegion* dirty) dirty->Include(redraw); } } + fTitleBarRect = tabRect; + fTabsRegion = fTitleBarRect; } } bool -BeDecorator::_SetTabLocation(float location, BRegion* updateRegion) +BeDecorator::_SetTabLocation(Decorator::Tab* _tab, float location, + bool isShifting, BRegion* updateRegion) { STRACE(("BeDecorator: Set Tab Location(%.1f)\n", location)); - if (!fTabRect.IsValid()) + if (CountTabs() > 1) { + if (isShifting == false) { + _DoTabLayout(); + if (updateRegion != NULL) + updateRegion->Include(fTitleBarRect); + fOldMovingTab = BRect(0, 0, -1, -1); + return true; + } else { + if (fOldMovingTab.IsValid() == false) + fOldMovingTab = _tab->tabRect; + } + } + + BeDecorator::Tab* tab = static_cast(_tab); + BRect& tabRect = tab->tabRect; + if (tabRect.IsValid() == false) return false; if (location < 0) location = 0; float maxLocation - = fRightBorder.right - fLeftBorder.left - fTabRect.Width(); + = fRightBorder.right - fLeftBorder.left - tabRect.Width(); + if (CountTabs() > 1) + maxLocation = fTitleBarRect.right - fLeftBorder.left - tabRect.Width(); + if (location > maxLocation) location = maxLocation; - float delta = location - fTabOffset; + float delta = floor(location - tab->tabOffset); if (delta == 0.0) return false; - // redraw old rect (1 pix on the border also must be updated) - BRect trect(fTabRect); - trect.bottom++; - updateRegion->Include(trect); + // redraw old rect (1 pixel on the border must also be updated) + BRect rect(tabRect); + rect.bottom++; + if (updateRegion != NULL) + updateRegion->Include(rect); - fTabRect.OffsetBy(delta, 0); - fTabOffset = (int32)location; - _LayoutTabItems(fTabRect); + tabRect.OffsetBy(delta, 0); + tab->tabOffset = (int32)location; + _LayoutTabItems(_tab, tabRect); + tab->tabLocation = maxLocation > 0.0 ? tab->tabOffset / maxLocation : 0.0; - fTabLocation = maxLocation > 0.0 ? fTabOffset / maxLocation : 0.0; + if (fTabList.CountItems() == 1) + fTitleBarRect = tabRect; + + _CalculateTabsRegion(); // redraw new rect as well - trect = fTabRect; - trect.bottom++; - updateRegion->Include(trect); + rect = tabRect; + rect.bottom++; + if (updateRegion != NULL) + updateRegion->Include(rect); + return true; } @@ -1053,26 +1238,82 @@ bool BeDecorator::_SetSettings(const BMessage& settings, BRegion* updateRegion) { float tabLocation; - if (settings.FindFloat("tab location", &tabLocation) == B_OK) - return SetTabLocation(tabLocation, updateRegion); + bool modified = false; + for (int32 i = 0; i < fTabList.CountItems(); i++) { + if (settings.FindFloat("tab location", i, &tabLocation) != B_OK) + return false; + modified |= SetTabLocation(i, tabLocation, updateRegion); + } + return modified; +} - return false; + +bool +BeDecorator::_AddTab(DesktopSettings& settings, int32 index, + BRegion* updateRegion) +{ + _UpdateFont(settings); + + _DoLayout(); + if (updateRegion != NULL) + updateRegion->Include(fTitleBarRect); + return true; +} + + +bool +BeDecorator::_RemoveTab(int32 index, BRegion* updateRegion) +{ + BRect oldTitle = fTitleBarRect; + _DoLayout(); + if (updateRegion != NULL) { + updateRegion->Include(oldTitle); + updateRegion->Include(fTitleBarRect); + } + return true; +} + + +bool +BeDecorator::_MoveTab(int32 from, int32 to, bool isMoving, + BRegion* updateRegion) +{ + BeDecorator::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; } void -BeDecorator::_GetFootprint(BRegion* region) +BeDecorator::_GetFootprint(BRegion *region) { STRACE(("BeDecorator: Get Footprint\n")); // 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) + if (region == NULL) return; region->MakeEmpty(); - if (fLook == B_NO_BORDER_WINDOW_LOOK) + if (fTopTab->look == B_NO_BORDER_WINDOW_LOOK) return; region->Include(fTopBorder); @@ -1080,26 +1321,39 @@ BeDecorator::_GetFootprint(BRegion* region) region->Include(fRightBorder); region->Include(fBottomBorder); - if (fLook == B_BORDERED_WINDOW_LOOK) + if (fTopTab->look == B_BORDERED_WINDOW_LOOK) return; - region->Include(fTabRect); + region->Include(&fTabsRegion); - if (fLook == B_DOCUMENT_WINDOW_LOOK) { + if (fTopTab->look == B_DOCUMENT_WINDOW_LOOK) { // include the rectangular resize knob on the bottom right - region->Include(BRect(fFrame.right - 13.0f, fFrame.bottom - 13.0f, + float knobSize = kResizeKnobSize - fBorderWidth; + region->Include(BRect(fFrame.right - knobSize, fFrame.bottom - knobSize, fFrame.right, fFrame.bottom)); } } +void +BeDecorator::DrawButtons(Decorator::Tab* tab, const BRect& invalid) +{ + // Draw the buttons if we're supposed to + if (!(tab->flags & B_NOT_CLOSABLE) && invalid.Intersects(tab->closeRect)) + _DrawClose(tab, false, tab->closeRect); + if (!(tab->flags & B_NOT_ZOOMABLE) && invalid.Intersects(tab->zoomRect)) + _DrawZoom(tab, false, tab->zoomRect); +} + + void BeDecorator::_UpdateFont(DesktopSettings& settings) { ServerFont font; - if (fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook) { + if (fTopTab->look == B_FLOATING_WINDOW_LOOK + || fTopTab->look == kLeftTitledWindowLook) { settings.GetDefaultPlainFont(font); - if (fLook == kLeftTitledWindowLook) + if (fTopTab->look == kLeftTitledWindowLook) font.SetRotation(90.0f); } else settings.GetDefaultBoldFont(font); @@ -1177,68 +1431,153 @@ BeDecorator::_DrawBlendedRect(BRect r, bool down) fDrawingEngine->StrokeRect(r1, tabColorLight); // light box } -// _GetButtonSizeAndOffset + void BeDecorator::_GetButtonSizeAndOffset(const BRect& tabRect, float* _offset, - float* _size) const + float* _size, float* _inset) const { - *_offset = fLook == B_FLOATING_WINDOW_LOOK || fLook == kLeftTitledWindowLook ? 4.0 : 5.0; + float tabSize = fTopTab->look == kLeftTitledWindowLook ? + tabRect.Width() : tabRect.Height(); + + bool smallTab = fTopTab->look == B_FLOATING_WINDOW_LOOK + || fTopTab->look == kLeftTitledWindowLook; + + *_offset = smallTab ? floorf(fDrawState.Font().Size() / 2.6) + : floorf(fDrawState.Font().Size() / 2.3); + *_inset = smallTab ? floorf(fDrawState.Font().Size() / 5.0) + : floorf(fDrawState.Font().Size() / 6.0); // "+ 2" so that the rects are centered within the solid area // (without the 2 pixels for the top border) - if (fLook != kLeftTitledWindowLook) - *_size = tabRect.Height() - 2.0 * *_offset + 2.0f; - else - *_size = tabRect.Width() - 2.0 * *_offset + 2.0f; + *_size = tabSize - 2 * *_offset + *_inset; } -// _LayoutTabItems + void -BeDecorator::_LayoutTabItems(const BRect& tabRect) +BeDecorator::_LayoutTabItems(Decorator::Tab* _tab, const BRect& tabRect) { + BeDecorator::Tab* tab = static_cast(_tab); + float offset; float size; - _GetButtonSizeAndOffset(tabRect, &offset, &size); + float inset; + _GetButtonSizeAndOffset(tabRect, &offset, &size, &inset); + + // default textOffset + tab->textOffset = _DefaultTextOffset(); + + BRect& closeRect = tab->closeRect; + BRect& zoomRect = tab->zoomRect; // calulate close rect based on the tab rectangle - if (fLook != kLeftTitledWindowLook) { - fCloseRect.Set(tabRect.left + offset, tabRect.top + offset, + if (tab->look != kLeftTitledWindowLook) { + closeRect.Set(tabRect.left + offset, tabRect.top + offset, tabRect.left + offset + size, tabRect.top + offset + size); - fZoomRect.Set(tabRect.right - offset - size, tabRect.top + offset, + zoomRect.Set(tabRect.right - offset - size, tabRect.top + offset, tabRect.right - offset, tabRect.top + offset + size); // hidden buttons have no width - if ((Flags() & B_NOT_CLOSABLE) != 0) - fCloseRect.right = fCloseRect.left - offset; - if ((Flags() & B_NOT_ZOOMABLE) != 0) - fZoomRect.left = fZoomRect.right + offset; + if ((tab->flags & B_NOT_CLOSABLE) != 0) + closeRect.right = closeRect.left - offset; + if ((tab->flags & B_NOT_ZOOMABLE) != 0) + zoomRect.left = zoomRect.right + offset; } else { - fCloseRect.Set(tabRect.left + offset, tabRect.top + offset, + closeRect.Set(tabRect.left + offset, tabRect.top + offset, tabRect.left + offset + size, tabRect.top + offset + size); - fZoomRect.Set(tabRect.left + offset, tabRect.bottom - offset - size, + zoomRect.Set(tabRect.left + offset, tabRect.bottom - offset - size, tabRect.left + size + offset, tabRect.bottom - offset); // hidden buttons have no height - if ((Flags() & B_NOT_CLOSABLE) != 0) - fCloseRect.bottom = fCloseRect.top - offset; - if ((Flags() & B_NOT_ZOOMABLE) != 0) - fZoomRect.top = fZoomRect.bottom + offset; + if ((tab->flags & B_NOT_CLOSABLE) != 0) + closeRect.bottom = closeRect.top - offset; + if ((tab->flags & B_NOT_ZOOMABLE) != 0) + zoomRect.top = zoomRect.bottom + offset; } // calculate room for title // TODO: the +2 is there because the title often appeared // truncated for no apparent reason - OTOH the title does // also not appear perfectly in the middle - if (fLook != kLeftTitledWindowLook) - size = (fZoomRect.left - fCloseRect.right) - fTextOffset * 2 + 2; + if (tab->look != kLeftTitledWindowLook) + size = (zoomRect.left - closeRect.right) - tab->textOffset * 2 + inset; else - size = (fZoomRect.top - fCloseRect.bottom) - fTextOffset * 2 + 2; + size = (zoomRect.top - closeRect.bottom) - tab->textOffset * 2 + inset; - fTruncatedTitle = Title(); - fDrawState.Font().TruncateString(&fTruncatedTitle, B_TRUNCATE_END, size); - fTruncatedTitleLength = fTruncatedTitle.Length(); + bool stackMode = fTabList.CountItems() > 1; + if (stackMode && IsFocus(tab) == false) { + zoomRect.Set(0, 0, 0, 0); + size = (tab->tabRect.right - closeRect.right) - tab->textOffset * 2 + + inset; + } + uint8 truncateMode = B_TRUNCATE_MIDDLE; + if (stackMode) { + if (tab->tabRect.Width() < 100) + truncateMode = B_TRUNCATE_END; + float titleWidth = fDrawState.Font().StringWidth(Title(tab), + BString(Title(tab)).Length()); + if (size < titleWidth) { + float oldTextOffset = tab->textOffset; + tab->textOffset -= (titleWidth - size) / 2; + const float kMinTextOffset = 5.; + if (tab->textOffset < kMinTextOffset) + tab->textOffset = kMinTextOffset; + size += oldTextOffset * 2; + size -= tab->textOffset * 2; + } + } + tab->truncatedTitle = Title(tab); + fDrawState.Font().TruncateString(&tab->truncatedTitle, truncateMode, size); + tab->truncatedTitleLength = tab->truncatedTitle.Length(); +} + + +void +BeDecorator::_InvalidateBitmaps() +{ + for (int32 i = 0; i < fTabList.CountItems(); i++) { + BeDecorator::Tab* tab = _TabAt(i); + for (int32 index = 0; index < 4; index++) { + tab->closeBitmaps[index] = NULL; + tab->zoomBitmaps[index] = NULL; + } + } +} + + +float +BeDecorator::_DefaultTextOffset() const +{ + return (fTopTab->look == B_FLOATING_WINDOW_LOOK + || fTopTab->look == kLeftTitledWindowLook) ? 10 : 18; +} + + +float +BeDecorator::_SingleTabOffsetAndSize(float& tabSize) +{ + float maxLocation; + if (fTopTab->look != kLeftTitledWindowLook) { + tabSize = fRightBorder.right - fLeftBorder.left; + } else { + tabSize = fBottomBorder.bottom - fTopBorder.top; + } + BeDecorator::Tab* tab = _TabAt(0); + maxLocation = tabSize - tab->maxTabSize; + if (maxLocation < 0) + maxLocation = 0; + + return floorf(tab->tabLocation * maxLocation); +} + + +void +BeDecorator::_CalculateTabsRegion() +{ + fTabsRegion.MakeEmpty(); + for (int32 i = 0; i < fTabList.CountItems(); i++) + fTabsRegion.Include(fTabList.ItemAt(i)->tabRect); } diff --git a/src/add-ons/decorators/BeDecorator/BeDecorator.h b/src/add-ons/decorators/BeDecorator/BeDecorator.h index 34ad4b0208..d99aa0bc5f 100644 --- a/src/add-ons/decorators/BeDecorator/BeDecorator.h +++ b/src/add-ons/decorators/BeDecorator/BeDecorator.h @@ -18,7 +18,7 @@ class Desktop; - +class ServerBitmap; class BeDecorAddOn : public DecorAddOn { public: @@ -26,19 +26,36 @@ public: protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, - BRect rect, window_look look, uint32 flags); + BRect rect); }; - class BeDecorator: public Decorator { public: - BeDecorator(DesktopSettings& settings, - BRect frame, window_look look, - uint32 flags); + class Tab : public Decorator::Tab { + public: + Tab(); + + uint32 tabOffset; + float tabLocation; + float textOffset; + + BString truncatedTitle; + int32 truncatedTitleLength; + + bool buttonFocus : 1; + + bool isHighlighted : 1; + ServerBitmap* closeBitmaps[4]; + ServerBitmap* zoomBitmaps[4]; + + float minTabSize; + float maxTabSize; + }; + + BeDecorator(DesktopSettings& settings, BRect frame); virtual ~BeDecorator(); - virtual float TabLocation() const - { return (float)fTabOffset; } + virtual float TabLocation(int32 tab) const; virtual bool GetSettings(BMessage* settings) const; @@ -48,48 +65,107 @@ public: virtual void GetSizeLimits(int32* minWidth, int32* minHeight, int32* maxWidth, int32* maxHeight) const; - virtual Region RegionAt(BPoint where) const; + virtual Region RegionAt(BPoint where, int32& tab) const; + +protected: + enum Component { + COMPONENT_TAB, + + COMPONENT_CLOSE_BUTTON, + COMPONENT_ZOOM_BUTTON, + + COMPONENT_LEFT_BORDER, + COMPONENT_RIGHT_BORDER, + COMPONENT_TOP_BORDER, + COMPONENT_BOTTOM_BORDER, + + COMPONENT_RESIZE_CORNER + }; + + enum { + COLOR_TAB_FRAME_LIGHT = 0, + COLOR_TAB_FRAME_DARK = 1, + COLOR_TAB = 2, + COLOR_TAB_LIGHT = 3, + COLOR_TAB_BEVEL = 4, + COLOR_TAB_SHADOW = 5, + COLOR_TAB_TEXT = 6 + }; + + enum { + COLOR_BUTTON = 0, + COLOR_BUTTON_LIGHT = 1 + }; + + typedef rgb_color ComponentColors[7]; protected: virtual void _DoLayout(); + virtual void _DoTabLayout(); + void _DistributeTabSize(float delta); - virtual void _DrawFrame(BRect r); - virtual void _DrawTab(BRect r); + virtual Decorator::Tab* _AllocateNewTab(); + BeDecorator::Tab* _TabAt(int32 index) const; - virtual void _DrawClose(BRect r); - virtual void _DrawTitle(BRect r); - virtual void _DrawZoom(BRect r); + virtual void _DrawFrame(BRect rect); + virtual void _DrawTab(Decorator::Tab* tab, BRect rect); + virtual void _DrawTitle(Decorator::Tab* tab, BRect rect); - virtual void _SetTitle(const char* string, + virtual void _DrawClose(Decorator::Tab* tab, bool direct, + BRect rect); + virtual void _DrawZoom(Decorator::Tab* tab, bool direct, + BRect rect); + + virtual void _SetTitle(Decorator::Tab* tab, const char* string, BRegion* updateRegion = NULL); virtual void _FontsChanged(DesktopSettings& settings, BRegion* updateRegion); - virtual void _SetLook(DesktopSettings& settings, + virtual void _SetLook(Decorator::Tab* tab, + DesktopSettings& settings, window_look look, BRegion* updateRegion = NULL); - virtual void _SetFlags(uint32 flags, + virtual void _SetFlags(Decorator::Tab* tab, uint32 flags, BRegion* updateRegion = NULL); - virtual void _SetFocus(); + virtual void _SetFocus(Decorator::Tab* tab); virtual void _MoveBy(BPoint offset); virtual void _ResizeBy(BPoint offset, BRegion* dirty); - virtual bool _SetTabLocation(float location, + virtual bool _AddTab(DesktopSettings& settings, + int32 index = -1, BRegion* updateRegion = NULL); + virtual bool _RemoveTab(int32 index, + BRegion* updateRegion = NULL); + virtual bool _MoveTab(int32 from, int32 to, bool isMoving, + BRegion* updateRegion = NULL); + + virtual bool _SetTabLocation(Decorator::Tab* tab, float location, + bool isShifting, BRegion* updateRegion = NULL); virtual bool _SetSettings(const BMessage& settings, BRegion* updateRegion = NULL); virtual void _GetFootprint(BRegion* region); + void _GetButtonSizeAndOffset(const BRect& tabRect, + float* offset, float* size, + float* inset) const; + + virtual void DrawButtons(Decorator::Tab* tab, + const BRect& invalid); + private: void _UpdateFont(DesktopSettings& settings); void _DrawBlendedRect(BRect r, bool down); - void _GetButtonSizeAndOffset(const BRect& tabRect, - float* offset, float*size) const; - void _LayoutTabItems(const BRect& tabRect); + void _LayoutTabItems(Decorator::Tab* _tab, const BRect& tabRect); + void _InvalidateBitmaps(); + + inline float _DefaultTextOffset() const; + inline float _SingleTabOffsetAndSize(float& tabSize); + + void _CalculateTabsRegion(); private: RGBColor fButtonHighColor; @@ -108,6 +184,9 @@ private: int32 fBorderWidth; + BRegion fTabsRegion; + BRect fOldMovingTab; + uint32 fTabOffset; float fTabLocation; float fTextOffset;