/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. #include "AnimatedSplitter.h"
  19. #include "utils/Logger.h"
  20. #define ANIMATION_TIME 400
  21. AnimatedSplitter::AnimatedSplitter( QWidget* parent )
  22. : QSplitter( parent )
  23. , m_greedyIndex( 0 )
  24. {
  25. setHandleWidth( 1 );
  26. }
  27. void
  28. AnimatedSplitter::show( int index, bool animate )
  29. {
  30. QWidget* w = widget( index );
  31. emit shown( w, animate );
  32. }
  33. void
  34. AnimatedSplitter::hide( int index, bool animate )
  35. {
  36. QWidget* w = widget( index );
  37. emit hidden( w, animate );
  38. }
  39. void
  40. AnimatedSplitter::addWidget( QWidget* widget )
  41. {
  42. QSplitter::addWidget( widget );
  43. }
  44. void
  45. AnimatedSplitter::addWidget( AnimatedWidget* widget )
  46. {
  47. QSplitter::addWidget( widget );
  48. connect( widget, SIGNAL( showWidget() ), SLOT( onShowRequest() ) );
  49. connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) );
  50. connect( widget, SIGNAL( sizeHintChanged( QSize ) ), SLOT( onShowRequest() ) );
  51. connect( widget, SIGNAL( sizeChanged( QSize ) ), SLOT( onSizeChanged( QSize ) ) );
  52. connect( widget, SIGNAL( resizeBy( QPoint ) ), SLOT( onResizeRequest( QPoint ) ) );
  53. connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) );
  54. connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) );
  55. }
  56. void
  57. AnimatedSplitter::changeSize( QWidget* child, const QSize& size )
  58. {
  59. int wi = indexOf( child );
  60. QList< int > sizes;
  61. for ( int i = 0; i < count(); i ++ )
  62. {
  63. int j = 0;
  64. if ( i == m_greedyIndex )
  65. {
  66. j = height() - size.height();
  67. for ( int x = 0; x < count(); x++ )
  68. {
  69. if ( x != i && x != wi )
  70. j -= widget( x )->height();
  71. }
  72. }
  73. else if ( i == wi )
  74. {
  75. j = size.height();
  76. }
  77. else
  78. {
  79. j = widget( i )->height();
  80. }
  81. sizes << j;
  82. }
  83. setSizes( sizes );
  84. }
  85. void
  86. AnimatedSplitter::onResizeRequest( const QPoint& delta )
  87. {
  88. AnimatedWidget* w = (AnimatedWidget*)(sender());
  89. if ( indexOf( w ) > 0 )
  90. {
  91. int newheight = w->height() + delta.y();
  92. if ( newheight <= w->hiddenSize().height() )
  93. {
  94. w->hide();
  95. }
  96. else
  97. changeSize( w, QSize( w->width(), newheight ) );
  98. }
  99. else
  100. Q_ASSERT( false );
  101. }
  102. void
  103. AnimatedSplitter::onShowRequest()
  104. {
  105. AnimatedWidget* w = (AnimatedWidget*)(sender());
  106. if ( indexOf( w ) > 0 )
  107. show( indexOf( w ) );
  108. else
  109. Q_ASSERT( false );
  110. }
  111. void
  112. AnimatedSplitter::onHideRequest()
  113. {
  114. AnimatedWidget* w = (AnimatedWidget*)(sender());
  115. if ( indexOf( w ) > 0 )
  116. hide( indexOf( w ) );
  117. else
  118. Q_ASSERT( false );
  119. }
  120. void
  121. AnimatedSplitter::onSizeChanged( const QSize& size )
  122. {
  123. AnimatedWidget* w = (AnimatedWidget*)(sender());
  124. if ( indexOf( w ) > 0 )
  125. changeSize( w, size );
  126. else
  127. Q_ASSERT( false );
  128. }
  129. void
  130. AnimatedSplitter::setGreedyWidget( int index )
  131. {
  132. if( !widget( index ) )
  133. return;
  134. m_greedyIndex = index;
  135. QSizePolicy policy = widget( m_greedyIndex )->sizePolicy();
  136. if( orientation() == Qt::Horizontal )
  137. policy.setHorizontalStretch( 1 );
  138. else
  139. policy.setVerticalStretch( 1 );
  140. widget( m_greedyIndex )->setSizePolicy( policy );
  141. }
  142. QSplitterHandle*
  143. AnimatedSplitter::createHandle()
  144. {
  145. return new AnimatedSplitterHandle( orientation(), this );
  146. }
  147. AnimatedWidget::AnimatedWidget( AnimatedSplitter* parent )
  148. : m_parent( parent )
  149. , m_isHidden( false )
  150. {
  151. m_timeLine = new QTimeLine( ANIMATION_TIME, this );
  152. m_timeLine->setUpdateInterval( 20 );
  153. m_timeLine->setEasingCurve( QEasingCurve::OutCubic );
  154. connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) );
  155. connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) );
  156. }
  157. AnimatedWidget::~AnimatedWidget()
  158. {
  159. }
  160. void
  161. AnimatedWidget::onShown( QWidget* widget, bool animated )
  162. {
  163. if ( widget != this )
  164. return;
  165. m_animateForward = true;
  166. if ( animated )
  167. {
  168. if ( m_timeLine->state() == QTimeLine::Running )
  169. m_timeLine->stop();
  170. m_timeLine->setFrameRange( height(), sizeHint().height() );
  171. m_timeLine->setDirection( QTimeLine::Forward );
  172. m_timeLine->start();
  173. }
  174. else
  175. {
  176. onAnimationStep( sizeHint().height() );
  177. onAnimationFinished();
  178. }
  179. m_isHidden = false;
  180. }
  181. void
  182. AnimatedWidget::onHidden( QWidget* widget, bool animated )
  183. {
  184. if ( widget != this )
  185. return;
  186. m_animateForward = false;
  187. int minHeight = hiddenSize().height();
  188. if ( animated )
  189. {
  190. if ( m_timeLine->state() == QTimeLine::Running )
  191. m_timeLine->stop();
  192. m_timeLine->setFrameRange( minHeight, height() );
  193. m_timeLine->setDirection( QTimeLine::Backward );
  194. m_timeLine->start();
  195. }
  196. else
  197. {
  198. onAnimationStep( minHeight );
  199. onAnimationFinished();
  200. }
  201. m_isHidden = true;
  202. }
  203. void
  204. AnimatedWidget::onAnimationStep( int frame )
  205. {
  206. setFixedHeight( frame );
  207. QSize s( 0, frame ); //FIXME
  208. emit sizeChanged( s );
  209. }
  210. void
  211. AnimatedWidget::onAnimationFinished()
  212. {
  213. if ( m_animateForward )
  214. {
  215. setMinimumHeight( hiddenSize().height() );
  216. setMaximumHeight( QWIDGETSIZE_MAX );
  217. }
  218. else
  219. {
  220. setFixedHeight( hiddenSize().height() );
  221. }
  222. emit animationFinished();
  223. }
  224. QSize
  225. AnimatedSplitterHandle::sizeHint() const
  226. {
  227. // Re-calculate our position if the items in the splitter changed, or if we haven't calculated it yet
  228. if ( m_indexInSplitter == -1 || m_lastCount != splitter()->count() )
  229. {
  230. for ( int i = 0; i < splitter()->count(); i++ )
  231. {
  232. if ( splitter()->handle( i ) == this )
  233. {
  234. m_indexInSplitter = i;
  235. }
  236. }
  237. m_lastCount = splitter()->count();
  238. }
  239. // Since we are in an AnimatedSplitter, we always return 0,0 for SizeHint, simply
  240. // because we know there's going to be a handle in the bottom widget to move the
  241. // splitter.
  242. return QSize( 0, 0 );
  243. }