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