--- /dev/null
+/**\r
+ * \file fancylineedit.cpp\r
+ * This file is part of LyX, the document processor.\r
+ * Licence details can be found in the file COPYING.\r
+ *\r
+ * \author Nokia Corporation (qt-info@nokia.com)\r
+ *\r
+ * Full author contact details are available in file CREDITS.\r
+ *\r
+ */\r
+\r
+// Code taken from the Qt Creator project and customized a little\r
+\r
+#include "FancyLineEdit.h"\r
+\r
+#include <QtCore/QEvent>\r
+#include <QtCore/QDebug>\r
+#include <QtCore/QString>\r
+#include <QtCore/QPropertyAnimation>\r
+#include <QtGui/QApplication>\r
+#include <QtGui/QMenu>\r
+#include <QtGui/QMouseEvent>\r
+#include <QtGui/QLabel>\r
+#include <QtGui/QAbstractButton>\r
+#include <QtGui/QPainter>\r
+#include <QtGui/QStyle>\r
+#include <QtGui/QPaintEvent>\r
+\r
+enum { margin = 6 };\r
+\r
+#define ICONBUTTON_HEIGHT 18\r
+#define FADE_TIME 160\r
+\r
+\r
+namespace lyx {\r
+namespace frontend {\r
+\r
+// --------- FancyLineEditPrivate\r
+class FancyLineEditPrivate : public QObject {\r
+public:\r
+ explicit FancyLineEditPrivate(FancyLineEdit *parent);\r
+\r
+ virtual bool eventFilter(QObject *obj, QEvent *event);\r
+\r
+ FancyLineEdit *m_lineEdit;\r
+ QPixmap m_pixmap[2];\r
+ QMenu *m_menu[2];\r
+ bool m_menuTabFocusTrigger[2];\r
+ IconButton *m_iconbutton[2];\r
+ bool m_iconEnabled[2];\r
+};\r
+\r
+\r
+FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) :\r
+ QObject(parent),\r
+ m_lineEdit(parent)\r
+{\r
+ for (int i = 0; i < 2; ++i) {\r
+ m_menu[i] = 0;\r
+ m_menuTabFocusTrigger[i] = false;\r
+ m_iconbutton[i] = new IconButton(parent);\r
+ m_iconbutton[i]->installEventFilter(this);\r
+ m_iconbutton[i]->hide();\r
+ m_iconbutton[i]->setAutoHide(false);\r
+ m_iconEnabled[i] = false;\r
+ }\r
+}\r
+\r
+bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)\r
+{\r
+ int buttonIndex = -1;\r
+ for (int i = 0; i < 2; ++i) {\r
+ if (obj == m_iconbutton[i]) {\r
+ buttonIndex = i;\r
+ break;\r
+ }\r
+ }\r
+ if (buttonIndex == -1)\r
+ return QObject::eventFilter(obj, event);\r
+ switch (event->type()) {\r
+ case QEvent::FocusIn:\r
+ if (m_menuTabFocusTrigger[buttonIndex] && m_menu[buttonIndex]) {\r
+ m_lineEdit->setFocus();\r
+ m_menu[buttonIndex]->exec(m_iconbutton[buttonIndex]->mapToGlobal(\r
+ m_iconbutton[buttonIndex]->rect().center()));\r
+ return true;\r
+ }\r
+ default:\r
+ break;\r
+ }\r
+ return QObject::eventFilter(obj, event);\r
+}\r
+\r
+\r
+// --------- FancyLineEdit\r
+FancyLineEdit::FancyLineEdit(QWidget *parent) :\r
+ QLineEdit(parent),\r
+ m_d(new FancyLineEditPrivate(this))\r
+{\r
+ ensurePolished();\r
+ updateMargins();\r
+\r
+ connect(this, SIGNAL(textChanged(QString)), this, SLOT(checkButtons(QString)));\r
+ connect(m_d->m_iconbutton[Left], SIGNAL(clicked()), this, SLOT(iconClicked()));\r
+ connect(m_d->m_iconbutton[Right], SIGNAL(clicked()), this, SLOT(iconClicked()));\r
+}\r
+\r
+void FancyLineEdit::checkButtons(const QString &text)\r
+{\r
+ if (m_oldText.isEmpty() || text.isEmpty()) {\r
+ for (int i = 0; i < 2; ++i) {\r
+ if (m_d->m_iconbutton[i]->hasAutoHide())\r
+ m_d->m_iconbutton[i]->animateShow(!text.isEmpty());\r
+ }\r
+ m_oldText = text;\r
+ }\r
+}\r
+\r
+FancyLineEdit::~FancyLineEdit()\r
+{\r
+}\r
+\r
+void FancyLineEdit::setButtonVisible(Side side, bool visible)\r
+{\r
+ m_d->m_iconbutton[side]->setVisible(visible);\r
+ m_d->m_iconEnabled[side] = visible;\r
+ updateMargins();\r
+}\r
+\r
+bool FancyLineEdit::isButtonVisible(Side side) const\r
+{\r
+ return m_d->m_iconEnabled[side];\r
+}\r
+\r
+void FancyLineEdit::iconClicked()\r
+{\r
+ IconButton *button = qobject_cast<IconButton *>(sender());\r
+ int index = -1;\r
+ for (int i = 0; i < 2; ++i)\r
+ if (m_d->m_iconbutton[i] == button)\r
+ index = i;\r
+ if (index == -1)\r
+ return;\r
+ if (m_d->m_menu[index]) {\r
+ m_d->m_menu[index]->exec(QCursor::pos());\r
+ } else {\r
+ buttonClicked((Side)index);\r
+ if (index == Left)\r
+ leftButtonClicked();\r
+ else if (index == Right)\r
+ rightButtonClicked();\r
+ }\r
+}\r
+\r
+void FancyLineEdit::updateMargins()\r
+{\r
+ bool leftToRight = (layoutDirection() == Qt::LeftToRight);\r
+ Side realLeft = (leftToRight ? Left : Right);\r
+ Side realRight = (leftToRight ? Right : Left);\r
+\r
+ int leftMargin = m_d->m_iconbutton[realLeft]->pixmap().width() + 8;\r
+ int rightMargin = m_d->m_iconbutton[realRight]->pixmap().width() + 8;\r
+ // Note KDE does not reserve space for the highlight color\r
+ if (style()->inherits("OxygenStyle")) {\r
+ leftMargin = qMax(24, leftMargin);\r
+ rightMargin = qMax(24, rightMargin);\r
+ }\r
+\r
+ QMargins margins((m_d->m_iconEnabled[realLeft] ? leftMargin : 0), 0,\r
+ (m_d->m_iconEnabled[realRight] ? rightMargin : 0), 0);\r
+\r
+ setTextMargins(margins);\r
+}\r
+\r
+void FancyLineEdit::updateButtonPositions()\r
+{\r
+ QRect contentRect = rect();\r
+ for (int i = 0; i < 2; ++i) {\r
+ Side iconpos = (Side)i;\r
+ if (layoutDirection() == Qt::RightToLeft)\r
+ iconpos = (iconpos == Left ? Right : Left);\r
+\r
+ if (iconpos == FancyLineEdit::Right) {\r
+ const int iconoffset = textMargins().right() + 4;\r
+ m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(width() - iconoffset, 0, 0, 0));\r
+ } else {\r
+ const int iconoffset = textMargins().left() + 4;\r
+ m_d->m_iconbutton[i]->setGeometry(contentRect.adjusted(0, 0, -width() + iconoffset, 0));\r
+ }\r
+ }\r
+}\r
+\r
+void FancyLineEdit::resizeEvent(QResizeEvent *)\r
+{\r
+ updateButtonPositions();\r
+}\r
+\r
+void FancyLineEdit::setButtonPixmap(Side side, const QPixmap &buttonPixmap)\r
+{\r
+ m_d->m_iconbutton[side]->setPixmap(buttonPixmap);\r
+ updateMargins();\r
+ updateButtonPositions();\r
+ update();\r
+}\r
+\r
+QPixmap FancyLineEdit::buttonPixmap(Side side) const\r
+{\r
+ return m_d->m_pixmap[side];\r
+}\r
+\r
+void FancyLineEdit::setButtonMenu(Side side, QMenu *buttonMenu)\r
+{\r
+ m_d->m_menu[side] = buttonMenu;\r
+ m_d->m_iconbutton[side]->setIconOpacity(1.0);\r
+ }\r
+\r
+QMenu *FancyLineEdit::buttonMenu(Side side) const\r
+{\r
+ return m_d->m_menu[side];\r
+}\r
+\r
+bool FancyLineEdit::hasMenuTabFocusTrigger(Side side) const\r
+{\r
+ return m_d->m_menuTabFocusTrigger[side];\r
+}\r
+\r
+void FancyLineEdit::setMenuTabFocusTrigger(Side side, bool v)\r
+{\r
+ if (m_d->m_menuTabFocusTrigger[side] == v)\r
+ return;\r
+\r
+ m_d->m_menuTabFocusTrigger[side] = v;\r
+ m_d->m_iconbutton[side]->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);\r
+}\r
+\r
+bool FancyLineEdit::hasAutoHideButton(Side side) const\r
+{\r
+ return m_d->m_iconbutton[side]->hasAutoHide();\r
+}\r
+\r
+void FancyLineEdit::setAutoHideButton(Side side, bool h)\r
+{\r
+ m_d->m_iconbutton[side]->setAutoHide(h);\r
+ if (h)\r
+ m_d->m_iconbutton[side]->setIconOpacity(text().isEmpty() ? 0.0 : 1.0);\r
+ else\r
+ m_d->m_iconbutton[side]->setIconOpacity(1.0);\r
+}\r
+\r
+void FancyLineEdit::setButtonToolTip(Side side, const QString &tip)\r
+{\r
+ m_d->m_iconbutton[side]->setToolTip(tip);\r
+}\r
+\r
+void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)\r
+{\r
+ m_d->m_iconbutton[side]->setFocusPolicy(policy);\r
+}\r
+\r
+// IconButton - helper class to represent a clickable icon\r
+\r
+IconButton::IconButton(QWidget *parent)\r
+ : QAbstractButton(parent), m_autoHide(false)\r
+{\r
+ setCursor(Qt::ArrowCursor);\r
+ setFocusPolicy(Qt::NoFocus);\r
+}\r
+\r
+void IconButton::paintEvent(QPaintEvent *)\r
+{\r
+ QPainter painter(this);\r
+ // Note isDown should really use the active state but in most styles\r
+ // this has no proper feedback\r
+ QIcon::Mode state = QIcon::Disabled;\r
+ if (isEnabled())\r
+ state = isDown() ? QIcon::Selected : QIcon::Normal;\r
+ QRect pixmapRect = QRect(0, 0, m_pixmap.width(), m_pixmap.height());\r
+ pixmapRect.moveCenter(rect().center());\r
+\r
+ if (m_autoHide)\r
+ painter.setOpacity(m_iconOpacity);\r
+\r
+ painter.drawPixmap(pixmapRect, m_pixmap);\r
+}\r
+\r
+void IconButton::animateShow(bool visible)\r
+{\r
+ if (visible) {\r
+ QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");\r
+ animation->setDuration(FADE_TIME);\r
+ animation->setEndValue(1.0);\r
+ animation->start(QAbstractAnimation::DeleteWhenStopped);\r
+ } else {\r
+ QPropertyAnimation *animation = new QPropertyAnimation(this, "iconOpacity");\r
+ animation->setDuration(FADE_TIME);\r
+ animation->setEndValue(0.0);\r
+ animation->start(QAbstractAnimation::DeleteWhenStopped);\r
+ }\r
+}\r
+\r
+}\r
+\r
+}\r
+\r
+#include "moc_FancyLineEdit.cpp"\r
--- /dev/null
+/**\r
+ * \file fancylineedit.h\r
+ * This file is part of LyX, the document processor.\r
+ * Licence details can be found in the file COPYING.\r
+ *\r
+ * \author Nokia Corporation (qt-info@nokia.com)\r
+ *\r
+ * Full author contact details are available in file CREDITS.\r
+ *\r
+ */\r
+\r
+// Code taken from the Qt Creator project and customized a little\r
+\r
+#ifndef FANCYLINEEDIT_H\r
+#define FANCYLINEEDIT_H\r
+\r
+#include <QtGui/QLineEdit>\r
+#include <QtGui/QAbstractButton>\r
+\r
+namespace lyx {\r
+namespace frontend {\r
+\r
+class FancyLineEditPrivate;\r
+\r
+class IconButton: public QAbstractButton\r
+{\r
+ Q_OBJECT\r
+ Q_PROPERTY(float iconOpacity READ iconOpacity WRITE setIconOpacity)\r
+ Q_PROPERTY(bool autoHide READ hasAutoHide WRITE setAutoHide)\r
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)\r
+public:\r
+ explicit IconButton(QWidget *parent = 0);\r
+ void paintEvent(QPaintEvent *event);\r
+ void setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; update(); }\r
+ QPixmap pixmap() const { return m_pixmap; }\r
+ float iconOpacity() { return m_iconOpacity; }\r
+ void setIconOpacity(float value) { m_iconOpacity = value; update(); }\r
+ void animateShow(bool visible);\r
+\r
+ void setAutoHide(bool hide) { m_autoHide = hide; }\r
+ bool hasAutoHide() const { return m_autoHide; }\r
+private:\r
+ float m_iconOpacity;\r
+ bool m_autoHide;\r
+ QPixmap m_pixmap;\r
+};\r
+\r
+\r
+/* A line edit with an embedded pixmap on one side that is connected to\r
+ * a menu. Additionally, it can display a grayed hintText (like "Type Here to")\r
+ * when not focused and empty. When connecting to the changed signals and\r
+ * querying text, one has to be aware that the text is set to that hint\r
+ * text if isShowingHintText() returns true (that is, does not contain\r
+ * valid user input).\r
+ */\r
+class FancyLineEdit : public QLineEdit\r
+{\r
+ Q_DISABLE_COPY(FancyLineEdit)\r
+ Q_OBJECT\r
+ Q_ENUMS(Side)\r
+\r
+public:\r
+ enum Side {Left = 0, Right = 1};\r
+\r
+ explicit FancyLineEdit(QWidget *parent = 0);\r
+ ~FancyLineEdit();\r
+\r
+ QPixmap buttonPixmap(Side side) const;\r
+ void setButtonPixmap(Side side, const QPixmap &pixmap);\r
+\r
+ QMenu *buttonMenu(Side side) const;\r
+ void setButtonMenu(Side side, QMenu *menu);\r
+\r
+ void setButtonVisible(Side side, bool visible);\r
+ bool isButtonVisible(Side side) const;\r
+\r
+ void setButtonToolTip(Side side, const QString &);\r
+ void setButtonFocusPolicy(Side side, Qt::FocusPolicy policy);\r
+\r
+ // Set whether tabbing in will trigger the menu.\r
+ void setMenuTabFocusTrigger(Side side, bool v);\r
+ bool hasMenuTabFocusTrigger(Side side) const;\r
+\r
+ // Set if icon should be hidden when text is empty\r
+ void setAutoHideButton(Side side, bool h);\r
+ bool hasAutoHideButton(Side side) const;\r
+\r
+Q_SIGNALS:\r
+ void buttonClicked(Side side);\r
+ void leftButtonClicked();\r
+ void rightButtonClicked();\r
+\r
+private Q_SLOTS:\r
+ void checkButtons(const QString &);\r
+ void iconClicked();\r
+\r
+protected:\r
+ virtual void resizeEvent(QResizeEvent *e);\r
+\r
+private:\r
+ void updateMargins();\r
+ void updateButtonPositions();\r
+\r
+ FancyLineEditPrivate *m_d;\r
+ QString m_oldText;\r
+};\r
+\r
+}\r
+}\r
+\r
+#endif // FANCYLINEEDIT_H\r