ctkSearchBox.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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 <QDebug>
  17. #include <QIcon>
  18. #include <QMouseEvent>
  19. #include <QPainter>
  20. #include <QRect>
  21. #include <QStyleOption>
  22. // CTK includes
  23. #include "ctkSearchBox.h"
  24. // --------------------------------------------------
  25. class ctkSearchBoxPrivate
  26. {
  27. Q_DECLARE_PUBLIC(ctkSearchBox);
  28. protected:
  29. ctkSearchBox* const q_ptr;
  30. public:
  31. ctkSearchBoxPrivate(ctkSearchBox& object);
  32. void init();
  33. /// Position and size for the clear icon in the QLineEdit
  34. QRect clearRect()const;
  35. /// Position and size for the search icon in the QLineEdit
  36. QRect searchRect()const;
  37. QIcon clearIcon;
  38. QIcon searchIcon;
  39. QIcon::Mode clearIconMode;
  40. };
  41. // --------------------------------------------------
  42. ctkSearchBoxPrivate::ctkSearchBoxPrivate(ctkSearchBox &object)
  43. : q_ptr(&object)
  44. {
  45. this->clearIcon = QIcon(":Icons/clear.svg");
  46. this->searchIcon = QIcon(":Icons/search.svg");
  47. this->clearIconMode = QIcon::Disabled;
  48. }
  49. // --------------------------------------------------
  50. void ctkSearchBoxPrivate::init()
  51. {
  52. Q_Q(ctkSearchBox);
  53. // Set a text by default on the QLineEdit
  54. q->setPlaceholderText(q->tr("Search..."));
  55. QObject::connect(q, SIGNAL(textChanged(const QString&)),
  56. q, SLOT(updateClearButtonState()));
  57. }
  58. // --------------------------------------------------
  59. QRect ctkSearchBoxPrivate::clearRect()const
  60. {
  61. Q_Q(const ctkSearchBox);
  62. QRect cRect = this->searchRect();
  63. cRect.moveLeft(q->width() - cRect.width() - cRect.left());
  64. return cRect;
  65. }
  66. // --------------------------------------------------
  67. QRect ctkSearchBoxPrivate::searchRect()const
  68. {
  69. Q_Q(const ctkSearchBox);
  70. QRect sRect;
  71. // If the QLineEdit has a frame, the icon must be shifted from
  72. // the frame line width
  73. if (q->hasFrame())
  74. {
  75. QStyleOptionFrameV2 opt;
  76. q->initStyleOption(&opt);
  77. sRect.moveTopLeft(QPoint(opt.lineWidth, opt.lineWidth));
  78. }
  79. // Hardcoded: shift by 1 pixel because some styles have a focus frame inside
  80. // the line edit frame.
  81. sRect.translate(QPoint(1,1));
  82. // Square size
  83. sRect.setSize(QSize(q->height(),q->height()) -
  84. 2*QSize(sRect.left(), sRect.top()));
  85. return sRect;
  86. }
  87. // --------------------------------------------------
  88. ctkSearchBox::ctkSearchBox(QWidget* _parent)
  89. : QLineEdit(_parent)
  90. , d_ptr(new ctkSearchBoxPrivate(*this))
  91. {
  92. Q_D(ctkSearchBox);
  93. d->init();
  94. }
  95. // --------------------------------------------------
  96. ctkSearchBox::~ctkSearchBox()
  97. {
  98. }
  99. // --------------------------------------------------
  100. void ctkSearchBox::paintEvent(QPaintEvent * event)
  101. {
  102. Q_D(ctkSearchBox);
  103. QPainter p(this);
  104. // Draw the line edit with text.
  105. // Text has already been shifted to the right (in resizeEvent()) to leave
  106. // space for the search icon.
  107. this->Superclass::paintEvent(event);
  108. // Draw clearIcon
  109. QRect cRect = d->clearRect();
  110. QPixmap closePixmap = d->clearIcon.pixmap(cRect.size(),d->clearIconMode);
  111. this->style()->drawItemPixmap(&p, cRect, Qt::AlignCenter, closePixmap);
  112. // Draw searchIcon
  113. QRect sRect = d->searchRect();
  114. QPixmap searchPixmap = d->searchIcon.pixmap(sRect.size());
  115. this->style()->drawItemPixmap(&p, sRect, Qt::AlignCenter, searchPixmap);
  116. }
  117. // --------------------------------------------------
  118. void ctkSearchBox::mousePressEvent(QMouseEvent *e)
  119. {
  120. Q_D(ctkSearchBox);
  121. if(d->clearRect().contains(e->pos()))
  122. {
  123. this->clear();
  124. return;
  125. }
  126. if(d->searchRect().contains(e->pos()))
  127. {
  128. this->selectAll();
  129. return;
  130. }
  131. this->Superclass::mousePressEvent(e);
  132. }
  133. // --------------------------------------------------
  134. void ctkSearchBox::mouseMoveEvent(QMouseEvent *e)
  135. {
  136. Q_D(ctkSearchBox);
  137. if(d->clearRect().contains(e->pos()) || d->searchRect().contains(e->pos()))
  138. {
  139. this->setCursor(Qt::ArrowCursor);
  140. }
  141. else
  142. {
  143. this->setCursor(this->isReadOnly() ? Qt::ArrowCursor : Qt::IBeamCursor);
  144. }
  145. this->Superclass::mouseMoveEvent(e);
  146. }
  147. // --------------------------------------------------
  148. void ctkSearchBox::resizeEvent(QResizeEvent * event)
  149. {
  150. Q_D(ctkSearchBox);
  151. static int iconSpacing = 4; // hardcoded, same way as pushbutton icon spacing
  152. QRect cRect = d->clearRect();
  153. QRect sRect = d->searchRect();
  154. // Set 2 margins each sides of the QLineEdit, according to the icons
  155. this->setTextMargins( sRect.right() + iconSpacing, 0,
  156. event->size().width() - cRect.left() - iconSpacing,0);
  157. }
  158. // --------------------------------------------------
  159. void ctkSearchBox::updateClearButtonState()
  160. {
  161. Q_D(ctkSearchBox);
  162. d->clearIconMode = this->text().isEmpty() ? QIcon::Disabled : QIcon::Normal;
  163. }