PageRenderTime 386ms CodeModel.GetById 60ms app.highlight 263ms RepoModel.GetById 50ms app.codeStats 0ms

/src/libtomahawk/widgets/AnimatedSplitter.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 305 lines | 222 code | 62 blank | 21 comment | 37 complexity | aafd75960e8a40395ac1942aed35572f MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *
  5 *   Tomahawk is free software: you can redistribute it and/or modify
  6 *   it under the terms of the GNU General Public License as published by
  7 *   the Free Software Foundation, either version 3 of the License, or
  8 *   (at your option) any later version.
  9 *
 10 *   Tomahawk is distributed in the hope that it will be useful,
 11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13 *   GNU General Public License for more details.
 14 *
 15 *   You should have received a copy of the GNU General Public License
 16 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 17 */
 18
 19#include "AnimatedSplitter.h"
 20
 21#include "utils/Logger.h"
 22
 23#define ANIMATION_TIME 400
 24
 25
 26AnimatedSplitter::AnimatedSplitter( QWidget* parent )
 27    : QSplitter( parent )
 28    , m_greedyIndex( 0 )
 29{
 30    setHandleWidth( 1 );
 31}
 32
 33
 34void
 35AnimatedSplitter::show( int index, bool animate )
 36{
 37    QWidget* w = widget( index );
 38    emit shown( w, animate );
 39}
 40
 41
 42void
 43AnimatedSplitter::hide( int index, bool animate )
 44{
 45    QWidget* w = widget( index );
 46    emit hidden( w, animate );
 47}
 48
 49
 50void
 51AnimatedSplitter::addWidget( QWidget* widget )
 52{
 53    QSplitter::addWidget( widget );
 54}
 55
 56
 57void
 58AnimatedSplitter::addWidget( AnimatedWidget* widget )
 59{
 60    QSplitter::addWidget( widget );
 61
 62    connect( widget, SIGNAL( showWidget() ), SLOT( onShowRequest() ) );
 63    connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) );
 64    connect( widget, SIGNAL( sizeHintChanged( QSize ) ), SLOT( onShowRequest() ) );
 65    connect( widget, SIGNAL( sizeChanged( QSize ) ), SLOT( onSizeChanged( QSize ) ) );
 66    connect( widget, SIGNAL( resizeBy( QPoint ) ), SLOT( onResizeRequest( QPoint ) ) );
 67
 68    connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) );
 69    connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) );
 70}
 71
 72
 73void
 74AnimatedSplitter::changeSize( QWidget* child, const QSize& size )
 75{
 76    int wi = indexOf( child );
 77
 78    QList< int > sizes;
 79    for ( int i = 0; i < count(); i ++ )
 80    {
 81        int j = 0;
 82
 83        if ( i == m_greedyIndex )
 84        {
 85            j = height() - size.height();
 86            for ( int x = 0; x < count(); x++ )
 87            {
 88                if ( x != i && x != wi )
 89                    j -= widget( x )->height();
 90            }
 91        }
 92        else if ( i == wi )
 93        {
 94            j = size.height();
 95        }
 96        else
 97        {
 98            j = widget( i )->height();
 99        }
100
101        sizes << j;
102    }
103
104    setSizes( sizes );
105}
106
107
108void
109AnimatedSplitter::onResizeRequest( const QPoint& delta )
110{
111    AnimatedWidget* w = (AnimatedWidget*)(sender());
112    if ( indexOf( w ) > 0 )
113    {
114        int newheight = w->height() + delta.y();
115        if ( newheight <= w->hiddenSize().height() )
116        {
117            w->hide();
118        }
119        else
120            changeSize( w, QSize( w->width(), newheight ) );
121    }
122    else
123        Q_ASSERT( false );
124}
125
126
127void
128AnimatedSplitter::onShowRequest()
129{
130    AnimatedWidget* w = (AnimatedWidget*)(sender());
131    if ( indexOf( w ) > 0 )
132        show( indexOf( w ) );
133    else
134        Q_ASSERT( false );
135}
136
137
138void
139AnimatedSplitter::onHideRequest()
140{
141    AnimatedWidget* w = (AnimatedWidget*)(sender());
142    if ( indexOf( w ) > 0 )
143        hide( indexOf( w ) );
144    else
145        Q_ASSERT( false );
146}
147
148
149void
150AnimatedSplitter::onSizeChanged( const QSize& size )
151{
152    AnimatedWidget* w = (AnimatedWidget*)(sender());
153    if ( indexOf( w ) > 0 )
154        changeSize( w, size );
155    else
156        Q_ASSERT( false );
157}
158
159
160void
161AnimatedSplitter::setGreedyWidget( int index )
162{
163    if( !widget( index ) )
164        return;
165
166    m_greedyIndex = index;
167
168    QSizePolicy policy = widget( m_greedyIndex )->sizePolicy();
169    if( orientation() == Qt::Horizontal )
170        policy.setHorizontalStretch( 1 );
171    else
172        policy.setVerticalStretch( 1 );
173
174    widget( m_greedyIndex )->setSizePolicy( policy );
175
176}
177
178
179QSplitterHandle*
180AnimatedSplitter::createHandle()
181{
182    return new AnimatedSplitterHandle( orientation(), this );
183}
184
185
186AnimatedWidget::AnimatedWidget( AnimatedSplitter* parent )
187    : m_parent( parent )
188    , m_isHidden( false )
189{
190    m_timeLine = new QTimeLine( ANIMATION_TIME, this );
191    m_timeLine->setUpdateInterval( 20 );
192    m_timeLine->setEasingCurve( QEasingCurve::OutCubic );
193
194    connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) );
195    connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) );
196}
197
198
199AnimatedWidget::~AnimatedWidget()
200{
201}
202
203
204void
205AnimatedWidget::onShown( QWidget* widget, bool animated )
206{
207    if ( widget != this )
208        return;
209
210    m_animateForward = true;
211    if ( animated )
212    {
213        if ( m_timeLine->state() == QTimeLine::Running )
214            m_timeLine->stop();
215
216        m_timeLine->setFrameRange( height(), sizeHint().height() );
217        m_timeLine->setDirection( QTimeLine::Forward );
218        m_timeLine->start();
219    }
220    else
221    {
222        onAnimationStep( sizeHint().height() );
223        onAnimationFinished();
224    }
225
226    m_isHidden = false;
227}
228
229
230void
231AnimatedWidget::onHidden( QWidget* widget, bool animated )
232{
233    if ( widget != this )
234        return;
235
236    m_animateForward = false;
237    int minHeight = hiddenSize().height();
238
239    if ( animated )
240    {
241        if ( m_timeLine->state() == QTimeLine::Running )
242            m_timeLine->stop();
243
244        m_timeLine->setFrameRange( minHeight, height() );
245        m_timeLine->setDirection( QTimeLine::Backward );
246        m_timeLine->start();
247    }
248    else
249    {
250        onAnimationStep( minHeight );
251        onAnimationFinished();
252    }
253
254    m_isHidden = true;
255}
256
257
258void
259AnimatedWidget::onAnimationStep( int frame )
260{
261    setFixedHeight( frame );
262
263    QSize s( 0, frame ); //FIXME
264    emit sizeChanged( s );
265}
266
267
268void
269AnimatedWidget::onAnimationFinished()
270{
271    if ( m_animateForward )
272    {
273        setMinimumHeight( hiddenSize().height() );
274        setMaximumHeight( QWIDGETSIZE_MAX );
275    }
276    else
277    {
278        setFixedHeight( hiddenSize().height() );
279    }
280    
281    emit animationFinished();
282}
283
284
285QSize
286AnimatedSplitterHandle::sizeHint() const
287{
288    // Re-calculate our position if the items in the splitter changed, or if we haven't calculated it yet
289    if ( m_indexInSplitter == -1 || m_lastCount != splitter()->count() )
290    {
291        for ( int i = 0; i < splitter()->count(); i++ )
292        {
293            if ( splitter()->handle( i ) == this )
294            {
295                m_indexInSplitter = i;
296            }
297        }
298        m_lastCount = splitter()->count();
299    }
300
301    // Since we are in an AnimatedSplitter, we always return 0,0 for SizeHint, simply
302    // because we know there's going to be a handle in the bottom widget to move the
303    // splitter.
304    return QSize( 0, 0 );
305}