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