add more spacing
[personal-kdebase.git] / workspace / kwin / effects / slide.cpp
bloba43c4e15cd69bd269a0997761146322da0da0a9b
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
6 Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
22 #include "slide.h"
24 #include <math.h>
26 namespace KWin
29 KWIN_EFFECT( slide, SlideEffect )
31 SlideEffect::SlideEffect()
32 : slide( false )
34 mTimeLine.setCurveShape(TimeLine::EaseInOutCurve);
35 reconfigure( ReconfigureAll );
38 void SlideEffect::reconfigure( ReconfigureFlags )
40 mTimeLine.setDuration( animationTime( 250 ));
43 void SlideEffect::prePaintScreen( ScreenPrePaintData& data, int time )
45 if( slide )
47 mTimeLine.addTime(time);
49 // PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once,
50 // so with normal screen painting second screen paint would erase parts of the first paint
51 if( mTimeLine.value() != 1 )
52 data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST;
53 else
55 slide = false;
56 mTimeLine.setProgress(0);
57 effects->setActiveFullScreenEffect( NULL );
60 effects->prePaintScreen( data, time );
63 void SlideEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
65 if( slide )
67 if( w->isOnAllDesktops())
69 if( slide_painting_sticky )
70 data.setTransformed();
71 else
72 w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
74 else if( w->isOnDesktop( painting_desktop ))
75 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
76 else
77 w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
79 effects->prePaintWindow( w, data, time );
82 void SlideEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
84 if( mTimeLine.value() == 0 )
86 effects->paintScreen( mask, region, data );
87 return;
91 Transformations are done by remembering starting position of the change and the progress
92 of it, the destination is computed from the current desktop. Positions of desktops
93 are done using their topleft corner.
95 QPoint destPos = desktopRect( effects->currentDesktop(), false ).topLeft();
96 QPoint diffPos = destPos - slide_start_pos;
97 int w = 0;
98 int h = 0;
99 if( effects->optionRollOverDesktops())
101 int x, y;
102 Qt::Orientation orientation;
103 effects->calcDesktopLayout( &x, &y, &orientation );
104 w = x * displayWidth();
105 h = y * displayHeight();
106 // wrap around if shorter
107 if( diffPos.x() > 0 && diffPos.x() > w / 2 )
108 diffPos.setX( diffPos.x() - w );
109 if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
110 diffPos.setX( diffPos.x() + w );
111 if( diffPos.y() > 0 && diffPos.y() > h / 2 )
112 diffPos.setY( diffPos.y() - h );
113 if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
114 diffPos.setY( diffPos.y() + h );
116 QPoint currentPos = slide_start_pos + mTimeLine.value() * diffPos;
117 QSize displaySize( displayWidth(), displayHeight());
118 QRegion currentRegion = QRect( currentPos, displaySize );
119 if( effects->optionRollOverDesktops())
121 currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
122 currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
123 currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
124 currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
126 bool do_sticky = true;
127 for( int desktop = 1;
128 desktop <= effects->numberOfDesktops();
129 ++desktop )
131 QRect rect = desktopRect( desktop, false );
132 if( currentRegion.contains( rect )) // part of the desktop needs painting
134 painting_desktop = desktop;
135 slide_painting_sticky = do_sticky;
136 slide_painting_diff = rect.topLeft() - currentPos;
137 if( effects->optionRollOverDesktops())
139 if( slide_painting_diff.x() > displayWidth())
140 slide_painting_diff.setX( slide_painting_diff.x() - w );
141 if( slide_painting_diff.x() < -displayWidth())
142 slide_painting_diff.setX( slide_painting_diff.x() + w );
143 if( slide_painting_diff.y() > displayHeight())
144 slide_painting_diff.setY( slide_painting_diff.y() - h );
145 if( slide_painting_diff.y() < -displayHeight())
146 slide_painting_diff.setY( slide_painting_diff.y() + h );
148 do_sticky = false; // paint on-all-desktop windows only once
149 ScreenPaintData d = data;
150 d.xTranslate += slide_painting_diff.x();
151 d.yTranslate += slide_painting_diff.y();
152 // TODO mask parts that are not visible?
153 effects->paintScreen( mask, region, d );
158 void SlideEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
160 if( slide )
161 { // don't move windows on all desktops (compensate screen transformation)
162 if( w->isOnAllDesktops()) // TODO also fix 'Workspace::movingClient'
164 data.xTranslate -= slide_painting_diff.x();
165 data.yTranslate -= slide_painting_diff.y();
168 effects->paintWindow( w, mask, region, data );
171 void SlideEffect::postPaintScreen()
173 if( slide )
174 effects->addRepaintFull();
175 effects->postPaintScreen();
178 // Gives a position of the given desktop when all desktops are arranged in a grid
179 QRect SlideEffect::desktopRect( int desktop, bool scaled ) const
181 int x, y;
182 Qt::Orientation orientation;
183 effects->calcDesktopLayout( &x, &y, &orientation );
184 --desktop; // make it start with 0
185 QRect rect;
186 if( orientation == Qt::Horizontal )
187 rect = QRect(( desktop % x ) * displayWidth(), ( desktop / x ) * displayHeight(),
188 displayWidth(), displayHeight());
189 else
190 rect = QRect(( desktop / y ) * displayWidth(), ( desktop % y ) * displayHeight(),
191 displayWidth(), displayHeight());
192 if( !scaled )
193 return rect;
194 QRect current = desktopRect( effects->currentDesktop(), false );
195 double progress = mTimeLine.value();
196 rect = QRect( qRound( interpolate( rect.x() - current.x(), rect.x() / double( x ), progress )),
197 qRound( interpolate( rect.y() - current.y(), rect.y() / double( y ), progress )),
198 qRound( interpolate( rect.width(), displayWidth() / double( x ), progress )),
199 qRound( interpolate( rect.height(), displayHeight() / double( y ), progress )));
200 return rect;
203 void SlideEffect::desktopChanged( int old )
205 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
206 return;
208 if( slide ) // old slide still in progress
210 QPoint diffPos = desktopRect( old, false ).topLeft() - slide_start_pos;
211 int w = 0;
212 int h = 0;
213 if( effects->optionRollOverDesktops())
215 int x, y;
216 Qt::Orientation orientation;
217 effects->calcDesktopLayout( &x, &y, &orientation );
218 w = x * displayWidth();
219 h = y * displayHeight();
220 // wrap around if shorter
221 if( diffPos.x() > 0 && diffPos.x() > w / 2 )
222 diffPos.setX( diffPos.x() - w );
223 if( diffPos.x() < 0 && abs( diffPos.x()) > w / 2 )
224 diffPos.setX( diffPos.x() + w );
225 if( diffPos.y() > 0 && diffPos.y() > h / 2 )
226 diffPos.setY( diffPos.y() - h );
227 if( diffPos.y() < 0 && abs( diffPos.y()) > h / 2 )
228 diffPos.setY( diffPos.y() + h );
230 QPoint currentPos = slide_start_pos + mTimeLine.value() * diffPos;
231 QRegion currentRegion = QRect( currentPos, QSize( displayWidth(), displayHeight()));
232 if( effects->optionRollOverDesktops())
234 currentRegion |= ( currentRegion & QRect( -w, 0, w, h )).translated( w, 0 );
235 currentRegion |= ( currentRegion & QRect( 0, -h, w, h )).translated( 0, h );
236 currentRegion |= ( currentRegion & QRect( w, 0, w, h )).translated( -w, 0 );
237 currentRegion |= ( currentRegion & QRect( 0, h, w, h )).translated( 0, -h );
239 QRect rect = desktopRect( effects->currentDesktop(), false );
240 if( currentRegion.contains( rect ))
241 { // current position is in new current desktop (e.g. quickly changing back),
242 // don't do full progress
243 if( abs( currentPos.x() - rect.x()) > abs( currentPos.y() - rect.y()))
244 mTimeLine.setProgress(1 - abs( currentPos.x() - rect.x()) / double( displayWidth()));
245 else
246 mTimeLine.setProgress(1 - abs( currentPos.y() - rect.y()) / double( displayHeight()));
248 else // current position is not on current desktop, do full progress
249 mTimeLine.setProgress(0);
250 diffPos = rect.topLeft() - currentPos;
251 if( mTimeLine.value() <= 0 )
253 // Compute starting point for this new move (given current and end positions)
254 slide_start_pos = rect.topLeft() - diffPos * 1 / ( 1 - mTimeLine.value() );
256 else
257 { // at the end, stop
258 slide = false;
259 mTimeLine.setProgress(0);
260 effects->setActiveFullScreenEffect( NULL );
263 else
265 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
266 return;
267 mTimeLine.setProgress(0);
268 slide_start_pos = desktopRect( old, false ).topLeft();
269 slide = true;
270 effects->setActiveFullScreenEffect( this );
272 effects->addRepaintFull();
275 } // namespace
277 #include "slide.moc"