ctkPushButton.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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.apache.org/licenses/LICENSE-2.0.txt
  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 <QLayout>
  17. #include <QPainter>
  18. #include <QStyle>
  19. #include <QStyleOptionButton>
  20. #include <QStylePainter>
  21. // CTK includes
  22. #include "ctkPushButton_p.h"
  23. //-----------------------------------------------------------------------------
  24. ctkPushButtonPrivate::ctkPushButtonPrivate(ctkPushButton& object)
  25. :q_ptr(&object)
  26. {
  27. this->ButtonTextAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
  28. this->IconAlignment = Qt::AlignLeft | Qt::AlignVCenter;
  29. this->IconSpacing = 4;
  30. }
  31. //-----------------------------------------------------------------------------
  32. ctkPushButtonPrivate::~ctkPushButtonPrivate()
  33. {
  34. }
  35. //-----------------------------------------------------------------------------
  36. void ctkPushButtonPrivate::init()
  37. {
  38. }
  39. //-----------------------------------------------------------------------------
  40. QRect ctkPushButtonPrivate::iconRect()const
  41. {
  42. Q_Q(const ctkPushButton);
  43. QRect rect;
  44. QStyleOptionButton opt;
  45. q->initStyleOption(&opt);
  46. QSize iconSize = q->iconSize();
  47. int buttonHeight = opt.rect.height();
  48. uint tf = this->ButtonTextAlignment;
  49. if (q->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, q))
  50. {
  51. tf |= Qt::TextShowMnemonic;
  52. }
  53. else
  54. {
  55. tf |= Qt::TextHideMnemonic;
  56. }
  57. int textWidth = opt.fontMetrics.boundingRect(opt.rect, tf, opt.text).width();
  58. int iconSpacing = this->IconSpacing;
  59. int buttonMargin = q->style()->pixelMetric(QStyle::PM_ButtonMargin, &opt, q);
  60. if (this->IconAlignment & Qt::AlignLeft)
  61. {
  62. rect = QRect((buttonHeight - iconSize.width()) / 2,
  63. (buttonHeight - iconSize.height()) / 2,
  64. iconSize.width(), iconSize.height());
  65. }
  66. else if (this->IconAlignment & Qt::AlignHCenter)
  67. {
  68. int w = iconSize.width();
  69. if (!opt.text.isEmpty() && (this->ButtonTextAlignment & Qt::AlignHCenter))
  70. {
  71. w += textWidth + iconSpacing;
  72. }
  73. rect = QRect(opt.rect.x()+ opt.rect.width() /2 - w / 2,
  74. (buttonHeight - iconSize.height()) / 2,
  75. iconSize.width(), iconSize.height());
  76. if (this->ButtonTextAlignment & Qt::AlignLeft &&
  77. rect.left() < opt.rect.x() + buttonMargin + textWidth)
  78. {
  79. rect.moveLeft(opt.rect.x() + buttonMargin + textWidth);
  80. }
  81. else if (this->ButtonTextAlignment & Qt::AlignRight &&
  82. rect.right() > opt.rect.right() - buttonMargin - textWidth)
  83. {
  84. rect.moveRight(opt.rect.right() - buttonMargin - textWidth);
  85. }
  86. }
  87. else if (this->IconAlignment & Qt::AlignRight)
  88. {
  89. rect = QRect(opt.rect.width() - (buttonHeight - iconSize.width()) / 2
  90. - iconSize.width(),
  91. (buttonHeight - iconSize.height()) / 2,
  92. iconSize.width(), iconSize.height());
  93. }
  94. return rect;
  95. }
  96. //-----------------------------------------------------------------------------
  97. QSize ctkPushButtonPrivate::buttonSizeHint()const
  98. {
  99. Q_Q(const ctkPushButton);
  100. int w = 0, h = 0;
  101. QStyleOptionButton opt;
  102. opt.initFrom(q);
  103. // icon
  104. QSize iconSize = q->iconSize();
  105. int ih = iconSize.height();
  106. int iw = iconSize.width() + this->IconSpacing;
  107. w += iw;
  108. h = qMax(h, ih);
  109. // text
  110. QString string(q->text());
  111. bool empty = string.isEmpty();
  112. if (empty)
  113. {
  114. string = QString::fromLatin1("XXXX");
  115. }
  116. QFontMetrics fm = q->fontMetrics();
  117. QSize sz = fm.size(Qt::TextShowMnemonic, string);
  118. if(!empty || !w)
  119. {
  120. w += sz.width();
  121. }
  122. h = qMax(h, sz.height());
  123. //opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
  124. QSize buttonSize = (q->style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h), q).
  125. expandedTo(QApplication::globalStrut()));
  126. return buttonSize;
  127. }
  128. //-----------------------------------------------------------------------------
  129. QStyleOptionButton ctkPushButtonPrivate::drawIcon(QPainter* p)
  130. {
  131. Q_Q(ctkPushButton);
  132. QStyleOptionButton iconOpt;
  133. iconOpt.init(q);
  134. iconOpt.rect = this->iconRect();
  135. if (q->icon().isNull())
  136. {
  137. iconOpt.rect.setWidth(0);
  138. return iconOpt;
  139. }
  140. QIcon::Mode mode = iconOpt.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
  141. if (mode == QIcon::Normal && iconOpt.state & QStyle::State_HasFocus)
  142. {
  143. mode = QIcon::Active;
  144. }
  145. QIcon::State state = QIcon::Off;
  146. if (iconOpt.state & QStyle::State_On)
  147. {
  148. state = QIcon::On;
  149. }
  150. QPixmap pixmap = q->icon().pixmap(iconOpt.rect.size(), mode, state);
  151. p->drawPixmap(iconOpt.rect, pixmap);
  152. return iconOpt;
  153. }
  154. //-----------------------------------------------------------------------------
  155. ctkPushButton::ctkPushButton(QWidget* _parent)
  156. : QPushButton(_parent)
  157. , d_ptr(new ctkPushButtonPrivate(*this))
  158. {
  159. Q_D(ctkPushButton);
  160. d->init();
  161. }
  162. //-----------------------------------------------------------------------------
  163. ctkPushButton::ctkPushButton(const QString& title, QWidget* _parent)
  164. : QPushButton(title, _parent)
  165. , d_ptr(new ctkPushButtonPrivate(*this))
  166. {
  167. Q_D(ctkPushButton);
  168. d->init();
  169. }
  170. //-----------------------------------------------------------------------------
  171. ctkPushButton::ctkPushButton(const QIcon& icon, const QString& title,
  172. QWidget* _parent)
  173. : QPushButton(icon, title, _parent)
  174. , d_ptr(new ctkPushButtonPrivate(*this))
  175. {
  176. Q_D(ctkPushButton);
  177. d->init();
  178. }
  179. //-----------------------------------------------------------------------------
  180. ctkPushButton::ctkPushButton(ctkPushButtonPrivate* pimpl, QWidget* _parent)
  181. : QPushButton(_parent)
  182. , d_ptr(pimpl)
  183. {
  184. }
  185. //-----------------------------------------------------------------------------
  186. ctkPushButton::~ctkPushButton()
  187. {
  188. }
  189. //-----------------------------------------------------------------------------
  190. void ctkPushButton::setButtonTextAlignment(Qt::Alignment newButtonTextAlignment)
  191. {
  192. Q_D(ctkPushButton);
  193. d->ButtonTextAlignment = newButtonTextAlignment;
  194. this->update();
  195. }
  196. //-----------------------------------------------------------------------------
  197. Qt::Alignment ctkPushButton::buttonTextAlignment()const
  198. {
  199. Q_D(const ctkPushButton);
  200. return d->ButtonTextAlignment;
  201. }
  202. //-----------------------------------------------------------------------------
  203. void ctkPushButton::setIconAlignment(Qt::Alignment newIconAlignment)
  204. {
  205. Q_D(ctkPushButton);
  206. d->IconAlignment = newIconAlignment;
  207. this->update();
  208. }
  209. //-----------------------------------------------------------------------------
  210. Qt::Alignment ctkPushButton::iconAlignment()const
  211. {
  212. Q_D(const ctkPushButton);
  213. return d->IconAlignment;
  214. }
  215. //-----------------------------------------------------------------------------
  216. QSize ctkPushButton::minimumSizeHint()const
  217. {
  218. Q_D(const ctkPushButton);
  219. return d->buttonSizeHint();
  220. }
  221. //-----------------------------------------------------------------------------
  222. QSize ctkPushButton::sizeHint()const
  223. {
  224. return this->minimumSizeHint();
  225. }
  226. //-----------------------------------------------------------------------------
  227. void ctkPushButton::paintEvent(QPaintEvent * _event)
  228. {
  229. Q_UNUSED(_event);
  230. Q_D(ctkPushButton);
  231. QPainter p(this);
  232. // Draw Button
  233. QStyleOptionButton opt;
  234. this->initStyleOption(&opt);
  235. // Checkbox size
  236. QSize iconSize = this->iconSize();
  237. // Replace the icon size by the checkbox size
  238. opt.iconSize = iconSize;
  239. // Draw the panel of the button (no text, no icon)
  240. style()->drawControl(QStyle::CE_PushButtonBevel, &opt, &p, this);
  241. // TBD is PE_PanelButtonCommand better ?
  242. //style()->drawPrimitive(QStyle::PE_PanelButtonCommand, &opt, &p, this);
  243. //int buttonHeight = opt.rect.height();
  244. uint tf = d->ButtonTextAlignment;
  245. if (this->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, this))
  246. {
  247. tf |= Qt::TextShowMnemonic;
  248. }
  249. else
  250. {
  251. tf |= Qt::TextHideMnemonic;
  252. }
  253. int textWidth = opt.fontMetrics.boundingRect(opt.rect, tf, opt.text).width();
  254. int buttonMargin = this->style()->pixelMetric(QStyle::PM_ButtonMargin, &opt, this);
  255. // Draw Icon
  256. QStyleOptionButton iconOpt = d->drawIcon(&p);
  257. // Spacing between the text and the checkbox
  258. int iconSpacing = d->IconSpacing;
  259. // Draw Text
  260. if (d->ButtonTextAlignment & Qt::AlignLeft)
  261. {
  262. if (d->IconAlignment & Qt::AlignLeft)
  263. {
  264. opt.rect.setLeft(iconOpt.rect.right() + iconSpacing);
  265. }
  266. else
  267. {
  268. opt.rect.setLeft(opt.rect.x() + buttonMargin);
  269. }
  270. }
  271. else if (d->ButtonTextAlignment & Qt::AlignHCenter)
  272. {
  273. if (d->IconAlignment & Qt::AlignHCenter)
  274. {
  275. opt.rect.setLeft(iconOpt.rect.right() + iconSpacing);
  276. }
  277. else
  278. {
  279. opt.rect.setLeft(opt.rect.x() + opt.rect.width() / 2 - textWidth / 2);
  280. if (d->IconAlignment & Qt::AlignLeft)
  281. {
  282. opt.rect.setLeft( qMax(iconOpt.rect.right() + iconSpacing, opt.rect.left()) );
  283. }
  284. }
  285. }
  286. else if (d->ButtonTextAlignment & Qt::AlignRight)
  287. {
  288. if (d->IconAlignment & Qt::AlignRight)
  289. {
  290. opt.rect.setLeft(iconOpt.rect.left() - iconSpacing - textWidth);
  291. }
  292. else
  293. {
  294. opt.rect.setLeft(opt.rect.right() - buttonMargin - textWidth);
  295. }
  296. }
  297. // all the computations have been made infering the text would be left oriented
  298. tf &= ~Qt::AlignHCenter & ~Qt::AlignRight;
  299. tf |= Qt::AlignLeft;
  300. this->style()->drawItemText(&p, opt.rect, tf, opt.palette, (opt.state & QStyle::State_Enabled),
  301. opt.text, QPalette::ButtonText);
  302. }