Add the SATDecorator. This is a new implementation of Stack and Tile with a different tiling logic. For example, this should make overlapping windows in the same tiling group impossible. There are still many issues I know about and this version is far from usable but the basic features are working now. So if you like to test it at this state please only report errors like crashes or memory leaks (think there is one).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38071 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler 2010-08-12 22:37:16 +00:00
parent 5483fa4e78
commit b960e45194
14 changed files with 4065 additions and 1 deletions

View File

@ -2,4 +2,5 @@ SubDir HAIKU_TOP src add-ons decorators ;
SubInclude HAIKU_TOP src add-ons decorators BeDecorator ;
SubInclude HAIKU_TOP src add-ons decorators MacDecorator ;
SubInclude HAIKU_TOP src add-ons decorators WinDecorator ;
SubInclude HAIKU_TOP src add-ons decorators WinDecorator ;
SubInclude HAIKU_TOP src add-ons decorators SATDecorator ;

View File

@ -0,0 +1,25 @@
SubDir HAIKU_TOP src add-ons decorators SATDecorator ;
UseLibraryHeaders agg lp_solve linprog ;
UsePrivateHeaders app graphics interface shared kernel ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ;
UseFreeTypeHeaders ;
Addon SATDecorator :
SATDecorator.cpp
SATGroup.cpp
SATWindow.cpp
StackAndTile.cpp
Stacking.cpp
Tiling.cpp
# libraries
:
libbe.so
<nogrist>app_server
$(TARGET_LIBSTDC++)
liblpsolve55.so liblinprog.so
;

View File

@ -0,0 +1,482 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "SATDecorator.h"
#include <new>
#include <GradientLinear.h>
#include <WindowPrivate.h>
#include "DrawingEngine.h"
#define DEBUG_SATDECORATOR
#ifdef DEBUG_SATDECORATOR
# define STRACE(x) debug_printf x
#else
# define STRACE(x) ;
#endif
static const float kResizeKnobSize = 18.0;
SATDecorAddOn::SATDecorAddOn(image_id id, const char* name)
:
DecorAddOn(id, name)
{
fDesktopListeners.AddItem(&fStackAndTile);
}
status_t
SATDecorAddOn::InitCheck() const
{
if (fDesktopListeners.CountItems() != 1)
return B_ERROR;
return B_OK;
}
float
SATDecorAddOn::Version()
{
return 0.1;
}
Decorator*
SATDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
window_look look, uint32 flags)
{
return new (std::nothrow)SATDecorator(settings, rect, look, flags);
}
SATDecorator::SATDecorator(DesktopSettings& settings, BRect frame,
window_look look, uint32 flags)
:
DefaultDecorator(settings, frame, look, flags),
fTabHighlighted(false),
fBordersHighlighted(false),
fStackedMode(false),
fStackedDrawZoom(false),
fStackedTabLength(0)
{
// all colors are state based
fNonHighlightFrameColors[0] = (rgb_color){ 152, 152, 152, 255 };
fNonHighlightFrameColors[1] = (rgb_color){ 240, 240, 240, 255 };
fNonHighlightFrameColors[2] = (rgb_color){ 152, 152, 152, 255 };
fNonHighlightFrameColors[3] = (rgb_color){ 108, 108, 108, 255 };
fHighlightFrameColors[0] = (rgb_color){ 152, 0, 0, 255 };
fHighlightFrameColors[1] = (rgb_color){ 240, 0, 0, 255 };
fHighlightFrameColors[2] = (rgb_color){ 224, 0, 0, 255 };
fHighlightFrameColors[3] = (rgb_color){ 208, 0, 0, 255 };
fHighlightFrameColors[4] = (rgb_color){ 152, 0, 0, 255 };
fHighlightFrameColors[5] = (rgb_color){ 108, 0, 0, 255 };
// initial colors
fFrameColors[0] = fNonHighlightFrameColors[0];
fFrameColors[1] = fNonHighlightFrameColors[1];
fFrameColors[4] = fNonHighlightFrameColors[2];
fFrameColors[5] = fNonHighlightFrameColors[3];
fHighlightTabColor = (rgb_color){ 255, 0, 0, 255 };
}
float
SATDecorator::GetZoomOffsetToRight()
{
float offset;
float size;
float inset;
_GetButtonSizeAndOffset(fTabRect, &offset, &size, &inset);
return 2 * offset + size;
}
void
SATDecorator::HighlightTab(bool active, BRegion* dirty)
{
if (active)
fTabColor = fHighlightTabColor;
else if (IsFocus())
fTabColor = fFocusTabColor;
else
fTabColor = fNonFocusTabColor;
dirty->Include(fTabRect);
fTabHighlighted = active;
}
void
SATDecorator::HighlightBorders(bool active, BRegion* dirty)
{
if (active) {
fFrameColors[0] = fHighlightFrameColors[0];
fFrameColors[1] = fHighlightFrameColors[1];
fFrameColors[2] = fHighlightFrameColors[2];
fFrameColors[3] = fHighlightFrameColors[3];
fFrameColors[4] = fHighlightFrameColors[4];
fFrameColors[5] = fHighlightFrameColors[5];
} else if (IsFocus()) {
fFrameColors[0] = fNonHighlightFrameColors[0];
fFrameColors[1] = fNonHighlightFrameColors[1];
fFrameColors[2] = fFocusFrameColors[0];
fFrameColors[3] = fFocusFrameColors[1];
fFrameColors[4] = fNonHighlightFrameColors[2];
fFrameColors[5] = fNonHighlightFrameColors[3];
} else {
fFrameColors[0] = fNonHighlightFrameColors[0];
fFrameColors[1] = fNonHighlightFrameColors[1];
fFrameColors[2] = fNonFocusFrameColors[0];
fFrameColors[3] = fNonFocusFrameColors[1];
fFrameColors[4] = fNonHighlightFrameColors[2];
fFrameColors[5] = fNonHighlightFrameColors[3];
}
dirty->Include(fLeftBorder);
dirty->Include(fRightBorder);
dirty->Include(fTopBorder);
dirty->Include(fBottomBorder);
dirty->Include(fResizeRect);
fBordersHighlighted = active;
}
void
SATDecorator::SetStackedMode(bool stacked, BRegion* dirty)
{
fStackedMode = stacked;
dirty->Include(fTabRect);
_DoLayout();
_InvalidateFootprint();
dirty->Include(fTabRect);
}
void
SATDecorator::SetStackedTabLength(float length, bool drawZoom, BRegion* dirty)
{
fStackedTabLength = length;
fStackedDrawZoom = drawZoom;
dirty->Include(fTabRect);
_DoLayout();
_InvalidateFootprint();
dirty->Include(fTabRect);
}
void
SATDecorator::_DoLayout()
{
STRACE(("DefaultDecorator: 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.
bool hasTab = false;
switch (Look()) {
case B_MODAL_WINDOW_LOOK:
fBorderWidth = 5;
break;
case B_TITLED_WINDOW_LOOK:
case B_DOCUMENT_WINDOW_LOOK:
hasTab = true;
fBorderWidth = 5;
break;
case B_FLOATING_WINDOW_LOOK:
case kLeftTitledWindowLook:
hasTab = true;
fBorderWidth = 3;
break;
case B_BORDERED_WINDOW_LOOK:
fBorderWidth = 1;
break;
default:
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
if (fStackedMode && false)
fTextOffset = 5;
else
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);
}
if (fStackedMode)
fTabRect.right = fTabRect.left + fStackedTabLength;
float offset;
float size;
float inset;
_GetButtonSizeAndOffset(fTabRect, &offset, &size, &inset);
// fMinTabSize contains just the room for the buttons
fMinTabSize = inset * 2 + 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 (fStackedMode) {
tabSize = fStackedTabLength;
fMaxTabSize = tabSize;
}
else {
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
// don't include the corners!
fLeftBorder.Set(fFrame.left - fBorderWidth, fFrame.top,
fFrame.left - 1, fFrame.bottom);
fRightBorder.Set(fFrame.right + 1, fFrame.top ,
fFrame.right + fBorderWidth, fFrame.bottom);
fTopBorder.Set(fFrame.left - fBorderWidth, fFrame.top - fBorderWidth,
fFrame.right + fBorderWidth, fFrame.top - 1);
fBottomBorder.Set(fFrame.left - fBorderWidth, fFrame.bottom + 1,
fFrame.right + fBorderWidth, fFrame.bottom + fBorderWidth);
} else {
// no border
fLeftBorder.Set(0.0, 0.0, -1.0, -1.0);
fRightBorder.Set(0.0, 0.0, -1.0, -1.0);
fTopBorder.Set(0.0, 0.0, -1.0, -1.0);
fBottomBorder.Set(0.0, 0.0, -1.0, -1.0);
}
// calculate resize rect
if (fBorderWidth > 1) {
fResizeRect.Set(fBottomBorder.right - kResizeKnobSize,
fBottomBorder.bottom - kResizeKnobSize, fBottomBorder.right,
fBottomBorder.bottom);
} else {
// no border or one pixel border (menus and such)
fResizeRect.Set(0, 0, -1, -1);
}
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);
}
}
void
SATDecorator::_LayoutTabItems(const BRect& tabRect)
{
float offset;
float size;
float inset;
_GetButtonSizeAndOffset(tabRect, &offset, &size, &inset);
// calulate close rect based on the tab rectangle
if (fLook != kLeftTitledWindowLook) {
fCloseRect.Set(tabRect.left + offset, tabRect.top + offset,
tabRect.left + offset + size, tabRect.top + offset + size);
fZoomRect.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;
} else {
fCloseRect.Set(tabRect.left + offset, tabRect.top + offset,
tabRect.left + offset + size, tabRect.top + offset + size);
fZoomRect.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;
}
// 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 + inset;
else
size = (fZoomRect.top - fCloseRect.bottom) - fTextOffset * 2 + inset;
if (fStackedMode && !fStackedDrawZoom) {
fZoomRect.Set(0, 0, 0, 0);
size = (fTabRect.right - fCloseRect.right) - fTextOffset * 2 + inset;
}
fTruncatedTitle = Title();
fDrawState.Font().TruncateString(&fTruncatedTitle, B_TRUNCATE_MIDDLE, size);
fTruncatedTitleLength = fTruncatedTitle.Length();
}
void
SATDecorator::_DrawTab(BRect invalid)
{
STRACE(("_DrawTab(%.1f,%.1f,%.1f,%.1f)\n",
invalid.left, invalid.top, invalid.right, invalid.bottom));
// If a window has a tab, this will draw it and any buttons which are
// in it.
if (!fTabRect.IsValid() || !invalid.Intersects(fTabRect))
return;
// outer frame
fDrawingEngine->StrokeLine(fTabRect.LeftTop(), fTabRect.LeftBottom(),
fFrameColors[0]);
fDrawingEngine->StrokeLine(fTabRect.LeftTop(), fTabRect.RightTop(),
fFrameColors[0]);
if (fLook != kLeftTitledWindowLook) {
fDrawingEngine->StrokeLine(fTabRect.RightTop(), fTabRect.RightBottom(),
fFrameColors[5]);
} else {
fDrawingEngine->StrokeLine(fTabRect.LeftBottom(),
fTabRect.RightBottom(), fFrameColors[5]);
}
// bevel
fDrawingEngine->StrokeLine(BPoint(fTabRect.left + 1, fTabRect.top + 1),
BPoint(fTabRect.left + 1,
fTabRect.bottom - (fLook == kLeftTitledWindowLook ? 1 : 0)),
fTabColorBevel);
fDrawingEngine->StrokeLine(BPoint(fTabRect.left + 1, fTabRect.top + 1),
BPoint(fTabRect.right - (fLook == kLeftTitledWindowLook ? 0 : 1),
fTabRect.top + 1),
fTabColorBevel);
if (fLook != kLeftTitledWindowLook) {
fDrawingEngine->StrokeLine(BPoint(fTabRect.right - 1, fTabRect.top + 2),
BPoint(fTabRect.right - 1, fTabRect.bottom), fTabColorShadow);
} else {
fDrawingEngine->StrokeLine(
BPoint(fTabRect.left + 2, fTabRect.bottom - 1),
BPoint(fTabRect.right, fTabRect.bottom - 1), fTabColorShadow);
}
// fill
BGradientLinear gradient;
gradient.SetStart(fTabRect.LeftTop());
gradient.AddColor(fTabColorLight, 0);
gradient.AddColor(fTabColor, 255);
if (fLook != kLeftTitledWindowLook) {
gradient.SetEnd(fTabRect.LeftBottom());
fDrawingEngine->FillRect(BRect(fTabRect.left + 2, fTabRect.top + 2,
fTabRect.right - 2, fTabRect.bottom), gradient);
} else {
gradient.SetEnd(fTabRect.RightTop());
fDrawingEngine->FillRect(BRect(fTabRect.left + 2, fTabRect.top + 2,
fTabRect.right, fTabRect.bottom - 2), gradient);
}
_DrawTitle(fTabRect);
// Draw the buttons if we're supposed to
if (!(fFlags & B_NOT_CLOSABLE) && invalid.Intersects(fCloseRect))
_DrawClose(fCloseRect);
if (fStackedMode) {
if (fStackedDrawZoom && invalid.Intersects(fZoomRect))
_DrawZoom(fZoomRect);
}
else if (!(fFlags & B_NOT_ZOOMABLE) && invalid.Intersects(fZoomRect))
_DrawZoom(fZoomRect);
}
extern "C" DecorAddOn* (instantiate_decor_addon)(image_id id, const char* name)
{
return new (std::nothrow)SATDecorAddOn(id, name);
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef SAT_DECORATOR_H
#define SAT_DECORATOR_H
#include "DecorManager.h"
#include "DefaultDecorator.h"
#include "StackAndTile.h"
class SATDecorAddOn : public DecorAddOn {
public:
SATDecorAddOn(image_id id, const char* name);
virtual status_t InitCheck() const;
float Version();
protected:
virtual Decorator* _AllocateDecorator(DesktopSettings& settings,
BRect rect, window_look look, uint32 flags);
StackAndTile fStackAndTile;
};
class SATDecorator : public DefaultDecorator {
public:
SATDecorator(DesktopSettings& settings,
BRect frame, window_look look, uint32 flags);
float GetZoomOffsetToRight();
void HighlightTab(bool active, BRegion* dirty);
void HighlightBorders(bool active, BRegion* dirty);
bool IsTabHighlighted() { return fTabHighlighted; }
bool IsBordersHighlighted() { return fBordersHighlighted; }
/*! Indicates that window is stacked */
void SetStackedMode(bool stacked, BRegion* dirty);
bool StackedMode() { return fStackedMode; };
/*! Set the tab length if the decorator is in stacked mode and if the
tab is the last one in the tab bar. */
void SetStackedTabLength(float length, bool drawZoom,
BRegion* dirty);
float StackedTabLength() { return fStackedTabLength; }
protected:
void _DoLayout();
void _DrawTab(BRect r);
void _LayoutTabItems(const BRect& tabRect);
private:
bool fTabHighlighted;
bool fBordersHighlighted;
rgb_color fHighlightTabColor;
rgb_color fNonHighlightFrameColors[4];
rgb_color fHighlightFrameColors[6];
bool fStackedMode;
bool fStackedDrawZoom;
float fStackedTabLength;
bool fStackedTabShifting;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,267 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef SAT_GROUP_H
#define SAT_GROUP_H
#include <Rect.h>
#include "ObjectList.h"
#include "Referenceable.h"
#include "LinearSpec.h"
class SATWindow;
class Tab;
class WindowArea;
typedef BObjectList<SATWindow> SATWindowList;
class Corner {
public:
enum info_t
{
kFree,
kUsed,
kNotDockable
};
enum position_t
{
kLeftTop,
kRightTop,
kLeftBottom,
kRightBottom
};
Corner();
void Trace() const;
info_t status;
WindowArea* windowArea;
};
class Crossing : public BReferenceable {
public:
Crossing(Tab* vertical, Tab* horizontal);
~Crossing();
Corner* GetCorner(Corner::position_t corner) const;
Corner* GetOppositeCorner(Corner::position_t corner) const;
Corner* LeftTopCorner() { return &fLeftTop; }
Corner* RightTopCorner() { return &fRightTop; }
Corner* LeftBottomCorner() { return &fLeftBottom; }
Corner* RightBottomCorner() { return &fRightBottom; }
Tab* VerticalTab() const;
Tab* HorizontalTab() const;
void Trace() const;
private:
Corner* _GetCorner(Corner::position_t corner) const;
Corner fLeftTop;
Corner fRightTop;
Corner fLeftBottom;
Corner fRightBottom;
Tab* fVerticalTab;
Tab* fHorizontalTab;
};
typedef BObjectList<Constraint> ConstraintList;
class SATGroup;
typedef BObjectList<Crossing> CrossingList;
class Tab : public BReferenceable {
public:
enum orientation_t
{
kVertical,
kHorizontal
};
Tab(SATGroup* group, Variable* variable,
orientation_t orientation);
~Tab();
float Position() const;
void SetPosition(float position);
orientation_t Orientation() const;
//! Caller takes ownership of the constraint.
Constraint* Connect(Variable* variable);
BReference<Crossing> AddCrossing(Tab* tab);
bool RemoveCrossing(Crossing* crossing);
int32 FindCrossingIndex(Tab* tab);
int32 FindCrossingIndex(float tabPosition);
Crossing* FindCrossing(Tab* tab);
Crossing* FindCrossing(float tabPosition);
const CrossingList* GetCrossingList() const;
static int CompareFunction(const Tab* tab1, const Tab* tab2);
private:
SATGroup* fGroup;
Variable* fVariable;
orientation_t fOrientation;
CrossingList fCrossingList;
};
class WindowArea : public BReferenceable {
public:
WindowArea(Crossing* leftTop,
Crossing* rightTop, Crossing* leftBottom,
Crossing* rightBottom);
~WindowArea();
const SATWindowList& WindowList() { return fWindowList; }
bool MoveWindowToPosition(SATWindow* window,
int32 index);
Crossing* LeftTopCrossing()
{ return fLeftTopCrossing.Get(); }
Crossing* RightTopCrossing()
{ return fRightTopCrossing.Get(); }
Crossing* LeftBottomCrossing()
{ return fLeftBottomCrossing.Get(); }
Crossing* RightBottomCrossing()
{ return fRightBottomCrossing.Get(); }
Tab* LeftTab();
Tab* RightTab();
Tab* TopTab();
Tab* BottomTab();
BRect Frame();
bool PropagateToGroup(SATGroup* group);
private:
friend class SATGroup;
/*! SATGroup adds new windows to the area. */
bool _AddWindow(SATWindow* window,
SATWindow* after = NULL);
/*! After the last window has been removed the WindowArea delete himself
and clean up all crossings. */
bool _RemoveWindow(SATWindow* window);
inline void _InitCorners();
inline void _CleanupCorners();
inline void _SetToWindowCorner(Corner* corner);
inline void _SetToNeighbourCorner(Corner* neighbour);
inline void _UnsetWindowCorner(Corner* corner);
//! opponent is the other neighbour of the neighbour
inline void _UnsetNeighbourCorner(Corner* neighbour,
Corner* opponent);
// Find crossing by tab position in group and if not exist create it.
BReference<Crossing> _CrossingByPosition(Crossing* crossing,
SATGroup* group);
SATWindowList fWindowList;
BReference<Crossing> fLeftTopCrossing;
BReference<Crossing> fRightTopCrossing;
BReference<Crossing> fLeftBottomCrossing;
BReference<Crossing> fRightBottomCrossing;
};
typedef BObjectList<WindowArea> WindowAreaList;
typedef BObjectList<Tab> TabList;
class SATGroup : public BReferenceable {
public:
friend class Tab;
friend class WindowArea;
friend class SATWindow;
SATGroup();
~SATGroup();
LinearSpec* GetLinearSpec() { return &fLinearSpec; }
void SolveSATAndAdjustWindows(SATWindow* triggerWindow);
/*! Create a new WindowArea from the crossing and add the window. */
bool AddWindow(SATWindow* window, Tab* left, Tab* top,
Tab* right, Tab* bottom);
/*! Add a window to an existing window area. */
bool AddWindow(SATWindow* window, WindowArea* area,
SATWindow* after = NULL);
bool RemoveWindow(SATWindow* window);
int32 CountItems();
SATWindow* WindowAt(int32 index);
/*! \return a sorted tab list. */
const TabList* HorizontalTabs();
const TabList* VerticalTabs();
Tab* FindHorizontalTab(float position);
Tab* FindVerticalTab(float position);
protected:
SATWindowList fSATWindowList;
LinearSpec fLinearSpec;
private:
BReference<Tab> _AddHorizontalTab(float position = 0);
BReference<Tab> _AddVerticalTab(float position = 0);
bool _RemoveHorizontalTab(Tab* tab);
bool _RemoveVerticalTab(Tab* tab);
Tab* _FindTab(const TabList& list, float position);
void _SplitGroupIfNecessary(SATWindow* removedWindow);
void _FillNeighbourList(WindowAreaList& neighbourWindows,
WindowArea* area);
void _LeftNeighbours(WindowAreaList& neighbourWindows,
WindowArea* window);
void _TopNeighbours(WindowAreaList& neighbourWindows,
WindowArea* window);
void _RightNeighbours(WindowAreaList& neighbourWindows,
WindowArea* window);
void _BottomNeighbours(WindowAreaList& neighbourWindows,
WindowArea* window);
bool _FindConnectedGroup(WindowAreaList& seedList,
SATWindow* removedWindow,
WindowAreaList& newGroup);
void _FollowSeed(WindowArea* area, WindowArea* veto,
WindowAreaList& seedList,
WindowAreaList& newGroup);
void _SpawnNewGroup(const WindowAreaList& newGroup);
void _EnsureGroupIsOnScreen(SATGroup* group);
inline void _CallculateXOffset(BPoint& offset, BRect& frame,
BRect& screen);
inline void _CallculateYOffset(BPoint& offset, BRect& frame,
BRect& screen);
TabList fHorizontalTabs;
bool fHorizontalTabsSorted;
TabList fVerticalTabs;
bool fVerticalTabsSorted;
};
typedef BObjectList<SATGroup> SATGroupList;
#endif

View File

@ -0,0 +1,546 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "SATWindow.h"
#include <Debug.h>
#include "Window.h"
SATWindow::SATWindow(StackAndTile* sat, Window* window)
:
fWindow(window),
fStackAndTile(sat),
fOwnGroupCookie(this),
fForeignGroupCookie(this),
fOngoingSnapping(NULL),
fSATStacking(this),
fSATTiling(this),
fShutdown(false)
{
fDecorator = dynamic_cast<SATDecorator*>(fWindow->Decorator());
fDesktop = fWindow->Desktop();
fGroupCookie = &fOwnGroupCookie;
_InitGroup();
fSATSnappingBehaviourList.AddItem(&fSATStacking);
fSATSnappingBehaviourList.AddItem(&fSATTiling);
}
SATWindow::~SATWindow()
{
fShutdown = true;
if (fForeignGroupCookie.GetGroup())
fForeignGroupCookie.GetGroup()->RemoveWindow(this);
if (fOwnGroupCookie.GetGroup())
fOwnGroupCookie.GetGroup()->RemoveWindow(this);
}
SATGroup*
SATWindow::GetGroup()
{
if (!fGroupCookie->GetGroup())
_InitGroup();
// manually set the tabs of the single window
WindowArea* windowArea = fGroupCookie->GetWindowArea();
if (!PositionManagedBySAT() && windowArea) {
BRect frame = CompleteWindowFrame();
windowArea->LeftTopCrossing()->VerticalTab()->SetPosition(frame.left);
windowArea->LeftTopCrossing()->HorizontalTab()->SetPosition(frame.top);
windowArea->RightBottomCrossing()->VerticalTab()->SetPosition(
frame.right);
windowArea->RightBottomCrossing()->HorizontalTab()->SetPosition(
frame.bottom);
}
return fGroupCookie->GetGroup();
}
bool
SATWindow::PropagateToGroup(SATGroup* group, WindowArea* area)
{
return fGroupCookie->PropagateToGroup(group, area);
}
void
SATWindow::MoveWindowToSAT(int32 workspace)
{
fGroupCookie->MoveWindow(workspace);
}
bool
SATWindow::AddedToGroup(SATGroup* group, WindowArea* area)
{
STRACE_SAT("SATWindow::AddedToGroup group: %p window %s\n", group,
fWindow->Title());
if (fGroupCookie == &fForeignGroupCookie)
return false;
if (fOwnGroupCookie.GetGroup())
fGroupCookie = &fForeignGroupCookie;
if (!fGroupCookie->Init(group, area)) {
fGroupCookie = &fOwnGroupCookie;
return false;
}
return true;
}
bool
SATWindow::RemovedFromGroup(SATGroup* group)
{
STRACE_SAT("SATWindow::RemovedFromGroup group: %p window %s\n", group,
fWindow->Title());
if (fShutdown) {
fGroupCookie->Uninit();
return true;
}
ASSERT(fGroupCookie->GetGroup() == group);
fGroupCookie->Uninit();
if (fGroupCookie == &fOwnGroupCookie)
_InitGroup();
else
fGroupCookie = &fOwnGroupCookie;
return true;
}
void
SATWindow::RemovedFromArea(WindowArea* area)
{
for (int i = 0; i < fSATSnappingBehaviourList.CountItems(); i++)
fSATSnappingBehaviourList.ItemAt(i)->RemovedFromArea(area);
}
void
SATWindow::FindSnappingCandidates()
{
fOngoingSnapping = NULL;
GroupIterator groupIterator(fStackAndTile, GetWindow()->Desktop());
for (SATGroup* group = groupIterator.NextGroup(); group;
group = groupIterator.NextGroup()) {
for (int i = 0; i < fSATSnappingBehaviourList.CountItems(); i++) {
if (fSATSnappingBehaviourList.ItemAt(i)->FindSnappingCandidates(
group)) {
fOngoingSnapping = fSATSnappingBehaviourList.ItemAt(i);
return;
}
}
}
}
bool
SATWindow::JoinCandidates()
{
if (!fOngoingSnapping)
return false;
bool status = fOngoingSnapping->JoinCandidates();
fOngoingSnapping = NULL;
return status;
}
void
SATWindow::DoGroupLayout()
{
if (!PositionManagedBySAT())
return;
fGroupCookie->DoGroupLayout(this);
for (int i = 0; i < fSATSnappingBehaviourList.CountItems(); i++)
fSATSnappingBehaviourList.ItemAt(i)->DoGroupLayout();
}
BRect
SATWindow::CompleteWindowFrame()
{
BRect frame = fWindow->Frame();
if (fDesktop
&& fDesktop->CurrentWorkspace() != fWindow->CurrentWorkspace()) {
window_anchor& anchor = fWindow->Anchor(fWindow->CurrentWorkspace());
if (anchor.position != kInvalidWindowPosition)
frame.OffsetTo(anchor.position);
}
// TODO get this values from the decorator
frame.left -= 5.;
frame.right += 6.;
frame.top -= 27;
frame.bottom += 5;
return frame;
}
bool
SATWindow::PositionManagedBySAT()
{
if (fGroupCookie->GetGroup() && fGroupCookie->GetGroup()->CountItems() == 1)
return false;
return true;
}
bool
SATWindow::HighlightTab(bool active)
{
if (!fDecorator)
return false;
if (IsTabHighlighted() == active)
return false;
BRegion dirty;
fDecorator->HighlightTab(active, &dirty);
fWindow->ProcessDirtyRegion(dirty);
return true;
}
bool
SATWindow::HighlightBorders(bool active)
{
if (!fDecorator)
return false;
if (IsBordersHighlighted() == active)
return false;
BRegion dirty;
fDecorator->HighlightBorders(active, &dirty);
fWindow->ProcessDirtyRegion(dirty);
return true;
}
bool
SATWindow::IsTabHighlighted()
{
if (fDecorator)
return fDecorator->IsTabHighlighted();
return false;
}
bool
SATWindow::IsBordersHighlighted()
{
if (fDecorator)
return fDecorator->IsBordersHighlighted();
return false;
}
bool
SATWindow::SetStackedMode(bool stacked)
{
if (!fDecorator)
return false;
BRegion dirty;
fDecorator->SetStackedMode(stacked, &dirty);
fDesktop->RebuildAndRedrawAfterWindowChange(fWindow, dirty);
return true;
}
bool
SATWindow::SetStackedTabLength(float length, bool drawZoom)
{
if (!fDecorator)
return false;
BRegion dirty;
fDecorator->SetStackedTabLength(length, drawZoom, &dirty);
fDesktop->RebuildAndRedrawAfterWindowChange(fWindow, dirty);
return true;
}
bool
SATWindow::SetStackedTabMoving(bool moving)
{
if (!fDecorator)
return false;
if (!moving)
DoGroupLayout();
return true;
}
void
SATWindow::TabLocationMoved(float location, bool shifting)
{
for (int i = 0; i < fSATSnappingBehaviourList.CountItems(); i++)
fSATSnappingBehaviourList.ItemAt(i)->TabLocationMoved(location,
shifting);
}
void
SATWindow::_InitGroup()
{
ASSERT(fGroupCookie == &fOwnGroupCookie);
ASSERT(fOwnGroupCookie.GetGroup() == NULL);
STRACE_SAT("SATWindow::_InitGroup %s\n", fWindow->Title());
SATGroup* group = new (std::nothrow)SATGroup;
if (!group)
return;
BReference<SATGroup> groupRef;
groupRef.SetTo(group, true);
/* AddWindow also will trigger the window to hold a reference on the new
group. */
if (!groupRef->AddWindow(this, NULL, NULL, NULL, NULL))
STRACE_SAT("SATWindow::_InitGroup(): adding window to group failed\n");
}
SATWindow::GroupCookie::GroupCookie(SATWindow* satWindow)
:
fSATWindow(satWindow),
windowArea(NULL),
leftBorder(NULL),
topBorder(NULL),
rightBorder(NULL),
bottomBorder(NULL),
leftBorderConstraint(NULL),
topBorderConstraint(NULL),
rightBorderConstraint(NULL),
bottomBorderConstraint(NULL),
leftConstraint(NULL),
topConstraint(NULL),
minWidthConstraint(NULL),
minHeightConstraint(NULL),
widthConstraint(NULL),
heightConstraint(NULL)
{
}
SATWindow::GroupCookie::~GroupCookie()
{
Uninit();
}
void
SATWindow::GroupCookie::DoGroupLayout(SATWindow* triggerWindow)
{
if (!fSATGroup.Get())
return;
BRect frame = triggerWindow->CompleteWindowFrame();
// adjust window size soft constraints
widthConstraint->SetRightSide(frame.Width());
heightConstraint->SetRightSide(frame.Height());
// adjust window position soft constraints
// (a bit more penalty for them so they take precedence)
leftConstraint->SetRightSide(frame.left);
topConstraint->SetRightSide(frame.top);
widthConstraint->SetPenaltyNeg(110);
widthConstraint->SetPenaltyPos(110);
heightConstraint->SetPenaltyNeg(110);
heightConstraint->SetPenaltyPos(110);
leftConstraint->SetPenaltyNeg(100);
leftConstraint->SetPenaltyPos(100);
topConstraint->SetPenaltyNeg(100);
topConstraint->SetPenaltyPos(100);
// After we set the new parameter solve and apply the new layout.
fSATGroup->SolveSATAndAdjustWindows(triggerWindow);
// set penalties back to normal
widthConstraint->SetPenaltyNeg(10);
widthConstraint->SetPenaltyPos(10);
heightConstraint->SetPenaltyNeg(10);
heightConstraint->SetPenaltyPos(10);
leftConstraint->SetPenaltyNeg(1);
leftConstraint->SetPenaltyPos(1);
topConstraint->SetPenaltyNeg(1);
topConstraint->SetPenaltyPos(1);
}
void
SATWindow::GroupCookie::MoveWindow(int32 workspace)
{
Window* window = fSATWindow->GetWindow();
Desktop* desktop = window->Desktop();
BRect frame = fSATWindow->CompleteWindowFrame();
desktop->MoveWindowBy(window, leftBorder->Value() - frame.left,
topBorder->Value() - frame.top, workspace);
// Update frame to the new position
frame.OffsetBy(leftBorder->Value() - frame.left,
topBorder->Value() - frame.top);
desktop->ResizeWindowBy(window, rightBorder->Value() - frame.right,
bottomBorder->Value() - frame.bottom);
}
bool
SATWindow::GroupCookie::Init(SATGroup* group, WindowArea* area)
{
ASSERT(fSATGroup.Get() == NULL);
Window* window = fSATWindow->GetWindow();
fSATGroup.SetTo(group);
windowArea = area;
LinearSpec* linearSpec = group->GetLinearSpec();
// create variables
leftBorder = linearSpec->AddVariable();
topBorder = linearSpec->AddVariable();
rightBorder = linearSpec->AddVariable();
bottomBorder = linearSpec->AddVariable();
leftBorder->SetRange(-DBL_MAX, DBL_MAX);
topBorder->SetRange(-DBL_MAX, DBL_MAX);
rightBorder->SetRange(-DBL_MAX, DBL_MAX);
bottomBorder->SetRange(-DBL_MAX, DBL_MAX);
if (!leftBorder || !topBorder || !rightBorder || !bottomBorder) {
// clean up
Uninit();
return false;
}
// create constraints
BRect frame = fSATWindow->CompleteWindowFrame();
leftConstraint = linearSpec->AddConstraint(1.0, leftBorder,
OperatorType(EQ), frame.left, 1, 1);
topConstraint = linearSpec->AddConstraint(1.0, topBorder,
OperatorType(EQ), frame.top, 1, 1);
int32 minWidth, maxWidth, minHeight, maxHeight;
window->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
minWidthConstraint = linearSpec->AddConstraint(1.0, leftBorder, -1.0,
rightBorder, OperatorType(LE), -minWidth);
minHeightConstraint = linearSpec->AddConstraint(1.0, topBorder, -1.0,
bottomBorder, OperatorType(LE), -minHeight);
// The width and height constraints have higher penalties than the
// position constraints (left, top), so a window will keep its size
// unless explicitly resized.
widthConstraint = linearSpec->AddConstraint(-1.0, leftBorder, 1.0,
rightBorder, OperatorType(EQ), frame.Width(), 10, 10);
heightConstraint = linearSpec->AddConstraint(-1.0, topBorder, 1.0,
bottomBorder, OperatorType(EQ), frame.Height(), 10, 10);
if (!leftConstraint || !topConstraint || !minWidthConstraint
|| !minHeightConstraint || !widthConstraint || !heightConstraint) {
// clean up
Uninit();
return false;
}
leftBorderConstraint = area->LeftTab()->Connect(leftBorder);
topBorderConstraint = area->TopTab()->Connect(topBorder);
rightBorderConstraint = area->RightTab()->Connect(rightBorder);
bottomBorderConstraint = area->BottomTab()->Connect(bottomBorder);
if (!leftBorderConstraint || !topBorderConstraint
|| !rightBorderConstraint || !bottomBorderConstraint) {
Uninit();
return false;
}
return true;
}
void
SATWindow::GroupCookie::Uninit()
{
delete leftBorder;
delete topBorder;
delete rightBorder;
delete bottomBorder;
leftBorder = NULL;
topBorder = NULL;
rightBorder = NULL;
bottomBorder = NULL;
delete leftBorderConstraint;
delete topBorderConstraint;
delete rightBorderConstraint;
delete bottomBorderConstraint;
leftBorderConstraint = NULL;
topBorderConstraint = NULL;
rightBorderConstraint = NULL;
bottomBorderConstraint = NULL;
delete leftConstraint;
delete topConstraint;
delete minWidthConstraint;
delete minHeightConstraint;
delete widthConstraint;
delete heightConstraint;
leftConstraint = NULL;
topConstraint = NULL;
minWidthConstraint = NULL;
minHeightConstraint = NULL;
widthConstraint = NULL;
heightConstraint = NULL;
fSATGroup.Unset();
windowArea = NULL;
}
bool
SATWindow::GroupCookie::PropagateToGroup(SATGroup* group, WindowArea* area)
{
if (!fSATGroup->fSATWindowList.RemoveItem(fSATWindow))
return false;
Uninit();
if (!Init(group, area))
return false;
if (!group->fSATWindowList.AddItem(fSATWindow)) {
Uninit();
return false;
}
return true;
}

View File

@ -0,0 +1,134 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef SAT_WINDOW_H
#define SAT_WINDOW_H
#include <Region.h>
#include "SATDecorator.h"
#include "SATGroup.h"
#include "Stacking.h"
#include "Tiling.h"
class Desktop;
class StackAndTile;
class Window;
class SATWindow {
public:
SATWindow(StackAndTile* sat, Window* window);
~SATWindow();
Window* GetWindow() { return fWindow; }
SATDecorator* GetDecorator() { return fDecorator; }
//! Can be NULL if memory allocation failed!
SATGroup* GetGroup();
WindowArea* GetWindowArea() {
return fGroupCookie->GetWindowArea(); }
bool PropagateToGroup(SATGroup* group, WindowArea* area);
//! Move the window to the tab's position.
void MoveWindowToSAT(int32 workspace);
// hook function called from SATGroup
bool AddedToGroup(SATGroup* group, WindowArea* area);
bool RemovedFromGroup(SATGroup* group);
void RemovedFromArea(WindowArea* area);
void FindSnappingCandidates();
bool JoinCandidates();
void DoGroupLayout();
//! \return the complete window frame including the Decorator
BRect CompleteWindowFrame();
//! \return true if window is in a group with a least another window
bool PositionManagedBySAT();
bool HighlightTab(bool active);
bool HighlightBorders(bool active);
bool IsTabHighlighted();
bool IsBordersHighlighted();
bool SetStackedMode(bool stacked = true);
bool SetStackedTabLength(float length, bool drawZoom);
bool SetStackedTabMoving(bool moving = true);
void TabLocationMoved(float location, bool shifting);
private:
void _InitGroup();
Window* fWindow;
SATDecorator* fDecorator;
StackAndTile* fStackAndTile;
Desktop* fDesktop;
class GroupCookie
{
public:
GroupCookie(SATWindow* satWindow);
~GroupCookie();
bool Init(SATGroup* group, WindowArea* area);
void Uninit();
void DoGroupLayout(SATWindow* triggerWindow);
void MoveWindow(int32 workspace);
SATGroup* GetGroup() { return fSATGroup.Get(); }
WindowArea* GetWindowArea() { return windowArea; }
bool PropagateToGroup(SATGroup* group,
WindowArea* area);
private:
SATWindow* fSATWindow;
BReference<SATGroup> fSATGroup;
WindowArea* windowArea;
Variable* leftBorder;
Variable* topBorder;
Variable* rightBorder;
Variable* bottomBorder;
Constraint* leftBorderConstraint;
Constraint* topBorderConstraint;
Constraint* rightBorderConstraint;
Constraint* bottomBorderConstraint;
Constraint* leftConstraint;
Constraint* topConstraint;
Constraint* minWidthConstraint;
Constraint* minHeightConstraint;
Constraint* widthConstraint;
Constraint* heightConstraint;
};
//! Current group.
GroupCookie* fGroupCookie;
/*! If the window is added to another group the own group is cached
here. */
GroupCookie fOwnGroupCookie;
GroupCookie fForeignGroupCookie;
SATSnappingBehaviour* fOngoingSnapping;
SATStacking fSATStacking;
SATTiling fSATTiling;
SATSnappingBehaviourList fSATSnappingBehaviourList;
bool fShutdown;
};
#endif

View File

@ -0,0 +1,399 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "StackAndTile.h"
#include <Debug.h>
#include "Desktop.h"
#include "SATWindow.h"
#include "Tiling.h"
#include "Window.h"
using namespace std;
StackAndTile::StackAndTile()
:
fSATKeyPressed(false),
fCurrentSATWindow(NULL),
fTabIsShifting(false)
{
}
StackAndTile::~StackAndTile()
{
}
void
StackAndTile::ListenerRegistered(Desktop* desktop)
{
WindowList& windows = desktop->AllWindows();
for (Window *window = windows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList))
AddWindow(window);
}
void
StackAndTile::ListenerUnregistered()
{
for (SATWindowMap::iterator it = fSATWindowMap.begin();
it != fSATWindowMap.end(); it++) {
SATWindow* satWindow = it->second;
delete satWindow;
}
fSATWindowMap.clear();
}
void
StackAndTile::AddWindow(Window* window)
{
SATWindow* satWindow = new (std::nothrow)SATWindow(this, window);
if (!satWindow)
return;
ASSERT(fSATWindowMap.find(window) == fSATWindowMap.end());
fSATWindowMap[window] = satWindow;
}
void
StackAndTile::RemoveWindow(Window* window)
{
STRACE_SAT("StackAndTile::WindowRemoved %s\n", window->Title());
SATWindowMap::iterator it = fSATWindowMap.find(window);
if (it == fSATWindowMap.end())
return;
SATWindow* satWindow = it->second;
// delete SATWindow
delete satWindow;
fSATWindowMap.erase(it);
}
void
StackAndTile::KeyEvent(uint32 what, int32 key, int32 modifiers)
{
// switch to and from stacking and snapping mode
if (what == B_MODIFIERS_CHANGED) {
bool wasPressed = fSATKeyPressed;
fSATKeyPressed = modifiers & B_OPTION_KEY;
if (wasPressed && !fSATKeyPressed)
_StopSAT();
if (!wasPressed && fSATKeyPressed)
_StartSAT();
}
return;
}
void
StackAndTile::MouseDown(Window* window, BMessage* message, const BPoint& where)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
ASSERT(fCurrentSATWindow == NULL);
fCurrentSATWindow = satWindow;
if (!SATKeyPressed())
return;
_StartSAT();
}
void
StackAndTile::MouseUp(Window* window, BMessage* message, const BPoint& where)
{
if (fTabIsShifting) {
SATWindow* satWindow = GetSATWindow(window);
if (satWindow) {
fTabIsShifting = false;
satWindow->TabLocationMoved(satWindow->GetWindow()->TabLocation(),
fTabIsShifting);
}
}
if (fSATKeyPressed)
_StopSAT();
fCurrentSATWindow = NULL;
}
void
StackAndTile::MoveWindow(Window* window)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
if (SATKeyPressed())
satWindow->FindSnappingCandidates();
else
satWindow->DoGroupLayout();
}
void
StackAndTile::ResizeWindow(Window* window)
{
MoveWindow(window);
}
void
StackAndTile::ActivateWindow(Window* window)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
_ActivateWindow(satWindow);
}
void
StackAndTile::SendWindowBehind(Window* window, Window* behindOf)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
SATGroup* group = satWindow->GetGroup();
if (!group)
return;
Desktop* desktop = satWindow->GetWindow()->Desktop();
if (!desktop)
return;
for (int i = 0; i < group->CountItems(); i++) {
SATWindow* listWindow = group->WindowAt(i);
if (listWindow != satWindow)
desktop->SendWindowBehind(listWindow->GetWindow(), behindOf);
}
}
void
StackAndTile::SetWindowWorkspaces(Window* window, uint32 workspaces)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
SATGroup* group = satWindow->GetGroup();
if (!group)
return;
Desktop* desktop = satWindow->GetWindow()->Desktop();
if (!desktop)
return;
for (int i = 0; i < group->CountItems(); i++) {
SATWindow* listWindow = group->WindowAt(i);
if (listWindow != satWindow)
desktop->SetWindowWorkspaces(listWindow->GetWindow(), workspaces);
}
}
void
StackAndTile::ShowWindow(Window* window)
{
}
void
StackAndTile::HideWindow(Window* window)
{
}
void
StackAndTile::MinimizeWindow(Window* window, bool minimize)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
SATGroup* group = satWindow->GetGroup();
if (!group)
return;
Desktop* desktop = satWindow->GetWindow()->Desktop();
if (!desktop)
return;
for (int i = 0; i < group->CountItems(); i++) {
SATWindow* listWindow = group->WindowAt(i);
if (listWindow != satWindow)
desktop->MinimizeWindow(listWindow->GetWindow(), minimize);
}
}
void
StackAndTile::SetWindowTabLocation(Window* window, float location)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
fTabIsShifting = true;
satWindow->TabLocationMoved(location, fTabIsShifting);
}
bool
StackAndTile::SetDecoratorSettings(Window* window, const BMessage& settings)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return false;
//return satWindow->SetSettings(settings);
return false;
}
void
StackAndTile::GetDecoratorSettings(Window* window, BMessage& settings)
{
SATWindow* satWindow = GetSATWindow(window);
if (!satWindow)
return;
//satWindow->GetSettings(&settings);
}
SATWindow*
StackAndTile::GetSATWindow(Window* window)
{
SATWindowMap::const_iterator it = fSATWindowMap.find(
window);
if (it != fSATWindowMap.end())
return it->second;
// for now don't create window on the fly
return NULL;
// If we don't know this window, memory allocation might has been failed
// previously. Try to add window now
/* SATWindow* satWindow = new (std::nothrow)SATWindow(
window, this);
if (satWindow)
fSATWindowMap[window] = satWindow;
return satWindow;*/
}
void
StackAndTile::_StartSAT()
{
STRACE_SAT("StackAndTile::_StartSAT()\n");
if (!fCurrentSATWindow)
return;
// Remove window from the group.
SATGroup* group = fCurrentSATWindow->GetGroup();
if (!group)
return;
group->RemoveWindow(fCurrentSATWindow);
fCurrentSATWindow->FindSnappingCandidates();
}
void
StackAndTile::_StopSAT()
{
STRACE_SAT("StackAndTile::_StopSAT()\n");
if (!fCurrentSATWindow)
return;
if (fCurrentSATWindow->JoinCandidates())
_ActivateWindow(fCurrentSATWindow);
}
void
StackAndTile::_ActivateWindow(SATWindow* satWindow)
{
SATGroup* group = satWindow->GetGroup();
if (!group)
return;
Desktop* desktop = satWindow->GetWindow()->Desktop();
if (!desktop)
return;
for (int i = 0; i < group->CountItems(); i++) {
SATWindow* listWindow = group->WindowAt(i);
if (listWindow != satWindow)
desktop->ActivateWindow(listWindow->GetWindow());
}
desktop->ActivateWindow(satWindow->GetWindow());
}
GroupIterator::GroupIterator(StackAndTile* sat, Desktop* desktop)
:
fStackAndTile(sat),
fDesktop(desktop),
fCurrentGroup(NULL)
{
RewindToFront();
}
void
GroupIterator::RewindToFront()
{
fCurrentWindow = fDesktop->CurrentWindows().LastWindow();
}
SATGroup*
GroupIterator::NextGroup()
{
SATGroup* group = NULL;
do {
Window* window = fCurrentWindow;
if (window == NULL) {
group = NULL;
break;
}
fCurrentWindow = fCurrentWindow->PreviousWindow(
fCurrentWindow->CurrentWorkspace());
if (window->IsHidden()
|| strcmp(window->Title(), "Deskbar") == 0
|| strcmp(window->Title(), "Desktop") == 0)
continue;
SATWindow* satWindow = fStackAndTile->GetSATWindow(window);
group = satWindow->GetGroup();
} while (group == NULL || fCurrentGroup == group);
fCurrentGroup = group;
return fCurrentGroup;
}
SATSnappingBehaviour::~SATSnappingBehaviour()
{
}

View File

@ -0,0 +1,137 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef STACK_AND_TILE_H
#define STACK_AND_TILE_H
#include <map>
#include <Message.h>
#include <MessageFilter.h>
#include "Desktop.h"
#include "ObjectList.h"
#include "SATGroup.h"
#include "WindowList.h"
#define DEBUG_STACK_AND_TILE
#ifdef DEBUG_STACK_AND_TILE
# define STRACE_SAT(x...) debug_printf("SAT: "x)
#else
# define STRACE_SAT(x...) ;
#endif
class SATWindow;
class Window;
typedef std::map<Window*, SATWindow*> SATWindowMap;
class StackAndTile : public DesktopListener {
public:
StackAndTile();
virtual ~StackAndTile();
// DesktopListener hooks
virtual void ListenerRegistered(Desktop* desktop);
virtual void ListenerUnregistered();
virtual void AddWindow(Window* window);
virtual void RemoveWindow(Window* window);
virtual void KeyEvent(uint32 what, int32 key,
int32 modifiers);
virtual void MouseEvent(BMessage* message) {}
virtual void MouseDown(Window* window, BMessage* message,
const BPoint& where);
virtual void MouseUp(Window* window, BMessage* message,
const BPoint& where);
virtual void MouseMoved(Window* window, BMessage* message,
const BPoint& where) {}
virtual void MoveWindow(Window* window);
virtual void ResizeWindow(Window* window);
virtual void ActivateWindow(Window* window);
virtual void SendWindowBehind(Window* window,
Window* behindOf);
virtual void SetWindowWorkspaces(Window* window,
uint32 workspaces);
virtual void ShowWindow(Window* window);
virtual void HideWindow(Window* window);
virtual void MinimizeWindow(Window* window, bool minimize);
virtual void SetWindowTabLocation(Window* window,
float location);
virtual bool SetDecoratorSettings(Window* window,
const BMessage& settings);
virtual void GetDecoratorSettings(Window* window,
BMessage& settings);
bool SATKeyPressed()
{ return fSATKeyPressed; }
SATWindow* GetSATWindow(Window* window);
protected:
void _StartSAT();
void _StopSAT();
void _ActivateWindow(SATWindow* window);
bool fSATKeyPressed;
SATWindowMap fSATWindowMap;
SATWindowList fGrouplessWindows;
SATWindow* fCurrentSATWindow;
bool fTabIsShifting;
};
class GroupIterator {
public:
GroupIterator(StackAndTile* sat, Desktop* desktop);
void RewindToFront();
SATGroup* NextGroup();
private:
StackAndTile* fStackAndTile;
Desktop* fDesktop;
Window* fCurrentWindow;
SATGroup* fCurrentGroup;
};
class SATSnappingBehaviour {
public:
virtual ~SATSnappingBehaviour();
/*! Find all window candidates which possibly can join the group. Found
candidates are marked here visual. */
virtual bool FindSnappingCandidates(SATGroup* group) = 0;
/*! Join all candidates found in FindSnappingCandidates to the group.
Previously visually mark should be removed here. \return true if
integration has been succeed. */
virtual bool JoinCandidates() = 0;
/*! Update the window tab values, solve the layout and move all windows in
the group accordantly. */
virtual void DoGroupLayout() = 0;
virtual void RemovedFromArea(WindowArea* area) {}
virtual void TabLocationMoved(float location, bool shifting) {}
};
typedef BObjectList<SATSnappingBehaviour> SATSnappingBehaviourList;
#endif

View File

@ -0,0 +1,225 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "Stacking.h"
#include <Debug.h>
#include "SATWindow.h"
#include "Window.h"
#define DEBUG_STACKING
#ifdef DEBUG_STACKING
# define STRACE_STACKING(x...) debug_printf("SAT Stacking: "x)
#else
# define STRACE_STACKING(x...) ;
#endif
SATStacking::SATStacking(SATWindow* window)
:
fSATWindow(window),
fStackingCandidate(NULL)
{
}
SATStacking::~SATStacking()
{
}
bool
SATStacking::FindSnappingCandidates(SATGroup* group)
{
_ClearSearchResult();
Window* window = fSATWindow->GetWindow();
BPoint leftTop = window->Decorator()->TabRect().LeftTop();
for (int i = 0; i < group->CountItems(); i++) {
SATWindow* satWindow = group->WindowAt(i);
// search for stacking candidate
Window* win = satWindow->GetWindow();
if (win != window && win->Decorator()
&& win->Decorator()->TabRect().Contains(leftTop)) {
// remember window as the candidate for stacking
fStackingCandidate = satWindow;
_HighlightWindows(true);
return true;
}
}
return false;
}
bool
SATStacking::JoinCandidates()
{
if (!fStackingCandidate)
return false;
SATGroup* group = fStackingCandidate->GetGroup();
WindowArea* area = fStackingCandidate->GetWindowArea();
if (!group || !area) {
_ClearSearchResult();
return false;
}
bool status = group->AddWindow(fSATWindow, area, fStackingCandidate);
if (status) {
area->WindowList().ItemAt(0)->SetStackedMode(true);
// for the case we are the first added window
fSATWindow->SetStackedMode(true);
}
fStackingCandidate->DoGroupLayout();
_ClearSearchResult();
return status;
}
void
SATStacking::DoGroupLayout()
{
_AdjustWindowTabs();
}
void
SATStacking::RemovedFromArea(WindowArea* area)
{
const SATWindowList& list = area->WindowList();
if (list.CountItems() == 1)
list.ItemAt(0)->SetStackedMode(false);
else if (list.CountItems() > 0)
list.ItemAt(0)->DoGroupLayout();
fSATWindow->SetStackedMode(false);
}
void
SATStacking::TabLocationMoved(float location, bool shifting)
{
if (!shifting) {
_AdjustWindowTabs();
return;
}
SATDecorator* decorator = fSATWindow->GetDecorator();
Desktop* desktop = fSATWindow->GetWindow()->Desktop();
WindowArea* area = fSATWindow->GetWindowArea();
if (!desktop || !area || ! decorator)
return;
const SATWindowList& stackedWindows = area->WindowList();
ASSERT(stackedWindows.CountItems() > 0);
int32 windowIndex = stackedWindows.IndexOf(fSATWindow);
ASSERT(windowIndex >= 0);
float tabLength = stackedWindows.ItemAt(0)->GetDecorator()
->StackedTabLength();
float tabLengthZoom = tabLength + decorator->GetZoomOffsetToRight();
float oldTabPosition = windowIndex * (tabLength + 1);
if (fabs(oldTabPosition - location) < tabLength / 2)
return;
int32 neighbourIndex = windowIndex;
if (oldTabPosition > location)
neighbourIndex--;
else
neighbourIndex++;
SATWindow* neighbour = stackedWindows.ItemAt(neighbourIndex);
if (!neighbour)
return;
float newNeighbourPosition = windowIndex * (tabLength + 1);
area->MoveWindowToPosition(fSATWindow, neighbourIndex);
desktop->SetWindowTabLocation(neighbour->GetWindow(), newNeighbourPosition);
// update zoom buttons
if (windowIndex == stackedWindows.CountItems() - 1) {
fSATWindow->SetStackedTabLength(tabLength, false);
neighbour->SetStackedTabLength(tabLengthZoom, true);
}
else if (neighbourIndex == stackedWindows.CountItems() - 1) {
neighbour->SetStackedTabLength(tabLength, false);
fSATWindow->SetStackedTabLength(tabLengthZoom, true);
}
}
void
SATStacking::_ClearSearchResult()
{
if (!fStackingCandidate)
return;
_HighlightWindows(false);
fStackingCandidate = NULL;
}
void
SATStacking::_HighlightWindows(bool highlight)
{
Desktop* desktop = fSATWindow->GetWindow()->Desktop();
if (!desktop)
return;
fStackingCandidate->HighlightTab(highlight);
fSATWindow->HighlightTab(highlight);
}
bool
SATStacking::_AdjustWindowTabs()
{
SATDecorator* decorator = fSATWindow->GetDecorator();
Desktop* desktop = fSATWindow->GetWindow()->Desktop();
WindowArea* area = fSATWindow->GetWindowArea();
if (!desktop || !area || ! decorator)
return false;
if (!decorator->StackedMode())
return false;
BRect frame = fSATWindow->CompleteWindowFrame();
const float kMaxTabWidth = 120.;
const SATWindowList& stackedWindows = area->WindowList();
float zoomOffset = decorator->GetZoomOffsetToRight();
float tabBarLength = frame.Width() - zoomOffset;
ASSERT(tabBarLength > 0);
float tabLength = tabBarLength / stackedWindows.CountItems();
if (tabLength > kMaxTabWidth)
tabLength = kMaxTabWidth;
float location = 0;
for (int i = 0; i < stackedWindows.CountItems(); i++) {
SATWindow* window = stackedWindows.ItemAt(i);
if (i == stackedWindows.CountItems() - 1)
window->SetStackedTabLength(tabLength - 1 + zoomOffset, true);
// last tab
else
window->SetStackedTabLength(tabLength - 1, false);
desktop->SetWindowTabLocation(window->GetWindow(), location);
location += tabLength;
}
return true;
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef STACKING_H
#define STACKING_H
#include "ObjectList.h"
#include "StackAndTile.h"
class SATWindow;
class SATStacking : public SATSnappingBehaviour {
public:
SATStacking(SATWindow* window);
~SATStacking();
bool FindSnappingCandidates(SATGroup* group);
bool JoinCandidates();
void DoGroupLayout();
void RemovedFromArea(WindowArea* area);
void TabLocationMoved(float location, bool shifting);
private:
void _ClearSearchResult();
void _HighlightWindows(bool highlight = true);
bool _AdjustWindowTabs();
SATWindow* fSATWindow;
SATWindow* fStackingCandidate;
};
#endif

View File

@ -0,0 +1,521 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "Tiling.h"
#include "SATWindow.h"
#include "StackAndTile.h"
#include "Window.h"
using namespace std;
//#define DEBUG_TILEING
#ifdef DEBUG_TILEING
# define STRACE_TILING(x...) debug_printf("SAT Tiling: "x)
#else
# define STRACE_TILING(x...) ;
#endif
SATTiling::SATTiling(SATWindow* window)
:
fSATWindow(window),
fFreeAreaGroup(NULL)
{
_ResetSearchResults();
}
SATTiling::~SATTiling()
{
}
bool
SATTiling::FindSnappingCandidates(SATGroup* group)
{
_ResetSearchResults();
if (fSATWindow->GetGroup() == group)
return false;
if (_FindFreeAreaInGroup(group)) {
fFreeAreaGroup = group;
_HighlightWindows(fFreeAreaGroup, true);
return true;
}
return false;
}
bool
SATTiling::JoinCandidates()
{
if (!fFreeAreaGroup)
return false;
if (!fFreeAreaGroup->AddWindow(fSATWindow, fFreeAreaLeft, fFreeAreaTop,
fFreeAreaRight, fFreeAreaBottom)) {
_ResetSearchResults();
return false;
}
fFreeAreaGroup->WindowAt(0)->DoGroupLayout();
_ResetSearchResults();
return true;
}
void
SATTiling::DoGroupLayout()
{
}
bool
SATTiling::_FindFreeAreaInGroup(SATGroup* group)
{
if (_FindFreeAreaInGroup(group, Corner::kLeftTop))
return true;
if (_FindFreeAreaInGroup(group, Corner::kRightTop))
return true;
if (_FindFreeAreaInGroup(group, Corner::kLeftBottom))
return true;
if (_FindFreeAreaInGroup(group, Corner::kRightBottom))
return true;
return false;
}
bool
SATTiling::_FindFreeAreaInGroup(SATGroup* group, Corner::position_t cor)
{
BRect windowFrame = fSATWindow->CompleteWindowFrame();
const TabList* verticalTabs = group->VerticalTabs();
for (int i = 0; i < verticalTabs->CountItems(); i++) {
Tab* tab = verticalTabs->ItemAt(i);
const CrossingList* crossingList = tab->GetCrossingList();
for (int c = 0; c < crossingList->CountItems(); c++) {
Crossing* crossing = crossingList->ItemAt(c);
if (_InteresstingCrossing(crossing, cor, windowFrame)) {
if (_FindFreeArea(group, crossing, cor, windowFrame)) {
STRACE_TILING("SATTiling: free area found; corner %i\n",
cor);
return true;
}
}
}
}
return false;
}
const float kNoMatch = 999.f;
const float kMaxMatchingDistance = 12.f;
bool
SATTiling::_InteresstingCrossing(Crossing* crossing,
Corner::position_t cor, BRect& windowFrame)
{
const Corner* corner = crossing->GetOppositeCorner(cor);
if (corner->status != Corner::kFree)
return false;
float hTabPosition = crossing->HorizontalTab()->Position();
float vTabPosition = crossing->VerticalTab()->Position();
float hBorder = 0., vBorder = 0.;
float vDistance = -1., hDistance = -1.;
bool windowAtH = false, windowAtV = false;
switch (cor) {
case Corner::kLeftTop:
if (crossing->RightBottomCorner()->status == Corner::kUsed)
return false;
vBorder = windowFrame.left;
hBorder = windowFrame.top;
if (crossing->LeftBottomCorner()->status == Corner::kUsed)
windowAtV = true;
if (crossing->RightTopCorner()->status == Corner::kUsed)
windowAtH = true;
vDistance = vTabPosition - vBorder;
hDistance = hTabPosition - hBorder;
break;
case Corner::kRightTop:
if (crossing->LeftBottomCorner()->status == Corner::kUsed)
return false;
vBorder = windowFrame.right;
hBorder = windowFrame.top;
if (crossing->RightBottomCorner()->status == Corner::kUsed)
windowAtV = true;
if (crossing->LeftTopCorner()->status == Corner::kUsed)
windowAtH = true;
vDistance = vBorder - vTabPosition;
hDistance = hTabPosition - hBorder;
break;
case Corner::kLeftBottom:
if (crossing->RightTopCorner()->status == Corner::kUsed)
return false;
vBorder = windowFrame.left;
hBorder = windowFrame.bottom;
if (crossing->LeftTopCorner()->status == Corner::kUsed)
windowAtV = true;
if (crossing->RightBottomCorner()->status == Corner::kUsed)
windowAtH = true;
vDistance = vTabPosition - vBorder;
hDistance = hBorder - hTabPosition;
break;
case Corner::kRightBottom:
if (crossing->LeftTopCorner()->status == Corner::kUsed)
return false;
vBorder = windowFrame.right;
hBorder = windowFrame.bottom;
if (crossing->RightTopCorner()->status == Corner::kUsed)
windowAtV = true;
if (crossing->LeftBottomCorner()->status == Corner::kUsed)
windowAtH = true;
vDistance = vBorder - vTabPosition;
hDistance = hBorder - hTabPosition;
break;
};
bool hValid = false;
if (windowAtH && fabs(hDistance) < kMaxMatchingDistance
&& vDistance < kMaxMatchingDistance)
hValid = true;
bool vValid = false;
if (windowAtV && fabs(vDistance) < kMaxMatchingDistance
&& hDistance < kMaxMatchingDistance)
vValid = true;
if (!hValid && !vValid)
return false;
return true;
};
const float kBigAreaError = 1E+17;
bool
SATTiling::_FindFreeArea(SATGroup* group, const Crossing* crossing,
Corner::position_t corner, BRect& windowFrame)
{
fFreeAreaLeft = fFreeAreaRight = fFreeAreaTop = fFreeAreaBottom = NULL;
const TabList* hTabs = group->HorizontalTabs();
const TabList* vTabs = group->VerticalTabs();
int32 hIndex = hTabs->IndexOf(crossing->HorizontalTab());
if (hIndex < 0)
return false;
int32 vIndex = vTabs->IndexOf(crossing->VerticalTab());
if (vIndex < 0)
return false;
Tab** endHTab = NULL, **endVTab = NULL;
int8 vSearchDirection = 1, hSearchDirection = 1;
switch (corner) {
case Corner::kLeftTop:
fFreeAreaLeft = crossing->VerticalTab();
fFreeAreaTop = crossing->HorizontalTab();
endHTab = &fFreeAreaBottom;
endVTab = &fFreeAreaRight;
vSearchDirection = 1;
hSearchDirection = 1;
break;
case Corner::kRightTop:
fFreeAreaRight = crossing->VerticalTab();
fFreeAreaTop = crossing->HorizontalTab();
endHTab = &fFreeAreaBottom;
endVTab = &fFreeAreaLeft;
vSearchDirection = -1;
hSearchDirection = 1;
break;
case Corner::kLeftBottom:
fFreeAreaLeft = crossing->VerticalTab();
fFreeAreaBottom = crossing->HorizontalTab();
endHTab = &fFreeAreaTop;
endVTab = &fFreeAreaRight;
vSearchDirection = 1;
hSearchDirection = -1;
break;
case Corner::kRightBottom:
fFreeAreaRight = crossing->VerticalTab();
fFreeAreaBottom = crossing->HorizontalTab();
endHTab = &fFreeAreaTop;
endVTab = &fFreeAreaLeft;
vSearchDirection = -1;
hSearchDirection = -1;
break;
};
Tab* bestLeftTab = NULL, *bestRightTab = NULL, *bestTopTab = NULL,
*bestBottomTab = NULL;
float bestError = kBigAreaError;
float error;
bool stop = false;
bool found = false;
int32 v = vIndex;
do {
v += vSearchDirection;
*endVTab = vTabs->ItemAt(v);
int32 h = hIndex;
do {
h += hSearchDirection;
*endHTab = hTabs->ItemAt(h);
if (!_CheckArea(group, corner, windowFrame, error)) {
if (h == hIndex + hSearchDirection)
stop = true;
break;
}
found = true;
if (error < bestError) {
bestError = error;
bestLeftTab = fFreeAreaLeft;
bestRightTab = fFreeAreaRight;
bestTopTab = fFreeAreaTop;
bestBottomTab = fFreeAreaBottom;
}
} while (*endHTab);
if (stop)
break;
} while (*endVTab);
if (!found)
return false;
fFreeAreaLeft = bestLeftTab;
fFreeAreaRight = bestRightTab;
fFreeAreaTop = bestTopTab;
fFreeAreaBottom = bestBottomTab;
return true;
}
bool
SATTiling::_HasOverlapp(SATGroup* group)
{
BRect areaRect = _FreeAreaSize();
areaRect.InsetBy(1., 1.);
const TabList* hTabs = group->HorizontalTabs();
for (int32 h = 0; h < hTabs->CountItems(); h++) {
Tab* hTab = hTabs->ItemAt(h);
if (hTab->Position() >= areaRect.bottom)
return false;
const CrossingList* crossings = hTab->GetCrossingList();
for (int32 i = 0; i < crossings->CountItems(); i++) {
Crossing* leftTopCrossing = crossings->ItemAt(i);
Tab* vTab = leftTopCrossing->VerticalTab();
if (vTab->Position() > areaRect.right)
continue;
Corner* corner = leftTopCrossing->RightBottomCorner();
if (corner->status != Corner::kUsed)
continue;
BRect rect = corner->windowArea->Frame();
if (areaRect.Intersects(rect))
return true;
}
}
return false;
}
bool
SATTiling::_CheckArea(SATGroup* group, Corner::position_t corner,
BRect& windowFrame, float& error)
{
error = kBigAreaError;
if (!_CheckMinFreeAreaSize())
return false;
// check if corner is in the free area
if (!_IsCornerInFreeArea(corner, windowFrame))
return false;
error = _FreeAreaError(windowFrame);
if (!_HasOverlapp(group))
return true;
return false;
}
bool
SATTiling::_CheckMinFreeAreaSize()
{
// check if the area has a minimum size
if (fFreeAreaLeft && fFreeAreaRight
&& fFreeAreaRight->Position() - fFreeAreaLeft->Position()
< 2 * kMaxMatchingDistance)
return false;
if (fFreeAreaBottom && fFreeAreaTop
&& fFreeAreaBottom->Position() - fFreeAreaTop->Position()
< 2 * kMaxMatchingDistance)
return false;
return true;
}
float
SATTiling::_FreeAreaError(BRect& windowFrame)
{
const float kEndTabError = 9999999;
float error = 0.;
if (fFreeAreaLeft && fFreeAreaRight)
error += pow(fFreeAreaRight->Position() - fFreeAreaLeft->Position()
- windowFrame.Width(), 2);
else
error += kEndTabError;
if (fFreeAreaBottom && fFreeAreaTop)
error += pow(fFreeAreaBottom->Position() - fFreeAreaTop->Position()
- windowFrame.Height(), 2);
else
error += kEndTabError;
return error;
}
bool
SATTiling::_IsCornerInFreeArea(Corner::position_t corner, BRect& frame)
{
BRect freeArea = _FreeAreaSize();
switch (corner) {
case Corner::kLeftTop:
if (freeArea.bottom - kMaxMatchingDistance > frame.top
&& freeArea.right - kMaxMatchingDistance > frame.left)
return true;
break;
case Corner::kRightTop:
if (freeArea.bottom - kMaxMatchingDistance > frame.top
&& freeArea.left + kMaxMatchingDistance < frame.right)
return true;
break;
case Corner::kLeftBottom:
if (freeArea.top + kMaxMatchingDistance < frame.bottom
&& freeArea.right - kMaxMatchingDistance > frame.left)
return true;
break;
case Corner::kRightBottom:
if (freeArea.top + kMaxMatchingDistance < frame.bottom
&& freeArea.left + kMaxMatchingDistance < frame.right)
return true;
break;
}
return false;
}
BRect
SATTiling::_FreeAreaSize()
{
// not to big to be be able to add/sub small float values
const float kBigValue = 9999999.;
float left = fFreeAreaLeft ? fFreeAreaLeft->Position() : -kBigValue;
float right = fFreeAreaRight ? fFreeAreaRight->Position() : kBigValue;
float top = fFreeAreaTop ? fFreeAreaTop->Position() : -kBigValue;
float bottom = fFreeAreaBottom ? fFreeAreaBottom->Position() : kBigValue;
return BRect(left, top, right, bottom);
}
void
SATTiling::_HighlightWindows(SATGroup* group, bool highlight)
{
BRect windowFrame = fSATWindow->CompleteWindowFrame();
const TabList* hTabs = group->HorizontalTabs();
const TabList* vTabs = group->VerticalTabs();
// height light windows at all four sites
_SearchHighlightWindow(fFreeAreaLeft, fFreeAreaTop, fFreeAreaBottom, hTabs,
Corner::kLeftBottom, highlight);
_SearchHighlightWindow(fFreeAreaTop, fFreeAreaLeft, fFreeAreaRight, vTabs,
Corner::kRightTop, highlight);
_SearchHighlightWindow(fFreeAreaRight, fFreeAreaTop, fFreeAreaBottom, hTabs,
Corner::kRightBottom, highlight);
_SearchHighlightWindow(fFreeAreaBottom, fFreeAreaLeft, fFreeAreaRight,
vTabs, Corner::kRightBottom, highlight);
}
void
SATTiling::_SearchHighlightWindow(Tab* tab, Tab* firstOrthTab,
Tab* secondOrthTab, const TabList* orthTabs, Corner::position_t areaCorner,
bool highlight)
{
if (!tab)
return;
int8 searchDir = 1;
Tab* startOrthTab = NULL;
Tab* endOrthTab = NULL;
if (firstOrthTab) {
searchDir = 1;
startOrthTab = firstOrthTab;
endOrthTab = secondOrthTab;
}
else if (secondOrthTab) {
searchDir = -1;
startOrthTab = secondOrthTab;
endOrthTab = firstOrthTab;
}
else
return;
int32 index = orthTabs->IndexOf(startOrthTab);
if (index < 0)
return;
for (; index < orthTabs->CountItems() && index >= 0; index += searchDir) {
Tab* orthTab = orthTabs->ItemAt(index);
Crossing* crossing = tab->FindCrossing(orthTab);
if (!crossing)
continue;
if (orthTab == endOrthTab)
break;
Corner* corner = crossing->GetCorner(areaCorner);
if (corner->windowArea)
_HighlightWindows(corner->windowArea, highlight);
}
}
void
SATTiling::_HighlightWindows(WindowArea* area, bool highlight)
{
const SATWindowList& list = area->WindowList();
for (int i = 0; i < list.CountItems(); i++)
list.ItemAt(i)->HighlightBorders(highlight);
fSATWindow->HighlightBorders(highlight);
}
void
SATTiling::_ResetSearchResults()
{
if (!fFreeAreaGroup)
return;
_HighlightWindows(fFreeAreaGroup, false);
fFreeAreaGroup = NULL;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2010, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#ifndef TILING_H
#define TILING_H
#include "ObjectList.h"
#include "StackAndTile.h"
class SATWindow;
class SATTiling : public SATSnappingBehaviour {
public:
SATTiling(SATWindow* window);
~SATTiling();
bool FindSnappingCandidates(SATGroup* group);
bool JoinCandidates();
void DoGroupLayout();
private:
bool _FindFreeAreaInGroup(SATGroup* group);
bool _FindFreeAreaInGroup(SATGroup* group,
Corner::position_t corner);
bool _InteresstingCrossing(Crossing* crossing,
Corner::position_t corner, BRect& windowFrame);
bool _FindFreeArea(SATGroup* group,
const Crossing* crossing,
Corner::position_t areaCorner,
BRect& windowFrame);
bool _HasOverlapp(SATGroup* group);
bool _CheckArea(SATGroup* group,
Corner::position_t corner, BRect& windowFrame,
float& error);
bool _CheckMinFreeAreaSize();
float _FreeAreaError(BRect& windowFrame);
bool _IsCornerInFreeArea(Corner::position_t corner,
BRect& windowFrame);
BRect _FreeAreaSize();
void _HighlightWindows(SATGroup* group,
bool highlight = true);
void _SearchHighlightWindow(Tab* tab, Tab* firstOrthTab,
Tab* secondOrthTab, const TabList* orthTabs,
Corner::position_t areaCorner, bool highlight);
void _HighlightWindows(WindowArea* area,
bool highlight);
void _ResetSearchResults();
SATWindow* fSATWindow;
SATGroup* fFreeAreaGroup;
Tab* fFreeAreaLeft;
Tab* fFreeAreaRight;
Tab* fFreeAreaTop;
Tab* fFreeAreaBottom;
};
#endif