#include "Decorator.h"
#include <stdio.h>
#include <Region.h>
#include "Desktop.h"
#include "DesktopSettings.h"
#include "DrawingEngine.h"
Decorator::Tab::Tab()
:
tabRect(),
zoomRect(),
closeRect(),
minimizeRect(),
closePressed(false),
zoomPressed(false),
minimizePressed(false),
look(B_TITLED_WINDOW_LOOK),
flags(0),
isFocused(false),
title(""),
tabOffset(0),
tabLocation(0.0f),
textOffset(10.0f),
truncatedTitle(""),
truncatedTitleLength(0),
buttonFocus(false),
isHighlighted(false),
minTabSize(0.0f),
maxTabSize(0.0f)
{
closeBitmaps[0] = closeBitmaps[1] = closeBitmaps[2] = closeBitmaps[3]
= minimizeBitmaps[0] = minimizeBitmaps[1] = minimizeBitmaps[2]
= minimizeBitmaps[3] = zoomBitmaps[0] = zoomBitmaps[1] = zoomBitmaps[2]
= zoomBitmaps[3] = NULL;
}
Decorator::Decorator(DesktopSettings& settings, BRect frame,
Desktop* desktop)
:
fLocker("Decorator"),
fDrawingEngine(NULL),
fDrawState(),
fTitleBarRect(),
fFrame(frame),
fResizeRect(),
fBorderRect(),
fOutlineBorderRect(),
fLeftBorder(),
fTopBorder(),
fBottomBorder(),
fRightBorder(),
fLeftOutlineBorder(),
fTopOutlineBorder(),
fBottomOutlineBorder(),
fRightOutlineBorder(),
fBorderWidth(-1),
fOutlineBorderWidth(-1),
fTopTab(NULL),
fDesktop(desktop),
fFootprintValid(false)
{
memset(&fRegionHighlights, HIGHLIGHT_NONE, sizeof(fRegionHighlights));
}
Decorator::~Decorator()
{
}
Decorator::Tab*
Decorator::AddTab(DesktopSettings& settings, const char* title,
window_look look, uint32 flags, int32 index, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* tab = _AllocateNewTab();
if (tab == NULL)
return NULL;
tab->title = title;
tab->look = look;
tab->flags = flags;
bool ok = false;
if (index >= 0) {
if (fTabList.AddItem(tab, index) == true)
ok = true;
} else if (fTabList.AddItem(tab) == true)
ok = true;
if (ok == false) {
delete tab;
return NULL;
}
Decorator::Tab* oldTop = fTopTab;
fTopTab = tab;
if (_AddTab(settings, index, updateRegion) == false) {
fTabList.RemoveItem(tab);
delete tab;
fTopTab = oldTop;
return NULL;
}
_InvalidateFootprint();
return tab;
}
bool
Decorator::RemoveTab(int32 index, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
if (updateRegion != NULL)
updateRegion->Include(TabRect(index));
Decorator::Tab* tab = fTabList.RemoveItemAt(index);
if (tab == NULL)
return false;
_RemoveTab(index, updateRegion);
delete tab;
_InvalidateFootprint();
return true;
}
bool
Decorator::MoveTab(int32 from, int32 to, bool isMoving, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
if (_MoveTab(from, to, isMoving, updateRegion) == false)
return false;
if (fTabList.MoveItem(from, to) == false) {
_MoveTab(from, to, isMoving, updateRegion);
return false;
}
return true;
}
int32
Decorator::TabAt(const BPoint& where) const
{
AutoReadLocker _(fLocker);
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
if (tab->tabRect.Contains(where))
return i;
}
return -1;
}
void
Decorator::SetTopTab(int32 tab)
{
AutoWriteLocker _(fLocker);
fTopTab = fTabList.ItemAt(tab);
}
void
Decorator::SetDrawingEngine(DrawingEngine* engine)
{
AutoWriteLocker _(fLocker);
fDrawingEngine = engine;
if (fDrawingEngine != NULL) {
_DoLayout();
_DoOutlineLayout();
}
}
void
Decorator::SetFlags(int32 tab, uint32 flags, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
if ((flags & (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE))
== (B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE))
flags |= B_NOT_RESIZABLE;
if (flags & B_NOT_RESIZABLE)
flags |= B_NOT_H_RESIZABLE | B_NOT_V_RESIZABLE;
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_SetFlags(decoratorTab, flags, updateRegion);
_InvalidateFootprint();
}
void
Decorator::FontsChanged(DesktopSettings& settings, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
_FontsChanged(settings, updateRegion);
_InvalidateFootprint();
}
void
Decorator::ColorsChanged(DesktopSettings& settings, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
UpdateColors(settings);
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
_InvalidateBitmaps();
}
void
Decorator::SetLook(int32 tab, DesktopSettings& settings, window_look look,
BRegion* updateRect)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_SetLook(decoratorTab, settings, look, updateRect);
_InvalidateFootprint();
}
window_look
Decorator::Look(int32 tab) const
{
AutoReadLocker _(fLocker);
return TabAt(tab)->look;
}
uint32
Decorator::Flags(int32 tab) const
{
AutoReadLocker _(fLocker);
return TabAt(tab)->flags;
}
BRect
Decorator::BorderRect() const
{
AutoReadLocker _(fLocker);
return fBorderRect;
}
BRect
Decorator::TitleBarRect() const
{
AutoReadLocker _(fLocker);
return fTitleBarRect;
}
BRect
Decorator::TabRect(int32 tab) const
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return BRect();
return decoratorTab->tabRect;
}
BRect
Decorator::TabRect(Decorator::Tab* tab) const
{
return tab->tabRect;
}
void
Decorator::SetClose(int32 tab, bool pressed)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
if (pressed != decoratorTab->closePressed) {
decoratorTab->closePressed = pressed;
DrawClose(tab);
}
}
void
Decorator::SetMinimize(int32 tab, bool pressed)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
if (pressed != decoratorTab->minimizePressed) {
decoratorTab->minimizePressed = pressed;
DrawMinimize(tab);
}
}
void
Decorator::SetZoom(int32 tab, bool pressed)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
if (pressed != decoratorTab->zoomPressed) {
decoratorTab->zoomPressed = pressed;
DrawZoom(tab);
}
}
void
Decorator::SetTitle(int32 tab, const char* string, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
decoratorTab->title.SetTo(string);
_SetTitle(decoratorTab, string, updateRegion);
_InvalidateFootprint();
}
const char*
Decorator::Title(int32 tab) const
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return "";
return decoratorTab->title;
}
const char*
Decorator::Title(Decorator::Tab* tab) const
{
AutoReadLocker _(fLocker);
return tab->title;
}
float
Decorator::TabLocation(int32 tab) const
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = _TabAt(tab);
if (decoratorTab == NULL)
return 0.0f;
return (float)decoratorTab->tabOffset;
}
bool
Decorator::SetTabLocation(int32 tab, float location, bool isShifting,
BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return false;
if (_SetTabLocation(decoratorTab, location, isShifting, updateRegion)) {
_InvalidateFootprint();
return true;
}
return false;
}
void
Decorator::SetFocus(int32 tab, bool active)
{
AutoWriteLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
decoratorTab->isFocused = active;
_SetFocus(decoratorTab);
}
bool
Decorator::IsFocus(int32 tab) const
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return false;
return decoratorTab->isFocused;
};
bool
Decorator::IsFocus(Decorator::Tab* tab) const
{
AutoReadLocker _(fLocker);
return tab->isFocused;
}
const BRegion&
Decorator::GetFootprint()
{
AutoReadLocker _(fLocker);
if (!fFootprintValid) {
fFootprint.MakeEmpty();
_GetFootprint(&fFootprint);
if (IsOutlineResizing())
_GetOutlineFootprint(&fFootprint);
fFootprintValid = true;
}
return fFootprint;
}
::Desktop*
Decorator::GetDesktop()
{
AutoReadLocker _(fLocker);
return fDesktop;
}
Decorator::Region
Decorator::RegionAt(BPoint where, int32& tabIndex) const
{
AutoReadLocker _(fLocker);
tabIndex = -1;
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
if (tab->closeRect.Contains(where)) {
tabIndex = i;
return REGION_CLOSE_BUTTON;
}
if (tab->zoomRect.Contains(where)) {
tabIndex = i;
return REGION_ZOOM_BUTTON;
}
if (tab->tabRect.Contains(where)) {
tabIndex = i;
return REGION_TAB;
}
}
return REGION_NONE;
}
void
Decorator::MoveBy(float x, float y)
{
MoveBy(BPoint(x, y));
}
void
Decorator::MoveBy(BPoint offset)
{
AutoWriteLocker _(fLocker);
if (fFootprintValid)
fFootprint.OffsetBy(offset.x, offset.y);
_MoveBy(offset);
_MoveOutlineBy(offset);
}
void
Decorator::ResizeBy(float x, float y, BRegion* dirty)
{
ResizeBy(BPoint(x, y), dirty);
}
void
Decorator::ResizeBy(BPoint offset, BRegion* dirty)
{
AutoWriteLocker _(fLocker);
_ResizeBy(offset, dirty);
_ResizeOutlineBy(offset, dirty);
_InvalidateFootprint();
}
void
Decorator::SetOutlinesDelta(BPoint delta, BRegion* dirty)
{
_SetOutlinesDelta(delta, dirty);
_InvalidateFootprint();
}
void
Decorator::ExtendDirtyRegion(Region region, BRegion& dirty)
{
AutoReadLocker _(fLocker);
switch (region) {
case REGION_TAB:
dirty.Include(fTitleBarRect);
break;
case REGION_CLOSE_BUTTON:
if ((fTopTab->flags & B_NOT_CLOSABLE) == 0) {
for (int32 i = 0; i < fTabList.CountItems(); i++)
dirty.Include(fTabList.ItemAt(i)->closeRect);
}
break;
case REGION_MINIMIZE_BUTTON:
if ((fTopTab->flags & B_NOT_MINIMIZABLE) == 0) {
for (int32 i = 0; i < fTabList.CountItems(); i++)
dirty.Include(fTabList.ItemAt(i)->minimizeRect);
}
break;
case REGION_ZOOM_BUTTON:
if ((fTopTab->flags & B_NOT_ZOOMABLE) == 0) {
for (int32 i = 0; i < fTabList.CountItems(); i++)
dirty.Include(fTabList.ItemAt(i)->zoomRect);
}
break;
case REGION_LEFT_BORDER:
if (fLeftBorder.IsValid()) {
BRect rect(fLeftBorder);
rect.top = fTopBorder.top;
rect.bottom = fBottomBorder.bottom;
dirty.Include(rect);
}
break;
case REGION_RIGHT_BORDER:
if (fRightBorder.IsValid()) {
BRect rect(fRightBorder);
rect.top = fTopBorder.top;
rect.bottom = fBottomBorder.bottom;
dirty.Include(rect);
}
break;
case REGION_TOP_BORDER:
dirty.Include(fTopBorder);
break;
case REGION_BOTTOM_BORDER:
dirty.Include(fBottomBorder);
break;
case REGION_RIGHT_BOTTOM_CORNER:
if ((fTopTab->flags & B_NOT_RESIZABLE) == 0)
dirty.Include(fResizeRect);
break;
default:
break;
}
}
bool
Decorator::SetRegionHighlight(Region region, uint8 highlight, BRegion* dirty,
int32 tab)
{
AutoWriteLocker _(fLocker);
int32 index = (int32)region - 1;
if (index < 0 || index >= REGION_COUNT - 1)
return false;
if (fRegionHighlights[index] == highlight)
return true;
fRegionHighlights[index] = highlight;
if (dirty != NULL)
ExtendDirtyRegion(region, *dirty);
return true;
}
bool
Decorator::SetSettings(const BMessage& settings, BRegion* updateRegion)
{
AutoWriteLocker _(fLocker);
if (_SetSettings(settings, updateRegion)) {
_InvalidateFootprint();
return true;
}
return false;
}
bool
Decorator::GetSettings(BMessage* settings) const
{
AutoReadLocker _(fLocker);
if (!fTitleBarRect.IsValid())
return false;
if (settings->AddRect("tab frame", fTitleBarRect) != B_OK)
return false;
if (settings->AddFloat("border width", fBorderWidth) != B_OK)
return false;
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = _TabAt(i);
if (settings->AddFloat("tab location", (float)tab->tabOffset) != B_OK)
return false;
}
return true;
}
void
Decorator::GetSizeLimits(int32* minWidth, int32* minHeight,
int32* maxWidth, int32* maxHeight) const
{
AutoReadLocker _(fLocker);
float minTabSize = 0;
if (CountTabs() > 0)
minTabSize = _TabAt(0)->minTabSize;
if (fTitleBarRect.IsValid()) {
*minWidth = (int32)roundf(max_c(*minWidth,
minTabSize - 2 * fBorderWidth));
}
if (fResizeRect.IsValid()) {
*minHeight = (int32)roundf(max_c(*minHeight,
fResizeRect.Height() - fBorderWidth));
}
}
void
Decorator::DrawTab(int32 tabIndex)
{
AutoReadLocker _(fLocker);
Decorator::Tab* tab = fTabList.ItemAt(tabIndex);
if (tab == NULL)
return;
_DrawTab(tab, tab->tabRect);
_DrawZoom(tab, false, tab->zoomRect);
_DrawMinimize(tab, false, tab->minimizeRect);
_DrawTitle(tab, tab->tabRect);
_DrawClose(tab, false, tab->closeRect);
}
void
Decorator::DrawTitle(int32 tab)
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_DrawTitle(decoratorTab, decoratorTab->tabRect);
}
void
Decorator::DrawClose(int32 tab)
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_DrawClose(decoratorTab, true, decoratorTab->closeRect);
}
void
Decorator::DrawMinimize(int32 tab)
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_DrawTab(decoratorTab, decoratorTab->minimizeRect);
}
void
Decorator::DrawZoom(int32 tab)
{
AutoReadLocker _(fLocker);
Decorator::Tab* decoratorTab = fTabList.ItemAt(tab);
if (decoratorTab == NULL)
return;
_DrawZoom(decoratorTab, true, decoratorTab->zoomRect);
}
rgb_color
Decorator::UIColor(color_which which)
{
AutoReadLocker _(fLocker);
DesktopSettings settings(fDesktop);
return settings.UIColor(which);
}
float
Decorator::BorderWidth()
{
AutoReadLocker _(fLocker);
return fBorderWidth;
}
float
Decorator::TabHeight()
{
AutoReadLocker _(fLocker);
if (fTitleBarRect.IsValid())
return fTitleBarRect.Height();
return fBorderWidth;
}
Decorator::Tab*
Decorator::_AllocateNewTab()
{
Decorator::Tab* tab = new(std::nothrow) Decorator::Tab;
if (tab == NULL)
return NULL;
_SetFocus(tab);
return tab;
}
void
Decorator::_DrawTabs(BRect rect)
{
Decorator::Tab* focusTab = NULL;
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = fTabList.ItemAt(i);
if (tab->isFocused) {
focusTab = tab;
continue;
}
_DrawTab(tab, rect);
}
if (focusTab != NULL)
_DrawTab(focusTab, rect);
}
void
Decorator::_SetFocus(Decorator::Tab* tab)
{
}
bool
Decorator::_SetTabLocation(Decorator::Tab* tab, float location, bool isShifting,
BRegion* )
{
return false;
}
Decorator::Tab*
Decorator::_TabAt(int32 index) const
{
return static_cast<Decorator::Tab*>(fTabList.ItemAt(index));
}
void
Decorator::_FontsChanged(DesktopSettings& settings, BRegion* updateRegion)
{
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
_InvalidateBitmaps();
_UpdateFont(settings);
_DoLayout();
_DoOutlineLayout();
_InvalidateFootprint();
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
}
void
Decorator::_SetLook(Decorator::Tab* tab, DesktopSettings& settings,
window_look look, BRegion* updateRegion)
{
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
tab->look = look;
_UpdateFont(settings);
_DoLayout();
_DoOutlineLayout();
_InvalidateFootprint();
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
}
void
Decorator::_SetFlags(Decorator::Tab* tab, uint32 flags, BRegion* updateRegion)
{
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
tab->flags = flags;
_DoLayout();
_DoOutlineLayout();
_InvalidateFootprint();
if (updateRegion != NULL)
updateRegion->Include(&GetFootprint());
}
void
Decorator::_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);
}
fTitleBarRect.OffsetBy(offset);
fFrame.OffsetBy(offset);
fResizeRect.OffsetBy(offset);
fBorderRect.OffsetBy(offset);
}
void
Decorator::_MoveOutlineBy(BPoint offset)
{
fOutlineBorderRect.OffsetBy(offset);
fLeftOutlineBorder.OffsetBy(offset);
fRightOutlineBorder.OffsetBy(offset);
fTopOutlineBorder.OffsetBy(offset);
fBottomOutlineBorder.OffsetBy(offset);
}
void
Decorator::_ResizeOutlineBy(BPoint offset, BRegion* dirty)
{
fOutlineBorderRect.right += offset.x;
fOutlineBorderRect.bottom += offset.y;
fLeftOutlineBorder.bottom += offset.y;
fTopOutlineBorder.right += offset.x;
fRightOutlineBorder.OffsetBy(offset.x, 0.0);
fRightOutlineBorder.bottom += offset.y;
fBottomOutlineBorder.OffsetBy(0.0, offset.y);
fBottomOutlineBorder.right += offset.x;
}
void
Decorator::_SetOutlinesDelta(BPoint delta, BRegion* dirty)
{
BPoint offset = delta - fOutlinesDelta;
fOutlinesDelta = delta;
dirty->Include(fLeftOutlineBorder);
dirty->Include(fRightOutlineBorder);
dirty->Include(fTopOutlineBorder);
dirty->Include(fBottomOutlineBorder);
fOutlineBorderRect.right += offset.x;
fOutlineBorderRect.bottom += offset.y;
fLeftOutlineBorder.bottom += offset.y;
fTopOutlineBorder.right += offset.x;
fRightOutlineBorder.OffsetBy(offset.x, 0.0);
fRightOutlineBorder.bottom += offset.y;
fBottomOutlineBorder.OffsetBy(0.0, offset.y);
fBottomOutlineBorder.right += offset.x;
dirty->Include(fLeftOutlineBorder);
dirty->Include(fRightOutlineBorder);
dirty->Include(fTopOutlineBorder);
dirty->Include(fBottomOutlineBorder);
}
bool
Decorator::_SetSettings(const BMessage& settings, BRegion* updateRegion)
{
return false;
}
void
Decorator::_GetFootprint(BRegion *region)
{
}
void
Decorator::_GetOutlineFootprint(BRegion* region)
{
if (region == NULL)
return;
region->Include(fTopOutlineBorder);
region->Include(fLeftOutlineBorder);
region->Include(fRightOutlineBorder);
region->Include(fBottomOutlineBorder);
}
void
Decorator::_InvalidateFootprint()
{
fFootprintValid = false;
}
void
Decorator::_InvalidateBitmaps()
{
for (int32 i = 0; i < fTabList.CountItems(); i++) {
Decorator::Tab* tab = static_cast<Decorator::Tab*>(_TabAt(i));
for (int32 index = 0; index < 4; index++) {
tab->closeBitmaps[index] = NULL;
tab->minimizeBitmaps[index] = NULL;
tab->zoomBitmaps[index] = NULL;
}
}
}