ctkBasePopupWidget.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  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. #include "ctkWidgetsUtils.h"
  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->Effect = ctkBasePopupWidget::ScrollEffect;
  74. this->EffectDuration = 333; // in ms
  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. }
  90. // -------------------------------------------------------------------------
  91. void ctkBasePopupWidgetPrivate::init()
  92. {
  93. Q_Q(ctkBasePopupWidget);
  94. // By default, Tooltips are shown only on active windows. In a popup widget
  95. // case, we sometimes aren't the active window but we still would like to
  96. // show the children tooltips.
  97. q->setAttribute(Qt::WA_AlwaysShowToolTips, true);
  98. //q->setAttribute(Qt::WA_MacAlwaysShowToolWindow, true);
  99. this->AlphaAnimation = new QPropertyAnimation(q, "effectAlpha", q);
  100. this->AlphaAnimation->setDuration(this->EffectDuration);
  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(q, Qt::ToolTip | Qt::FramelessWindowHint);
  106. this->ScrollAnimation = new QPropertyAnimation(q, "effectGeometry", q);
  107. this->ScrollAnimation->setDuration(this->EffectDuration);
  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. q->setBaseWidget(q->parentWidget());
  115. }
  116. // -------------------------------------------------------------------------
  117. QPropertyAnimation* ctkBasePopupWidgetPrivate::currentAnimation()const
  118. {
  119. return this->Effect == ctkBasePopupWidget::ScrollEffect ?
  120. this->ScrollAnimation : this->AlphaAnimation;
  121. }
  122. // -------------------------------------------------------------------------
  123. bool ctkBasePopupWidgetPrivate::isOpening()const
  124. {
  125. return this->currentAnimation()->state() == QAbstractAnimation::Running &&
  126. this->currentAnimation()->direction() == QAbstractAnimation::Forward;
  127. }
  128. // -------------------------------------------------------------------------
  129. bool ctkBasePopupWidgetPrivate::isClosing()const
  130. {
  131. return this->currentAnimation()->state() == QAbstractAnimation::Running &&
  132. this->currentAnimation()->direction() == QAbstractAnimation::Backward;
  133. }
  134. // -------------------------------------------------------------------------
  135. bool ctkBasePopupWidgetPrivate::wasClosing()const
  136. {
  137. Q_Q(const ctkBasePopupWidget);
  138. return qobject_cast<QAbstractAnimation*>(q->sender())->direction()
  139. == QAbstractAnimation::Backward;
  140. }
  141. // -------------------------------------------------------------------------
  142. QWidgetList ctkBasePopupWidgetPrivate::focusWidgets(bool onlyVisible)const
  143. {
  144. Q_Q(const ctkBasePopupWidget);
  145. QWidgetList res;
  146. if (!onlyVisible || q->isVisible())
  147. {
  148. res << const_cast<ctkBasePopupWidget*>(q);
  149. }
  150. if (!this->BaseWidget.isNull() && (!onlyVisible || this->BaseWidget->isVisible()))
  151. {
  152. res << this->BaseWidget;
  153. }
  154. if (this->PopupPixmapWidget && (!onlyVisible || this->PopupPixmapWidget->isVisible()))
  155. {
  156. res << this->PopupPixmapWidget;
  157. }
  158. return res;
  159. }
  160. // -------------------------------------------------------------------------
  161. QWidget* ctkBasePopupWidgetPrivate::mouseOver()
  162. {
  163. QList<QWidget*> widgets = this->focusWidgets(true);
  164. foreach(QWidget* widget, widgets)
  165. {
  166. if (widget->underMouse())
  167. {
  168. return widget;
  169. }
  170. }
  171. // Warning QApplication::widgetAt(QCursor::pos()) can be a bit slow...
  172. const QPoint pos = QCursor::pos();
  173. QWidget* widgetUnderCursor = qApp->widgetAt(pos);
  174. foreach(const QWidget* focusWidget, widgets)
  175. {
  176. if (this->isAncestorOf(focusWidget, widgetUnderCursor) &&
  177. // Ignore when cursor is above a title bar of a focusWidget, underMouse
  178. // wouldn't have return false, but QApplication::widgetAt would return
  179. // the widget
  180. (focusWidget != widgetUnderCursor ||
  181. QRect(QPoint(0,0), focusWidget->size()).contains(
  182. focusWidget->mapFromGlobal(pos))))
  183. {
  184. return widgetUnderCursor;
  185. }
  186. }
  187. return 0;
  188. }
  189. // -------------------------------------------------------------------------
  190. bool ctkBasePopupWidgetPrivate::isAncestorOf(const QWidget* ancestor, const QWidget* child)const
  191. {
  192. while (child)
  193. {
  194. if (child == ancestor)
  195. {
  196. return true;
  197. }
  198. child = child->parentWidget();
  199. }
  200. return false;
  201. }
  202. // -------------------------------------------------------------------------
  203. void ctkBasePopupWidgetPrivate::setupPopupPixmapWidget()
  204. {
  205. Q_Q(ctkBasePopupWidget);
  206. this->PopupPixmapWidget->setAlignment(this->pixmapAlignment());
  207. QPixmap pixmap;
  208. if (q->testAttribute(Qt::WA_TranslucentBackground))
  209. {
  210. // only QImage handle transparency correctly
  211. QImage image(q->geometry().size(), QImage::Format_ARGB32);
  212. image.fill(0);
  213. q->render(&image);
  214. pixmap = QPixmap::fromImage(image);
  215. }
  216. else
  217. {
  218. pixmap = QPixmap::fromImage(
  219. ctk::grabWidget(q, QRect(QPoint(0,0), q->geometry().size())));
  220. }
  221. this->PopupPixmapWidget->setPixmap(pixmap);
  222. this->PopupPixmapWidget->setAttribute(
  223. Qt::WA_TranslucentBackground, q->testAttribute(Qt::WA_TranslucentBackground));
  224. this->PopupPixmapWidget->setWindowOpacity(q->windowOpacity());
  225. }
  226. // -------------------------------------------------------------------------
  227. Qt::Alignment ctkBasePopupWidgetPrivate::pixmapAlignment()const
  228. {
  229. Qt::Alignment alignment;
  230. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  231. {
  232. alignment |= Qt::AlignBottom;
  233. }
  234. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  235. {
  236. alignment |= Qt::AlignTop;
  237. }
  238. if (this->HorizontalDirection == Qt::LeftToRight)
  239. {
  240. alignment |= Qt::AlignRight;
  241. }
  242. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  243. {
  244. alignment |= Qt::AlignLeft;
  245. }
  246. return alignment;
  247. }
  248. // -------------------------------------------------------------------------
  249. QRect ctkBasePopupWidgetPrivate::closedGeometry()const
  250. {
  251. Q_Q(const ctkBasePopupWidget);
  252. return this->closedGeometry(q->geometry());
  253. }
  254. // -------------------------------------------------------------------------
  255. QRect ctkBasePopupWidgetPrivate::closedGeometry(QRect openGeom)const
  256. {
  257. if (this->Orientations & Qt::Vertical)
  258. {
  259. if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  260. {
  261. openGeom.moveTop(openGeom.bottom());
  262. }
  263. openGeom.setHeight(0);
  264. }
  265. if (this->Orientations & Qt::Horizontal)
  266. {
  267. if (this->HorizontalDirection == Qt::RightToLeft)
  268. {
  269. openGeom.moveLeft(openGeom.right());
  270. }
  271. openGeom.setWidth(0);
  272. }
  273. return openGeom;
  274. }
  275. // -------------------------------------------------------------------------
  276. QRect ctkBasePopupWidgetPrivate::baseGeometry()const
  277. {
  278. if (this->BaseWidget.isNull())
  279. {
  280. return QRect();
  281. }
  282. return QRect(this->mapToGlobal(this->BaseWidget->geometry().topLeft()),
  283. this->BaseWidget->size());
  284. }
  285. // -------------------------------------------------------------------------
  286. QPoint ctkBasePopupWidgetPrivate::mapToGlobal(const QPoint& baseWidgetPoint)const
  287. {
  288. QPoint mappedPoint = baseWidgetPoint;
  289. if (!this->BaseWidget.isNull() && this->BaseWidget->parentWidget())
  290. {
  291. mappedPoint = this->BaseWidget->parentWidget()->mapToGlobal(mappedPoint);
  292. }
  293. return mappedPoint;
  294. }
  295. // -------------------------------------------------------------------------
  296. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry()const
  297. {
  298. return this->desiredOpenGeometry(this->baseGeometry());
  299. }
  300. // -------------------------------------------------------------------------
  301. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry(QRect baseGeometry)const
  302. {
  303. Q_Q(const ctkBasePopupWidget);
  304. QSize size = q->size();
  305. if (!q->testAttribute(Qt::WA_WState_Created))
  306. {
  307. size = q->sizeHint();
  308. }
  309. if (baseGeometry.isNull())
  310. {
  311. return QRect(q->pos(), size);
  312. }
  313. QRect geometry;
  314. if (this->Alignment & Qt::AlignJustify)
  315. {
  316. if (this->Orientations & Qt::Vertical)
  317. {
  318. size.setWidth(baseGeometry.width());
  319. }
  320. }
  321. if (this->Alignment & Qt::AlignTop &&
  322. this->Alignment & Qt::AlignBottom)
  323. {
  324. size.setHeight(baseGeometry.height());
  325. }
  326. geometry.setSize(size);
  327. QPoint topLeft = baseGeometry.topLeft();
  328. QPoint bottomRight = baseGeometry.bottomRight();
  329. if (this->Alignment & Qt::AlignLeft)
  330. {
  331. if (this->HorizontalDirection == Qt::LeftToRight)
  332. {
  333. geometry.moveLeft(topLeft.x());
  334. }
  335. else
  336. {
  337. geometry.moveRight(topLeft.x() - 1);
  338. }
  339. }
  340. else if (this->Alignment & Qt::AlignRight)
  341. {
  342. if (this->HorizontalDirection == Qt::LeftToRight)
  343. {
  344. geometry.moveLeft(bottomRight.x() + 1);
  345. }
  346. else
  347. {
  348. geometry.moveRight(bottomRight.x());
  349. }
  350. }
  351. else if (this->Alignment & Qt::AlignHCenter)
  352. {
  353. geometry.moveLeft((topLeft.x() + bottomRight.x()) / 2 - size.width() / 2);
  354. }
  355. else if (this->Alignment & Qt::AlignJustify)
  356. {
  357. geometry.moveLeft(topLeft.x());
  358. }
  359. if (this->Alignment & Qt::AlignTop)
  360. {
  361. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  362. {
  363. geometry.moveTop(topLeft.y());
  364. }
  365. else
  366. {
  367. geometry.moveBottom(topLeft.y() - 1);
  368. }
  369. }
  370. else if (this->Alignment & Qt::AlignBottom)
  371. {
  372. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  373. {
  374. geometry.moveTop(bottomRight.y() + 1);
  375. }
  376. else
  377. {
  378. geometry.moveBottom(bottomRight.y());
  379. }
  380. }
  381. else if (this->Alignment & Qt::AlignVCenter)
  382. {
  383. geometry.moveTop((topLeft.y() + bottomRight.y()) / 2 - size.height() / 2);
  384. }
  385. return geometry;
  386. }
  387. // -------------------------------------------------------------------------
  388. void ctkBasePopupWidgetPrivate::hideAll()
  389. {
  390. Q_Q(ctkBasePopupWidget);
  391. // It is possible to have the popup widget not being a popup but inside
  392. // a layout: maybe the popup has been pin-down in a way that it gets parented
  393. // In that case, there is no reason to hide the popup.
  394. if (!(q->windowFlags() & PopupWindowType))
  395. {
  396. return;
  397. }
  398. // Before hiding, transfer the active window flag to its parent, this will
  399. // prevent the application to send a ApplicationDeactivate signal that
  400. // doesn't need to be done.
  401. #ifndef Q_OS_MAC // See Slicer issue #3850
  402. if (q->isActiveWindow() && !this->BaseWidget.isNull())
  403. {
  404. qApp->setActiveWindow(this->BaseWidget->window());
  405. }
  406. #endif
  407. q->hide();
  408. this->PopupPixmapWidget->hide();
  409. // If there is a popup open in the ctkBasePopupWidget children, then hide it
  410. // as well so we don't have a popup open while the ctkBasePopupWidget is hidden.
  411. QPointer<QWidget> activePopupWidget = qApp->activePopupWidget();
  412. if (activePopupWidget && this->isAncestorOf(q, activePopupWidget))
  413. {
  414. activePopupWidget->close();
  415. }
  416. }
  417. // -------------------------------------------------------------------------
  418. // Qt::FramelessWindowHint is required on Windows for Translucent background
  419. // Qt::Toolip is preferred to Qt::Popup as it would close itself at the first
  420. // click outside the widget (typically a click in the BaseWidget)
  421. ctkBasePopupWidget::ctkBasePopupWidget(QWidget* parentWidget)
  422. //: Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  423. : Superclass(parentWidget,
  424. PopupWindowType | Qt::FramelessWindowHint)
  425. , d_ptr(new ctkBasePopupWidgetPrivate(*this))
  426. {
  427. Q_D(ctkBasePopupWidget);
  428. d->init();
  429. }
  430. // -------------------------------------------------------------------------
  431. ctkBasePopupWidget::ctkBasePopupWidget(ctkBasePopupWidgetPrivate* pimpl, QWidget* parentWidget)
  432. //: //Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  433. : Superclass(parentWidget,
  434. PopupWindowType | Qt::FramelessWindowHint)
  435. , d_ptr(pimpl)
  436. {
  437. }
  438. // -------------------------------------------------------------------------
  439. ctkBasePopupWidget::~ctkBasePopupWidget()
  440. {
  441. }
  442. // -------------------------------------------------------------------------
  443. QWidget* ctkBasePopupWidget::baseWidget()const
  444. {
  445. Q_D(const ctkBasePopupWidget);
  446. return d->BaseWidget;
  447. }
  448. // -------------------------------------------------------------------------
  449. void ctkBasePopupWidget::setBaseWidget(QWidget* widget)
  450. {
  451. Q_D(ctkBasePopupWidget);
  452. if (!d->BaseWidget.isNull())
  453. {
  454. //disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  455. // this, SLOT(onBaseWidgetDestroyed()));
  456. }
  457. d->BaseWidget = widget;
  458. if (!d->BaseWidget.isNull())
  459. {
  460. //connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  461. // this, SLOT(onBaseWidgetDestroyed()));
  462. }
  463. }
  464. // -------------------------------------------------------------------------
  465. void ctkBasePopupWidget::onBaseWidgetDestroyed()
  466. {
  467. Q_D(ctkBasePopupWidget);
  468. d->hideAll();
  469. this->setBaseWidget(0);
  470. // could be a property.
  471. this->deleteLater();
  472. }
  473. // -------------------------------------------------------------------------
  474. ctkBasePopupWidget::AnimationEffect ctkBasePopupWidget::animationEffect()const
  475. {
  476. Q_D(const ctkBasePopupWidget);
  477. return d->Effect;
  478. }
  479. // -------------------------------------------------------------------------
  480. void ctkBasePopupWidget::setAnimationEffect(ctkBasePopupWidget::AnimationEffect effect)
  481. {
  482. Q_D(ctkBasePopupWidget);
  483. /// TODO: handle the case where there is an animation running
  484. d->Effect = effect;
  485. }
  486. // -------------------------------------------------------------------------
  487. int ctkBasePopupWidget::effectDuration()const
  488. {
  489. Q_D(const ctkBasePopupWidget);
  490. return d->EffectDuration;
  491. }
  492. // -------------------------------------------------------------------------
  493. void ctkBasePopupWidget::setEffectDuration(int duration)
  494. {
  495. Q_D(ctkBasePopupWidget);
  496. d->EffectDuration = duration;
  497. d->AlphaAnimation->setDuration(d->EffectDuration);
  498. d->ScrollAnimation->setDuration(d->EffectDuration);
  499. }
  500. // -------------------------------------------------------------------------
  501. QEasingCurve::Type ctkBasePopupWidget::easingCurve()const
  502. {
  503. Q_D(const ctkBasePopupWidget);
  504. return d->AlphaAnimation->easingCurve().type();
  505. }
  506. // -------------------------------------------------------------------------
  507. void ctkBasePopupWidget::setEasingCurve(QEasingCurve::Type easingCurve)
  508. {
  509. Q_D(ctkBasePopupWidget);
  510. d->AlphaAnimation->setEasingCurve(easingCurve);
  511. d->ScrollAnimation->setEasingCurve(easingCurve);
  512. }
  513. // -------------------------------------------------------------------------
  514. Qt::Alignment ctkBasePopupWidget::alignment()const
  515. {
  516. Q_D(const ctkBasePopupWidget);
  517. return d->Alignment;
  518. }
  519. // -------------------------------------------------------------------------
  520. void ctkBasePopupWidget::setAlignment(Qt::Alignment alignment)
  521. {
  522. Q_D(ctkBasePopupWidget);
  523. d->Alignment = alignment;
  524. }
  525. // -------------------------------------------------------------------------
  526. Qt::Orientations ctkBasePopupWidget::orientation()const
  527. {
  528. Q_D(const ctkBasePopupWidget);
  529. return d->Orientations;
  530. }
  531. // -------------------------------------------------------------------------
  532. void ctkBasePopupWidget::setOrientation(Qt::Orientations orientations)
  533. {
  534. Q_D(ctkBasePopupWidget);
  535. d->Orientations = orientations;
  536. }
  537. // -------------------------------------------------------------------------
  538. ctkBasePopupWidget::VerticalDirection ctkBasePopupWidget::verticalDirection()const
  539. {
  540. Q_D(const ctkBasePopupWidget);
  541. return d->VerticalDirection;
  542. }
  543. // -------------------------------------------------------------------------
  544. void ctkBasePopupWidget::setVerticalDirection(ctkBasePopupWidget::VerticalDirection verticalDirection)
  545. {
  546. Q_D(ctkBasePopupWidget);
  547. d->VerticalDirection = verticalDirection;
  548. }
  549. // -------------------------------------------------------------------------
  550. Qt::LayoutDirection ctkBasePopupWidget::horizontalDirection()const
  551. {
  552. Q_D(const ctkBasePopupWidget);
  553. return d->HorizontalDirection;
  554. }
  555. // -------------------------------------------------------------------------
  556. void ctkBasePopupWidget::setHorizontalDirection(Qt::LayoutDirection horizontalDirection)
  557. {
  558. Q_D(ctkBasePopupWidget);
  559. d->HorizontalDirection = horizontalDirection;
  560. }
  561. // -------------------------------------------------------------------------
  562. void ctkBasePopupWidget::onEffectFinished()
  563. {
  564. Q_D(ctkBasePopupWidget);
  565. if (d->ForcedTranslucent)
  566. {
  567. d->ForcedTranslucent = false;
  568. this->setAttribute(Qt::WA_TranslucentBackground, false);
  569. }
  570. if (d->wasClosing())
  571. {
  572. d->hideAll();
  573. emit this->popupOpened(false);
  574. }
  575. else
  576. {
  577. this->show();
  578. emit this->popupOpened(true);
  579. }
  580. }
  581. // -------------------------------------------------------------------------
  582. bool ctkBasePopupWidget::event(QEvent* event)
  583. {
  584. switch(event->type())
  585. {
  586. case QEvent::ParentChange:
  587. // For now the base widget is the parent widget
  588. this->setBaseWidget(this->parentWidget());
  589. break;
  590. default:
  591. break;
  592. }
  593. return this->Superclass::event(event);
  594. }
  595. // -------------------------------------------------------------------------
  596. void ctkBasePopupWidget::paintEvent(QPaintEvent* event)
  597. {
  598. Q_D(ctkBasePopupWidget);
  599. Q_UNUSED(event);
  600. QPainter painter(this);
  601. QBrush brush = this->palette().window();
  602. if (brush.style() == Qt::LinearGradientPattern ||
  603. brush.style() == Qt::ConicalGradientPattern ||
  604. brush.style() == Qt::RadialGradientPattern)
  605. {
  606. QGradient* newGradient = duplicateGradient(brush.gradient());
  607. QGradientStops stops;
  608. foreach(QGradientStop stop, newGradient->stops())
  609. {
  610. stop.second.setAlpha(stop.second.alpha() * d->EffectAlpha);
  611. stops.push_back(stop);
  612. }
  613. newGradient->setStops(stops);
  614. brush = QBrush(*newGradient);
  615. delete newGradient;
  616. }
  617. else
  618. {
  619. QColor color = brush.color();
  620. color.setAlpha(color.alpha() * d->EffectAlpha);
  621. brush.setColor(color);
  622. }
  623. //QColor semiTransparentColor = this->palette().window().color();
  624. //semiTransparentColor.setAlpha(d->CurrentAlpha);
  625. painter.fillRect(this->rect(), brush);
  626. painter.end();
  627. // Let the QFrame draw itself if needed
  628. this->Superclass::paintEvent(event);
  629. }
  630. // --------------------------------------------------------------------------
  631. void ctkBasePopupWidget::showPopup()
  632. {
  633. Q_D(ctkBasePopupWidget);
  634. if ((this->isVisible() &&
  635. d->currentAnimation()->state() == QAbstractAnimation::Stopped) ||
  636. (!d->BaseWidget.isNull() && !d->BaseWidget->isVisible()))
  637. {
  638. return;
  639. }
  640. // If the layout has never been activated, the widget doesn't know its
  641. // minSize/maxSize and we then wouldn't know what's its true geometry.
  642. if (this->layout() && !this->testAttribute(Qt::WA_WState_Created))
  643. {
  644. this->layout()->activate();
  645. }
  646. this->setGeometry(d->desiredOpenGeometry());
  647. /// Maybe the popup doesn't allow the desiredOpenGeometry if the widget
  648. /// minimum size is larger than the desired size.
  649. QRect openGeometry = this->geometry();
  650. QRect closedGeometry = d->closedGeometry();
  651. d->currentAnimation()->setDirection(QAbstractAnimation::Forward);
  652. switch(d->Effect)
  653. {
  654. case WindowOpacityFadeEffect:
  655. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  656. {
  657. d->ForcedTranslucent = true;
  658. this->setAttribute(Qt::WA_TranslucentBackground, true);
  659. }
  660. this->show();
  661. break;
  662. case ScrollEffect:
  663. {
  664. d->PopupPixmapWidget->setGeometry(closedGeometry);
  665. d->ScrollAnimation->setStartValue(closedGeometry);
  666. d->ScrollAnimation->setEndValue(openGeometry);
  667. d->setupPopupPixmapWidget();
  668. d->PopupPixmapWidget->show();
  669. break;
  670. }
  671. default:
  672. break;
  673. }
  674. switch(d->currentAnimation()->state())
  675. {
  676. case QAbstractAnimation::Stopped:
  677. d->currentAnimation()->start();
  678. break;
  679. case QAbstractAnimation::Paused:
  680. d->currentAnimation()->resume();
  681. break;
  682. default:
  683. case QAbstractAnimation::Running:
  684. break;
  685. }
  686. }
  687. // --------------------------------------------------------------------------
  688. void ctkBasePopupWidget::hidePopup()
  689. {
  690. Q_D(ctkBasePopupWidget);
  691. if (!this->isVisible() &&
  692. d->currentAnimation()->state() == QAbstractAnimation::Stopped)
  693. {
  694. return;
  695. }
  696. d->currentAnimation()->setDirection(QAbstractAnimation::Backward);
  697. QRect openGeometry = this->geometry();
  698. QRect closedGeometry = d->closedGeometry();
  699. switch(d->Effect)
  700. {
  701. case WindowOpacityFadeEffect:
  702. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  703. {
  704. d->ForcedTranslucent = true;
  705. this->setAttribute(Qt::WA_TranslucentBackground, true);
  706. }
  707. break;
  708. case ScrollEffect:
  709. {
  710. d->ScrollAnimation->setStartValue(closedGeometry);
  711. d->ScrollAnimation->setEndValue(openGeometry);
  712. d->setupPopupPixmapWidget();
  713. d->PopupPixmapWidget->setGeometry(this->geometry());
  714. d->PopupPixmapWidget->show();
  715. if (this->isActiveWindow())
  716. {
  717. qApp->setActiveWindow(!d->BaseWidget.isNull() ? d->BaseWidget->window() : 0);
  718. }
  719. this->hide();
  720. break;
  721. }
  722. default:
  723. break;
  724. }
  725. switch(d->currentAnimation()->state())
  726. {
  727. case QAbstractAnimation::Stopped:
  728. d->currentAnimation()->start();
  729. break;
  730. case QAbstractAnimation::Paused:
  731. d->currentAnimation()->resume();
  732. break;
  733. default:
  734. case QAbstractAnimation::Running:
  735. break;
  736. }
  737. }
  738. // --------------------------------------------------------------------------
  739. double ctkBasePopupWidget::effectAlpha()const
  740. {
  741. Q_D(const ctkBasePopupWidget);
  742. return d->EffectAlpha;
  743. }
  744. // --------------------------------------------------------------------------
  745. void ctkBasePopupWidget::setEffectAlpha(double alpha)
  746. {
  747. Q_D(ctkBasePopupWidget);
  748. d->EffectAlpha = alpha;
  749. this->repaint();
  750. }
  751. // --------------------------------------------------------------------------
  752. QRect ctkBasePopupWidget::effectGeometry()const
  753. {
  754. Q_D(const ctkBasePopupWidget);
  755. return d->PopupPixmapWidget->geometry();
  756. }
  757. // --------------------------------------------------------------------------
  758. void ctkBasePopupWidget::setEffectGeometry(QRect newGeometry)
  759. {
  760. Q_D(ctkBasePopupWidget);
  761. d->PopupPixmapWidget->setGeometry(newGeometry);
  762. d->PopupPixmapWidget->repaint();
  763. }