2 * \file fancylineedit.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Nokia Corporation (qt-info@nokia.com)
8 * Full author contact details are available in file CREDITS.
12 // Code taken from the Qt Creator project and customized a little
16 #include "FancyLineEdit.h"
21 #include <QPropertyAnimation>
22 #include <QApplication>
24 #include <QMouseEvent>
26 #include <QAbstractButton>
29 #include <QPaintEvent>
34 #define ICONBUTTON_HEIGHT 18
41 ////////////////////////////////////////////////////////////////////////
43 // FancyLineEditPrivate
45 ////////////////////////////////////////////////////////////////////////
47 class FancyLineEditPrivate : public QObject {
49 explicit FancyLineEditPrivate(FancyLineEdit *parent);
51 bool eventFilter(QObject *obj, QEvent *event) override;
53 FancyLineEdit *m_lineEdit;
56 bool m_menuTabFocusTrigger[2];
57 IconButton *m_iconbutton[2];
58 bool m_iconEnabled[2];
62 FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent)
63 : QObject(parent), m_lineEdit(parent)
65 for (int i = 0; i < 2; ++i) {
67 m_menuTabFocusTrigger[i] = false;
68 m_iconbutton[i] = new IconButton(parent);
69 m_iconbutton[i]->installEventFilter(this);
70 m_iconbutton[i]->hide();
71 m_iconbutton[i]->setAutoHide(false);
72 m_iconEnabled[i] = false;
77 bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
80 for (int i = 0; i < 2; ++i) {
81 if (obj == m_iconbutton[i]) {
86 if (buttonIndex == -1)
87 return QObject::eventFilter(obj, event);
88 switch (event->type()) {
90 if (m_menuTabFocusTrigger[buttonIndex] && m_menu[buttonIndex]) {
91 m_lineEdit->setFocus();
92 m_menu[buttonIndex]->exec(m_iconbutton[buttonIndex]->mapToGlobal(
93 m_iconbutton[buttonIndex]->rect().center()));
99 return QObject::eventFilter(obj, event);
103 ////////////////////////////////////////////////////////////////////////
107 ////////////////////////////////////////////////////////////////////////
109 FancyLineEdit::FancyLineEdit(QWidget *parent) :
111 m_d(new FancyLineEditPrivate(this))
116 connect(this, SIGNAL(textChanged(QString)),
117 this, SLOT(checkButtons(QString)));
118 connect(m_d->m_iconbutton[Left], SIGNAL(clicked()),
119 this, SLOT(iconClicked()));
120 connect(m_d->m_iconbutton[Right], SIGNAL(clicked()),
121 this, SLOT(iconClicked()));
125 void FancyLineEdit::checkButtons(const QString &text)
127 if (m_oldText.isEmpty() || text.isEmpty()) {
128 for (int i = 0; i < 2; ++i) {
129 if (m_d->m_iconbutton[i]->hasAutoHide())
130 m_d->m_iconbutton[i]->animateShow(!text.isEmpty());
137 void FancyLineEdit::setClearButton(bool visible)
139 // QLineEdit::setClearButtonEnabled() has been implemented in Qt 5.2.
140 // This is now the minimum required version
141 setClearButtonEnabled(visible);
145 void FancyLineEdit::setButtonVisible(Side side, bool visible)
147 m_d->m_iconbutton[side]->setVisible(visible);
148 m_d->m_iconEnabled[side] = visible;
153 bool FancyLineEdit::isButtonVisible(Side side) const
155 return m_d->m_iconEnabled[side];
159 void FancyLineEdit::iconClicked()
161 IconButton *button = qobject_cast<IconButton *>(sender());
163 for (int i = 0; i < 2; ++i)
164 if (m_d->m_iconbutton[i] == button)
168 if (m_d->m_menu[index]) {
169 m_d->m_menu[index]->exec(QCursor::pos());
171 buttonClicked((Side)index);
174 else if (index == Right)
175 rightButtonClicked();
180 void FancyLineEdit::updateMargins()
182 bool leftToRight = (layoutDirection() == Qt::LeftToRight);
183 Side realLeft = (leftToRight ? Left : Right);
184 Side realRight = (leftToRight ? Right : Left);
187 // Consider device/pixel ratio (HiDPI)
188 dpr = devicePixelRatio();
189 int leftMargin = (m_d->m_iconbutton[realLeft]->pixmap().width() / dpr ) + 8;
190 int rightMargin = (m_d->m_iconbutton[realRight]->pixmap().width() / dpr) + 8;
191 // Note KDE does not reserve space for the highlight color
192 if (style()->inherits("OxygenStyle")) {
193 leftMargin = qMax(24, leftMargin);
194 rightMargin = qMax(24, rightMargin);
197 QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,
198 (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);
200 setTextMargins(margins);
204 void FancyLineEdit::updateButtonPositions()
206 QRect contentRect = rect();
207 for (int i = 0; i < 2; ++i) {
208 Side iconpos = (Side)i;
209 if (layoutDirection() == Qt::RightToLeft)
210 iconpos = (iconpos == Left ? Right : Left);
212 if (iconpos == FancyLineEdit::Right) {
213 const int iconoffset = textMargins().right() + 4;
214 m_d->m_iconbutton[i]->setGeometry(
215 contentRect.adjusted(width() - iconoffset,
218 const int iconoffset = textMargins().left() + 4;
219 m_d->m_iconbutton[i]->setGeometry(
220 contentRect.adjusted(0, 0,
221 -width() + iconoffset, 0));
227 void FancyLineEdit::resizeEvent(QResizeEvent *)
229 updateButtonPositions();
233 void FancyLineEdit::keyPressEvent(QKeyEvent * e)
235 if (e->type() == QEvent::KeyPress && e->key() == Qt::Key_Down)
236 Q_EMIT downPressed();
238 QLineEdit::keyPressEvent(e);
242 void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)
244 m_d->m_iconbutton[side]->setPixmap(buttonPixmap);
246 updateButtonPositions();
251 QPixmap FancyLineEdit::buttonPixmap(Side side) const
253 return m_d->m_pixmap[side];
257 void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)
259 m_d->m_menu[side] = buttonMenu;
260 m_d->m_iconbutton[side]->setIconOpacity(1.0);
263 QMenu *FancyLineEdit::buttonMenu(Side side) const
265 return m_d->m_menu[side];
269 bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const
271 return m_d->m_menuTabFocusTrigger[side];
275 void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)
277 if (m_d->m_menuTabFocusTrigger[side] == v)
280 m_d->m_menuTabFocusTrigger[side] = v;
281 m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
285 bool FancyLineEdit::hasAutoHideButton(Side side) const
287 return m_d->m_iconbutton[side]->hasAutoHide();
291 void FancyLineEdit::setAutoHideButton(Side side, bool h)
293 m_d->m_iconbutton[side]->setAutoHide(h);
295 m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ? 0.0 : 1.0);
297 m_d->m_iconbutton[side]->setIconOpacity(1.0);
301 void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)
303 m_d->m_iconbutton[side]->setToolTip(tip);
307 void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
309 m_d->m_iconbutton[side]->setFocusPolicy(policy);
313 ////////////////////////////////////////////////////////////////////////
315 // IconButton - helper class to represent a clickable icon
317 ////////////////////////////////////////////////////////////////////////
319 IconButton::IconButton(QWidget *parent)
320 : QAbstractButton(parent), m_iconOpacity(0.0), m_autoHide(false)
322 setCursor(Qt::ArrowCursor);
323 setFocusPolicy(Qt::NoFocus);
327 void IconButton::paintEvent(QPaintEvent *)
329 // Consider device/pixel ratio (HiDPI)
330 QWindow * window = this->window()->windowHandle();
331 qreal const dpr = window->devicePixelRatio();
332 QRect pixmapRect(QPoint(), m_pixmap.size() / dpr);
333 pixmapRect.moveCenter(rect().center());
334 QPixmap pm = m_pixmap;
336 QPainter painter(this);
338 painter.setOpacity(m_iconOpacity);
340 painter.drawPixmap(pixmapRect, pm);
344 void IconButton::animateShow(bool visible)
347 QPropertyAnimation *animation =
348 new QPropertyAnimation(this, "iconOpacity");
349 animation->setDuration(FADE_TIME);
350 animation->setEndValue(1.0);
351 animation->start(QAbstractAnimation::DeleteWhenStopped);
353 QPropertyAnimation *animation =
354 new QPropertyAnimation(this, "iconOpacity");
355 animation->setDuration(FADE_TIME);
356 animation->setEndValue(0.0);
357 animation->start(QAbstractAnimation::DeleteWhenStopped);
361 } // namespace frontend
365 #include "moc_FancyLineEdit.cpp"