ctkBasePopupWidget.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QApplication>
  16. #include <QDebug>
  17. #include <QDesktopWidget>
  18. #include <QDir>
  19. #include <QEvent>
  20. #include <QLabel>
  21. #include <QLayout>
  22. #include <QMouseEvent>
  23. #include <QMoveEvent>
  24. #include <QPainter>
  25. #include <QPointer>
  26. #include <QPropertyAnimation>
  27. #include <QStyle>
  28. #include <QTimer>
  29. // CTK includes
  30. #include "ctkBasePopupWidget_p.h"
  31. #define DEFAULT_FADING_DURATION 333 // fast enough without being too slow
  32. // -------------------------------------------------------------------------
  33. QGradient* duplicateGradient(const QGradient* gradient)
  34. {
  35. QGradient* newGradient = 0;
  36. switch (gradient->type())
  37. {
  38. case QGradient::LinearGradient:
  39. {
  40. const QLinearGradient* linearGradient = static_cast<const QLinearGradient*>(gradient);
  41. newGradient = new QLinearGradient(linearGradient->start(), linearGradient->finalStop());
  42. break;
  43. }
  44. case QGradient::RadialGradient:
  45. {
  46. const QRadialGradient* radialGradient = static_cast<const QRadialGradient*>(gradient);
  47. newGradient = new QRadialGradient(radialGradient->center(), radialGradient->radius());
  48. break;
  49. }
  50. case QGradient::ConicalGradient:
  51. {
  52. const QConicalGradient* conicalGradient = static_cast<const QConicalGradient*>(gradient);
  53. newGradient = new QConicalGradient(conicalGradient->center(), conicalGradient->angle());
  54. break;
  55. }
  56. default:
  57. break;
  58. }
  59. if (!newGradient)
  60. {
  61. Q_ASSERT(gradient->type() != QGradient::NoGradient);
  62. return newGradient;
  63. }
  64. newGradient->setCoordinateMode(gradient->coordinateMode());
  65. newGradient->setSpread(gradient->spread());
  66. newGradient->setStops(gradient->stops());
  67. return newGradient;
  68. }
  69. // -------------------------------------------------------------------------
  70. ctkBasePopupWidgetPrivate::ctkBasePopupWidgetPrivate(ctkBasePopupWidget& object)
  71. :q_ptr(&object)
  72. {
  73. this->BaseWidget = 0;
  74. this->Effect = ctkBasePopupWidget::ScrollEffect;
  75. this->EffectAlpha = 1.;
  76. this->AlphaAnimation = 0;
  77. this->ForcedTranslucent = false;
  78. this->ScrollAnimation = 0;
  79. this->PopupPixmapWidget = 0;
  80. // Geometry attributes
  81. this->Alignment = Qt::AlignJustify | Qt::AlignBottom;
  82. this->Orientations = Qt::Vertical;
  83. this->VerticalDirection = ctkBasePopupWidget::TopToBottom;
  84. this->HorizontalDirection = Qt::LeftToRight;
  85. }
  86. // -------------------------------------------------------------------------
  87. ctkBasePopupWidgetPrivate::~ctkBasePopupWidgetPrivate()
  88. {
  89. delete this->PopupPixmapWidget;
  90. }
  91. // -------------------------------------------------------------------------
  92. void ctkBasePopupWidgetPrivate::init()
  93. {
  94. Q_Q(ctkBasePopupWidget);
  95. // By default, Tooltips are shown only on active windows. In a popup widget
  96. // case, we sometimes aren't the active window but we still would like to
  97. // show the children tooltips.
  98. q->setAttribute(Qt::WA_AlwaysShowToolTips, true);
  99. this->AlphaAnimation = new QPropertyAnimation(q, "effectAlpha", q);
  100. this->AlphaAnimation->setDuration(DEFAULT_FADING_DURATION);
  101. this->AlphaAnimation->setStartValue(0.);
  102. this->AlphaAnimation->setEndValue(1.);
  103. QObject::connect(this->AlphaAnimation, SIGNAL(finished()),
  104. q, SLOT(onEffectFinished()));
  105. this->PopupPixmapWidget = new QLabel(0, Qt::ToolTip | Qt::FramelessWindowHint);
  106. this->ScrollAnimation = new QPropertyAnimation(q, "effectGeometry", q);
  107. this->ScrollAnimation->setDuration(DEFAULT_FADING_DURATION);
  108. QObject::connect(this->ScrollAnimation, SIGNAL(finished()),
  109. q, SLOT(onEffectFinished()));
  110. QObject::connect(this->ScrollAnimation, SIGNAL(finished()),
  111. this->PopupPixmapWidget, SLOT(hide()));
  112. q->setAnimationEffect(this->Effect);
  113. q->setEasingCurve(QEasingCurve::OutCubic);
  114. }
  115. // -------------------------------------------------------------------------
  116. QPropertyAnimation* ctkBasePopupWidgetPrivate::currentAnimation()const
  117. {
  118. return this->Effect == ctkBasePopupWidget::ScrollEffect ?
  119. this->ScrollAnimation : this->AlphaAnimation;
  120. }
  121. // -------------------------------------------------------------------------
  122. bool ctkBasePopupWidgetPrivate::isOpening()const
  123. {
  124. return this->currentAnimation()->state() == QAbstractAnimation::Running &&
  125. this->currentAnimation()->direction() == QAbstractAnimation::Forward;
  126. }
  127. // -------------------------------------------------------------------------
  128. bool ctkBasePopupWidgetPrivate::isClosing()const
  129. {
  130. return this->currentAnimation()->state() == QAbstractAnimation::Running &&
  131. this->currentAnimation()->direction() == QAbstractAnimation::Backward;
  132. }
  133. // -------------------------------------------------------------------------
  134. bool ctkBasePopupWidgetPrivate::wasClosing()const
  135. {
  136. Q_Q(const ctkBasePopupWidget);
  137. return qobject_cast<QAbstractAnimation*>(q->sender())->direction()
  138. == QAbstractAnimation::Backward;
  139. }
  140. // -------------------------------------------------------------------------
  141. QWidgetList ctkBasePopupWidgetPrivate::focusWidgets(bool onlyVisible)const
  142. {
  143. Q_Q(const ctkBasePopupWidget);
  144. QWidgetList res;
  145. if (!onlyVisible || q->isVisible())
  146. {
  147. res << const_cast<ctkBasePopupWidget*>(q);
  148. }
  149. if (this->BaseWidget && (!onlyVisible || this->BaseWidget->isVisible()))
  150. {
  151. res << this->BaseWidget;
  152. }
  153. if (this->PopupPixmapWidget && (!onlyVisible || this->PopupPixmapWidget->isVisible()))
  154. {
  155. res << this->PopupPixmapWidget;
  156. }
  157. return res;
  158. }
  159. // -------------------------------------------------------------------------
  160. QWidget* ctkBasePopupWidgetPrivate::mouseOver()
  161. {
  162. QList<QWidget*> widgets = this->focusWidgets(true);
  163. foreach(QWidget* widget, widgets)
  164. {
  165. if (widget->underMouse())
  166. {
  167. return widget;
  168. }
  169. }
  170. // Warning QApplication::widgetAt(QCursor::pos()) can be a bit slow...
  171. const QPoint pos = QCursor::pos();
  172. QWidget* widgetUnderCursor = qApp->widgetAt(pos);
  173. foreach(const QWidget* focusWidget, widgets)
  174. {
  175. if (this->isAncestorOf(focusWidget, widgetUnderCursor) &&
  176. // Ignore when cursor is above a title bar of a focusWidget, underMouse
  177. // wouldn't have return false, but QApplication::widgetAt would return
  178. // the widget
  179. (focusWidget != widgetUnderCursor ||
  180. QRect(QPoint(0,0), focusWidget->size()).contains(
  181. focusWidget->mapFromGlobal(pos))))
  182. {
  183. return widgetUnderCursor;
  184. }
  185. }
  186. return 0;
  187. }
  188. // -------------------------------------------------------------------------
  189. bool ctkBasePopupWidgetPrivate::isAncestorOf(const QWidget* ancestor, const QWidget* child)const
  190. {
  191. while (child)
  192. {
  193. if (child == ancestor)
  194. return true;
  195. child = child->parentWidget();
  196. }
  197. return false;
  198. }
  199. // -------------------------------------------------------------------------
  200. void ctkBasePopupWidgetPrivate::setupPopupPixmapWidget()
  201. {
  202. Q_Q(ctkBasePopupWidget);
  203. this->PopupPixmapWidget->setAlignment(this->pixmapAlignment());
  204. QPixmap pixmap;
  205. if (q->testAttribute(Qt::WA_TranslucentBackground))
  206. {
  207. // only QImage handle transparency correctly
  208. QImage image(q->geometry().size(), QImage::Format_ARGB32);
  209. image.fill(0);
  210. q->render(&image);
  211. pixmap = QPixmap::fromImage(image);
  212. }
  213. else
  214. {
  215. pixmap = QPixmap::grabWidget(q, QRect(QPoint(0,0), q->geometry().size()));
  216. }
  217. this->PopupPixmapWidget->setPixmap(pixmap);
  218. this->PopupPixmapWidget->setAttribute(
  219. Qt::WA_TranslucentBackground, q->testAttribute(Qt::WA_TranslucentBackground));
  220. this->PopupPixmapWidget->setWindowOpacity(q->windowOpacity());
  221. }
  222. // -------------------------------------------------------------------------
  223. Qt::Alignment ctkBasePopupWidgetPrivate::pixmapAlignment()const
  224. {
  225. Qt::Alignment alignment;
  226. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  227. {
  228. alignment |= Qt::AlignBottom;
  229. }
  230. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  231. {
  232. alignment |= Qt::AlignTop;
  233. }
  234. if (this->HorizontalDirection == Qt::LeftToRight)
  235. {
  236. alignment |= Qt::AlignRight;
  237. }
  238. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  239. {
  240. alignment |= Qt::AlignLeft;
  241. }
  242. return alignment;
  243. }
  244. // -------------------------------------------------------------------------
  245. QRect ctkBasePopupWidgetPrivate::closedGeometry()const
  246. {
  247. Q_Q(const ctkBasePopupWidget);
  248. return this->closedGeometry(q->geometry());
  249. }
  250. // -------------------------------------------------------------------------
  251. QRect ctkBasePopupWidgetPrivate::closedGeometry(QRect openGeom)const
  252. {
  253. if (this->Orientations & Qt::Vertical)
  254. {
  255. if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  256. {
  257. openGeom.moveTop(openGeom.bottom());
  258. }
  259. openGeom.setHeight(0);
  260. }
  261. if (this->Orientations & Qt::Horizontal)
  262. {
  263. if (this->HorizontalDirection == Qt::RightToLeft)
  264. {
  265. openGeom.moveLeft(openGeom.right());
  266. }
  267. openGeom.setWidth(0);
  268. }
  269. return openGeom;
  270. }
  271. // -------------------------------------------------------------------------
  272. QRect ctkBasePopupWidgetPrivate::baseGeometry()const
  273. {
  274. if (!this->BaseWidget)
  275. {
  276. return QRect();
  277. }
  278. return QRect(this->mapToGlobal(this->BaseWidget->geometry().topLeft()),
  279. this->BaseWidget->size());
  280. }
  281. // -------------------------------------------------------------------------
  282. QPoint ctkBasePopupWidgetPrivate::mapToGlobal(const QPoint& baseWidgetPoint)const
  283. {
  284. QPoint mappedPoint = baseWidgetPoint;
  285. if (this->BaseWidget && this->BaseWidget->parentWidget())
  286. {
  287. mappedPoint = this->BaseWidget->parentWidget()->mapToGlobal(mappedPoint);
  288. }
  289. return mappedPoint;
  290. }
  291. // -------------------------------------------------------------------------
  292. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry()const
  293. {
  294. return this->desiredOpenGeometry(this->baseGeometry());
  295. }
  296. // -------------------------------------------------------------------------
  297. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry(QRect baseGeometry)const
  298. {
  299. Q_Q(const ctkBasePopupWidget);
  300. QSize size = q->size();
  301. if (!q->testAttribute(Qt::WA_WState_Created))
  302. {
  303. size = q->sizeHint();
  304. }
  305. if (baseGeometry.isNull())
  306. {
  307. return QRect(q->pos(), size);
  308. }
  309. QRect geometry;
  310. if (this->Alignment & Qt::AlignJustify)
  311. {
  312. if (this->Orientations & Qt::Vertical)
  313. {
  314. size.setWidth(baseGeometry.width());
  315. }
  316. }
  317. if (this->Alignment & Qt::AlignTop &&
  318. this->Alignment & Qt::AlignBottom)
  319. {
  320. size.setHeight(baseGeometry.height());
  321. }
  322. geometry.setSize(size);
  323. QPoint topLeft = baseGeometry.topLeft();
  324. QPoint bottomRight = baseGeometry.bottomRight();
  325. if (this->Alignment & Qt::AlignLeft)
  326. {
  327. if (this->HorizontalDirection == Qt::LeftToRight)
  328. {
  329. geometry.moveLeft(topLeft.x());
  330. }
  331. else
  332. {
  333. geometry.moveRight(topLeft.x());
  334. }
  335. }
  336. else if (this->Alignment & Qt::AlignRight)
  337. {
  338. if (this->HorizontalDirection == Qt::LeftToRight)
  339. {
  340. geometry.moveLeft(bottomRight.x());
  341. }
  342. else
  343. {
  344. geometry.moveRight(bottomRight.x());
  345. }
  346. }
  347. else if (this->Alignment & Qt::AlignHCenter)
  348. {
  349. geometry.moveLeft((topLeft.x() + bottomRight.x()) / 2 - size.width() / 2);
  350. }
  351. else if (this->Alignment & Qt::AlignJustify)
  352. {
  353. geometry.moveLeft(topLeft.x());
  354. }
  355. if (this->Alignment & Qt::AlignTop)
  356. {
  357. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  358. {
  359. geometry.moveTop(topLeft.y());
  360. }
  361. else
  362. {
  363. geometry.moveBottom(topLeft.y());
  364. }
  365. }
  366. else if (this->Alignment & Qt::AlignBottom)
  367. {
  368. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  369. {
  370. geometry.moveTop(bottomRight.y());
  371. }
  372. else
  373. {
  374. geometry.moveBottom(bottomRight.y());
  375. }
  376. }
  377. else if (this->Alignment & Qt::AlignVCenter)
  378. {
  379. geometry.moveTop((topLeft.y() + bottomRight.y()) / 2 - size.height() / 2);
  380. }
  381. return geometry;
  382. }
  383. // -------------------------------------------------------------------------
  384. void ctkBasePopupWidgetPrivate::hideAll()
  385. {
  386. Q_Q(ctkBasePopupWidget);
  387. // It is possible to have the popup widget not being a popup but inside
  388. // a layout: maybe the popup has been pin-down in a way that it gets parented
  389. // In that case, there is no reason to hide the popup.
  390. if (q->parentWidget() != 0)
  391. {
  392. return;
  393. }
  394. // Before hiding, transfer the active window flag to its parent, this will
  395. // prevent the application to send a ApplicationDeactivate signal that
  396. // doesn't need to be done.
  397. if (q->isActiveWindow() && this->BaseWidget)
  398. {
  399. qApp->setActiveWindow(this->BaseWidget->window());
  400. }
  401. q->hide();
  402. this->PopupPixmapWidget->hide();
  403. // If there is a popup open in the ctkBasePopupWidget children, then hide it
  404. // as well so we don't have a popup open while the ctkBasePopupWidget is hidden.
  405. QPointer<QWidget> activePopupWidget = qApp->activePopupWidget();
  406. if (activePopupWidget && this->isAncestorOf(q, activePopupWidget))
  407. {
  408. activePopupWidget->close();
  409. }
  410. }
  411. // -------------------------------------------------------------------------
  412. // Qt::FramelessWindowHint is required on Windows for Translucent background
  413. // Qt::Toolip is preferred to Qt::Popup as it would close itself at the first
  414. // click outside the widget (typically a click in the BaseWidget)
  415. ctkBasePopupWidget::ctkBasePopupWidget(QWidget* parentWidget)
  416. : Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  417. Qt::ToolTip | Qt::FramelessWindowHint)
  418. , d_ptr(new ctkBasePopupWidgetPrivate(*this))
  419. {
  420. Q_D(ctkBasePopupWidget);
  421. d->init();
  422. }
  423. // -------------------------------------------------------------------------
  424. ctkBasePopupWidget::ctkBasePopupWidget(ctkBasePopupWidgetPrivate* pimpl, QWidget* parentWidget)
  425. : Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  426. Qt::ToolTip | Qt::FramelessWindowHint)
  427. , d_ptr(pimpl)
  428. {
  429. }
  430. // -------------------------------------------------------------------------
  431. ctkBasePopupWidget::~ctkBasePopupWidget()
  432. {
  433. }
  434. // -------------------------------------------------------------------------
  435. QWidget* ctkBasePopupWidget::baseWidget()const
  436. {
  437. Q_D(const ctkBasePopupWidget);
  438. return d->BaseWidget;
  439. }
  440. // -------------------------------------------------------------------------
  441. void ctkBasePopupWidget::setBaseWidget(QWidget* widget)
  442. {
  443. Q_D(ctkBasePopupWidget);
  444. if (d->BaseWidget)
  445. {
  446. disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  447. this, SLOT(onBaseWidgetDestroyed()));
  448. }
  449. d->BaseWidget = widget;
  450. if (d->BaseWidget)
  451. {
  452. connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  453. this, SLOT(onBaseWidgetDestroyed()));
  454. }
  455. }
  456. // -------------------------------------------------------------------------
  457. void ctkBasePopupWidget::onBaseWidgetDestroyed()
  458. {
  459. Q_D(ctkBasePopupWidget);
  460. d->hideAll();
  461. this->setBaseWidget(0);
  462. // could be a property.
  463. this->deleteLater();
  464. }
  465. // -------------------------------------------------------------------------
  466. ctkBasePopupWidget::AnimationEffect ctkBasePopupWidget::animationEffect()const
  467. {
  468. Q_D(const ctkBasePopupWidget);
  469. return d->Effect;
  470. }
  471. // -------------------------------------------------------------------------
  472. void ctkBasePopupWidget::setAnimationEffect(ctkBasePopupWidget::AnimationEffect effect)
  473. {
  474. Q_D(ctkBasePopupWidget);
  475. /// TODO: handle the case where there is an animation running
  476. d->Effect = effect;
  477. }
  478. // -------------------------------------------------------------------------
  479. QEasingCurve::Type ctkBasePopupWidget::easingCurve()const
  480. {
  481. Q_D(const ctkBasePopupWidget);
  482. return d->AlphaAnimation->easingCurve().type();
  483. }
  484. // -------------------------------------------------------------------------
  485. void ctkBasePopupWidget::setEasingCurve(QEasingCurve::Type easingCurve)
  486. {
  487. Q_D(ctkBasePopupWidget);
  488. d->AlphaAnimation->setEasingCurve(easingCurve);
  489. d->ScrollAnimation->setEasingCurve(easingCurve);
  490. }
  491. // -------------------------------------------------------------------------
  492. Qt::Alignment ctkBasePopupWidget::alignment()const
  493. {
  494. Q_D(const ctkBasePopupWidget);
  495. return d->Alignment;
  496. }
  497. // -------------------------------------------------------------------------
  498. void ctkBasePopupWidget::setAlignment(Qt::Alignment alignment)
  499. {
  500. Q_D(ctkBasePopupWidget);
  501. d->Alignment = alignment;
  502. }
  503. // -------------------------------------------------------------------------
  504. Qt::Orientations ctkBasePopupWidget::orientation()const
  505. {
  506. Q_D(const ctkBasePopupWidget);
  507. return d->Orientations;
  508. }
  509. // -------------------------------------------------------------------------
  510. void ctkBasePopupWidget::setOrientation(Qt::Orientations orientations)
  511. {
  512. Q_D(ctkBasePopupWidget);
  513. d->Orientations = orientations;
  514. }
  515. // -------------------------------------------------------------------------
  516. ctkBasePopupWidget::VerticalDirection ctkBasePopupWidget::verticalDirection()const
  517. {
  518. Q_D(const ctkBasePopupWidget);
  519. return d->VerticalDirection;
  520. }
  521. // -------------------------------------------------------------------------
  522. void ctkBasePopupWidget::setVerticalDirection(ctkBasePopupWidget::VerticalDirection verticalDirection)
  523. {
  524. Q_D(ctkBasePopupWidget);
  525. d->VerticalDirection = verticalDirection;
  526. }
  527. // -------------------------------------------------------------------------
  528. Qt::LayoutDirection ctkBasePopupWidget::horizontalDirection()const
  529. {
  530. Q_D(const ctkBasePopupWidget);
  531. return d->HorizontalDirection;
  532. }
  533. // -------------------------------------------------------------------------
  534. void ctkBasePopupWidget::setHorizontalDirection(Qt::LayoutDirection horizontalDirection)
  535. {
  536. Q_D(ctkBasePopupWidget);
  537. d->HorizontalDirection = horizontalDirection;
  538. }
  539. // -------------------------------------------------------------------------
  540. void ctkBasePopupWidget::onEffectFinished()
  541. {
  542. Q_D(ctkBasePopupWidget);
  543. if (d->ForcedTranslucent)
  544. {
  545. d->ForcedTranslucent = false;
  546. this->setAttribute(Qt::WA_TranslucentBackground, false);
  547. }
  548. if (d->wasClosing())
  549. {
  550. d->hideAll();
  551. emit this->popupOpened(false);
  552. }
  553. else
  554. {
  555. this->show();
  556. emit this->popupOpened(true);
  557. }
  558. }
  559. // -------------------------------------------------------------------------
  560. void ctkBasePopupWidget::paintEvent(QPaintEvent* event)
  561. {
  562. Q_D(ctkBasePopupWidget);
  563. Q_UNUSED(event);
  564. QPainter painter(this);
  565. QBrush brush = this->palette().window();
  566. if (brush.style() == Qt::LinearGradientPattern ||
  567. brush.style() == Qt::ConicalGradientPattern ||
  568. brush.style() == Qt::RadialGradientPattern)
  569. {
  570. QGradient* newGradient = duplicateGradient(brush.gradient());
  571. QGradientStops stops;
  572. foreach(QGradientStop stop, newGradient->stops())
  573. {
  574. stop.second.setAlpha(stop.second.alpha() * d->EffectAlpha);
  575. stops.push_back(stop);
  576. }
  577. newGradient->setStops(stops);
  578. brush = QBrush(*newGradient);
  579. delete newGradient;
  580. }
  581. else
  582. {
  583. QColor color = brush.color();
  584. color.setAlpha(color.alpha() * d->EffectAlpha);
  585. brush.setColor(color);
  586. }
  587. //QColor semiTransparentColor = this->palette().window().color();
  588. //semiTransparentColor.setAlpha(d->CurrentAlpha);
  589. painter.fillRect(this->rect(), brush);
  590. painter.end();
  591. // Let the QFrame draw itself if needed
  592. this->Superclass::paintEvent(event);
  593. }
  594. // --------------------------------------------------------------------------
  595. void ctkBasePopupWidget::showPopup()
  596. {
  597. Q_D(ctkBasePopupWidget);
  598. if ((this->isVisible() &&
  599. d->currentAnimation()->state() == QAbstractAnimation::Stopped) ||
  600. (d->BaseWidget && !d->BaseWidget->isVisible()))
  601. {
  602. return;
  603. }
  604. // If the layout has never been activated, the widget doesn't know its
  605. // minSize/maxSize and we then wouldn't know what's its true geometry.
  606. if (this->layout() && !this->testAttribute(Qt::WA_WState_Created))
  607. {
  608. this->layout()->activate();
  609. }
  610. this->setGeometry(d->desiredOpenGeometry());
  611. /// Maybe the popup doesn't allow the desiredOpenGeometry if the widget
  612. /// minimum size is larger than the desired size.
  613. QRect openGeometry = this->geometry();
  614. QRect closedGeometry = d->closedGeometry();
  615. d->currentAnimation()->setDirection(QAbstractAnimation::Forward);
  616. switch(d->Effect)
  617. {
  618. case WindowOpacityFadeEffect:
  619. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  620. {
  621. d->ForcedTranslucent = true;
  622. this->setAttribute(Qt::WA_TranslucentBackground, true);
  623. }
  624. this->show();
  625. break;
  626. case ScrollEffect:
  627. {
  628. d->PopupPixmapWidget->setGeometry(closedGeometry);
  629. d->ScrollAnimation->setStartValue(closedGeometry);
  630. d->ScrollAnimation->setEndValue(openGeometry);
  631. d->setupPopupPixmapWidget();
  632. d->PopupPixmapWidget->show();
  633. break;
  634. }
  635. default:
  636. break;
  637. }
  638. switch(d->currentAnimation()->state())
  639. {
  640. case QAbstractAnimation::Stopped:
  641. d->currentAnimation()->start();
  642. break;
  643. case QAbstractAnimation::Paused:
  644. d->currentAnimation()->resume();
  645. break;
  646. default:
  647. case QAbstractAnimation::Running:
  648. break;
  649. }
  650. }
  651. // --------------------------------------------------------------------------
  652. void ctkBasePopupWidget::hidePopup()
  653. {
  654. Q_D(ctkBasePopupWidget);
  655. if (!this->isVisible() &&
  656. d->currentAnimation()->state() == QAbstractAnimation::Stopped)
  657. {
  658. return;
  659. }
  660. d->currentAnimation()->setDirection(QAbstractAnimation::Backward);
  661. QRect openGeometry = this->geometry();
  662. QRect closedGeometry = d->closedGeometry();
  663. switch(d->Effect)
  664. {
  665. case WindowOpacityFadeEffect:
  666. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  667. {
  668. d->ForcedTranslucent = true;
  669. this->setAttribute(Qt::WA_TranslucentBackground, true);
  670. }
  671. break;
  672. case ScrollEffect:
  673. {
  674. d->ScrollAnimation->setStartValue(closedGeometry);
  675. d->ScrollAnimation->setEndValue(openGeometry);
  676. d->setupPopupPixmapWidget();
  677. d->PopupPixmapWidget->setGeometry(this->geometry());
  678. d->PopupPixmapWidget->show();
  679. if (this->isActiveWindow())
  680. {
  681. qApp->setActiveWindow(d->BaseWidget ? d->BaseWidget->window() : 0);
  682. }
  683. this->hide();
  684. break;
  685. }
  686. default:
  687. break;
  688. }
  689. switch(d->currentAnimation()->state())
  690. {
  691. case QAbstractAnimation::Stopped:
  692. d->currentAnimation()->start();
  693. break;
  694. case QAbstractAnimation::Paused:
  695. d->currentAnimation()->resume();
  696. break;
  697. default:
  698. case QAbstractAnimation::Running:
  699. break;
  700. }
  701. }
  702. // --------------------------------------------------------------------------
  703. double ctkBasePopupWidget::effectAlpha()const
  704. {
  705. Q_D(const ctkBasePopupWidget);
  706. return d->EffectAlpha;
  707. }
  708. // --------------------------------------------------------------------------
  709. void ctkBasePopupWidget::setEffectAlpha(double alpha)
  710. {
  711. Q_D(ctkBasePopupWidget);
  712. d->EffectAlpha = alpha;
  713. this->repaint();
  714. }
  715. // --------------------------------------------------------------------------
  716. QRect ctkBasePopupWidget::effectGeometry()const
  717. {
  718. Q_D(const ctkBasePopupWidget);
  719. return d->PopupPixmapWidget->geometry();
  720. }
  721. // --------------------------------------------------------------------------
  722. void ctkBasePopupWidget::setEffectGeometry(QRect newGeometry)
  723. {
  724. Q_D(ctkBasePopupWidget);
  725. d->PopupPixmapWidget->setGeometry(newGeometry);
  726. d->PopupPixmapWidget->repaint();
  727. }