kwin/effects/boxswitch/boxswitch.cpp
Martin Gräßlin 17ea2bf146 setTabBoxWindow causes the ItemInfo to be regenerated, so we have to break the loop after finding a window.
Makes more sense anyway as we do not have to go through the hash to find the item we already found.
BUG: 222120

svn path=/trunk/KDE/kdebase/workspace/; revision=1080616
2010-01-26 15:26:48 +00:00

1125 lines
40 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "boxswitch.h"
#include <kwinconfig.h>
#include <QMouseEvent>
#include <QSize>
#include <kapplication.h>
#include <kcolorscheme.h>
#include <kconfiggroup.h>
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
#include <GL/gl.h>
#endif
namespace KWin
{
KWIN_EFFECT( boxswitch, BoxSwitchEffect )
BoxSwitchEffect::BoxSwitchEffect()
: mActivated( 0 )
, mMode( 0 )
, thumbnailFrame( EffectFrame::Styled )
, selected_window( 0 )
, painting_desktop( 0 )
, animation( false )
, highlight_is_set( false )
, primaryTabBox( true )
, secondaryTabBox( false )
, mProxy( this )
, mProxyActivated( 0 )
, mProxyAnimateSwitch( 0 )
, mProxyShowText( 0 )
, mPositioningFactor( 0.5f )
{
text_font.setBold( true );
text_font.setPointSize( 12 );
thumbnailFrame.setFont( text_font );
thumbnailFrame.setAlignment( Qt::AlignBottom | Qt::AlignHCenter );
highlight_margin = 10;
reconfigure( ReconfigureAll );
}
BoxSwitchEffect::~BoxSwitchEffect()
{
}
void BoxSwitchEffect::reconfigure( ReconfigureFlags )
{
color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color();
color_frame.setAlphaF( 0.9 );
color_highlight = KColorScheme( QPalette::Active, KColorScheme::Selection ).background().color();
color_highlight.setAlphaF( 0.9 );
activeTimeLine.setDuration( animationTime( 250 ));
activeTimeLine.setCurveShape( TimeLine::EaseInOutCurve );
timeLine.setDuration( animationTime( 150 ));
timeLine.setCurveShape( TimeLine::EaseInOutCurve );
KConfigGroup conf = effects->effectConfig( "BoxSwitch" );
bg_opacity = conf.readEntry( "BackgroundOpacity", 25 ) / 100.0;
elevate_window = conf.readEntry( "ElevateSelected", true );
mAnimateSwitch = conf.readEntry( "AnimateSwitch", false );
primaryTabBox = conf.readEntry( "TabBox", true );
secondaryTabBox = conf.readEntry( "TabBoxAlternative", false );
}
void BoxSwitchEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{
if( activeTimeLine.value() != 0.0 && !mProxyActivated )
{
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
if( windows.contains( w ))
{
if( w == selected_window )
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_CLIENT_GROUP );
else
data.setTranslucent();
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE | EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
}
else
{
if( painting_desktop )
{
if( w->isOnDesktop( painting_desktop ))
w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
else
w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
}
}
}
effects->prePaintWindow( w, data, time );
}
void BoxSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
if( mActivated )
activeTimeLine.addTime( time );
else
{
activeTimeLine.removeTime( time );
if( activeTimeLine.value() == 0.0 )
{ // No longer need the window data
qDeleteAll( windows );
windows.clear();
}
}
if( mActivated && animation )
{
timeLine.addTime( time );
calculateItemSizes();
}
effects->prePaintScreen( data, time );
}
void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
effects->paintScreen( mask, region, data );
if( mActivated && !mProxyActivated )
{
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
paintWindowsBox(region);
}
else
{
if( !painting_desktop )
{
thumbnailFrame.render( region );
QHash< int, ItemInfo* >::const_iterator i;
for( i = desktops.constBegin(); i != desktops.constEnd(); ++i )
{
painting_desktop = i.key();
if( painting_desktop == selected_desktop )
paintHighlight( desktops[ painting_desktop ]->area ); //effects->desktopName( painting_desktop )
paintDesktopThumbnail( painting_desktop );
}
painting_desktop = 0;
}
}
}
}
void BoxSwitchEffect::paintWindowsBox(const QRegion& region)
{
thumbnailFrame.render( region );
if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) )
{
// HACK: PaintClipper is used because window split is somehow wrong if the height is greater than width
PaintClipper::push( frame_area );
paintHighlight( highlight_area );
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
for( i = windows.constBegin(); i != windows.constEnd(); ++i )
{
paintWindowThumbnail( i.key() );
paintWindowIcon( i.key() );
}
PaintClipper::pop( frame_area );
}
else
{
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
for( i = windows.constBegin(); i != windows.constEnd(); ++i )
{
if( i.key() == selected_window )
paintHighlight( i.value()->area );
paintWindowThumbnail( i.key() );
paintWindowIcon( i.key() );
}
}
}
void BoxSwitchEffect::postPaintScreen()
{
if( mActivated && activeTimeLine.value() != 1.0 )
effects->addRepaintFull();
if( !mActivated && activeTimeLine.value() != 0.0 )
effects->addRepaintFull();
if( mActivated && animation )
{
if( timeLine.value() == 1.0 )
{
timeLine.setProgress( 0.0 );
animation = false;
if( !scheduled_directions.isEmpty() )
{
direction = scheduled_directions.dequeue();
animation = true;
}
}
QRect repaint = QRect( frame_area.x() - item_max_size.width()*0.5,
frame_area.y(),
frame_area.width() + item_max_size.width(),
frame_area.height() );
effects->addRepaint( repaint );
}
effects->postPaintScreen();
}
void BoxSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if((( mActivated && (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode) )
|| ( !mActivated && activeTimeLine.value() != 0.0 )) && !mProxyActivated)
{
if( windows.contains( w ) && w != selected_window )
{
if( w->isMinimized() || !w->isOnCurrentDesktop() )
// TODO: When deactivating minimized windows are not painted at all
data.opacity *= activeTimeLine.value() * bg_opacity;
else
data.opacity *= 1.0 - activeTimeLine.value() * ( 1.0 - bg_opacity );
}
}
effects->paintWindow( w, mask, region, data );
}
void BoxSwitchEffect::windowInputMouseEvent( Window w, QEvent* e )
{
assert( w == mInput );
Q_UNUSED( w );
if( e->type() != QEvent::MouseButtonPress )
return;
QPoint pos = static_cast< QMouseEvent* >( e )->pos();
pos += frame_area.topLeft();
// determine which item was clicked
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
for( i = windows.constBegin(); i != windows.constEnd(); ++i )
{
if( i.value()->clickable.contains( pos ))
{
effects->setTabBoxWindow( i.key() );
break;
}
}
// special handling for second half of window in case of animation and even number of windows
if( mAnimateSwitch && ( windows.size() % 2 == 0 ) )
{
QRect additionalRect = QRect( frame_area.x(), frame_area.y(),
item_max_size.width()*0.5, item_max_size.height());
if( additionalRect.contains( pos ))
{
effects->setTabBoxWindow( right_window );
}
}
}
else
{
QHash< int, ItemInfo* >::const_iterator i;
for( i = desktops.constBegin(); i != desktops.constEnd(); ++i )
{
if( i.value()->clickable.contains( pos ))
effects->setTabBoxDesktop( i.key() );
}
}
}
void BoxSwitchEffect::windowDamaged( EffectWindow* w, const QRect& damage )
{
Q_UNUSED( damage );
if( mActivated )
{
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
if( windows.contains( w ))
{
effects->addRepaint( frame_area );
}
}
else
{
if( w->isOnAllDesktops())
{
foreach( ItemInfo* info, desktops )
effects->addRepaint( info->area );
}
else
{
effects->addRepaint( desktops[ w->desktop() ]->area );
}
}
}
}
void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
{
if( mActivated )
{
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
if( windows.contains( w ) && w->size() != old.size())
{
effects->addRepaint( windows[ w ]->area );
}
}
else
{
if( w->isOnAllDesktops())
{
foreach( ItemInfo* info, desktops )
effects->addRepaint( info->area );
}
else
{
effects->addRepaint( desktops[ w->desktop() ]->area );
}
}
}
}
void BoxSwitchEffect::tabBoxAdded( int mode )
{
if( !mActivated )
{
if( ( mode == TabBoxWindowsMode && primaryTabBox ) ||
( mode == TabBoxWindowsAlternativeMode && secondaryTabBox) )
{
if( effects->currentTabBoxWindowList().count() > 0 )
{
mMode = mode;
effects->refTabBox();
highlight_is_set = false;
animation = false;
scheduled_directions.clear();
right_window = 0;
setActive();
}
}
else if( mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode )
{ // DesktopMode
if( effects->currentTabBoxDesktopList().count() > 0 )
{
mMode = mode;
painting_desktop = 0;
effects->refTabBox();
setActive();
}
}
}
}
void BoxSwitchEffect::tabBoxClosed()
{
if( mActivated )
setInactive();
}
void BoxSwitchEffect::tabBoxUpdated()
{
if( mActivated )
{
if( (mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode)
&& selected_window != effects->currentTabBoxWindow() )
{
if( selected_window != NULL )
{
if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) )
{
int old_index = effects->currentTabBoxWindowList().indexOf( selected_window );
int new_index = effects->currentTabBoxWindowList().indexOf( effects->currentTabBoxWindow() );
Direction new_direction;
int distance = new_index - old_index;
if( distance > 0 )
new_direction = Left;
if( distance < 0 )
new_direction = Right;
if( distance != 0 )
{
distance = abs( distance );
int tempDistance = effects->currentTabBoxWindowList().count() - distance;
if( tempDistance < abs( distance ) )
{
distance = tempDistance;
if( new_direction == Left )
new_direction = Right;
else
new_direction = Left;
}
if( !animation )
{
animation = true;
direction = new_direction;
distance--;
}
for( int i=0; i<distance; i++ )
{
if( !scheduled_directions.isEmpty() && scheduled_directions.last() != new_direction )
scheduled_directions.pop_back();
else
scheduled_directions.enqueue( new_direction );
if( scheduled_directions.count() == effects->currentTabBoxWindowList().count() )
scheduled_directions.clear();
}
}
}
if( windows.contains( selected_window ))
effects->addRepaint( windows.value( selected_window )->area );
selected_window->addRepaintFull();
}
setSelectedWindow( effects->currentTabBoxWindow());
if( windows.contains( selected_window ))
effects->addRepaint( windows.value( selected_window )->area );
selected_window->addRepaintFull();
effects->addRepaint( text_area );
}
else if( mMode != TabBoxWindowsMode && mMode != TabBoxWindowsAlternativeMode )
{ // DesktopMode
if( desktops.contains( selected_desktop ))
effects->addRepaint( desktops.value( selected_desktop )->area );
selected_desktop = effects->currentTabBoxDesktop();
if( !mProxyActivated || mProxyShowText )
thumbnailFrame.setText( effects->desktopName( selected_desktop ));
if( desktops.contains( selected_desktop ))
effects->addRepaint( desktops.value( selected_desktop )->area );
effects->addRepaint( text_area );
if( effects->currentTabBoxDesktopList() == original_desktops )
return;
original_desktops = effects->currentTabBoxDesktopList();
}
// for safety copy list each time tabbox is updated
original_windows = effects->currentTabBoxWindowList();
effects->addRepaint( frame_area );
calculateFrameSize();
calculateItemSizes();
moveResizeInputWindow( frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height());
effects->addRepaint( frame_area );
}
}
void BoxSwitchEffect::setActive()
{
mActivated = true;
// Just in case we are activated again before the deactivation animation finished
qDeleteAll( windows );
windows.clear();
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
original_windows = effects->currentTabBoxWindowList();
setSelectedWindow( effects->currentTabBoxWindow());
}
else
{
original_desktops = effects->currentTabBoxDesktopList();
selected_desktop = effects->currentTabBoxDesktop();
if( !mProxyActivated || mProxyShowText )
thumbnailFrame.setText( effects->desktopName( selected_desktop ));
}
calculateFrameSize();
calculateItemSizes();
if( !mProxyActivated )
{
// only create the input window when effect is not activated via the proxy
mInput = effects->createInputWindow( this, frame_area.x(), frame_area.y(),
frame_area.width(), frame_area.height(), Qt::ArrowCursor );
}
effects->addRepaint( frame_area );
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
for( i = windows.constBegin(); i != windows.constEnd(); ++i )
{
i.key()->addRepaintFull();
}
}
}
void BoxSwitchEffect::setInactive()
{
mActivated = false;
effects->unrefTabBox();
if( !mProxyActivated && mInput != None )
{
effects->destroyInputWindow( mInput );
mInput = None;
}
mProxyActivated = false;
mPositioningFactor = 0.5f;
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
QHash< EffectWindow*, ItemInfo* >::const_iterator i;
for( i = windows.constBegin(); i != windows.constEnd(); ++i )
{
if( i.key() != selected_window )
i.key()->addRepaintFull();
}
// We don't unset the selected window so we have correct fading
// But we do need to remove elevation status
if( elevate_window && selected_window )
effects->setElevatedWindow( selected_window, false );
foreach( EffectWindow* w, referrencedWindows )
{
w->unrefWindow();
}
referrencedWindows.clear();
}
else
{ // DesktopMode
qDeleteAll( windows );
desktops.clear();
}
thumbnailFrame.free();
effects->addRepaint( frame_area );
frame_area = QRect();
}
void BoxSwitchEffect::setSelectedWindow( EffectWindow* w )
{
if( elevate_window && selected_window )
{
effects->setElevatedWindow( selected_window, false );
}
selected_window = w;
if( selected_window && ( !mProxyActivated || mProxyShowText ) )
thumbnailFrame.setText( selected_window->caption() );
if( elevate_window && w )
{
effects->setElevatedWindow( selected_window, true );
}
}
void BoxSwitchEffect::windowClosed( EffectWindow* w )
{
if( w == selected_window )
{
setSelectedWindow( 0 );
}
if( windows.contains( w ) )
{
w->refWindow();
referrencedWindows.append( w );
original_windows.removeAll( w );
delete windows[ w ];
windows.remove( w );
effects->addRepaintFull();
}
}
void BoxSwitchEffect::moveResizeInputWindow( int x, int y, int width, int height )
{
XMoveWindow( display(), mInput, x, y );
XResizeWindow( display(), mInput, width, height );
}
void BoxSwitchEffect::calculateFrameSize()
{
int itemcount;
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
itemcount = original_windows.count();
item_max_size.setWidth( 200 );
item_max_size.setHeight( 200 );
}
else
{
itemcount = original_desktops.count();
item_max_size.setWidth( 200 );
item_max_size.setHeight( 200 );
}
// How much height to reserve for a one-line text label
text_area.setHeight( QFontMetrics( text_font ).height() * 1.2 );
// Separator space between items and text
const int separator_height = 6;
// Shrink the size until all windows/desktops can fit onscreen
frame_area.setWidth( itemcount * item_max_size.width());
QRect screenr = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
while( frame_area.width() > screenr.width())
{
item_max_size /= 2;
frame_area.setWidth( itemcount * item_max_size.width());
}
frame_area.setHeight( item_max_size.height() +
separator_height + text_area.height());
if( mProxyActivated && !mProxyShowText )
frame_area.setHeight( item_max_size.height() );
text_area.setWidth( frame_area.width() );
frame_area.moveTo( screenr.x() + ( screenr.width() - frame_area.width()) / 2,
screenr.y() + ( screenr.height() - frame_area.height()) / 2 * mPositioningFactor * 2 );
text_area.moveTo( frame_area.x(),
frame_area.y() + item_max_size.height() + separator_height);
thumbnailFrame.setGeometry( frame_area );
}
void BoxSwitchEffect::calculateItemSizes()
{
if( mMode == TabBoxWindowsMode || mMode == TabBoxWindowsAlternativeMode )
{
qDeleteAll( windows );
windows.clear();
if( (mAnimateSwitch && !mProxyActivated) || (mProxyActivated && mProxyAnimateSwitch) )
{
int index = original_windows.indexOf( effects->currentTabBoxWindow() );
int leftIndex = index;
int rightIndex = index + 1;
if( rightIndex == original_windows.count() )
rightIndex = 0;
EffectWindowList ordered_windows;
int leftWindowCount = original_windows.count()/2;
int rightWindowCount = leftWindowCount;
if( original_windows.count()%2 == 1 )
leftWindowCount++;
for( int i=0; i < leftWindowCount; i++ )
{
int tempIndex = ( leftIndex - i );
if( tempIndex < 0 )
tempIndex = original_windows.count() + tempIndex;
ordered_windows.prepend( original_windows[ tempIndex ] );
}
for( int i=0; i < rightWindowCount; i++ )
{
int tempIndex = ( rightIndex + i ) % original_windows.count();
ordered_windows.append( original_windows[ tempIndex ] );
}
// move items cause of schedule
for( int i=0; i < scheduled_directions.count(); i++ )
{
Direction actual = scheduled_directions[ i ];
if( actual == Left )
{
EffectWindow* w = ordered_windows.takeLast();
ordered_windows.prepend( w );
}
else
{
EffectWindow* w = ordered_windows.takeFirst();
ordered_windows.append( w );
}
}
if( animation && timeLine.value() < 0.5 )
{
if( direction == Left )
{
EffectWindow* w = ordered_windows.takeLast();
edge_window = w;
ordered_windows.prepend( w );
}
else
{
EffectWindow* w = ordered_windows.takeFirst();
edge_window = w;
ordered_windows.append( w );
}
}
else if( animation && timeLine.value() >= 0.5 )
{
if( animation && direction == Left )
edge_window = ordered_windows.last();
if( animation && direction == Right )
edge_window = ordered_windows.first();
}
int offset = 0;
if( animation )
{
if( direction == Left )
offset = (float)item_max_size.width()*(1.0-timeLine.value());
else
offset = -(float)item_max_size.width()*(1.0-timeLine.value());
}
for( int i = 0; i < ordered_windows.count(); i++ )
{
if( !ordered_windows.at( i ) )
continue;
EffectWindow* w = ordered_windows.at( i );
windows[ w ] = new ItemInfo();
windows[ w ]->iconFrame = new EffectFrame( EffectFrame::Unstyled, false );
windows[ w ]->iconFrame->setAlignment( Qt::AlignTop | Qt::AlignLeft );
windows[ w ]->iconFrame->setIcon( w->icon() );
float moveIndex = i;
if( animation && timeLine.value() < 0.5 )
{
if( direction == Left )
moveIndex--;
else
moveIndex++;
}
if( ordered_windows.count()%2 == 0 )
moveIndex += 0.5;
windows[ w ]->area = QRect( frame_area.x() + moveIndex * item_max_size.width() + offset,
frame_area.y(),
item_max_size.width(), item_max_size.height());
windows[ w ]->clickable = windows[ w ]->area;
}
if( ordered_windows.count()%2 == 0 )
{
right_window = ordered_windows.last();
}
if( !highlight_is_set )
{
highlight_area = windows[ selected_window ]->area;
highlight_is_set = true;
}
}
else
{
for( int i = 0; i < original_windows.count(); i++ )
{
if( !original_windows.at( i ) )
continue;
EffectWindow* w = original_windows.at( i );
windows[ w ] = new ItemInfo();
windows[ w ]->iconFrame = new EffectFrame( EffectFrame::Unstyled, false );
windows[ w ]->iconFrame->setAlignment( Qt::AlignTop | Qt::AlignLeft );
windows[ w ]->iconFrame->setIcon( w->icon() );
windows[ w ]->area = QRect( frame_area.x() + i * item_max_size.width(),
frame_area.y(),
item_max_size.width(), item_max_size.height());
windows[ w ]->clickable = windows[ w ]->area;
}
}
}
else
{
desktops.clear();
for( int i = 0; i < original_desktops.count(); i++ )
{
int it = original_desktops.at( i );
desktops[ it ] = new ItemInfo();
desktops[ it ]->area = QRect( frame_area.x() + i * item_max_size.width(),
frame_area.y(),
item_max_size.width(), item_max_size.height());
desktops[ it ]->clickable = desktops[ it ]->area;
}
}
}
void BoxSwitchEffect::paintHighlight( QRect area )
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
if( effects->compositingType() == OpenGLCompositing )
{
glPushAttrib( GL_CURRENT_BIT );
glColor4f( color_highlight.redF(), color_highlight.greenF(), color_highlight.blueF(), color_highlight.alphaF());
renderRoundBox( area, 6 );
glPopAttrib();
}
#endif
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
if( effects->compositingType() == XRenderCompositing )
{
Pixmap pixmap = XCreatePixmap( display(), rootWindow(),
area.width(), area.height(), 32 );
XRenderPicture pic( pixmap, 32 );
XFreePixmap( display(), pixmap );
XRenderColor col;
col.alpha = int( color_highlight.alphaF() * 0xffff );
col.red = int( color_highlight.redF() * color_highlight.alphaF() * 0xffff );
col.green = int( color_highlight.greenF() * color_highlight.alphaF() * 0xffff );
col.blue = int( color_highlight.blueF() * color_highlight.alphaF() * 0xffff );
XRenderFillRectangle( display(), PictOpSrc, pic, &col, 0, 0,
area.width(), area.height());
XRenderComposite( display(), color_highlight.alphaF() != 1.0 ? PictOpOver : PictOpSrc,
pic, None, effects->xrenderBufferPicture(),
0, 0, 0, 0, area.x(), area.y(), area.width(), area.height());
}
#endif
}
void BoxSwitchEffect::paintWindowThumbnail( EffectWindow* w )
{
if( !windows.contains( w ))
return;
WindowPaintData data( w );
setPositionTransformations( data,
windows[ w ]->thumbnail, w,
windows[ w ]->area.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
Qt::KeepAspectRatio );
if( animation && ( w == edge_window ) && ( windows.size() % 2 == 1 ) )
{
// in case of animation:
// the window which has to change the side will be split and painted on both sides of the edge
double splitPoint = 0.0;
if( direction == Left )
{
splitPoint = w->geometry().width()*timeLine.value();
}
else
{
splitPoint = w->geometry().width() - w->geometry().width()*timeLine.value();
}
data.quads = data.quads.splitAtX( splitPoint );
WindowQuadList left_quads;
WindowQuadList right_quads;
foreach( const WindowQuad &quad, data.quads )
{
if( quad.left() >= splitPoint )
left_quads << quad;
if( quad.right() <= splitPoint )
right_quads << quad;
}
// the base position of the window is changed after half of the animation
if( timeLine.value() < 0.5 )
{
if( direction == Left )
data.quads = left_quads;
else
data.quads = right_quads;
}
else
{
if( direction == Left )
data.quads = right_quads;
else
data.quads = left_quads;
}
// paint one part of the thumbnail
effects->paintWindow( w,
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
windows[ w ]->thumbnail, data );
QRect secondThumbnail;
// paint the second part of the thumbnail:
// the other window quads are needed and a new rect for transformation has to be calculated
if( direction == Left )
{
if( timeLine.value() < 0.5 )
{
data.quads = right_quads;
secondThumbnail = QRect( frame_area.x() + frame_area.width() -
(float)item_max_size.width()*timeLine.value(),
frame_area.y(), item_max_size.width(), item_max_size.height());
}
else
{
data.quads = left_quads;
secondThumbnail = QRect( frame_area.x() - (float)item_max_size.width()*timeLine.value(),
frame_area.y(), item_max_size.width(), item_max_size.height());
if( right_window )
secondThumbnail = QRect( frame_area.x() -
(float)item_max_size.width()*(timeLine.value()-0.5),
frame_area.y(), item_max_size.width(), item_max_size.height());
}
}
else
{
if( timeLine.value() < 0.5 )
{
data.quads = left_quads;
secondThumbnail = QRect( frame_area.x() -
(float)item_max_size.width()*(1.0 - timeLine.value()),
frame_area.y(), item_max_size.width(), item_max_size.height());
}
else
{
data.quads = right_quads;
secondThumbnail = QRect( frame_area.x() + frame_area.width() -
(float)item_max_size.width()*(1.0 - timeLine.value()),
frame_area.y(), item_max_size.width(), item_max_size.height());
}
}
setPositionTransformations( data,
windows[ w ]->thumbnail, w,
secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
Qt::KeepAspectRatio );
effects->paintWindow( w,
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
windows[ w ]->thumbnail, data );
}
else if( ( windows.size() % 2 == 0 ) && ( w == right_window ) )
{
// in case of even number of thumbnails:
// the window on the right is painted one half on left and on half on the right side
float animationOffset = 0.0f;
double splitPoint = w->geometry().width()*0.5;
if( animation && timeLine.value() <= 0.5 )
{
// in case of animation the right window has only to be split during first half of animation
if( direction == Left )
{
splitPoint += w->geometry().width()*timeLine.value();
animationOffset = -(float)item_max_size.width()*timeLine.value();
}
else
{
splitPoint -= w->geometry().width()*timeLine.value();
animationOffset = (float)item_max_size.width()*timeLine.value();
}
}
if( animation && timeLine.value() > 0.5 )
{
// at half of animation a different window has become the right window
// we have to adjust the splitting again
if( direction == Left )
{
splitPoint -= w->geometry().width()*(1.0-timeLine.value());
animationOffset = (float)item_max_size.width()*(1.0-timeLine.value());
}
else
{
splitPoint += w->geometry().width()*(1.0-timeLine.value());
animationOffset = -(float)item_max_size.width()*(1.0-timeLine.value());
}
}
data.quads = data.quads.splitAtX( splitPoint );
WindowQuadList rightQuads;
WindowQuadList leftQuads;
foreach( const WindowQuad &quad, data.quads )
{
if( quad.right() <= splitPoint )
leftQuads << quad;
else
rightQuads << quad;
}
// left quads are painted on right side of frame
data.quads = leftQuads;
effects->drawWindow( w,
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
windows[ w ]->thumbnail, data );
// right quads are painted on left side of frame
data.quads = rightQuads;
QRect secondThumbnail;
secondThumbnail = QRect( frame_area.x() -
(float)item_max_size.width()*0.5 + animationOffset,
frame_area.y(), item_max_size.width(), item_max_size.height());
setPositionTransformations( data,
windows[ w ]->thumbnail, w,
secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
Qt::KeepAspectRatio );
effects->drawWindow( w,
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
windows[ w ]->thumbnail, data );
}
else
{
effects->drawWindow( w,
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
windows[ w ]->thumbnail, data );
}
}
void BoxSwitchEffect::paintDesktopThumbnail( int iDesktop )
{
if( !desktops.contains( iDesktop ))
return;
ScreenPaintData data;
QRect region;
QRect r = desktops[ iDesktop ]->area.adjusted( highlight_margin, highlight_margin,
-highlight_margin, -highlight_margin );
QSize size = QSize( displayWidth(), displayHeight());
size.scale( r.size(), Qt::KeepAspectRatio );
data.xScale = size.width() / double( displayWidth());
data.yScale = size.height() / double( displayHeight());
int width = int( displayWidth() * data.xScale );
int height = int( displayHeight() * data.yScale );
int x = r.x() + ( r.width() - width ) / 2;
int y = r.y() + ( r.height() - height ) / 2;
region = QRect( x, y, width, height );
data.xTranslate = x;
data.yTranslate = y;
effects->paintScreen( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST,
region, data );
}
void BoxSwitchEffect::paintWindowIcon( EffectWindow* w )
{
if( !windows.contains( w ))
return;
// Don't render null icons
if( w->icon().isNull() )
{
return;
}
int width = w->icon().width();
int height = w->icon().height();
int x = windows[ w ]->area.x() + windows[ w ]->area.width() - width - highlight_margin;
int y = windows[ w ]->area.y() + windows[ w ]->area.height() - height - highlight_margin;
if( ( windows.size() % 2 == 0 ) )
{
if( w == right_window )
{
// in case of right window the icon has to be painted on the left side of the frame
x = frame_area.x() + windows[ w ]->area.width()*0.5 - width - highlight_margin;
if( animation )
{
if( timeLine.value() <= 0.5 )
{
if( direction == Left )
{
x -= windows[ w ]->area.width()*timeLine.value();
x = qMax( x, frame_area.x() );
}
else
x += windows[ w ]->area.width()*timeLine.value();
}
else
{
if( direction == Left )
x += windows[ w ]->area.width()*(1.0-timeLine.value());
else
{
x -= windows[ w ]->area.width()*(1.0-timeLine.value());
x = qMax( x, frame_area.x() );
}
}
}
}
}
else
{
// during animation the icon of the edge window has to change position
if( animation && w == edge_window )
{
if( timeLine.value() < 0.5 )
{
if( direction == Left )
x += windows[ w ]->area.width()*timeLine.value();
else
x -= windows[ w ]->area.width()*timeLine.value();
}
else
{
if( direction == Left )
x -= windows[ w ]->area.width()*(1.0 - timeLine.value());
else
x += windows[ w ]->area.width()*(1.0 - timeLine.value());
}
}
}
windows[ w ]->iconFrame->setPosition( QPoint( x, y ));
windows[ w ]->iconFrame->render( infiniteRegion(), 1.0, 0.75 );
}
void* BoxSwitchEffect::proxy()
{
return &mProxy;
}
void BoxSwitchEffect::activateFromProxy( int mode, bool animate, bool showText, float positioningFactor )
{
if( !mActivated )
{
mProxyActivated = true;
mProxyAnimateSwitch = animate;
mProxyShowText = showText;
mPositioningFactor = positioningFactor;
thumbnailFrame.setText(" ");
if( ( mode == TabBoxWindowsMode ) || ( mode == TabBoxWindowsAlternativeMode ) )
{
if( effects->currentTabBoxWindowList().count() > 0 )
{
mMode = mode;
effects->refTabBox();
highlight_is_set = false;
animation = false;
scheduled_directions.clear();
right_window = 0;
setActive();
}
}
else if( mode == TabBoxDesktopListMode || mode == TabBoxDesktopMode )
{ // DesktopMode
if( effects->currentTabBoxDesktopList().count() > 0 )
{
mMode = mode;
painting_desktop = 0;
effects->refTabBox();
setActive();
}
}
if( !mActivated )
mProxyActivated = false;
}
}
BoxSwitchEffect::ItemInfo::ItemInfo()
: iconFrame( NULL )
{
}
BoxSwitchEffect::ItemInfo::~ItemInfo()
{
delete iconFrame;
}
} // namespace