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