From 391f5f49b76a847113e1e27013a5d6027070bbd0 Mon Sep 17 00:00:00 2001 From: Kevin Smith <git@kismith.co.uk> Date: Sun, 23 May 2010 13:10:55 +0100 Subject: Start creating a prettier roster header. diff --git a/Swift/QtUI/QtRosterHeader.cpp b/Swift/QtUI/QtRosterHeader.cpp index 88fbf7b..3ab12dd 100644 --- a/Swift/QtUI/QtRosterHeader.cpp +++ b/Swift/QtUI/QtRosterHeader.cpp @@ -17,84 +17,68 @@ namespace Swift { QtRosterHeader::QtRosterHeader(QWidget* parent) : QWidget(parent) { - QVBoxLayout* vLayout = new QVBoxLayout(); - vLayout->setSpacing(0); - vLayout->setContentsMargins(0,0,0,0); - setLayout(vLayout); + QHBoxLayout* topLayout = new QHBoxLayout(); + topLayout->setSpacing(0); + topLayout->setContentsMargins(0,0,0,0); + setLayout(topLayout); + setMinimumHeight(64); + setMaximumHeight(64); - toolBar_ = new QToolBar(this); - vLayout->addWidget(toolBar_); + avatarLabel_ = new QLabel(this); + avatarLabel_->setMinimumSize(64, 64); + avatarLabel_->setMaximumSize(64, 64); + setAvatar(":/icons/avatar.png"); + avatarLabel_->setScaledContents(true); + topLayout->addWidget(avatarLabel_); - statusWidget_ = new QtStatusWidget(this); - toolBar_->addWidget(statusWidget_); - statusWidget_->setMaximumWidth(60); - connect(statusWidget_, SIGNAL(onChangeStatusRequest(StatusShow::Type)), this, SLOT(handleChangeStatusRequest(StatusShow::Type))); + QVBoxLayout* rightLayout = new QVBoxLayout(); + rightLayout->setSpacing(4); + rightLayout->setContentsMargins(4,4,4,4); + topLayout->addLayout(rightLayout); nameLabel_ = new QLabel(this); setName("Me"); - toolBar_->addWidget(nameLabel_); - //nameLabel_->setMaximumWidth(width() - 5 - statusWidget_->width()); - - expandedLayout_ = new QHBoxLayout(); - expandedLayout_->setContentsMargins(0,0,0,0); - expandedLayout_->setSpacing(0); - - avatarLabel_ = new QLabel(this); - setAvatar(":/icons/avatar.png"); - expandedLayout_->addWidget(avatarLabel_); - - statusEdit_ = new QtTextEdit(this); - expandedLayout_->addWidget(statusEdit_); - statusEdit_->resize(statusEdit_->width(), 64); - statusEdit_->setAcceptRichText(false); - statusEdit_->setReadOnly(false); - setStatusText(""); - - vLayout->addLayout(expandedLayout_); - expanded_ = false; - avatarLabel_->hide(); - statusEdit_->hide(); - connect(statusEdit_, SIGNAL(returnPressed()), this, SLOT(emitStatus())); - - setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); + rightLayout->addWidget(nameLabel_); + + + statusWidget_ = new QtStatusWidget(this); + connect(statusWidget_, SIGNAL(onChangeStatusRequest(StatusShow::Type, const QString&)), this, SLOT(handleChangeStatusRequest(StatusShow::Type, const QString&))); + rightLayout->addWidget(statusWidget_); + show(); + //statusWidget_->setMaximumWidth(60); + + // statusEdit_ = new QtTextEdit(this); + // expandedLayout_->addWidget(statusEdit_); + // statusEdit_->resize(statusEdit_->width(), 64); + // statusEdit_->setAcceptRichText(false); + // statusEdit_->setReadOnly(false); + // setStatusText(""); + // connect(statusEdit_, SIGNAL(returnPressed()), this, SLOT(emitStatus())); + + //setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); } -void QtRosterHeader::mousePressEvent(QMouseEvent* event) { - if (nameLabel_->underMouse() || (toolBar_->underMouse() && !statusWidget_->underMouse())) { - toggleExpanded(); - event->accept(); - } else { - event->ignore(); - } +// void QtRosterHeader::mousePressEvent(QMouseEvent* event) { +// if (nameLabel_->underMouse() || (toolBar_->underMouse() && !statusWidget_->underMouse())) { +// toggleExpanded(); +// event->accept(); +// } else { +// event->ignore(); +// } -} +// } -void QtRosterHeader::toggleExpanded() { - expanded_ = !expanded_; - if (expanded_) { - expandedLayout_->setContentsMargins(5,5,5,5); - expandedLayout_->setSpacing(11); - avatarLabel_->show(); - statusEdit_->show(); - } else { - expandedLayout_->setContentsMargins(0,0,0,0); - expandedLayout_->setSpacing(0); - avatarLabel_->hide(); - statusEdit_->hide(); - } -} -void QtRosterHeader::handleChangeStatusRequest(StatusShow::Type type) { - Q_UNUSED(type); - emitStatus(); +void QtRosterHeader::handleChangeStatusRequest(StatusShow::Type type, const QString& text) { + emit onChangeStatusRequest(type, text); } -void QtRosterHeader::emitStatus() { - emit onChangeStatusRequest(statusWidget_->getSelectedStatusShow(), statusEdit_->toPlainText()); -} +//void QtRosterHeader::emitStatus() { +// emit onChangeStatusRequest(statusWidget_->getSelectedStatusShow(), statusEdit_->toPlainText()); +//} void QtRosterHeader::setStatusText(const QString& statusMessage) { - statusEdit_->setText(statusMessage); + statusWidget_->setStatusText(statusMessage); } void QtRosterHeader::setStatusType(StatusShow::Type type) { @@ -103,40 +87,48 @@ void QtRosterHeader::setStatusType(StatusShow::Type type) { void QtRosterHeader::setName(const QString& name) { name_ = name; - resizeNameLabel(); -} - -void QtRosterHeader::resizeNameLabel() { QString escapedName = name_; escapedName.replace("<","<"); - nameLabel_->setText("<b>" + escapedName + "</b>"); - return; - //FIXME: Make this not an infinite loop, so it can be continued. - - int reductionCount = 0; - while (nameLabel_->sizeHint().width() + statusWidget_->width() + 30 > width()) { - //qDebug() << nameLabel_->sizeHint().width() << " " << statusWidget_->width() << " " << width(); - reductionCount++; - QString reducedName = name_; - reducedName.remove(name_.length() - reductionCount, reductionCount); - reducedName.replace("<","<"); - nameLabel_->setText("<b>" + reducedName + + "...</b>"); - // qDebug() << "Shrunk " << escapedName << " down to " << reducedName; - } - nameLabel_->setToolTip(name_); + nameLabel_->setText("<b>" + escapedName + "</b>"); +// resizeNameLabel(); } -void QtRosterHeader::resizeEvent(QResizeEvent* event) { - QWidget::resizeEvent(event); - resizeNameLabel(); -} +// void QtRosterHeader::resizeNameLabel() { +// QString escapedName = name_; +// escapedName.replace("<","<"); +// nameLabel_->setText("<b>" + escapedName + "</b>"); +// return; +// //FIXME: Make this not an infinite loop, so it can be continued. + +// int reductionCount = 0; +// while (nameLabel_->sizeHint().width() + statusWidget_->width() + 30 > width()) { +// //qDebug() << nameLabel_->sizeHint().width() << " " << statusWidget_->width() << " " << width(); +// reductionCount++; +// QString reducedName = name_; +// reducedName.remove(name_.length() - reductionCount, reductionCount); +// reducedName.replace("<","<"); +// nameLabel_->setText("<b>" + reducedName + + "...</b>"); +// // qDebug() << "Shrunk " << escapedName << " down to " << reducedName; +// } +// nameLabel_->setToolTip(name_); +// } + +//void QtRosterHeader::resizeEvent(QResizeEvent* event) { +// QWidget::resizeEvent(event); +// resizeNameLabel(); +//} void QtRosterHeader::setAvatar(const QString& path) { - avatarLabel_->setPixmap(QIcon(path).pixmap(64, 64)); + QIcon avatar(path); + if (avatar.isNull()) { + qDebug() << "Setting null avatar"; + avatar = QIcon(":/icons/avatar.png"); + } + avatarLabel_->setPixmap(avatar.pixmap(64, 64)); } -QSize QtRosterHeader::sizeHint() const { - return minimumSizeHint(); -} +//QSize QtRosterHeader::sizeHint() const { +// return minimumSizeHint(); +//} } diff --git a/Swift/QtUI/QtRosterHeader.h b/Swift/QtUI/QtRosterHeader.h index 719674e..7fed2c0 100644 --- a/Swift/QtUI/QtRosterHeader.h +++ b/Swift/QtUI/QtRosterHeader.h @@ -30,26 +30,28 @@ namespace Swift { void setName(const QString& name); void setStatusText(const QString& statusMessage); void setStatusType(StatusShow::Type type); - QSize sizeHint() const; - public slots: - void emitStatus(); +// QSize sizeHint() const; +// public slots: +// void emitStatus(); signals: void onChangeStatusRequest(StatusShow::Type showType, const QString &statusMessage); private slots: - void handleChangeStatusRequest(StatusShow::Type type); - protected: - virtual void resizeEvent(QResizeEvent* event); - virtual void mousePressEvent(QMouseEvent* event); + void handleChangeStatusRequest(StatusShow::Type type, const QString &statusMessage); +// protected: +// virtual void resizeEvent(QResizeEvent* event); +// virtual void mousePressEvent(QMouseEvent* event); private: - void resizeNameLabel(); - void toggleExpanded(); +// void resizeNameLabel(); +// void toggleExpanded(); QString name_; QLabel* avatarLabel_; +#warning FIXME - replace QLabel with override to do elide +//http://lists.trolltech.com/pipermail/qt-interest/2010-January/018056.html QLabel* nameLabel_; QtTextEdit* statusEdit_; QToolBar* toolBar_; QtStatusWidget* statusWidget_; - QHBoxLayout* expandedLayout_; - bool expanded_; + //QHBoxLayout* expandedLayout_; + //bool expanded_; }; } diff --git a/Swift/QtUI/QtStatusWidget.cpp b/Swift/QtUI/QtStatusWidget.cpp index 3de2641..c6b0464 100644 --- a/Swift/QtUI/QtStatusWidget.cpp +++ b/Swift/QtUI/QtStatusWidget.cpp @@ -9,40 +9,155 @@ #include <QBoxLayout> #include <QComboBox> #include <QLineEdit> - +#include <QLabel> +#include <QFrame> +#include <QPoint> +#include <QStackedWidget> +#include <QApplication> +#include <QDesktopWidget> +#include <qdebug.h> +#include <QListWidget> +#include <QListWidgetItem> namespace Swift { -QtStatusWidget::QtStatusWidget(QWidget *parent) : QWidget(parent) { - types_ = new QComboBox(this); - types_->addItem(QIcon(":/icons/online.png"), "Available", QVariant(StatusShow::Online)); - types_->addItem(QIcon(":/icons/online.png"), "Free For Chat", QVariant(StatusShow::FFC)); - types_->addItem(QIcon(":/icons/away.png"), "Away", QVariant(StatusShow::Away)); - types_->addItem(QIcon(":/icons/away.png"), "Extended Away", QVariant(StatusShow::XA)); - types_->addItem(QIcon(":/icons/dnd.png"), "Do Not Disturb", QVariant(StatusShow::DND)); - types_->addItem(QIcon(":/icons/offline.png"), "Offline", QVariant(StatusShow::None)); - connect(types_, SIGNAL(activated(int)), this, SLOT(handleTypeSelected(int))); - QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); - mainLayout->setContentsMargins(0,0,0,0); + +QtStatusWidget::QtStatusWidget(QWidget *parent) : QWidget(parent), editCursor_(Qt::IBeamCursor), viewCursor_(Qt::PointingHandCursor) { + isClicking_ = false; + setMaximumHeight(24); + + QHBoxLayout* mainLayout = new QHBoxLayout(this); mainLayout->setSpacing(0); - mainLayout->addWidget(types_); + mainLayout->setContentsMargins(0,0,0,0); + + stack_ = new QStackedWidget(this); + stack_->setLineWidth(2); + stack_->setFrameShape(QFrame::StyledPanel); + mainLayout->addWidget(stack_); + + QWidget* page1 = new QWidget(this); + stack_->addWidget(page1); + QHBoxLayout* page1Layout = new QHBoxLayout(page1); + page1Layout->setSpacing(0); + page1Layout->setContentsMargins(0,0,0,0); + page1->setCursor(viewCursor_); + + statusIcon_ = new QLabel(this); + statusIcon_->setMinimumSize(16, 16); + statusIcon_->setMaximumSize(16, 16); + page1Layout->addWidget(statusIcon_); + + statusTextLabel_ = new QLabel(this); + page1Layout->addWidget(statusTextLabel_); + + icons_[StatusShow::Online] = QIcon(":/icons/online.png"); + icons_[StatusShow::Away] = QIcon(":/icons/away.png"); + icons_[StatusShow::DND] = QIcon(":/icons/dnd.png"); + icons_[StatusShow::None] = QIcon(":/icons/offline.png"); + + setStatusType(StatusShow::None); + + QWidget* page2 = new QWidget(this); + QHBoxLayout* page2Layout = new QHBoxLayout(page2); + page2Layout->setSpacing(0); + page2Layout->setContentsMargins(0,0,0,0); + stack_->addWidget(page2); + + statusEdit_ = new QLineEdit(this); + page2Layout->addWidget(statusEdit_); + connect(statusEdit_, SIGNAL(returnPressed()), this, SLOT(handleEditComplete())); + connect(statusEdit_, SIGNAL(textChanged(const QString&)), this, SLOT(generateList())); + + setStatusText(""); + + + menu_ = new QListWidget(); + menu_->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + menu_->setAlternatingRowColors(true); + + connect(menu_, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(handleItemClicked(QListWidgetItem*))); + viewMode(); } -void QtStatusWidget::handleTypeSelected(int index) { - Q_UNUSED(index); - emit onChangeStatusRequest(getSelectedStatusShow()); +QtStatusWidget::~QtStatusWidget() { + delete menu_; +} + +void QtStatusWidget::mousePressEvent(QMouseEvent*) { + handleClicked(); +} + +void QtStatusWidget::generateList() { + QString text = statusEdit_->text(); + menu_->clear(); + foreach (StatusShow::Type type, icons_.keys()) { + QListWidgetItem* item = new QListWidgetItem(text, menu_); + item->setIcon(icons_[type]); + item->setData(Qt::UserRole, QVariant(type)); + } +} + + +void QtStatusWidget::handleClicked() { + QPoint point = mapToGlobal(QPoint(0, height())); + int x = point.x(); + int y = point.y(); + int width = 200; + int height = 80; + int screenWidth = QApplication::desktop()->screenGeometry().width(); + if (x + width > screenWidth) { + x = screenWidth - width; + } + menu_->setGeometry(x, y, width, height); + menu_->setMaximumWidth(width); + QSizePolicy policy(menu_->sizePolicy()); + policy.setVerticalPolicy(QSizePolicy::Expanding); + menu_->setSizePolicy(policy); + menu_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + generateList(); + + menu_->show(); + activateWindow(); + stack_->setCurrentIndex(1); + statusEdit_->setFocus(); +} + +void QtStatusWidget::viewMode() { + menu_->hide(); + stack_->setCurrentIndex(0); +} + +void QtStatusWidget::handleEditComplete() { + statusText_ = statusEdit_->text(); + viewMode(); + emit onChangeStatusRequest(selectedStatusType_, statusText_); +} + +void QtStatusWidget::handleEditCancelled() { + setStatusText(statusText_); + viewMode(); } StatusShow::Type QtStatusWidget::getSelectedStatusShow() { - return (StatusShow::Type)types_->itemData(types_->currentIndex()).toInt(); + return selectedStatusType_; +} + +void QtStatusWidget::handleItemClicked(QListWidgetItem* item) { + selectedStatusType_ = (StatusShow::Type)(item->data(Qt::UserRole).toInt()); + handleEditComplete(); +} + + +void QtStatusWidget::setStatusText(const QString& text) { + statusText_ = text; + statusEdit_->setText(text); + QString escapedText(text.isEmpty() ? "(No message)" : text); + escapedText.replace("<","<"); + statusTextLabel_->setText("<i>" + escapedText + "</i>"); } void QtStatusWidget::setStatusType(StatusShow::Type type) { - for (int i = 0; i < types_->count(); i++) { - if (types_->itemData(i).toInt() == type) { - types_->setCurrentIndex(i); - break; - } - } + selectedStatusType_ = icons_.contains(type) ? type : StatusShow::Online; + statusIcon_->setPixmap(icons_[selectedStatusType_].pixmap(16, 16)); } } diff --git a/Swift/QtUI/QtStatusWidget.h b/Swift/QtUI/QtStatusWidget.h index 95c1870..84994d8 100644 --- a/Swift/QtUI/QtStatusWidget.h +++ b/Swift/QtUI/QtStatusWidget.h @@ -10,23 +10,50 @@ #include "Swiften/Elements/StatusShow.h" #include <QWidget> +#include <QMap> +#include <QIcon> class QComboBox; +class QLabel; +class QStackedWidget; class QLineEdit; +class QListWidget; +class QListWidgetItem; namespace Swift { class QtStatusWidget : public QWidget { Q_OBJECT public: QtStatusWidget(QWidget *parent); + ~QtStatusWidget(); StatusShow::Type getSelectedStatusShow(); void setStatusType(StatusShow::Type type); signals: - void onChangeStatusRequest(StatusShow::Type showType); + void onChangeStatusRequest(StatusShow::Type showType, const QString& text); + public slots: + void setStatusText(const QString& text); private slots: - void handleTypeSelected(int index); + void generateList(); + void handleClicked(); + void handleEditComplete(); + void handleEditCancelled(); + protected slots: + virtual void mousePressEvent(QMouseEvent* event); + void handleItemClicked(QListWidgetItem* item); private: - QComboBox *types_; + void viewMode(); + //QComboBox *types_; + QStackedWidget* stack_; + QLabel* statusIcon_; + QLabel* statusTextLabel_; + QLineEdit* statusEdit_; + QString statusText_; + QMap<StatusShow::Type, QIcon> icons_; + StatusShow::Type selectedStatusType_; + bool isClicking_; + QListWidget* menu_; + QCursor editCursor_; + QCursor viewCursor_; }; } -- cgit v0.10.2-6-g49f6