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:
parent
5483fa4e78
commit
b960e45194
|
@ -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 ;
|
|
@ -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
|
||||
;
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue