ctkMenuButton.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. All rights reserved.
  5. Distributed under a BSD License. See LICENSE.txt file.
  6. This software is distributed "AS IS" WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the above copyright notice for more information.
  9. =========================================================================*/
  10. // Qt includes
  11. #include <QApplication>
  12. #include <QCleanlooksStyle>
  13. #include <QDebug>
  14. #include <QDesktopWidget>
  15. #include <QLayout>
  16. #include <QMouseEvent>
  17. #include <QMenu>
  18. #include <QPainter>
  19. #include <QPointer>
  20. #include <QPushButton>
  21. #include <QStyle>
  22. #include <QStyleOptionButton>
  23. #include <QStylePainter>
  24. #include <QToolBar>
  25. // CTK includes
  26. #include "ctkMenuButton.h"
  27. //-----------------------------------------------------------------------------
  28. class ctkMenuButtonPrivate : public ctkPrivate<ctkMenuButton>
  29. {
  30. public:
  31. CTK_DECLARE_PUBLIC(ctkMenuButton);
  32. ctkMenuButtonPrivate();
  33. QRect indicatorRect() const;
  34. bool ShowMenu;
  35. };
  36. //-----------------------------------------------------------------------------
  37. ctkMenuButtonPrivate::ctkMenuButtonPrivate()
  38. {
  39. this->ShowMenu = false;
  40. }
  41. //-----------------------------------------------------------------------------
  42. QRect ctkMenuButtonPrivate::indicatorRect()const
  43. {
  44. CTK_P(const ctkMenuButton);
  45. QStyleOptionButton option;
  46. p->initStyleOption(&option);
  47. QRect downArrowRect = p->style()->visualRect(option.direction, option.rect, option.rect);
  48. downArrowRect.setRect(downArrowRect.right() - 13, downArrowRect.top(),
  49. 14, downArrowRect.height());
  50. downArrowRect = p->style()->visualRect(option.direction, option.rect, downArrowRect);
  51. return downArrowRect;
  52. }
  53. //-----------------------------------------------------------------------------
  54. ctkMenuButton::ctkMenuButton(QWidget* _parent)
  55. :QPushButton(_parent)
  56. {
  57. CTK_INIT_PRIVATE(ctkMenuButton);
  58. }
  59. //-----------------------------------------------------------------------------
  60. ctkMenuButton::ctkMenuButton(const QString& title, QWidget* _parent)
  61. :QPushButton(title, _parent)
  62. {
  63. CTK_INIT_PRIVATE(ctkMenuButton);
  64. }
  65. //-----------------------------------------------------------------------------
  66. ctkMenuButton::~ctkMenuButton()
  67. {
  68. }
  69. //-----------------------------------------------------------------------------
  70. QSize ctkMenuButton::minimumSizeHint()const
  71. {
  72. QSize min = QPushButton::minimumSizeHint();
  73. return QSize(min.width() + 13, min.height());
  74. }
  75. //-----------------------------------------------------------------------------
  76. QSize ctkMenuButton::sizeHint()const
  77. {
  78. QSize buttonSizeHint = QPushButton::sizeHint();
  79. return QSize(buttonSizeHint.width() + 13, buttonSizeHint.height());
  80. }
  81. //-----------------------------------------------------------------------------
  82. void ctkMenuButton::paintEvent(QPaintEvent * _event)
  83. {
  84. Q_UNUSED(_event);
  85. CTK_D(ctkMenuButton);
  86. QStylePainter painter(this);
  87. QStyleOptionButton option;
  88. initStyleOption(&option);
  89. bool drawIndicatorBackground =
  90. option.state & QStyle::State_Sunken ||
  91. option.state & QStyle::State_On;
  92. // Draw button
  93. option.features &= ~QStyleOptionButton::HasMenu;
  94. if (this->menu() && (this->menu()->isVisible() || d->ShowMenu))
  95. {
  96. option.state &= ~QStyle::State_Sunken;
  97. option.state |= QStyle::State_Raised;
  98. }
  99. painter.drawControl(QStyle::CE_PushButtonBevel, option);
  100. // is PE_PanelButtonCommand better ?
  101. //painter.drawPrimitive(QStyle::PE_PanelButtonCommand, option);
  102. QRect downArrowRect = d->indicatorRect();
  103. if (drawIndicatorBackground)
  104. {
  105. // if the button is down, draw the part under the indicator up
  106. QPixmap cache = QPixmap(option.rect.size());
  107. cache.fill(Qt::transparent);
  108. QPainter cachePainter(&cache);
  109. option.state &= ~QStyle::State_Sunken;
  110. option.state |= QStyle::State_Raised;
  111. option.state &= ~QStyle::State_On;
  112. option.state |= QStyle::State_Off;
  113. //option.state &= ~QStyle::State_HasFocus;
  114. option.state &= ~QStyle::State_MouseOver;
  115. this->style()->drawControl(QStyle::CE_PushButtonBevel, &option, &cachePainter, this);
  116. painter.drawItemPixmap(downArrowRect, Qt::AlignLeft | Qt::AlignTop, cache.copy(downArrowRect));
  117. }
  118. // Separator
  119. // Freely inspired by the painting of CC_ComboBox in qcleanlooksstyle.cpp
  120. QColor buttonColor = this->palette().button().color();
  121. QColor darkColor;
  122. darkColor.setHsv(buttonColor.hue(),
  123. qMin(255, (int)(buttonColor.saturation()*1.9)),
  124. qMin(255, (int)(buttonColor.value()*0.7)));
  125. painter.setPen(buttonColor.darker(130));
  126. int borderSize = 2;
  127. painter.drawLine(QPoint(downArrowRect.left() - 1, downArrowRect.top() + borderSize),
  128. QPoint(downArrowRect.left() - 1, downArrowRect.bottom() - borderSize));
  129. painter.setPen(this->palette().light().color());
  130. painter.drawLine(QPoint(downArrowRect.left(), downArrowRect.top() + borderSize),
  131. QPoint(downArrowRect.left(), downArrowRect.bottom() - borderSize));
  132. // Draw arrow
  133. QStyleOption indicatorOpt;
  134. indicatorOpt.init(this);
  135. indicatorOpt.rect = downArrowRect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
  136. painter.drawPrimitive(QStyle::PE_IndicatorArrowDown, indicatorOpt);
  137. // Draw Icon & Text
  138. option.rect.setRight( downArrowRect.left());
  139. painter.drawControl(QStyle::CE_PushButtonLabel, option);
  140. }
  141. //-----------------------------------------------------------------------------
  142. bool ctkMenuButton::hitButton(const QPoint & _pos)const
  143. {
  144. CTK_D(const ctkMenuButton);
  145. return !d->indicatorRect().contains(_pos)
  146. && this->QPushButton::hitButton(_pos);
  147. }
  148. //-----------------------------------------------------------------------------
  149. void ctkMenuButton::initStyleOption(QStyleOptionButton* option)const
  150. {
  151. this->QPushButton::initStyleOption(option);
  152. }
  153. //-----------------------------------------------------------------------------
  154. void ctkMenuButton::mousePressEvent(QMouseEvent *e)
  155. {
  156. CTK_D(ctkMenuButton);
  157. // we don't want to open the menu if the mouse is clicked anywhere on
  158. // the button, only if it's clicked on the indecator
  159. this->disconnect(this,SIGNAL(pressed()), this, SLOT(_q_popupPressed()));
  160. this->QPushButton::mousePressEvent(e);
  161. if (e->isAccepted())
  162. {
  163. return;
  164. }
  165. if (d->indicatorRect().contains(e->pos()))
  166. {
  167. d->ShowMenu = true;
  168. this->showMenu();
  169. d->ShowMenu = false;
  170. e->accept();
  171. }
  172. }