FEATURE: Two new layout modes for the present windows effect

BUG: Keyboard operation now works correctly in present windows on multi-monitor setups

svn path=/trunk/KDE/kdebase/workspace/; revision=852066
This commit is contained in:
Lucas Murray 2008-08-25 09:17:15 +00:00
parent a59111148c
commit 255889ca65
7 changed files with 838 additions and 184 deletions

View file

@ -90,6 +90,7 @@ SET(kwin4_effect_builtins_config_sources
maketransparent_config.cpp
maketransparent_config.ui
presentwindows_config.cpp
presentwindows_config.ui
shadow_config.cpp
showfps_config.cpp
showfps_config.ui

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -55,26 +56,30 @@ PresentWindowsEffect::PresentWindowsEffect()
KActionCollection* actionCollection = new KActionCollection( this );
KAction* a = (KAction*)actionCollection->addAction( "Expose" );
a->setText( i18n("Toggle Expose Effect" ));
a->setText( i18n("Toggle Present Windows (Current desktop)" ));
a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F9));
connect(a, SIGNAL(triggered(bool)), this, SLOT(toggleActive()));
KAction* b = (KAction*)actionCollection->addAction( "ExposeAll" );
b->setText( i18n("Toggle Expose Effect (incl. other desktops)" ));
b->setText( i18n("Toggle Present Windows (All desktops)" ));
b->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10));
connect(b, SIGNAL(triggered(bool)), this, SLOT(toggleActiveAllDesktops()));
borderActivate = (ElectricBorder)conf.readEntry("BorderActivate", (int)ElectricNone);
borderActivateAll = (ElectricBorder)conf.readEntry("BorderActivateAll", (int)ElectricTopLeft);
layoutMode = conf.readEntry( "LayoutMode", int( LayoutNatural ));
drawWindowCaptions = conf.readEntry("DrawWindowCaptions", true);
drawWindowIcons = conf.readEntry("DrawWindowIcons", true);
tabBox = conf.readEntry("TabBox", false);
accuracy = conf.readEntry("Accuracy", 1) * 20;
fillGaps = conf.readEntry("FillGaps", true);
effects->reserveElectricBorder( borderActivate );
effects->reserveElectricBorder( borderActivateAll );
mActiveness.setCurveShape( TimeLine::EaseInOutCurve );
mActiveness.setDuration( 250 );
mActiveness.setDuration( conf.readEntry( "RearrangeDuration", 250 ));
mRearranging.setCurveShape( TimeLine::EaseInOutCurve );
mRearranging.setDuration( 250 );
mRearranging.setDuration( conf.readEntry( "RearrangeDuration", 250 ));
mRearranging.setProgress( 1.0 );
}
@ -205,7 +210,8 @@ void PresentWindowsEffect::paintWindow( EffectWindow* w, int mask, QRegion regio
if(mActiveness.value() > 0.0 && mWindowData.contains(w))
{
const WindowData& windata = mWindowData[w];
paintWindowIcon( w, data );
if (drawWindowIcons)
paintWindowIcon( w, data );
if (drawWindowCaptions)
{
@ -453,25 +459,39 @@ void PresentWindowsEffect::rearrangeWindows()
newScreenGridSizes.append( GridSize() );
// Do not rearrange if filtering only removed windows, so that the remaining ones don't possibly
// jump into the freed slots if they'd be a better match.
// jump into the freed slots if they'd be a better match. This only works with the regular grid
// This can probably still lead to such things when removing the filter again, but that'd need
// more complex remembering of window positions.
newNumOfWindows[i] = windowlists[i].count();
newScreenGridSizes[i].columns = int( ceil( sqrt( (double)windowlists[i].count())));
newScreenGridSizes[i].rows = int( ceil( windowlists[i].count() / double( newScreenGridSizes[i].columns )));
if( newNumOfWindows[i] && ( firstTime || newNumOfWindows[i] > numOfWindows[i] ||
( newNumOfWindows[i] < numOfWindows[i] && ( newScreenGridSizes[i].rows != screenGridSizes[i].rows ||
newScreenGridSizes[i].columns != screenGridSizes[i].columns ))))
bool doRearrange = false;
if( layoutMode != LayoutRegularGrid )
doRearrange = true;
else
{
newNumOfWindows[i] = windowlists[i].count();
newScreenGridSizes[i].columns = int( ceil( sqrt( (double)windowlists[i].count())));
newScreenGridSizes[i].rows = int( ceil( windowlists[i].count() / double( newScreenGridSizes[i].columns )));
if( newNumOfWindows[i] && ( firstTime || newNumOfWindows[i] > numOfWindows[i] ||
( newNumOfWindows[i] < numOfWindows[i] && ( newScreenGridSizes[i].rows != screenGridSizes[i].rows ||
newScreenGridSizes[i].columns != screenGridSizes[i].columns ))))
doRearrange = true;
}
if( doRearrange )
{
if( !firstTime && !rearranging )
{
rearranging = true;
prepareToRearrange();
}
// No point calculating if there is no windows
if( !windowlists[i].size() )
continue;
// Calculate new positions and scales for windows
// calculateWindowTransformationsDumb( windowlist ); // Haven't added screen support to these yet
// calculateWindowTransformationsKompose( windowlist );
calculateWindowTransformationsClosest( windowlists[i], i );
if( layoutMode == LayoutRegularGrid )
calculateWindowTransformationsClosest( windowlists[i], i );
else if( layoutMode == LayoutFlexibleGrid )
calculateWindowTransformationsKompose( windowlists[i], i );
else
calculateWindowTransformationsNatural( windowlists[i], i );
}
}
@ -499,43 +519,6 @@ void PresentWindowsEffect::prepareToRearrange()
mRearranging.setProgress(0.0); // start animation again
}
void PresentWindowsEffect::calculateWindowTransformationsDumb(EffectWindowList windowlist)
{
// Calculate number of rows/cols
int rows = windowlist.count() / 4 + 1;
int cols = windowlist.count() / rows + windowlist.count() % rows;
// Get rect which we can use on current desktop. This excludes e.g. panels
QRect placementRect = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
// Size of one cell
int cellwidth = placementRect.width() / cols;
int cellheight = placementRect.height() / rows;
kDebug(1212) << "Got " << windowlist.count() << " clients, using " << rows << "x" << cols << " grid";
// Calculate position and scale factor for each window
int i = 0;
foreach( EffectWindow* window, windowlist )
{
// Row/Col of this window
int r = i / cols;
int c = i % cols;
mWindowData[window].slot = i;
mWindowData[window].x = c;
mWindowData[window].y = r;
mWindowData[window].highlight = 0.0f;
mWindowData[window].scale = qMin(cellwidth / (double)window->width(), cellheight / (double)window->height());
mWindowData[window].area.setLeft(placementRect.left() + cellwidth * c);
mWindowData[window].area.setTop(placementRect.top() + cellheight * r);
mWindowData[window].area.setWidth((int)(window->width() * mWindowData[window].scale));
mWindowData[window].area.setHeight((int)(window->height() * mWindowData[window].scale));
kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
"), scale: " << mWindowData[window].scale << endl;
i++;
}
}
double PresentWindowsEffect::windowAspectRatio(EffectWindow* c)
{
return c->width() / (double)c->height();
@ -551,10 +534,10 @@ int PresentWindowsEffect::windowHeightForWidth(EffectWindow* c, int w)
return (int)((w / (double)c->width()) * c->height());
}
void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowList windowlist)
void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowList windowlist, int screen)
{
// Get rect which we can use on current desktop. This excludes e.g. panels
QRect availRect = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
QRect availRect = effects->clientArea( ScreenArea, screen, effects->currentDesktop());
qSort( windowlist ); // The location of the windows should not depend on the stacking order
// Following code is taken from Kompose 0.5.4, src/komposelayout.cpp
@ -572,7 +555,7 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
rows = (int)ceil( sqrt((double)windowlist.count()) );
columns = (int)ceil( (double)windowlist.count() / (double)rows );
}
kDebug(1212) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
//kDebug(1212) << "Using " << rows << " rows & " << columns << " columns for " << windowlist.count() << " clients";
// Calculate width & height
int w = (availRect.width() - (columns+1) * spacing ) / columns;
@ -641,6 +624,12 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
widgeth = usableH;
widgetw = (int)widthForHeight;
}
// Don't upscale large-ish windows
if( widgetw > window->width() && ( window->width() > 300 || window->height() > 300 ))
{
widgetw = window->width();
widgeth = window->height();
}
}
// Set the Widget's size
@ -684,9 +673,9 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
mWindowData[window].scale = geom.width() / (double)window->width();
mWindowData[window].highlight = 0.0f;
kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
"), scale: " << mWindowData[window].scale << endl;
//kDebug(1212) << "Window '" << window->caption() << "' gets moved to (" <<
// mWindowData[window].area.left() << "; " << mWindowData[window].area.right() <<
// "), scale: " << mWindowData[window].scale << endl;
}
if ( maxRowHeights[i]-h > 0 )
topOffset += maxRowHeights[i]-h;
@ -695,7 +684,7 @@ void PresentWindowsEffect::calculateWindowTransformationsKompose(EffectWindowLis
void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen)
{
QRect area = effects->clientArea( PlacementArea, screen, effects->currentDesktop());
QRect area = effects->clientArea( ScreenArea, screen, effects->currentDesktop());
int columns = int( ceil( sqrt( (double)windowlist.count())));
int rows = int( ceil( windowlist.count() / double( columns )));
foreach( EffectWindow* w, windowlist )
@ -742,7 +731,6 @@ void PresentWindowsEffect::calculateWindowTransformationsClosest(EffectWindowLis
if( scale > 2.0 || ( scale > 1.0 && ( w->width() > 300 || w->height() > 300 )))
{
scale = ( w->width() > 300 || w->height() > 300 ) ? 1.0 : 2.0;
QPoint center = geom.center();
geom = QRect( geom.center().x() - int( w->width() * scale ) / 2, geom.center().y() - int( w->height() * scale ) / 2,
scale * w->width(), scale * w->height() );
}
@ -781,7 +769,7 @@ void PresentWindowsEffect::assignSlots( EffectWindowList windowlist, const QRect
pos.setY( area.top());
if( pos.y() > area.bottom())
pos.setY( area.bottom());
int distance = INT_MAX;
//int distance = INT_MAX;
int xdiff = pos.x() - ( area.x() + slotwidth * x + slotwidth / 2 ); // slotwidth/2 for center
int ydiff = pos.y() - ( area.y() + slotheight * y + slotheight / 2 );
int dist = int( sqrt( (double)(xdiff * xdiff + ydiff * ydiff) ));
@ -851,6 +839,254 @@ void PresentWindowsEffect::getBestAssignments( EffectWindowList windowlist )
}
}
void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowList windowlist, int screen)
{
// As we are using pseudo-random movement (See "slot") we need to make sure the list
// is always sorted the same way no matter which window is currently active.
qSort( windowlist );
QRect area = effects->clientArea( ScreenArea, screen, effects->currentDesktop());
QRect bounds = area;//mWindowData[0].area;
int direction = 0;
foreach( EffectWindow* w, windowlist )
{
bounds = bounds.united( w->geometry() );
mWindowData[ w ].area = w->geometry();
mWindowData[ w ].scale = 1.0;
// Reuse the unused "slot" as a preferred direction attribute. This is used when the window
// is on the edge of the screen to try to use as much screen real estate as possible.
mWindowData[ w ].slot = direction;
direction++;
if( direction == 4 )
direction = 0;
}
// Iterate over all windows, if two overlap push them apart _slightly_ as we try to
// brute-force the most optimal positions over many iterations.
bool overlap;
do
{
overlap = false;
foreach( EffectWindow* w, windowlist )
{
foreach( EffectWindow* e, windowlist )
{
if( w != e && mWindowData[ w ].area.adjusted( -5, -5, 5, 5 ).intersects(
mWindowData[ e ].area.adjusted( -5, -5, 5, 5 )))
{
overlap = true;
// Determine pushing direction
QPoint diff( mWindowData[ e ].area.center() - mWindowData[ w ].area.center() );
// Prevent dividing by zero and non-movement
if( diff.x() == 0 && diff.y() == 0 )
diff.setX( 1 );
// Try to keep screen aspect ratio
//if( bounds.height() / bounds.width() > area.height() / area.width() )
// diff.setY( diff.y() / 2 );
//else
// diff.setX( diff.x() / 2 );
// Approximate a vector of between 10px and 20px in magnitude in the same direction
diff *= accuracy / double( diff.manhattanLength() );
// Move both windows apart
mWindowData[ w ].area.translate( -diff );
mWindowData[ e ].area.translate( diff );
// Try to keep the bounding rect the same aspect as the screen so that more
// screen real estate is utilised. We do this by splitting the screen into nine
// equal sections, if the window center is in any of the corner sections pull the
// window towards the outer corner. If it is in any of the other edge sections
// alternate between each corner on that edge. We don't want to determine it
// randomly as it will not produce consistant locations when using the filter.
// Only move one window so we don't cause large amounts of unnecessary zooming
// in some situations. We only need to do this if we are not expanding later.
// (We are using an old bounding rect for this, hopefully it doesn't matter)
if( !fillGaps )
{
int xSection = ( mWindowData[ w ].area.x() - bounds.x() ) / ( bounds.width() / 3 );
int ySection = ( mWindowData[ w ].area.y() - bounds.y() ) / ( bounds.height() / 3 );
diff = QPoint( 0, 0 );
if( xSection != 1 || ySection != 1 ) // Remove this if you want the center to pull as well
{
if( xSection == 1 )
xSection = ( mWindowData[ w ].slot / 2 ? 2 : 0 );
if( ySection == 1 )
ySection = ( mWindowData[ w ].slot % 2 ? 2 : 0 );
}
if( xSection == 0 && ySection == 0 )
diff = QPoint( bounds.topLeft() - mWindowData[ w ].area.center() );
if( xSection == 2 && ySection == 0 )
diff = QPoint( bounds.topRight() - mWindowData[ w ].area.center() );
if( xSection == 2 && ySection == 2 )
diff = QPoint( bounds.bottomRight() - mWindowData[ w ].area.center() );
if( xSection == 0 && ySection == 2 )
diff = QPoint( bounds.bottomLeft() - mWindowData[ w ].area.center() );
if( diff.x() != 0 || diff.y() != 0 )
{
diff *= accuracy / double( diff.manhattanLength() );
mWindowData[ w ].area.translate( diff );
}
}
// Update bounding rect
bounds = bounds.united( mWindowData[ w ].area );
bounds = bounds.united( mWindowData[ e ].area );
}
}
}
} while( overlap );
// Work out scaling by getting the most top-left and most bottom-right window coords.
// The 20's and 10's are so that the windows don't touch the edge of the screen.
double scale;
if( bounds == area )
scale = 1.0; // Don't add borders to the screen
else if( area.width() / double( bounds.width() ) < area.height() / double( bounds.height() ))
scale = ( area.width() - 20 ) / double( bounds.width() );
else
scale = ( area.height() - 20 ) / double( bounds.height() );
// Make bounding rect fill the screen size for later steps
bounds = QRect(
bounds.x() - ( area.width() - 20 - bounds.width() * scale ) / 2 - 10 / scale,
bounds.y() - ( area.height() - 20 - bounds.height() * scale ) / 2 - 10 / scale,
area.width() / scale,
area.height() / scale
);
// Move all windows back onto the screen and set their scale
foreach( EffectWindow* w, windowlist )
{
mWindowData[ w ].scale = scale;
mWindowData[ w ].area = QRect(
( mWindowData[ w ].area.x() - bounds.x() ) * scale + area.x(),
( mWindowData[ w ].area.y() - bounds.y() ) * scale + area.y(),
mWindowData[ w ].area.width() * scale,
mWindowData[ w ].area.height() * scale
);
}
// Try to fill the gaps by enlarging windows if they have the space
if( fillGaps )
{
// Don't expand onto or over the border
QRegion borderRegion( area.adjusted( -200, -200, 200, 200 ));
borderRegion ^= area.adjusted( 10 / scale, 10 / scale, -10 / scale, -10 / scale );
bool moved;
do
{
moved = false;
foreach( EffectWindow* w, windowlist )
{
QRect oldRect;
// This may cause some slight distortion if the windows are enlarged a large amount
int widthDiff = accuracy;
int heightDiff = windowHeightForWidth( w, mWindowData[ w ].area.width() + widthDiff ) - mWindowData[ w ].area.height();
int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the
int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side.
// Attempt enlarging to the top-right
oldRect = mWindowData[ w ].area;
mWindowData[ w ].area = QRect(
mWindowData[ w ].area.x() + xDiff,
mWindowData[ w ].area.y() - yDiff - heightDiff,
mWindowData[ w ].area.width() + widthDiff,
mWindowData[ w ].area.height() + heightDiff
);
if( isOverlappingAny( w, windowlist, borderRegion ))
mWindowData[ w ].area = oldRect;
else
{
mWindowData[ w ].scale = mWindowData[ w ].area.width() / double( w->width() );
moved = true;
}
// Attempt enlarging to the bottom-right
oldRect = mWindowData[ w ].area;
mWindowData[ w ].area = QRect(
mWindowData[ w ].area.x() + xDiff,
mWindowData[ w ].area.y() + yDiff,
mWindowData[ w ].area.width() + widthDiff,
mWindowData[ w ].area.height() + heightDiff
);
if( isOverlappingAny( w, windowlist, borderRegion ))
mWindowData[ w ].area = oldRect;
else
{
mWindowData[ w ].scale = mWindowData[ w ].area.width() / double( w->width() );
moved = true;
}
// Attempt enlarging to the bottom-left
oldRect = mWindowData[ w ].area;
mWindowData[ w ].area = QRect(
mWindowData[ w ].area.x() - xDiff - widthDiff,
mWindowData[ w ].area.y() + yDiff,
mWindowData[ w ].area.width() + widthDiff,
mWindowData[ w ].area.height() + heightDiff
);
if( isOverlappingAny( w, windowlist, borderRegion ))
mWindowData[ w ].area = oldRect;
else
{
mWindowData[ w ].scale = mWindowData[ w ].area.width() / double( w->width() );
moved = true;
}
// Attempt enlarging to the top-left
oldRect = mWindowData[ w ].area;
mWindowData[ w ].area = QRect(
mWindowData[ w ].area.x() - xDiff - widthDiff,
mWindowData[ w ].area.y() - yDiff - heightDiff,
mWindowData[ w ].area.width() + widthDiff,
mWindowData[ w ].area.height() + heightDiff
);
if( isOverlappingAny( w, windowlist, borderRegion ))
mWindowData[ w ].area = oldRect;
else
{
mWindowData[ w ].scale = mWindowData[ w ].area.width() / double( w->width() );
moved = true;
}
}
} while( moved );
// The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
// We can't add this to the loop above as it would cause a never-ending loop so we have to make
// do with the less-than-optimal space usage with using this method.
foreach( EffectWindow* w, windowlist )
{
if( mWindowData[ w ].scale > 2.0 ||
( mWindowData[ w ].scale > 1.0 && ( w->width() > 300 || w->height() > 300 )))
{
mWindowData[ w ].scale = ( w->width() > 300 || w->height() > 300 ) ? 1.0 : 2.0;
mWindowData[ w ].area = QRect(
mWindowData[ w ].area.center().x() - int( w->width() * mWindowData[ w ].scale ) / 2,
mWindowData[ w ].area.center().y() - int( w->height() * mWindowData[ w ].scale ) / 2,
w->width() * mWindowData[ w ].scale,
w->height() * mWindowData[ w ].scale
);
}
}
}
}
bool PresentWindowsEffect::isOverlappingAny( EffectWindow* w, const EffectWindowList& windowlist, const QRegion& border )
{
if( border.intersects( mWindowData[ w ].area ))
return true;
// Is there a better way to do this?
foreach( EffectWindow* e, windowlist )
{
if( w == e )
continue;
if( mWindowData[ w ].area.adjusted( -5, -5, 5, 5 ).intersects(
mWindowData[ e ].area.adjusted( -5, -5, 5, 5 )))
return true;
}
return false;
}
bool PresentWindowsEffect::borderActivated( ElectricBorder border )
{
if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
@ -946,6 +1182,140 @@ void PresentWindowsEffect::setHighlightedWindow( EffectWindow* w )
// returns a window which is to relative position <xdiff,ydiff> from the given window
EffectWindow* PresentWindowsEffect::relativeWindow( EffectWindow* w, int xdiff, int ydiff, bool wrap ) const
{
// Using the grid to determine the window only works on grid layouts and only have one screen.
// On multi-screen setups the grid coords are reused on each screen and each screen may also
// have a different grid size.
if( layoutMode != LayoutNatural && effects->numScreens() < 2 )
return relativeWindowGrid( w, xdiff, ydiff, wrap );
// Attempt to find the window from its rect instead
EffectWindow* next;
QRect area = effects->clientArea( FullArea, 0, effects->currentDesktop() );
QRect detectRect;
// Detect across the width of the desktop
if( xdiff != 0 )
{
if( xdiff > 0 )
{ // Detect right
for( int i = 0; i < xdiff; i++ )
{
detectRect = QRect( 0, mWindowData[ w ].area.y(), area.width(), mWindowData[ w ].area.height() );
next = NULL;
foreach( EffectWindow* e, mWindowsToPresent )
{
if( mWindowData[ e ].area.intersects( detectRect ) &&
mWindowData[ e ].area.x() > mWindowData[ w ].area.x() )
{
if( next == NULL )
next = e;
else if( mWindowData[ e ].area.x() < mWindowData[ next ].area.x() )
next = e;
}
}
if( next == NULL )
{
if( wrap ) // We are at the right-most window, now get the left-most one to wrap
return relativeWindow( w, -1000, 0, false );
break; // No more windows to the right
}
w = next;
}
return w;
}
else
{ // Detect left
for( int i = 0; i < -xdiff; i++ )
{
detectRect = QRect( 0, mWindowData[ w ].area.y(), area.width(), mWindowData[ w ].area.height() );
next = NULL;
foreach( EffectWindow* e, mWindowsToPresent )
{
if( mWindowData[ e ].area.intersects( detectRect ) &&
mWindowData[ e ].area.x() + mWindowData[ e ].area.width() < mWindowData[ w ].area.x() + mWindowData[ w ].area.width() )
{
if( next == NULL )
next = e;
else if( mWindowData[ e ].area.x() + mWindowData[ e ].area.width() > mWindowData[ next ].area.x() + mWindowData[ next ].area.width() )
next = e;
}
}
if( next == NULL )
{
if( wrap ) // We are at the left-most window, now get the right-most one to wrap
return relativeWindow( w, 1000, 0, false );
break; // No more windows to the left
}
w = next;
}
return w;
}
}
// Detect across the height of the desktop
if( ydiff != 0 )
{
if( ydiff > 0 )
{ // Detect down
for( int i = 0; i < ydiff; i++ )
{
detectRect = QRect( mWindowData[ w ].area.x(), 0, mWindowData[ w ].area.width(), area.height() );
next = NULL;
foreach( EffectWindow* e, mWindowsToPresent )
{
if( mWindowData[ e ].area.intersects( detectRect ) &&
mWindowData[ e ].area.y() > mWindowData[ w ].area.y() )
{
if( next == NULL )
next = e;
else if( mWindowData[ e ].area.y() < mWindowData[ next ].area.y() )
next = e;
}
}
if( next == NULL )
{
if( wrap ) // We are at the bottom-most window, now get the top-most one to wrap
return relativeWindow( w, 0, -1000, false );
break; // No more windows to the bottom
}
w = next;
}
return w;
}
else
{ // Detect up
for( int i = 0; i < -ydiff; i++ )
{
detectRect = QRect( mWindowData[ w ].area.x(), 0, mWindowData[ w ].area.width(), area.height() );
next = NULL;
foreach( EffectWindow* e, mWindowsToPresent )
{
if( mWindowData[ e ].area.intersects( detectRect ) &&
mWindowData[ e ].area.y() + mWindowData[ e ].area.height() < mWindowData[ w ].area.y() + mWindowData[ w ].area.height() )
{
if( next == NULL )
next = e;
else if( mWindowData[ e ].area.y() + mWindowData[ e ].area.height() > mWindowData[ next ].area.y() + mWindowData[ next ].area.height() )
next = e;
}
}
if( next == NULL )
{
if( wrap ) // We are at the top-most window, now get the bottom-most one to wrap
return relativeWindow( w, 0, 1000, false );
break; // No more windows to the top
}
w = next;
}
return w;
}
}
assert( false ); // Should never get here
}
EffectWindow* PresentWindowsEffect::relativeWindowGrid( EffectWindow* w, int xdiff, int ydiff, bool wrap ) const
{
if( mWindowData.count() == 0 )
return NULL;
@ -1043,11 +1413,26 @@ EffectWindow* PresentWindowsEffect::relativeWindow( EffectWindow* w, int xdiff,
// returns the window that is the most to the topleft, if any
EffectWindow* PresentWindowsEffect::findFirstWindow() const
{
if( layoutMode == LayoutNatural || effects->numScreens() > 1 )
{
EffectWindow* topLeft = NULL;
foreach( EffectWindow* w, mWindowsToPresent )
{
if( topLeft == NULL )
topLeft = w;
else if( w->x() < topLeft->x() || w->y() < topLeft->y() )
topLeft = w;
}
return topLeft;
}
// The following only works on grid layouts on a single screen
int minslot = INT_MAX;
EffectWindow* ret = NULL;
for( DataHash::ConstIterator it = mWindowData.begin();
it != mWindowData.end();
++it )
it != mWindowData.end();
++it )
{
if( (*it).slot < minslot )
{

View file

@ -120,10 +120,10 @@ Comment[zh_TW]=讓所有視窗排排站
Type=Service
X-KDE-ServiceTypes=KWin/Effect
X-KDE-PluginInfo-Author=Rivo Laks
X-KDE-PluginInfo-Email=rivolaks@hot.ee
X-KDE-PluginInfo-Author=Rivo Laks & Lucas Murray
X-KDE-PluginInfo-Email=rivolaks@hot.ee & lmurray@undefinedfire.com
X-KDE-PluginInfo-Name=kwin4_effect_presentwindows
X-KDE-PluginInfo-Version=0.1.0
X-KDE-PluginInfo-Version=0.2.0
X-KDE-PluginInfo-Category=Appearance
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL

View file

@ -58,6 +58,8 @@ class PresentWindowsEffect
virtual void tabBoxClosed();
virtual void tabBoxUpdated();
enum { LayoutNatural, LayoutRegularGrid, LayoutFlexibleGrid }; // Layout modes
public slots:
void setActive(bool active);
void toggleActive() { mShowWindowsFromAllDesktops = false; setActive(!mActivated); }
@ -67,9 +69,9 @@ class PresentWindowsEffect
// Updates window tranformations, i.e. destination pos and scale of the window
void rearrangeWindows();
void prepareToRearrange();
void calculateWindowTransformationsDumb(EffectWindowList windowlist);
void calculateWindowTransformationsKompose(EffectWindowList windowlist);
void calculateWindowTransformationsKompose(EffectWindowList windowlist, int screen);
void calculateWindowTransformationsClosest(EffectWindowList windowlist, int screen);
void calculateWindowTransformationsNatural(EffectWindowList windowlist, int screen);
// Helper methods for layout calculation
double windowAspectRatio(EffectWindow* c);
@ -79,6 +81,8 @@ class PresentWindowsEffect
void assignSlots( EffectWindowList windowlist, const QRect& area, int columns, int rows );
void getBestAssignments( EffectWindowList windowlist );
bool isOverlappingAny( EffectWindow* w, const EffectWindowList& windowlist, const QRegion& border );
void updateFilterTexture();
void discardFilterTexture();
@ -86,6 +90,7 @@ class PresentWindowsEffect
void setHighlightedWindow( EffectWindow* w );
EffectWindow* relativeWindow( EffectWindow* w, int xdiff, int ydiff, bool wrap ) const;
EffectWindow* relativeWindowGrid( EffectWindow* w, int xdiff, int ydiff, bool wrap ) const;
EffectWindow* findFirstWindow() const;
// Called once the effect is activated (and wasn't activated before)
@ -146,9 +151,13 @@ class PresentWindowsEffect
ElectricBorder borderActivate;
ElectricBorder borderActivateAll;
int layoutMode;
bool drawWindowCaptions;
bool drawWindowIcons;
bool mTabBoxMode;
bool tabBox;
int accuracy;
bool fillGaps;
};
} // namespace

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,170 +20,183 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "presentwindows_config.h"
#include <kwineffects.h>
#include <klocale.h>
#include <kdebug.h>
#include <kconfiggroup.h>
#include <KActionCollection>
#include <kaction.h>
#include <KShortcutsEditor>
#include <QWidget>
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QCheckBox>
#include <QVBoxLayout>
#include <QColor>
#ifndef KDE_USE_FINAL
KWIN_EFFECT_CONFIG_FACTORY
#endif
namespace KWin
{
PresentWindowsEffectConfig::PresentWindowsEffectConfig(QWidget* parent, const QVariantList& args) :
KCModule(EffectFactory::componentData(), parent, args)
PresentWindowsEffectConfigForm::PresentWindowsEffectConfigForm(QWidget* parent) : QWidget(parent)
{
setupUi(this);
}
PresentWindowsEffectConfig::PresentWindowsEffectConfig(QWidget* parent, const QVariantList& args)
: KCModule( EffectFactory::componentData(), parent, args )
{
kDebug();
m_ui = new PresentWindowsEffectConfigForm( this );
QGridLayout* layout = new QGridLayout(this);
QVBoxLayout* layout = new QVBoxLayout( this );
mDrawWindowText = new QCheckBox(i18n("Draw window caption on top of window"), this);
connect(mDrawWindowText, SIGNAL(stateChanged(int)), this, SLOT(changed()));
layout->addWidget(mDrawWindowText, 0, 0);
layout->addWidget( m_ui );
mTabBoxCheck = new QCheckBox(i18n("Use for window switching"), this);
connect(mTabBoxCheck, SIGNAL(stateChanged(int)), this, SLOT(changed()));
layout->addWidget(mTabBoxCheck, 1, 0 );
m_actionCollection = new KActionCollection( this, componentData() );
m_actionCollection->setConfigGroup( "PresentWindows" );
m_actionCollection->setConfigGlobal( true );
layout->addWidget(new QLabel(i18n("Activate when cursor is at a specific edge "
"or corner of the screen:"), this), 2, 0, 1, 3);
layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Fixed), 2, 0, 2, 1);
KAction* a = (KAction*) m_actionCollection->addAction( "ExposeAll" );
a->setText( i18n( "Toggle Present Windows (All desktops)" ));
a->setProperty( "isConfigurationAction", true );
a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F10 ));
layout->addWidget(new QLabel(i18n("for windows on current desktop: "), this), 3, 1);
mActivateCombo = new QComboBox;
addItems(mActivateCombo);
connect(mActivateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed()));
layout->addWidget(mActivateCombo, 3, 2);
KAction* b = (KAction*) m_actionCollection->addAction( "Expose" );
b->setText( i18n( "Toggle Present Windows (Current desktop)" ));
b->setProperty( "isConfigurationAction", true );
b->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F9 ));
layout->addWidget(new QLabel(i18n("for windows on all desktops: "), this), 4, 1);
mActivateAllCombo = new QComboBox;
addItems(mActivateAllCombo);
connect(mActivateAllCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed()));
layout->addWidget(mActivateAllCombo, 4, 2);
m_ui->shortcutEditor->addCollection( m_actionCollection );
layout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding), 5, 0, 1, 3);
m_ui->screenEdgeAllCombo->addItem( i18n( "Top" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Top-right" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Right" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Bottom-right" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Bottom" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Bottom-left" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Left" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "Top-left" ));
m_ui->screenEdgeAllCombo->addItem( i18n( "None" ));
// Shortcut config
KActionCollection* actionCollection = new KActionCollection( this, componentData() );
KAction* a = (KAction*)actionCollection->addAction( "Expose" );
a->setText( i18n("Toggle Expose Effect" ));
a->setProperty("isConfigurationAction", true);
a->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F9));
m_ui->screenEdgeCombo->addItem( i18n( "Top" ));
m_ui->screenEdgeCombo->addItem( i18n( "Top-right" ));
m_ui->screenEdgeCombo->addItem( i18n( "Right" ));
m_ui->screenEdgeCombo->addItem( i18n( "Bottom-right" ));
m_ui->screenEdgeCombo->addItem( i18n( "Bottom" ));
m_ui->screenEdgeCombo->addItem( i18n( "Bottom-left" ));
m_ui->screenEdgeCombo->addItem( i18n( "Left" ));
m_ui->screenEdgeCombo->addItem( i18n( "Top-left" ));
m_ui->screenEdgeCombo->addItem( i18n( "None" ));
KAction* b = (KAction*)actionCollection->addAction( "ExposeAll" );
b->setText( i18n("Toggle Expose Effect (incl. other desktops)" ));
b->setProperty("isConfigurationAction", true);
b->setGlobalShortcut(KShortcut(Qt::CTRL + Qt::Key_F10));
mShortcutEditor = new KShortcutsEditor(actionCollection, this,
KShortcutsEditor::GlobalAction, KShortcutsEditor::LetterShortcutsDisallowed);
connect(mShortcutEditor, SIGNAL(keyChange()), this, SLOT(changed()));
layout->addWidget(mShortcutEditor, 6, 0, 1, 3);
layout->addItem(new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding), 7, 0, 1, 3);
connect( m_ui->layoutCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() ));
connect( m_ui->rearrangeDurationSpin, SIGNAL( valueChanged( int )), this, SLOT( changed() ));
connect( m_ui->displayTitleBox, SIGNAL( stateChanged( int )), this, SLOT( changed() ));
connect( m_ui->displayIconBox, SIGNAL( stateChanged( int )), this, SLOT( changed() ));
connect( m_ui->switchingBox, SIGNAL( stateChanged( int )), this, SLOT( changed() ));
connect( m_ui->accuracySlider, SIGNAL( valueChanged( int )), this, SLOT( changed() ));
connect( m_ui->fillGapsBox, SIGNAL( stateChanged( int )), this, SLOT( changed() ));
connect( m_ui->screenEdgeAllCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() ));
connect( m_ui->screenEdgeCombo, SIGNAL( currentIndexChanged( int )), this, SLOT( changed() ));
connect( m_ui->shortcutEditor, SIGNAL( keyChange() ), this, SLOT( changed() ));
load();
}
PresentWindowsEffectConfig::~PresentWindowsEffectConfig()
{
kDebug();
// Undo (only) unsaved changes to global key shortcuts
mShortcutEditor->undoChanges();
}
void PresentWindowsEffectConfig::addItems(QComboBox* combo)
{
combo->addItem(i18n("Top"));
combo->addItem(i18n("Top-right"));
combo->addItem(i18n("Right"));
combo->addItem(i18n("Bottom-right"));
combo->addItem(i18n("Bottom"));
combo->addItem(i18n("Bottom-left"));
combo->addItem(i18n("Left"));
combo->addItem(i18n("Top-left"));
combo->addItem(i18n("None"));
// If save() is called undoChanges() has no effect
m_ui->shortcutEditor->undoChanges();
}
void PresentWindowsEffectConfig::load()
{
kDebug() ;
KCModule::load();
KConfigGroup conf = EffectsHandler::effectConfig("PresentWindows");
int activateBorder = conf.readEntry("BorderActivate", (int)ElectricNone);
if(activateBorder == (int)ElectricNone)
activateBorder--;
mActivateCombo->setCurrentIndex(activateBorder);
KConfigGroup conf = EffectsHandler::effectConfig( "PresentWindows" );
int layoutMode = conf.readEntry( "LayoutMode", int( PresentWindowsEffect::LayoutNatural ));
m_ui->layoutCombo->setCurrentIndex( layoutMode );
int activateAllBorder = conf.readEntry("BorderActivateAll", (int)ElectricTopLeft);
if(activateAllBorder == (int)ElectricNone)
m_ui->rearrangeDurationSpin->setValue( conf.readEntry( "RearrangeDuration", 250 ));
bool displayTitle = conf.readEntry( "DrawWindowCaptions", true );
m_ui->displayTitleBox->setChecked( displayTitle );
bool displayIcon = conf.readEntry( "DrawWindowIcons", true );
m_ui->displayIconBox->setChecked( displayIcon );
bool switching = conf.readEntry( "TabBox", false );
m_ui->switchingBox->setChecked( switching );
int accuracy = conf.readEntry( "Accuracy", 1 );
m_ui->accuracySlider->setSliderPosition( accuracy );
bool fillGaps = conf.readEntry( "FillGaps", true );
m_ui->fillGapsBox->setChecked( fillGaps );
int activateAllBorder = conf.readEntry( "BorderActivateAll", int( ElectricTopLeft ));
if( activateAllBorder == int( ElectricNone ))
activateAllBorder--;
mActivateAllCombo->setCurrentIndex(activateAllBorder);
m_ui->screenEdgeAllCombo->setCurrentIndex( activateAllBorder );
bool drawWindowCaptions = conf.readEntry("DrawWindowCaptions", true);
mDrawWindowText->setChecked(drawWindowCaptions);
bool tabBox = conf.readEntry("TabBox", false);
mTabBoxCheck->setChecked(tabBox);
int activateBorder = conf.readEntry( "BorderActivate", int( ElectricNone ));
if( activateBorder == int( ElectricNone ))
activateBorder--;
m_ui->screenEdgeCombo->setCurrentIndex( activateBorder );
emit changed(false);
}
void PresentWindowsEffectConfig::save()
{
kDebug() ;
KCModule::save();
KConfigGroup conf = EffectsHandler::effectConfig("PresentWindows");
KConfigGroup conf = EffectsHandler::effectConfig( "PresentWindows" );
int activateBorder = mActivateCombo->currentIndex();
if(activateBorder == (int)ELECTRIC_COUNT)
activateBorder = (int)ElectricNone;
conf.writeEntry("BorderActivate", activateBorder);
int layoutMode = m_ui->layoutCombo->currentIndex();
conf.writeEntry( "LayoutMode", layoutMode );
int activateAllBorder = mActivateAllCombo->currentIndex();
if(activateAllBorder == (int)ELECTRIC_COUNT)
activateAllBorder = (int)ElectricNone;
conf.writeEntry("BorderActivateAll", activateAllBorder);
conf.writeEntry( "RearrangeDuration", m_ui->rearrangeDurationSpin->value() );
bool drawWindowCaptions = mDrawWindowText->isChecked();
conf.writeEntry("DrawWindowCaptions", drawWindowCaptions);
conf.writeEntry( "DrawWindowCaptions", m_ui->displayTitleBox->isChecked() );
conf.writeEntry( "DrawWindowIcons", m_ui->displayIconBox->isChecked() );
conf.writeEntry( "TabBox", m_ui->switchingBox->isChecked() );
bool tabBox = mTabBoxCheck->isChecked();
conf.writeEntry("TabBox", tabBox);
int accuracy = m_ui->accuracySlider->value();
conf.writeEntry( "Accuracy", accuracy );
conf.writeEntry( "FillGaps", m_ui->fillGapsBox->isChecked() );
int activateAllBorder = m_ui->screenEdgeAllCombo->currentIndex();
if( activateAllBorder == int( ELECTRIC_COUNT ))
activateAllBorder = int( ElectricNone );
conf.writeEntry( "BorderActivateAll", activateAllBorder );
int activateBorder = m_ui->screenEdgeCombo->currentIndex();
if( activateBorder == int( ELECTRIC_COUNT ))
activateBorder = int( ElectricNone );
conf.writeEntry( "BorderActivate", activateBorder );
m_ui->shortcutEditor->save();
conf.sync();
mShortcutEditor->save(); // undo() will restore to this state from now on
emit changed(false);
EffectsHandler::sendReloadMessage( "presentwindows" );
}
void PresentWindowsEffectConfig::defaults()
{
kDebug() ;
mActivateCombo->setCurrentIndex( (int)ElectricNone - 1 );
mActivateAllCombo->setCurrentIndex( (int)ElectricTopLeft );
mDrawWindowText->setChecked(true);
mTabBoxCheck->setChecked(false);
mShortcutEditor->allDefault();
m_ui->layoutCombo->setCurrentIndex( int( PresentWindowsEffect::LayoutNatural ));
m_ui->rearrangeDurationSpin->setValue( 250 );
m_ui->displayTitleBox->setChecked( true );
m_ui->displayIconBox->setChecked( true );
m_ui->switchingBox->setChecked( false );
m_ui->accuracySlider->setSliderPosition( 1 );
m_ui->fillGapsBox->setChecked( true );
m_ui->screenEdgeAllCombo->setCurrentIndex( int( ElectricTopLeft ));
m_ui->screenEdgeCombo->setCurrentIndex( int( ElectricNone - 1 ));
m_ui->shortcutEditor->allDefault();
emit changed(true);
}
} // namespace
#include "presentwindows_config.moc"

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -23,13 +24,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kcmodule.h>
class QCheckBox;
class QComboBox;
class KShortcutsEditor;
#include "ui_presentwindows_config.h"
#include "presentwindows.h"
namespace KWin
{
class PresentWindowsEffectConfigForm : public QWidget, public Ui::PresentWindowsEffectConfigForm
{
Q_OBJECT
public:
explicit PresentWindowsEffectConfigForm(QWidget* parent);
};
class PresentWindowsEffectConfig : public KCModule
{
Q_OBJECT
@ -37,19 +44,14 @@ class PresentWindowsEffectConfig : public KCModule
explicit PresentWindowsEffectConfig(QWidget* parent = 0, const QVariantList& args = QVariantList());
~PresentWindowsEffectConfig();
public slots:
virtual void save();
virtual void load();
virtual void defaults();
protected:
void addItems(QComboBox* combo);
private:
QCheckBox* mDrawWindowText;
QCheckBox* mTabBoxCheck;
QComboBox* mActivateCombo;
QComboBox* mActivateAllCombo;
KShortcutsEditor* mShortcutEditor;
PresentWindowsEffectConfigForm* m_ui;
KActionCollection* m_actionCollection;
};
} // namespace

View file

@ -0,0 +1,243 @@
<ui version="4.0" >
<class>KWin::PresentWindowsEffectConfigForm</class>
<widget class="QWidget" name="KWin::PresentWindowsEffectConfigForm" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>430</width>
<height>306</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Appearance</string>
</property>
<layout class="QGridLayout" name="gridLayout_3" >
<item row="2" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Rearrange &amp;duration:</string>
</property>
<property name="buddy" >
<cstring>rearrangeDurationSpin</cstring>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QSpinBox" name="rearrangeDurationSpin" >
<property name="suffix" >
<string> msec</string>
</property>
<property name="maximum" >
<number>5000</number>
</property>
<property name="value" >
<number>250</number>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2" >
<widget class="QCheckBox" name="displayTitleBox" >
<property name="text" >
<string>Display window &amp;titles</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2" >
<widget class="QCheckBox" name="displayIconBox" >
<property name="text" >
<string>Display window &amp;icons</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2" >
<widget class="QCheckBox" name="switchingBox" >
<property name="text" >
<string>Use for window &amp;switching</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Layout mode:</string>
</property>
<property name="buddy" >
<cstring>layoutCombo</cstring>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QComboBox" name="layoutCombo" >
<item>
<property name="text" >
<string>Natural</string>
</property>
</item>
<item>
<property name="text" >
<string>Regular grid</string>
</property>
</item>
<item>
<property name="text" >
<string>Flexible grid</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2" >
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Activation</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" >
<item row="5" column="0" colspan="2" >
<widget class="KWin::GlobalShortcutsEditor" native="1" name="shortcutEditor" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Active screen &amp;edge (Current desktop):</string>
</property>
<property name="buddy" >
<cstring>screenEdgeCombo</cstring>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QComboBox" name="screenEdgeCombo" />
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Active screen &amp;edge (All desktops):</string>
</property>
<property name="buddy" >
<cstring>screenEdgeAllCombo</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QComboBox" name="screenEdgeAllCombo" />
</item>
</layout>
</widget>
</item>
<item row="0" column="1" >
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Natural Layout Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_4" >
<item row="5" column="0" >
<widget class="QCheckBox" name="fillGapsBox" >
<property name="text" >
<string>Fill &amp;gaps</string>
</property>
</widget>
</item>
<item row="6" column="0" >
<spacer name="verticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" >
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>Faster</string>
</property>
<property name="buddy" >
<cstring></cstring>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="accuracySlider" >
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>8</number>
</property>
<property name="singleStep" >
<number>1</number>
</property>
<property name="pageStep" >
<number>1</number>
</property>
<property name="value" >
<number>1</number>
</property>
<property name="tracking" >
<bool>true</bool>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance" >
<bool>true</bool>
</property>
<property name="invertedControls" >
<bool>false</bool>
</property>
<property name="tickPosition" >
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Nicer</string>
</property>
<property name="buddy" >
<cstring></cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KWin::GlobalShortcutsEditor</class>
<extends>QWidget</extends>
<header location="global" >kwineffects.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>rearrangeDurationSpin</tabstop>
<tabstop>displayTitleBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>