ctkBasePopupWidget.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  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. // -------------------------------------------------------------------------
  32. QGradient* duplicateGradient(const QGradient* gradient)
  33. {
  34. QGradient* newGradient = 0;
  35. switch (gradient->type())
  36. {
  37. case QGradient::LinearGradient:
  38. {
  39. const QLinearGradient* linearGradient = static_cast<const QLinearGradient*>(gradient);
  40. newGradient = new QLinearGradient(linearGradient->start(), linearGradient->finalStop());
  41. break;
  42. }
  43. case QGradient::RadialGradient:
  44. {
  45. const QRadialGradient* radialGradient = static_cast<const QRadialGradient*>(gradient);
  46. newGradient = new QRadialGradient(radialGradient->center(), radialGradient->radius());
  47. break;
  48. }
  49. case QGradient::ConicalGradient:
  50. {
  51. const QConicalGradient* conicalGradient = static_cast<const QConicalGradient*>(gradient);
  52. newGradient = new QConicalGradient(conicalGradient->center(), conicalGradient->angle());
  53. break;
  54. }
  55. default:
  56. break;
  57. }
  58. if (!newGradient)
  59. {
  60. Q_ASSERT(gradient->type() != QGradient::NoGradient);
  61. return newGradient;
  62. }
  63. newGradient->setCoordinateMode(gradient->coordinateMode());
  64. newGradient->setSpread(gradient->spread());
  65. newGradient->setStops(gradient->stops());
  66. return newGradient;
  67. }
  68. // -------------------------------------------------------------------------
  69. ctkBasePopupWidgetPrivate::ctkBasePopupWidgetPrivate(ctkBasePopupWidget& object)
  70. :q_ptr(&object)
  71. {
  72. this->BaseWidget = 0;
  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 && (!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::grabWidget(q, QRect(QPoint(0,0), q->geometry().size()));
  219. }
  220. this->PopupPixmapWidget->setPixmap(pixmap);
  221. this->PopupPixmapWidget->setAttribute(
  222. Qt::WA_TranslucentBackground, q->testAttribute(Qt::WA_TranslucentBackground));
  223. this->PopupPixmapWidget->setWindowOpacity(q->windowOpacity());
  224. }
  225. // -------------------------------------------------------------------------
  226. Qt::Alignment ctkBasePopupWidgetPrivate::pixmapAlignment()const
  227. {
  228. Qt::Alignment alignment;
  229. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  230. {
  231. alignment |= Qt::AlignBottom;
  232. }
  233. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  234. {
  235. alignment |= Qt::AlignTop;
  236. }
  237. if (this->HorizontalDirection == Qt::LeftToRight)
  238. {
  239. alignment |= Qt::AlignRight;
  240. }
  241. else// if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  242. {
  243. alignment |= Qt::AlignLeft;
  244. }
  245. return alignment;
  246. }
  247. // -------------------------------------------------------------------------
  248. QRect ctkBasePopupWidgetPrivate::closedGeometry()const
  249. {
  250. Q_Q(const ctkBasePopupWidget);
  251. return this->closedGeometry(q->geometry());
  252. }
  253. // -------------------------------------------------------------------------
  254. QRect ctkBasePopupWidgetPrivate::closedGeometry(QRect openGeom)const
  255. {
  256. if (this->Orientations & Qt::Vertical)
  257. {
  258. if (this->VerticalDirection == ctkBasePopupWidget::BottomToTop)
  259. {
  260. openGeom.moveTop(openGeom.bottom());
  261. }
  262. openGeom.setHeight(0);
  263. }
  264. if (this->Orientations & Qt::Horizontal)
  265. {
  266. if (this->HorizontalDirection == Qt::RightToLeft)
  267. {
  268. openGeom.moveLeft(openGeom.right());
  269. }
  270. openGeom.setWidth(0);
  271. }
  272. return openGeom;
  273. }
  274. // -------------------------------------------------------------------------
  275. QRect ctkBasePopupWidgetPrivate::baseGeometry()const
  276. {
  277. if (!this->BaseWidget)
  278. {
  279. return QRect();
  280. }
  281. return QRect(this->mapToGlobal(this->BaseWidget->geometry().topLeft()),
  282. this->BaseWidget->size());
  283. }
  284. // -------------------------------------------------------------------------
  285. QPoint ctkBasePopupWidgetPrivate::mapToGlobal(const QPoint& baseWidgetPoint)const
  286. {
  287. QPoint mappedPoint = baseWidgetPoint;
  288. if (this->BaseWidget && this->BaseWidget->parentWidget())
  289. {
  290. mappedPoint = this->BaseWidget->parentWidget()->mapToGlobal(mappedPoint);
  291. }
  292. return mappedPoint;
  293. }
  294. // -------------------------------------------------------------------------
  295. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry()const
  296. {
  297. return this->desiredOpenGeometry(this->baseGeometry());
  298. }
  299. // -------------------------------------------------------------------------
  300. QRect ctkBasePopupWidgetPrivate::desiredOpenGeometry(QRect baseGeometry)const
  301. {
  302. Q_Q(const ctkBasePopupWidget);
  303. QSize size = q->size();
  304. if (!q->testAttribute(Qt::WA_WState_Created))
  305. {
  306. size = q->sizeHint();
  307. }
  308. if (baseGeometry.isNull())
  309. {
  310. return QRect(q->pos(), size);
  311. }
  312. QRect geometry;
  313. if (this->Alignment & Qt::AlignJustify)
  314. {
  315. if (this->Orientations & Qt::Vertical)
  316. {
  317. size.setWidth(baseGeometry.width());
  318. }
  319. }
  320. if (this->Alignment & Qt::AlignTop &&
  321. this->Alignment & Qt::AlignBottom)
  322. {
  323. size.setHeight(baseGeometry.height());
  324. }
  325. geometry.setSize(size);
  326. QPoint topLeft = baseGeometry.topLeft();
  327. QPoint bottomRight = baseGeometry.bottomRight();
  328. if (this->Alignment & Qt::AlignLeft)
  329. {
  330. if (this->HorizontalDirection == Qt::LeftToRight)
  331. {
  332. geometry.moveLeft(topLeft.x());
  333. }
  334. else
  335. {
  336. geometry.moveRight(topLeft.x() - 1);
  337. }
  338. }
  339. else if (this->Alignment & Qt::AlignRight)
  340. {
  341. if (this->HorizontalDirection == Qt::LeftToRight)
  342. {
  343. geometry.moveLeft(bottomRight.x() + 1);
  344. }
  345. else
  346. {
  347. geometry.moveRight(bottomRight.x());
  348. }
  349. }
  350. else if (this->Alignment & Qt::AlignHCenter)
  351. {
  352. geometry.moveLeft((topLeft.x() + bottomRight.x()) / 2 - size.width() / 2);
  353. }
  354. else if (this->Alignment & Qt::AlignJustify)
  355. {
  356. geometry.moveLeft(topLeft.x());
  357. }
  358. if (this->Alignment & Qt::AlignTop)
  359. {
  360. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  361. {
  362. geometry.moveTop(topLeft.y());
  363. }
  364. else
  365. {
  366. geometry.moveBottom(topLeft.y() - 1);
  367. }
  368. }
  369. else if (this->Alignment & Qt::AlignBottom)
  370. {
  371. if (this->VerticalDirection == ctkBasePopupWidget::TopToBottom)
  372. {
  373. geometry.moveTop(bottomRight.y() + 1);
  374. }
  375. else
  376. {
  377. geometry.moveBottom(bottomRight.y());
  378. }
  379. }
  380. else if (this->Alignment & Qt::AlignVCenter)
  381. {
  382. geometry.moveTop((topLeft.y() + bottomRight.y()) / 2 - size.height() / 2);
  383. }
  384. return geometry;
  385. }
  386. // -------------------------------------------------------------------------
  387. void ctkBasePopupWidgetPrivate::hideAll()
  388. {
  389. Q_Q(ctkBasePopupWidget);
  390. // It is possible to have the popup widget not being a popup but inside
  391. // a layout: maybe the popup has been pin-down in a way that it gets parented
  392. // In that case, there is no reason to hide the popup.
  393. if (!(q->windowFlags() & PopupWindowType))
  394. {
  395. return;
  396. }
  397. // Before hiding, transfer the active window flag to its parent, this will
  398. // prevent the application to send a ApplicationDeactivate signal that
  399. // doesn't need to be done.
  400. if (q->isActiveWindow() && this->BaseWidget)
  401. {
  402. qApp->setActiveWindow(this->BaseWidget->window());
  403. }
  404. q->hide();
  405. this->PopupPixmapWidget->hide();
  406. // If there is a popup open in the ctkBasePopupWidget children, then hide it
  407. // as well so we don't have a popup open while the ctkBasePopupWidget is hidden.
  408. QPointer<QWidget> activePopupWidget = qApp->activePopupWidget();
  409. if (activePopupWidget && this->isAncestorOf(q, activePopupWidget))
  410. {
  411. activePopupWidget->close();
  412. }
  413. }
  414. // -------------------------------------------------------------------------
  415. // Qt::FramelessWindowHint is required on Windows for Translucent background
  416. // Qt::Toolip is preferred to Qt::Popup as it would close itself at the first
  417. // click outside the widget (typically a click in the BaseWidget)
  418. ctkBasePopupWidget::ctkBasePopupWidget(QWidget* parentWidget)
  419. //: Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  420. : Superclass(parentWidget,
  421. PopupWindowType | Qt::FramelessWindowHint)
  422. , d_ptr(new ctkBasePopupWidgetPrivate(*this))
  423. {
  424. Q_D(ctkBasePopupWidget);
  425. d->init();
  426. }
  427. // -------------------------------------------------------------------------
  428. ctkBasePopupWidget::ctkBasePopupWidget(ctkBasePopupWidgetPrivate* pimpl, QWidget* parentWidget)
  429. //: //Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
  430. : Superclass(parentWidget,
  431. PopupWindowType | Qt::FramelessWindowHint)
  432. , d_ptr(pimpl)
  433. {
  434. }
  435. // -------------------------------------------------------------------------
  436. ctkBasePopupWidget::~ctkBasePopupWidget()
  437. {
  438. }
  439. // -------------------------------------------------------------------------
  440. QWidget* ctkBasePopupWidget::baseWidget()const
  441. {
  442. Q_D(const ctkBasePopupWidget);
  443. return d->BaseWidget;
  444. }
  445. // -------------------------------------------------------------------------
  446. void ctkBasePopupWidget::setBaseWidget(QWidget* widget)
  447. {
  448. Q_D(ctkBasePopupWidget);
  449. if (d->BaseWidget)
  450. {
  451. //disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  452. // this, SLOT(onBaseWidgetDestroyed()));
  453. }
  454. d->BaseWidget = widget;
  455. if (d->BaseWidget)
  456. {
  457. //connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
  458. // this, SLOT(onBaseWidgetDestroyed()));
  459. }
  460. }
  461. // -------------------------------------------------------------------------
  462. void ctkBasePopupWidget::onBaseWidgetDestroyed()
  463. {
  464. Q_D(ctkBasePopupWidget);
  465. d->hideAll();
  466. this->setBaseWidget(0);
  467. // could be a property.
  468. this->deleteLater();
  469. }
  470. // -------------------------------------------------------------------------
  471. ctkBasePopupWidget::AnimationEffect ctkBasePopupWidget::animationEffect()const
  472. {
  473. Q_D(const ctkBasePopupWidget);
  474. return d->Effect;
  475. }
  476. // -------------------------------------------------------------------------
  477. void ctkBasePopupWidget::setAnimationEffect(ctkBasePopupWidget::AnimationEffect effect)
  478. {
  479. Q_D(ctkBasePopupWidget);
  480. /// TODO: handle the case where there is an animation running
  481. d->Effect = effect;
  482. }
  483. // -------------------------------------------------------------------------
  484. int ctkBasePopupWidget::effectDuration()const
  485. {
  486. Q_D(const ctkBasePopupWidget);
  487. return d->EffectDuration;
  488. }
  489. // -------------------------------------------------------------------------
  490. void ctkBasePopupWidget::setEffectDuration(int duration)
  491. {
  492. Q_D(ctkBasePopupWidget);
  493. d->EffectDuration = duration;
  494. d->AlphaAnimation->setDuration(d->EffectDuration);
  495. d->ScrollAnimation->setDuration(d->EffectDuration);
  496. }
  497. // -------------------------------------------------------------------------
  498. QEasingCurve::Type ctkBasePopupWidget::easingCurve()const
  499. {
  500. Q_D(const ctkBasePopupWidget);
  501. return d->AlphaAnimation->easingCurve().type();
  502. }
  503. // -------------------------------------------------------------------------
  504. void ctkBasePopupWidget::setEasingCurve(QEasingCurve::Type easingCurve)
  505. {
  506. Q_D(ctkBasePopupWidget);
  507. d->AlphaAnimation->setEasingCurve(easingCurve);
  508. d->ScrollAnimation->setEasingCurve(easingCurve);
  509. }
  510. // -------------------------------------------------------------------------
  511. Qt::Alignment ctkBasePopupWidget::alignment()const
  512. {
  513. Q_D(const ctkBasePopupWidget);
  514. return d->Alignment;
  515. }
  516. // -------------------------------------------------------------------------
  517. void ctkBasePopupWidget::setAlignment(Qt::Alignment alignment)
  518. {
  519. Q_D(ctkBasePopupWidget);
  520. d->Alignment = alignment;
  521. }
  522. // -------------------------------------------------------------------------
  523. Qt::Orientations ctkBasePopupWidget::orientation()const
  524. {
  525. Q_D(const ctkBasePopupWidget);
  526. return d->Orientations;
  527. }
  528. // -------------------------------------------------------------------------
  529. void ctkBasePopupWidget::setOrientation(Qt::Orientations orientations)
  530. {
  531. Q_D(ctkBasePopupWidget);
  532. d->Orientations = orientations;
  533. }
  534. // -------------------------------------------------------------------------
  535. ctkBasePopupWidget::VerticalDirection ctkBasePopupWidget::verticalDirection()const
  536. {
  537. Q_D(const ctkBasePopupWidget);
  538. return d->VerticalDirection;
  539. }
  540. // -------------------------------------------------------------------------
  541. void ctkBasePopupWidget::setVerticalDirection(ctkBasePopupWidget::VerticalDirection verticalDirection)
  542. {
  543. Q_D(ctkBasePopupWidget);
  544. d->VerticalDirection = verticalDirection;
  545. }
  546. // -------------------------------------------------------------------------
  547. Qt::LayoutDirection ctkBasePopupWidget::horizontalDirection()const
  548. {
  549. Q_D(const ctkBasePopupWidget);
  550. return d->HorizontalDirection;
  551. }
  552. // -------------------------------------------------------------------------
  553. void ctkBasePopupWidget::setHorizontalDirection(Qt::LayoutDirection horizontalDirection)
  554. {
  555. Q_D(ctkBasePopupWidget);
  556. d->HorizontalDirection = horizontalDirection;
  557. }
  558. // -------------------------------------------------------------------------
  559. void ctkBasePopupWidget::onEffectFinished()
  560. {
  561. Q_D(ctkBasePopupWidget);
  562. if (d->ForcedTranslucent)
  563. {
  564. d->ForcedTranslucent = false;
  565. this->setAttribute(Qt::WA_TranslucentBackground, false);
  566. }
  567. if (d->wasClosing())
  568. {
  569. d->hideAll();
  570. emit this->popupOpened(false);
  571. }
  572. else
  573. {
  574. this->show();
  575. emit this->popupOpened(true);
  576. }
  577. }
  578. // -------------------------------------------------------------------------
  579. bool ctkBasePopupWidget::event(QEvent* event)
  580. {
  581. switch(event->type())
  582. {
  583. case QEvent::ParentChange:
  584. // For now the base widget is the parent widget
  585. this->setBaseWidget(this->parentWidget());
  586. break;
  587. default:
  588. break;
  589. }
  590. return this->Superclass::event(event);
  591. }
  592. // -------------------------------------------------------------------------
  593. void ctkBasePopupWidget::paintEvent(QPaintEvent* event)
  594. {
  595. Q_D(ctkBasePopupWidget);
  596. Q_UNUSED(event);
  597. QPainter painter(this);
  598. QBrush brush = this->palette().window();
  599. if (brush.style() == Qt::LinearGradientPattern ||
  600. brush.style() == Qt::ConicalGradientPattern ||
  601. brush.style() == Qt::RadialGradientPattern)
  602. {
  603. QGradient* newGradient = duplicateGradient(brush.gradient());
  604. QGradientStops stops;
  605. foreach(QGradientStop stop, newGradient->stops())
  606. {
  607. stop.second.setAlpha(stop.second.alpha() * d->EffectAlpha);
  608. stops.push_back(stop);
  609. }
  610. newGradient->setStops(stops);
  611. brush = QBrush(*newGradient);
  612. delete newGradient;
  613. }
  614. else
  615. {
  616. QColor color = brush.color();
  617. color.setAlpha(color.alpha() * d->EffectAlpha);
  618. brush.setColor(color);
  619. }
  620. //QColor semiTransparentColor = this->palette().window().color();
  621. //semiTransparentColor.setAlpha(d->CurrentAlpha);
  622. painter.fillRect(this->rect(), brush);
  623. painter.end();
  624. // Let the QFrame draw itself if needed
  625. this->Superclass::paintEvent(event);
  626. }
  627. // --------------------------------------------------------------------------
  628. void ctkBasePopupWidget::showPopup()
  629. {
  630. Q_D(ctkBasePopupWidget);
  631. if ((this->isVisible() &&
  632. d->currentAnimation()->state() == QAbstractAnimation::Stopped) ||
  633. (d->BaseWidget && !d->BaseWidget->isVisible()))
  634. {
  635. return;
  636. }
  637. // If the layout has never been activated, the widget doesn't know its
  638. // minSize/maxSize and we then wouldn't know what's its true geometry.
  639. if (this->layout() && !this->testAttribute(Qt::WA_WState_Created))
  640. {
  641. this->layout()->activate();
  642. }
  643. this->setGeometry(d->desiredOpenGeometry());
  644. /// Maybe the popup doesn't allow the desiredOpenGeometry if the widget
  645. /// minimum size is larger than the desired size.
  646. QRect openGeometry = this->geometry();
  647. QRect closedGeometry = d->closedGeometry();
  648. d->currentAnimation()->setDirection(QAbstractAnimation::Forward);
  649. switch(d->Effect)
  650. {
  651. case WindowOpacityFadeEffect:
  652. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  653. {
  654. d->ForcedTranslucent = true;
  655. this->setAttribute(Qt::WA_TranslucentBackground, true);
  656. }
  657. this->show();
  658. break;
  659. case ScrollEffect:
  660. {
  661. d->PopupPixmapWidget->setGeometry(closedGeometry);
  662. d->ScrollAnimation->setStartValue(closedGeometry);
  663. d->ScrollAnimation->setEndValue(openGeometry);
  664. d->setupPopupPixmapWidget();
  665. d->PopupPixmapWidget->show();
  666. break;
  667. }
  668. default:
  669. break;
  670. }
  671. switch(d->currentAnimation()->state())
  672. {
  673. case QAbstractAnimation::Stopped:
  674. d->currentAnimation()->start();
  675. break;
  676. case QAbstractAnimation::Paused:
  677. d->currentAnimation()->resume();
  678. break;
  679. default:
  680. case QAbstractAnimation::Running:
  681. break;
  682. }
  683. }
  684. // --------------------------------------------------------------------------
  685. void ctkBasePopupWidget::hidePopup()
  686. {
  687. Q_D(ctkBasePopupWidget);
  688. if (!this->isVisible() &&
  689. d->currentAnimation()->state() == QAbstractAnimation::Stopped)
  690. {
  691. return;
  692. }
  693. d->currentAnimation()->setDirection(QAbstractAnimation::Backward);
  694. QRect openGeometry = this->geometry();
  695. QRect closedGeometry = d->closedGeometry();
  696. switch(d->Effect)
  697. {
  698. case WindowOpacityFadeEffect:
  699. if (!this->testAttribute(Qt::WA_TranslucentBackground))
  700. {
  701. d->ForcedTranslucent = true;
  702. this->setAttribute(Qt::WA_TranslucentBackground, true);
  703. }
  704. break;
  705. case ScrollEffect:
  706. {
  707. d->ScrollAnimation->setStartValue(closedGeometry);
  708. d->ScrollAnimation->setEndValue(openGeometry);
  709. d->setupPopupPixmapWidget();
  710. d->PopupPixmapWidget->setGeometry(this->geometry());
  711. d->PopupPixmapWidget->show();
  712. if (this->isActiveWindow())
  713. {
  714. qApp->setActiveWindow(d->BaseWidget ? d->BaseWidget->window() : 0);
  715. }
  716. this->hide();
  717. break;
  718. }
  719. default:
  720. break;
  721. }
  722. switch(d->currentAnimation()->state())
  723. {
  724. case QAbstractAnimation::Stopped:
  725. d->currentAnimation()->start();
  726. break;
  727. case QAbstractAnimation::Paused:
  728. d->currentAnimation()->resume();
  729. break;
  730. default:
  731. case QAbstractAnimation::Running:
  732. break;
  733. }
  734. }
  735. // --------------------------------------------------------------------------
  736. double ctkBasePopupWidget::effectAlpha()const
  737. {
  738. Q_D(const ctkBasePopupWidget);
  739. return d->EffectAlpha;
  740. }
  741. // --------------------------------------------------------------------------
  742. void ctkBasePopupWidget::setEffectAlpha(double alpha)
  743. {
  744. Q_D(ctkBasePopupWidget);
  745. d->EffectAlpha = alpha;
  746. this->repaint();
  747. }
  748. // --------------------------------------------------------------------------
  749. QRect ctkBasePopupWidget::effectGeometry()const
  750. {
  751. Q_D(const ctkBasePopupWidget);
  752. return d->PopupPixmapWidget->geometry();
  753. }
  754. // --------------------------------------------------------------------------
  755. void ctkBasePopupWidget::setEffectGeometry(QRect newGeometry)
  756. {
  757. Q_D(ctkBasePopupWidget);
  758. d->PopupPixmapWidget->setGeometry(newGeometry);
  759. d->PopupPixmapWidget->repaint();
  760. }