]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/FancyLineEdit.cpp
On Linux show in crash message box the backtrace
[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 <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
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
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
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)), this, SLOT(checkButtons(QString)));
108     connect(m_d->m_iconbutton[Left], SIGNAL(clicked()), this, SLOT(iconClicked()));
109     connect(m_d->m_iconbutton[Right], SIGNAL(clicked()), this, SLOT(iconClicked()));
110 }
111
112 void FancyLineEdit::checkButtons(const QString &text)
113 {
114     if (m_oldText.isEmpty() || text.isEmpty()) {
115         for (int i = 0; i < 2; ++i) {
116             if (m_d->m_iconbutton[i]->hasAutoHide())
117                 m_d->m_iconbutton[i]->animateShow(!text.isEmpty());
118         }
119         m_oldText = text;
120     }
121 }
122
123 FancyLineEdit::~FancyLineEdit()
124 {
125 }
126
127 void FancyLineEdit::setButtonVisible(Side side, bool visible)
128 {
129     m_d->m_iconbutton[side]->setVisible(visible);
130     m_d->m_iconEnabled[side] = visible;
131     updateMargins();
132 }
133
134 bool FancyLineEdit::isButtonVisible(Side side) const
135 {
136     return m_d->m_iconEnabled[side];
137 }
138
139 void FancyLineEdit::iconClicked()
140 {
141     IconButton *button = qobject_cast<IconButton *>(sender());
142     int index = -1;
143     for (int i = 0; i < 2; ++i)
144         if (m_d->m_iconbutton[i] == button)
145             index = i;
146     if (index == -1)
147         return;
148     if (m_d->m_menu[index]) {
149         m_d->m_menu[index]->exec(QCursor::pos());
150     } else {
151                 buttonClicked((Side)index);
152         if (index == Left)
153                         leftButtonClicked();
154         else if (index == Right)
155                         rightButtonClicked();
156     }
157 }
158
159 void FancyLineEdit::updateMargins()
160 {
161     bool leftToRight = (layoutDirection() == Qt::LeftToRight);
162     Side realLeft = (leftToRight ? Left : Right);
163     Side realRight = (leftToRight ? Right : Left);
164
165     int leftMargin = m_d->m_iconbutton[realLeft]->pixmap().width() + 8;
166     int rightMargin = m_d->m_iconbutton[realRight]->pixmap().width() + 8;
167     // Note KDE does not reserve space for the highlight color
168     if (style()->inherits("OxygenStyle")) {
169         leftMargin = qMax(24, leftMargin);
170         rightMargin = qMax(24, rightMargin);
171     }
172
173     QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,
174                      (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);
175
176     setTextMargins(margins);
177 }
178
179 void FancyLineEdit::updateButtonPositions()
180 {
181     QRect contentRect = rect();
182     for (int i = 0; i < 2; ++i) {
183         Side iconpos = (Side)i;
184         if (layoutDirection() == Qt::RightToLeft)
185             iconpos = (iconpos == Left ? Right : Left);
186
187         if (iconpos == FancyLineEdit::Right) {
188             const int iconoffset = textMargins().right() + 4;
189             m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(width() - iconoffset, 0, 0, 0));
190         } else {
191             const int iconoffset = textMargins().left() + 4;
192             m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(0, 0, -width() + iconoffset, 0));
193         }
194     }
195 }
196
197 void FancyLineEdit::resizeEvent(QResizeEvent *)
198 {
199     updateButtonPositions();
200 }
201
202 void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)
203 {
204     m_d->m_iconbutton[side]->setPixmap(buttonPixmap);
205     updateMargins();
206     updateButtonPositions();
207     update();
208 }
209
210 QPixmap FancyLineEdit::buttonPixmap(Side side) const
211 {
212     return m_d->m_pixmap[side];
213 }
214
215 void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)
216 {
217      m_d->m_menu[side] = buttonMenu;
218      m_d->m_iconbutton[side]->setIconOpacity(1.0);
219  }
220
221 QMenu *FancyLineEdit::buttonMenu(Side side) const
222 {
223     return  m_d->m_menu[side];
224 }
225
226 bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const
227 {
228     return m_d->m_menuTabFocusTrigger[side];
229 }
230
231 void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)
232 {
233     if (m_d->m_menuTabFocusTrigger[side] == v)
234         return;
235
236     m_d->m_menuTabFocusTrigger[side] = v;
237     m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
238 }
239
240 bool FancyLineEdit::hasAutoHideButton(Side side) const
241 {
242     return m_d->m_iconbutton[side]->hasAutoHide();
243 }
244
245 void FancyLineEdit::setAutoHideButton(Side side, bool h)
246 {
247     m_d->m_iconbutton[side]->setAutoHide(h);
248     if (h)
249         m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ?  0.0 : 1.0);
250     else
251         m_d->m_iconbutton[side]->setIconOpacity(1.0);
252 }
253
254 void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)
255 {
256     m_d->m_iconbutton[side]->setToolTip(tip);
257 }
258
259 void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
260 {
261     m_d->m_iconbutton[side]->setFocusPolicy(policy);
262 }
263
264 // IconButton - helper class to represent a clickable icon
265
266 IconButton::IconButton(QWidget *parent)
267     : QAbstractButton(parent), m_autoHide(false)
268 {
269     setCursor(Qt::ArrowCursor);
270     setFocusPolicy(Qt::NoFocus);
271 }
272
273 void IconButton::paintEvent(QPaintEvent *)
274 {
275     QPainter painter(this);
276     QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
277     pixmapRect.moveCenter(rect().center());
278
279     if (m_autoHide)
280         painter.setOpacity(m_iconOpacity);
281
282     painter.drawPixmap(pixmapRect, m_pixmap);
283 }
284
285 void IconButton::animateShow(bool visible)
286 {
287     if (visible) {
288         QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");
289         animation->setDuration(FADE_TIME);
290         animation->setEndValue(1.0);
291         animation->start(QAbstractAnimation::DeleteWhenStopped);
292     } else {
293         QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");
294         animation->setDuration(FADE_TIME);
295         animation->setEndValue(0.0);
296         animation->start(QAbstractAnimation::DeleteWhenStopped);
297     }
298 }
299
300 }
301
302 }
303
304 #endif // QT_VERSION >= 0x040600
305
306 #include "moc_FancyLineEdit.cpp"