fancylineedit.cpp 8.9 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
32
33
34
35
36
37
38
#include "fancylineedit.h"

#include <QtCore/QEvent>
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtGui/QApplication>
#include <QtGui/QMenu>
#include <QtGui/QMouseEvent>
#include <QtGui/QLabel>
39
40
41
42
#include <QtGui/QAbstractButton>
#include <QtGui/QPainter>
#include <QtGui/QStyle>
#include <QtCore/QPropertyAnimation>
con's avatar
con committed
43
44


45
enum { margin = 6 };
con's avatar
con committed
46

47
#define ICONBUTTON_HEIGHT 18
48
#define FADE_TIME 160
con's avatar
con committed
49

50
namespace Utils {
con's avatar
con committed
51

52
// --------- FancyLineEditPrivate
con's avatar
con committed
53
54
class FancyLineEditPrivate : public QObject {
public:
Friedemann Kleint's avatar
Friedemann Kleint committed
55
    explicit FancyLineEditPrivate(FancyLineEdit *parent);
con's avatar
con committed
56
57
58

    virtual bool eventFilter(QObject *obj, QEvent *event);

Friedemann Kleint's avatar
Friedemann Kleint committed
59
    FancyLineEdit  *m_lineEdit;
60
61
62
63
64
    QPixmap m_pixmap[2];
    QMenu *m_menu[2];
    bool m_menuTabFocusTrigger[2];
    IconButton *m_iconbutton[2];
    bool m_iconEnabled[2];
con's avatar
con committed
65
66
67
};


Friedemann Kleint's avatar
Friedemann Kleint committed
68
FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) :
con's avatar
con committed
69
    QObject(parent),
70
    m_lineEdit(parent)
con's avatar
con committed
71
{
72
73
74
75
76
77
78
79
80
    for (int i = 0; i < 2; ++i) {
        m_menu[i] = 0;
        m_menuTabFocusTrigger[i] = false;
        m_iconbutton[i] = new IconButton(parent);
        m_iconbutton[i]->installEventFilter(this);
        m_iconbutton[i]->hide();
        m_iconbutton[i]->setAutoHide(false);
        m_iconEnabled[i] = false;
    }
con's avatar
con committed
81
82
83
84
}

bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
{
85
86
87
88
89
90
91
92
    int buttonIndex = -1;
    for (int i = 0; i < 2; ++i) {
        if (obj == m_iconbutton[i]) {
            buttonIndex = i;
            break;
        }
    }
    if (buttonIndex == -1)
con's avatar
con committed
93
94
95
        return QObject::eventFilter(obj, event);
    switch (event->type()) {
    case QEvent::FocusIn:
96
        if (m_menuTabFocusTrigger[buttonIndex] && m_menu[buttonIndex]) {
con's avatar
con committed
97
            m_lineEdit->setFocus();
98
99
            m_menu[buttonIndex]->exec(m_iconbutton[buttonIndex]->mapToGlobal(
                    m_iconbutton[buttonIndex]->rect().center()));
con's avatar
con committed
100
101
102
103
104
105
106
107
            return true;
        }
    default:
        break;
    }
    return QObject::eventFilter(obj, event);
}

108

con's avatar
con committed
109
110
111
112
113
// --------- FancyLineEdit
FancyLineEdit::FancyLineEdit(QWidget *parent) :
    QLineEdit(parent),
    m_d(new FancyLineEditPrivate(this))
{
114
    ensurePolished();
115
    updateMargins();
116

117
118
119
    connect(this, SIGNAL(textChanged(QString)), this, SLOT(checkButtons(QString)));
    connect(m_d->m_iconbutton[Left], SIGNAL(clicked()), this, SLOT(iconClicked()));
    connect(m_d->m_iconbutton[Right], SIGNAL(clicked()), this, SLOT(iconClicked()));
con's avatar
con committed
120
121
}

122
void FancyLineEdit::checkButtons(const QString &text)
con's avatar
con committed
123
{
124
125
126
127
128
    if (m_oldText.isEmpty() || text.isEmpty()) {
        for (int i = 0; i < 2; ++i) {
            if (m_d->m_iconbutton[i]->hasAutoHide())
                m_d->m_iconbutton[i]->animateShow(!text.isEmpty());
        }
129
        m_oldText = text;
con's avatar
con committed
130
131
132
    }
}

133
FancyLineEdit::~FancyLineEdit()
con's avatar
con committed
134
135
136
{
}

137
void FancyLineEdit::setButtonVisible(Side side, bool visible)
con's avatar
con committed
138
{
139
140
141
142
    m_d->m_iconbutton[side]->setVisible(visible);
    m_d->m_iconEnabled[side] = visible;
    updateMargins();
}
143

144
145
146
147
bool FancyLineEdit::isButtonVisible(Side side) const
{
    return m_d->m_iconEnabled[side];
}
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
void FancyLineEdit::iconClicked()
{
    IconButton *button = qobject_cast<IconButton *>(sender());
    int index = -1;
    for (int i = 0; i < 2; ++i)
        if (m_d->m_iconbutton[i] == button)
            index = i;
    if (index == -1)
        return;
    if (m_d->m_menu[index]) {
        m_d->m_menu[index]->exec(QCursor::pos());
    } else {
        emit buttonClicked((Side)index);
        if (index == Left)
            emit leftButtonClicked();
        else if (index == Right)
            emit rightButtonClicked();
    }
}
168

169
170
171
172
173
void FancyLineEdit::updateMargins()
{
    bool leftToRight = (layoutDirection() == Qt::LeftToRight);
    Side realLeft = (leftToRight ? Left : Right);
    Side realRight = (leftToRight ? Right : Left);
174

175
176
    int leftMargin = m_d->m_iconbutton[realLeft]->pixmap().width() + 8;
    int rightMargin = m_d->m_iconbutton[realRight]->pixmap().width() + 8;
177
178
    // Note KDE does not reserve space for the highlight color
    if (style()->inherits("OxygenStyle")) {
179
180
        leftMargin = qMax(24, leftMargin);
        rightMargin = qMax(24, rightMargin);
con's avatar
con committed
181
    }
182

183
184
    QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,
                     (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);
185
186

    setTextMargins(margins);
con's avatar
con committed
187
188
}

189
void FancyLineEdit::updateButtonPositions()
con's avatar
con committed
190
{
191
192
193
194
195
196
197
198
199
200
201
202
203
    QRect contentRect = rect();
    for (int i = 0; i < 2; ++i) {
        Side iconpos = (Side)i;
        if (layoutDirection() == Qt::RightToLeft)
            iconpos = (iconpos == Left ? Right : Left);

        if (iconpos == FancyLineEdit::Right) {
            const int iconoffset = textMargins().right() + 4;
            m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(width() - iconoffset, 0, 0, 0));
        } else {
            const int iconoffset = textMargins().left() + 4;
            m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(0, 0, -width() + iconoffset, 0));
        }
204
    }
con's avatar
con committed
205
206
207
208
}

void FancyLineEdit::resizeEvent(QResizeEvent *)
{
209
    updateButtonPositions();
con's avatar
con committed
210
211
}

212
void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)
con's avatar
con committed
213
{
214
215
216
217
    m_d->m_iconbutton[side]->setPixmap(buttonPixmap);
    updateMargins();
    updateButtonPositions();
    update();
con's avatar
con committed
218
219
}

220
QPixmap FancyLineEdit::buttonPixmap(Side side) const
con's avatar
con committed
221
{
222
    return m_d->m_pixmap[side];
con's avatar
con committed
223
224
}

225
void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)
con's avatar
con committed
226
{
227
228
     m_d->m_menu[side] = buttonMenu;
     m_d->m_iconbutton[side]->setIconOpacity(1.0);
229
 }
con's avatar
con committed
230

231
QMenu *FancyLineEdit::buttonMenu(Side side) const
con's avatar
con committed
232
{
233
    return  m_d->m_menu[side];
con's avatar
con committed
234
235
}

236
bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const
con's avatar
con committed
237
{
238
    return m_d->m_menuTabFocusTrigger[side];
con's avatar
con committed
239
240
}

241
void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)
con's avatar
con committed
242
{
243
    if (m_d->m_menuTabFocusTrigger[side] == v)
244
245
        return;

246
247
    m_d->m_menuTabFocusTrigger[side] = v;
    m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
con's avatar
con committed
248
249
}

250
bool FancyLineEdit::hasAutoHideButton(Side side) const
con's avatar
con committed
251
{
252
    return m_d->m_iconbutton[side]->hasAutoHide();
con's avatar
con committed
253
254
}

255
void FancyLineEdit::setAutoHideButton(Side side, bool h)
con's avatar
con committed
256
{
257
    m_d->m_iconbutton[side]->setAutoHide(h);
258
    if (h)
259
        m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ?  0.0 : 1.0);
260
    else
261
        m_d->m_iconbutton[side]->setIconOpacity(1.0);
con's avatar
con committed
262
263
}

264
void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)
con's avatar
con committed
265
{
266
    m_d->m_iconbutton[side]->setToolTip(tip);
267
}
con's avatar
con committed
268

269
void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
270
{
271
    m_d->m_iconbutton[side]->setFocusPolicy(policy);
272
273
274
275
276
}

// IconButton - helper class to represent a clickable icon

IconButton::IconButton(QWidget *parent)
277
    : QAbstractButton(parent), m_autoHide(false)
278
279
280
281
282
283
284
285
286
287
288
289
290
{
    setCursor(Qt::ArrowCursor);
    setFocusPolicy(Qt::NoFocus);
}

void IconButton::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    // Note isDown should really use the active state but in most styles
    // this has no proper feedback
    QIcon::Mode state = QIcon::Disabled;
    if (isEnabled())
        state = isDown() ? QIcon::Selected : QIcon::Normal;
291
    QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());
con's avatar
con committed
292
    pixmapRect.moveCenter(rect().center());
293

294
    if (m_autoHide)
295
296
        painter.setOpacity(m_iconOpacity);

297
    painter.drawPixmap(pixmapRect, m_pixmap);
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
}

void IconButton::animateShow(bool visible)
{
    if (visible) {
        QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");
        animation->setDuration(FADE_TIME);
        animation->setEndValue(1.0);
        animation->start(QAbstractAnimation::DeleteWhenStopped);
    } else {
        QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");
        animation->setDuration(FADE_TIME);
        animation->setEndValue(0.0);
        animation->start(QAbstractAnimation::DeleteWhenStopped);
    }
con's avatar
con committed
313
314
315
}

} // namespace Utils