ctkComboBox.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 2010 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 <QStylePainter>
  16. #include <QApplication>
  17. #include <QDebug>
  18. // CTK includes
  19. #include "ctkComboBox.h"
  20. // -------------------------------------------------------------------------
  21. class ctkComboBoxPrivate: public ctkPrivate<ctkComboBox>
  22. {
  23. public:
  24. ctkComboBoxPrivate();
  25. void initStyleOption(QStyleOptionComboBox* opt)const;
  26. QSize recomputeSizeHint(QSize &sh) const;
  27. QString DefaultText;
  28. QIcon DefaultIcon;
  29. bool ForceDefault;
  30. Qt::TextElideMode ElideMode;
  31. mutable QSize MinimumSizeHint;
  32. mutable QSize SizeHint;
  33. };
  34. // -------------------------------------------------------------------------
  35. ctkComboBoxPrivate::ctkComboBoxPrivate()
  36. {
  37. this->DefaultText = "";
  38. this->ForceDefault = false;
  39. this->ElideMode = Qt::ElideNone;
  40. }
  41. // -------------------------------------------------------------------------
  42. QSize ctkComboBoxPrivate::recomputeSizeHint(QSize &sh) const
  43. {
  44. CTK_P(const ctkComboBox);
  45. if (sh.isValid())
  46. {
  47. return sh.expandedTo(QApplication::globalStrut());
  48. }
  49. bool hasIcon = false;
  50. int count = p->count();
  51. QSize iconSize = p->iconSize();
  52. const QFontMetrics &fm = p->fontMetrics();
  53. // text width
  54. if (&sh == &this->SizeHint || p->minimumContentsLength() == 0)
  55. {
  56. switch (p->sizeAdjustPolicy())
  57. {
  58. case QComboBox::AdjustToContents:
  59. case QComboBox::AdjustToContentsOnFirstShow:
  60. if (count == 0 || this->ForceDefault)
  61. {
  62. sh.rwidth() = this->DefaultText.isEmpty() ?
  63. 7 * fm.width(QLatin1Char('x')) :
  64. fm.boundingRect(this->DefaultText).width();
  65. if (!this->DefaultIcon.isNull())
  66. {
  67. hasIcon = true;
  68. sh.rwidth() += iconSize.width() + 4;
  69. }
  70. }
  71. for (int i = 0; i < count; ++i)
  72. {
  73. if (!p->itemIcon(i).isNull())
  74. {
  75. hasIcon = true;
  76. sh.setWidth(qMax(sh.width(), fm.boundingRect(p->itemText(i)).width() + iconSize.width() + 4));
  77. }
  78. else
  79. {
  80. sh.setWidth(qMax(sh.width(), fm.boundingRect(p->itemText(i)).width()));
  81. }
  82. }
  83. break;
  84. case QComboBox::AdjustToMinimumContentsLength:
  85. if ((count == 0 || this->ForceDefault) && !this->DefaultIcon.isNull())
  86. {
  87. hasIcon = true;
  88. }
  89. for (int i = 0; i < count && !hasIcon; ++i)
  90. {
  91. hasIcon = !p->itemIcon(i).isNull();
  92. }
  93. break;
  94. case QComboBox::AdjustToMinimumContentsLengthWithIcon:
  95. hasIcon = true;
  96. break;
  97. default:
  98. break;
  99. }
  100. }
  101. else // minimumsizehint is computing and minimumcontentslenght is > 0
  102. {
  103. if ((count == 0 || this->ForceDefault) && !this->DefaultIcon.isNull())
  104. {
  105. hasIcon = true;
  106. }
  107. for (int i = 0; i < count && !hasIcon; ++i)
  108. {
  109. hasIcon = !p->itemIcon(i).isNull();
  110. }
  111. }
  112. if (p->minimumContentsLength() > 0)
  113. {
  114. sh.setWidth(qMax(sh.width(),
  115. p->minimumContentsLength() * fm.width(QLatin1Char('X'))
  116. + (hasIcon ? iconSize.width() + 4 : 0)));
  117. }
  118. // height
  119. sh.setHeight(qMax(fm.height(), 14) + 2);
  120. if (hasIcon)
  121. {
  122. sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
  123. }
  124. // add style and strut values
  125. QStyleOptionComboBox opt;
  126. this->initStyleOption(&opt);
  127. sh = p->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, p);
  128. return sh.expandedTo(QApplication::globalStrut());
  129. }
  130. // -------------------------------------------------------------------------
  131. void ctkComboBoxPrivate::initStyleOption(QStyleOptionComboBox* opt)const
  132. {
  133. CTK_P(const ctkComboBox);
  134. p->initStyleOption(opt);
  135. if (p->currentIndex() == -1 ||
  136. this->ForceDefault)
  137. {
  138. opt->currentText = this->DefaultText;
  139. opt->currentIcon = this->DefaultIcon;
  140. }
  141. QRect textRect = p->style()->subControlRect(
  142. QStyle::CC_ComboBox, opt, QStyle::SC_ComboBoxEditField, p);
  143. // TODO substract icon size
  144. opt->currentText = opt->fontMetrics.elidedText(opt->currentText,
  145. this->ElideMode,
  146. textRect.width());
  147. }
  148. // -------------------------------------------------------------------------
  149. ctkComboBox::ctkComboBox(QWidget* _parent)
  150. : QComboBox(_parent)
  151. {
  152. CTK_INIT_PRIVATE(ctkComboBox);
  153. }
  154. // -------------------------------------------------------------------------
  155. ctkComboBox::~ctkComboBox()
  156. {
  157. }
  158. // -------------------------------------------------------------------------
  159. void ctkComboBox::setDefaultText(const QString& newDefaultText)
  160. {
  161. CTK_D(ctkComboBox);
  162. d->DefaultText = newDefaultText;
  163. d->SizeHint = QSize();
  164. this->update();
  165. }
  166. // -------------------------------------------------------------------------
  167. QString ctkComboBox::defaultText()const
  168. {
  169. CTK_D(const ctkComboBox);
  170. return d->DefaultText;
  171. }
  172. // -------------------------------------------------------------------------
  173. void ctkComboBox::setDefaultIcon(const QIcon& newIcon)
  174. {
  175. CTK_D(ctkComboBox);
  176. d->DefaultIcon = newIcon;
  177. d->SizeHint = QSize();
  178. this->update();
  179. }
  180. // -------------------------------------------------------------------------
  181. QIcon ctkComboBox::defaultIcon()const
  182. {
  183. CTK_D(const ctkComboBox);
  184. return d->DefaultIcon;
  185. }
  186. // -------------------------------------------------------------------------
  187. void ctkComboBox::forceDefault(bool newForceDefault)
  188. {
  189. CTK_D(ctkComboBox);
  190. if (newForceDefault == d->ForceDefault)
  191. {
  192. return;
  193. }
  194. d->ForceDefault = newForceDefault;
  195. d->SizeHint = QSize();
  196. this->updateGeometry();
  197. }
  198. // -------------------------------------------------------------------------
  199. void ctkComboBox::setElideMode(const Qt::TextElideMode& newMode)
  200. {
  201. CTK_D(ctkComboBox);
  202. d->ElideMode = newMode;
  203. this->update();
  204. }
  205. // -------------------------------------------------------------------------
  206. Qt::TextElideMode ctkComboBox::elideMode()const
  207. {
  208. CTK_D(const ctkComboBox);
  209. return d->ElideMode;
  210. }
  211. // -------------------------------------------------------------------------
  212. bool ctkComboBox::isDefaultForced()const
  213. {
  214. CTK_D(const ctkComboBox);
  215. return d->ForceDefault;
  216. }
  217. // -------------------------------------------------------------------------
  218. void ctkComboBox::paintEvent(QPaintEvent*)
  219. {
  220. CTK_D(ctkComboBox);
  221. QStylePainter painter(this);
  222. painter.setPen(palette().color(QPalette::Text));
  223. QStyleOptionComboBox opt;
  224. d->initStyleOption(&opt);
  225. // draw the combobox frame, focusrect and selected etc.
  226. painter.drawComplexControl(QStyle::CC_ComboBox, opt);
  227. // draw the icon and text
  228. painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
  229. }
  230. // -------------------------------------------------------------------------
  231. QSize ctkComboBox::minimumSizeHint() const
  232. {
  233. CTK_D(const ctkComboBox);
  234. return d->recomputeSizeHint(d->MinimumSizeHint);
  235. }
  236. // -------------------------------------------------------------------------
  237. /*!
  238. \reimp
  239. This implementation caches the size hint to avoid resizing when
  240. the contents change dynamically. To invalidate the cached value
  241. change the \l sizeAdjustPolicy.
  242. */
  243. QSize ctkComboBox::sizeHint() const
  244. {
  245. CTK_D(const ctkComboBox);
  246. return d->recomputeSizeHint(d->SizeHint);
  247. }