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 // --------- FancyLineEditPrivate
43 class FancyLineEditPrivate : public QObject {
44 public:
45 explicit FancyLineEditPrivate(FancyLineEdit *parent);
46
47 virtual bool eventFilter(QObject *obj, QEvent *event);
48
49 FancyLineEdit *m_lineEdit;
50 QPixmap m_pixmap[2];
51 QMenu *m_menu[2];
52 bool m_menuTabFocusTrigger[2];
53 IconButton *m_iconbutton[2];
54 bool m_iconEnabled[2];
55 };
56
57
FancyLineEditPrivate(FancyLineEdit * parent)58 FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) :
59 QObject(parent),
60 m_lineEdit(parent)
61 {
62 for (int i = 0; i < 2; ++i) {
63 m_menu[i] = 0;
64 m_menuTabFocusTrigger[i] = false;
65 m_iconbutton[i] = new IconButton(parent);
66 m_iconbutton[i]->installEventFilter(this);
67 m_iconbutton[i]->hide();
68 m_iconbutton[i]->setAutoHide(false);
69 m_iconEnabled[i] = false;
70 }
71 }
72
eventFilter(QObject * obj,QEvent * event)73 bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
74 {
75 int buttonIndex = -1;
76 for (int i = 0; i < 2; ++i) {
77 if (obj == m_iconbutton[i]) {
78 buttonIndex = i;
79 break;
80 }
81 }
82 if (buttonIndex == -1)
83 return QObject::eventFilter(obj, event);
84 switch (event->type()) {
85 case QEvent::FocusIn:
86 if (m_menuTabFocusTrigger[buttonIndex] && m_menu[buttonIndex]) {
87 m_lineEdit->setFocus();
88 m_menu[buttonIndex]->exec(m_iconbutton[buttonIndex]->mapToGlobal(
89 m_iconbutton[buttonIndex]->rect().center()));
90 return true;
91 }
92 default:
93 break;
94 }
95 return QObject::eventFilter(obj, event);
96 }
97
98
99 // --------- FancyLineEdit
FancyLineEdit(QWidget * parent)100 FancyLineEdit::FancyLineEdit(QWidget *parent) :
101 QLineEdit(parent),
102 m_d(new FancyLineEditPrivate(this))
103 {
104 ensurePolished();
105 updateMargins();
106
107 connect(this, SIGNAL(textChanged(QString)),
108 this, SLOT(checkButtons(QString)));
109 connect(m_d->m_iconbutton[Left], SIGNAL(clicked()),
110 this, SLOT(iconClicked()));
111 connect(m_d->m_iconbutton[Right], SIGNAL(clicked()),
112 this, SLOT(iconClicked()));
113 }
114
checkButtons(const QString & text)115 void FancyLineEdit::checkButtons(const QString &text)
116 {
117 if (m_oldText.isEmpty() || text.isEmpty()) {
118 for (int i = 0; i < 2; ++i) {
119 if (m_d->m_iconbutton[i]->hasAutoHide())
120 m_d->m_iconbutton[i]->animateShow(!text.isEmpty());
121 }
122 m_oldText = text;
123 }
124 }
125
~FancyLineEdit()126 FancyLineEdit::~FancyLineEdit()
127 {
128 }
129
setButtonVisible(Side side,bool visible)130 void FancyLineEdit::setButtonVisible(Side side, bool visible)
131 {
132 m_d->m_iconbutton[side]->setVisible(visible);
133 m_d->m_iconEnabled[side] = visible;
134 updateMargins();
135 }
136
isButtonVisible(Side side) const137 bool FancyLineEdit::isButtonVisible(Side side) const
138 {
139 return m_d->m_iconEnabled[side];
140 }
141
iconClicked()142 void FancyLineEdit::iconClicked()
143 {
144 IconButton *button = qobject_cast<IconButton *>(sender());
145 int index = -1;
146 for (int i = 0; i < 2; ++i)
147 if (m_d->m_iconbutton[i] == button)
148 index = i;
149 if (index == -1)
150 return;
151 if (m_d->m_menu[index]) {
152 m_d->m_menu[index]->exec(QCursor::pos());
153 } else {
154 buttonClicked((Side)index);
155 if (index == Left)
156 leftButtonClicked();
157 else if (index == Right)
158 rightButtonClicked();
159 }
160 }
161
updateMargins()162 void FancyLineEdit::updateMargins()
163 {
164 bool leftToRight = (layoutDirection() == Qt::LeftToRight);
165 Side realLeft = (leftToRight ? Left : Right);
166 Side realRight = (leftToRight ? Right : Left);
167
168 int leftMargin = m_d->m_iconbutton[realLeft]->pixmap().width() + 8;
169 int rightMargin = m_d->m_iconbutton[realRight]->pixmap().width() + 8;
170 // Note KDE does not reserve space for the highlight color
171 if (style()->inherits("OxygenStyle")) {
172 leftMargin = qMax(24, leftMargin);
173 rightMargin = qMax(24, rightMargin);
174 }
175
176 QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,
177 (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);
178
179 setTextMargins(margins);
180 }
181
updateButtonPositions()182 void FancyLineEdit::updateButtonPositions()
183 {
184 QRect contentRect = rect();
185 for (int i = 0; i < 2; ++i) {
186 Side iconpos = (Side)i;
187 if (layoutDirection() == Qt::RightToLeft)
188 iconpos = (iconpos == Left ? Right : Left);
189
190 if (iconpos == FancyLineEdit::Right) {
191 const int iconoffset = textMargins().right() + 4;
192 m_d->m_iconbutton[i]->
193 setGeometry(contentRect.adjusted(width() - iconoffset, 0, 0, 0));
194 } else {
195 const int iconoffset = textMargins().left() + 4;
196 m_d->m_iconbutton[i]->
197 setGeometry(contentRect.adjusted(0, 0, -width() + iconoffset, 0));
198 }
199 }
200 }
201
resizeEvent(QResizeEvent *)202 void FancyLineEdit::resizeEvent(QResizeEvent *)
203 {
204 updateButtonPositions();
205 }
206
207
keyPressEvent(QKeyEvent * e)208 void FancyLineEdit::keyPressEvent(QKeyEvent * e)
209 {
210 if (e->type() == QEvent::KeyPress && e->key() == Qt::Key_Down)
211 Q_EMIT downPressed();
212 else
213 QLineEdit::keyPressEvent(e);
214 }
215
216
setButtonPixmap(Side side,const QPixmap & buttonPixmap)217 void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)
218 {
219 m_d->m_iconbutton[side]->setPixmap(buttonPixmap);
220 updateMargins();
221 updateButtonPositions();
222 update();
223 }
224
buttonPixmap(Side side) const225 QPixmap FancyLineEdit::buttonPixmap(Side side) const
226 {
227 return m_d->m_pixmap[side];
228 }
229
setButtonMenu(Side side,QMenu * buttonMenu)230 void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)
231 {
232 m_d->m_menu[side] = buttonMenu;
233 m_d->m_iconbutton[side]->setIconOpacity(1.0);
234 }
235
buttonMenu(Side side) const236 QMenu *FancyLineEdit::buttonMenu(Side side) const
237 {
238 return m_d->m_menu[side];
239 }
240
hasMenuTabFocusTrigger(Side side) const241 bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const
242 {
243 return m_d->m_menuTabFocusTrigger[side];
244 }
245
setMenuTabFocusTrigger(Side side,bool v)246 void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)
247 {
248 if (m_d->m_menuTabFocusTrigger[side] == v)
249 return;
250
251 m_d->m_menuTabFocusTrigger[side] = v;
252 m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
253 }
254
hasAutoHideButton(Side side) const255 bool FancyLineEdit::hasAutoHideButton(Side side) const
256 {
257 return m_d->m_iconbutton[side]->hasAutoHide();
258 }
259
setAutoHideButton(Side side,bool h)260 void FancyLineEdit::setAutoHideButton(Side side, bool h)
261 {
262 m_d->m_iconbutton[side]->setAutoHide(h);
263 if (h)
264 m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ? 0.0 : 1.0);
265 else
266 m_d->m_iconbutton[side]->setIconOpacity(1.0);
267 }
268
setButtonToolTip(Side side,const QString & tip)269 void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)
270 {
271 m_d->m_iconbutton[side]->setToolTip(tip);
272 }
273
setButtonFocusPolicy(Side side,Qt::FocusPolicy policy)274 void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
275 {
276 m_d->m_iconbutton[side]->setFocusPolicy(policy);
277 }
278
279 // IconButton - helper class to represent a clickable icon
280
IconButton(QWidget * parent)281 IconButton::IconButton(QWidget *parent)
282 : QAbstractButton(parent), m_iconOpacity(0.0), m_autoHide(false)
283 {
284 setCursor(Qt::ArrowCursor);
285 setFocusPolicy(Qt::NoFocus);
286 }
287
paintEvent(QPaintEvent *)288 void IconButton::paintEvent(QPaintEvent *)
289 {
290 QPainter painter(this);
291 QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
292 pixmapRect.moveCenter(rect().center());
293
294 if (m_autoHide)
295 painter.setOpacity(m_iconOpacity);
296
297 painter.drawPixmap(pixmapRect, m_pixmap);
298 }
299
animateShow(bool visible)300 void IconButton::animateShow(bool visible)
301 {
302 if (visible) {
303 QPropertyAnimation *animation =
304 new QPropertyAnimation(this, "iconOpacity");
305 animation->setDuration(FADE_TIME);
306 animation->setEndValue(1.0);
307 animation->start(QAbstractAnimation::DeleteWhenStopped);
308 } else {
309 QPropertyAnimation *animation =
310 new QPropertyAnimation(this, "iconOpacity");
311 animation->setDuration(FADE_TIME);
312 animation->setEndValue(0.0);
313 animation->start(QAbstractAnimation::DeleteWhenStopped);
314 }
315 }
316
317 } // namespace frontend
318
319 } // namespace lyx
320
321 #endif // QT_VERSION >= 0x040600
322
323 #include "moc_FancyLineEdit.cpp"
324