]> git.lyx.org Git - features.git/blob - src/frontends/qt/FancyLineEdit.cpp
FancyLineEdit: reformat using our indentation style
[features.git] / src / frontends / qt / FancyLineEdit.cpp
1 /**
2  * \file fancylineedit.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Nokia Corporation (qt-info@nokia.com)
7  *
8  * Full author contact details are available in file CREDITS.
9  *
10  */
11
12 // Code taken from the Qt Creator project and customized a little
13
14 #include <config.h>
15
16 #include "FancyLineEdit.h"
17
18 #if QT_VERSION >= 0x040600
19
20 #include <QEvent>
21 #include <QDebug>
22 #include <QString>
23 #include <QPropertyAnimation>
24 #include <QApplication>
25 #include <QMenu>
26 #include <QMouseEvent>
27 #include <QLabel>
28 #include <QAbstractButton>
29 #include <QPainter>
30 #include <QStyle>
31 #include <QPaintEvent>
32
33 enum { margin = 6 };
34
35 #define ICONBUTTON_HEIGHT 18
36 #define FADE_TIME 160
37
38
39 namespace lyx {
40 namespace frontend {
41
42 ////////////////////////////////////////////////////////////////////////
43 //
44 // FancyLineEditPrivate
45 //
46 ////////////////////////////////////////////////////////////////////////
47
48 class FancyLineEditPrivate : public QObject {
49 public:
50         explicit FancyLineEditPrivate(FancyLineEdit *parent);
51
52         bool eventFilter(QObject *obj, QEvent *event) override;
53
54         FancyLineEdit  *m_lineEdit;
55         QPixmap m_pixmap[2];
56         QMenu *m_menu[2];
57         bool m_menuTabFocusTrigger[2];
58         IconButton *m_iconbutton[2];
59         bool m_iconEnabled[2];
60 };
61
62
63 FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent)
64         : QObject(parent), m_lineEdit(parent)
65 {
66         for (int i = 0; i < 2; ++i) {
67                 m_menu[i] = nullptr;
68                 m_menuTabFocusTrigger[i] = false;
69                 m_iconbutton[i] = new IconButton(parent);
70                 m_iconbutton[i]->installEventFilter(this);
71                 m_iconbutton[i]->hide();
72                 m_iconbutton[i]->setAutoHide(false);
73                 m_iconEnabled[i] = false;
74         }
75 }
76
77
78 bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
79 {
80         int buttonIndex = -1;
81         for (int i = 0; i < 2; ++i) {
82                 if (obj == m_iconbutton[i]) {
83                         buttonIndex = i;
84                         break;
85                 }
86         }
87         if (buttonIndex == -1)
88                 return QObject::eventFilter(obj, event);
89         switch (event->type()) {
90         case QEvent::FocusIn:
91                 if (m_menuTabFocusTrigger[buttonIndex] && m_menu[buttonIndex]) {
92                         m_lineEdit->setFocus();
93                         m_menu[buttonIndex]->exec(m_iconbutton[buttonIndex]->mapToGlobal(
94                                                           m_iconbutton[buttonIndex]->rect().center()));
95                         return true;
96                 }
97         default:
98                 break;
99         }
100         return QObject::eventFilter(obj, event);
101 }
102
103
104 ////////////////////////////////////////////////////////////////////////
105 //
106 // FancyLineEdit
107 //
108 ////////////////////////////////////////////////////////////////////////
109
110 FancyLineEdit::FancyLineEdit(QWidget *parent) :
111     QLineEdit(parent),
112     m_d(new FancyLineEditPrivate(this))
113 {
114         ensurePolished();
115         updateMargins();
116         
117         connect(this, SIGNAL(textChanged(QString)),
118                 this, SLOT(checkButtons(QString)));
119         connect(m_d->m_iconbutton[Left], SIGNAL(clicked()),
120                 this, SLOT(iconClicked()));
121         connect(m_d->m_iconbutton[Right], SIGNAL(clicked()),
122                 this, SLOT(iconClicked()));
123 }
124
125
126 void FancyLineEdit::checkButtons(const QString &text)
127 {
128         if (m_oldText.isEmpty() || text.isEmpty()) {
129                 for (int i = 0; i < 2; ++i) {
130                         if (m_d->m_iconbutton[i]->hasAutoHide())
131                                 m_d->m_iconbutton[i]->animateShow(!text.isEmpty());
132                 }
133                 m_oldText = text;
134         }
135 }
136
137
138 void FancyLineEdit::setButtonVisible(Side side, bool visible)
139 {
140         m_d->m_iconbutton[side]->setVisible(visible);
141         m_d->m_iconEnabled[side] = visible;
142         updateMargins();
143 }
144
145
146 bool FancyLineEdit::isButtonVisible(Side side) const
147 {
148         return m_d->m_iconEnabled[side];
149 }
150
151
152 void FancyLineEdit::iconClicked()
153 {
154         IconButton *button = qobject_cast<IconButton *>(sender());
155         int index = -1;
156         for (int i = 0; i < 2; ++i)
157                 if (m_d->m_iconbutton[i] == button)
158                         index = i;
159         if (index == -1)
160                 return;
161         if (m_d->m_menu[index]) {
162                 m_d->m_menu[index]->exec(QCursor::pos());
163         } else {
164                 buttonClicked((Side)index);
165                 if (index == Left)
166                         leftButtonClicked();
167                 else if (index == Right)
168                         rightButtonClicked();
169         }
170 }
171
172
173 void FancyLineEdit::updateMargins()
174 {
175         bool leftToRight = (layoutDirection() == Qt::LeftToRight);
176         Side realLeft = (leftToRight ? Left : Right);
177         Side realRight = (leftToRight ? Right : Left);
178
179         int leftMargin = m_d->m_iconbutton[realLeft]->pixmap().width() + 8;
180         int rightMargin = m_d->m_iconbutton[realRight]->pixmap().width() + 8;
181         // Note KDE does not reserve space for the highlight color
182         if (style()->inherits("OxygenStyle")) {
183                 leftMargin = qMax(24, leftMargin);
184                 rightMargin = qMax(24, rightMargin);
185         }
186
187         QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,
188                          (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);
189
190         setTextMargins(margins);
191 }
192
193
194 void FancyLineEdit::updateButtonPositions()
195 {
196         QRect contentRect = rect();
197         for (int i = 0; i < 2; ++i) {
198                 Side iconpos = (Side)i;
199                 if (layoutDirection() == Qt::RightToLeft)
200                         iconpos = (iconpos == Left ? Right : Left);
201                 
202                 if (iconpos == FancyLineEdit::Right) {
203                         const int iconoffset = textMargins().right() + 4;
204                         m_d->m_iconbutton[i]->setGeometry(
205                                                 contentRect.adjusted(width() - iconoffset,
206                                                                      0, 0, 0));
207                 } else {
208                         const int iconoffset = textMargins().left() + 4;
209                         m_d->m_iconbutton[i]->setGeometry(
210                                                 contentRect.adjusted(0, 0,
211                                                                      -width() + iconoffset, 0));
212                 }
213         }
214 }
215
216
217 void FancyLineEdit::resizeEvent(QResizeEvent *)
218 {
219         updateButtonPositions();
220 }
221
222
223 void FancyLineEdit::keyPressEvent(QKeyEvent * e)
224 {
225         if (e->type() == QEvent::KeyPress && e->key() == Qt::Key_Down)
226                 Q_EMIT downPressed();
227         else
228                 QLineEdit::keyPressEvent(e);
229 }
230
231
232 void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)
233 {
234         m_d->m_iconbutton[side]->setPixmap(buttonPixmap);
235         updateMargins();
236         updateButtonPositions();
237         update();
238 }
239
240
241 QPixmap FancyLineEdit::buttonPixmap(Side side) const
242 {
243         return m_d->m_pixmap[side];
244 }
245
246
247 void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)
248 {
249         m_d->m_menu[side] = buttonMenu;
250         m_d->m_iconbutton[side]->setIconOpacity(1.0);
251 }
252
253 QMenu *FancyLineEdit::buttonMenu(Side side) const
254 {
255         return  m_d->m_menu[side];
256 }
257
258
259 bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const
260 {
261         return m_d->m_menuTabFocusTrigger[side];
262 }
263
264
265 void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)
266 {
267         if (m_d->m_menuTabFocusTrigger[side] == v)
268                 return;
269
270         m_d->m_menuTabFocusTrigger[side] = v;
271         m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
272 }
273
274
275 bool FancyLineEdit::hasAutoHideButton(Side side) const
276 {
277         return m_d->m_iconbutton[side]->hasAutoHide();
278 }
279
280
281 void FancyLineEdit::setAutoHideButton(Side side, bool h)
282 {
283         m_d->m_iconbutton[side]->setAutoHide(h);
284         if (h)
285                 m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ?  0.0 : 1.0);
286         else
287                 m_d->m_iconbutton[side]->setIconOpacity(1.0);
288 }
289
290
291 void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)
292 {
293         m_d->m_iconbutton[side]->setToolTip(tip);
294 }
295
296
297 void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
298 {
299         m_d->m_iconbutton[side]->setFocusPolicy(policy);
300 }
301
302
303 ////////////////////////////////////////////////////////////////////////
304 //
305 // IconButton - helper class to represent a clickable icon
306 //
307 ////////////////////////////////////////////////////////////////////////
308
309 IconButton::IconButton(QWidget *parent)
310         : QAbstractButton(parent), m_iconOpacity(0.0), m_autoHide(false)
311 {
312         setCursor(Qt::ArrowCursor);
313         setFocusPolicy(Qt::NoFocus);
314 }
315
316
317 void IconButton::paintEvent(QPaintEvent *)
318 {
319         QPainter painter(this);
320         QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
321         pixmapRect.moveCenter(rect().center());
322
323         if (m_autoHide)
324                 painter.setOpacity(m_iconOpacity);
325
326         painter.drawPixmap(pixmapRect, m_pixmap);
327 }
328
329
330 void IconButton::animateShow(bool visible)
331 {
332         if (visible) {
333                 QPropertyAnimation *animation =
334                         new QPropertyAnimation(this, "iconOpacity");
335                 animation->setDuration(FADE_TIME);
336                 animation->setEndValue(1.0);
337                 animation->start(QAbstractAnimation::DeleteWhenStopped);
338         } else {
339                 QPropertyAnimation *animation =
340                         new QPropertyAnimation(this, "iconOpacity");
341                 animation->setDuration(FADE_TIME);
342                 animation->setEndValue(0.0);
343                 animation->start(QAbstractAnimation::DeleteWhenStopped);
344         }
345 }
346
347 } // namespace frontend
348
349 } // namespace lyx
350
351 #endif // QT_VERSION >= 0x040600
352
353 #include "moc_FancyLineEdit.cpp"