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("<","&lt;");
-	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("<","&lt;");
-		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("<","&lt;");
+// 	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("<","&lt;");
+// 		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("<","&lt;");
+	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