diff --git a/interface/resources/images/pin.svg b/interface/resources/images/pin.svg
deleted file mode 100644
index ec968a1ec1..0000000000
--- a/interface/resources/images/pin.svg
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
diff --git a/interface/resources/images/pinned.svg b/interface/resources/images/pinned.svg
deleted file mode 100644
index bda6f0e747..0000000000
--- a/interface/resources/images/pinned.svg
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 4adb2f772a..ab505ede93 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -3520,35 +3520,30 @@ void Application::parseVersionXml() {
QString operatingSystem("ubuntu");
#endif
- QString releaseDate;
- QString releaseNotes;
QString latestVersion;
QUrl downloadUrl;
+ QString releaseNotes("Unavailable");
QObject* sender = QObject::sender();
QXmlStreamReader xml(qobject_cast(sender));
+
while (!xml.atEnd() && !xml.hasError()) {
- QXmlStreamReader::TokenType token = xml.readNext();
-
- if (token == QXmlStreamReader::StartElement) {
- if (xml.name() == "ReleaseDate") {
+ if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
+ while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) {
+ if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") {
+ xml.readNext();
+ latestVersion = xml.text().toString();
+ }
+ if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "url") {
+ xml.readNext();
+ downloadUrl = QUrl(xml.text().toString());
+ }
xml.readNext();
- releaseDate = xml.text().toString();
- }
- if (xml.name() == "ReleaseNotes") {
- xml.readNext();
- releaseNotes = xml.text().toString();
- }
- if (xml.name() == "Version") {
- xml.readNext();
- latestVersion = xml.text().toString();
- }
- if (xml.name() == operatingSystem) {
- xml.readNext();
- downloadUrl = QUrl(xml.text().toString());
}
}
+ xml.readNext();
}
+
if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 5983b0d1a9..325770a8df 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -16,6 +16,7 @@
#include
#include
+#include
#include
#include
#include
diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp
index c182f6e842..68e38615bf 100644
--- a/interface/src/Audio.cpp
+++ b/interface/src/Audio.cpp
@@ -644,10 +644,10 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
const int NUM_INITIAL_PACKETS_DISCARD = 3;
const int STANDARD_DEVIATION_SAMPLE_COUNT = 500;
- _timeSinceLastRecieved.start();
_totalPacketsReceived++;
- double timeDiff = (double)_timeSinceLastRecieved.nsecsElapsed() / 1000000.0; // ns to ms
+ double timeDiff = (double)_timeSinceLastReceived.nsecsElapsed() / 1000000.0; // ns to ms
+ _timeSinceLastReceived.start();
// Discard first few received packets for computing jitter (often they pile up on start)
if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) {
@@ -1265,7 +1265,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo)
// setup a procedural audio output device
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
- _timeSinceLastRecieved.start();
+ _timeSinceLastReceived.start();
// setup spatial audio ringbuffer
int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount();
diff --git a/interface/src/Audio.h b/interface/src/Audio.h
index e1b8a7dddc..277c606d4b 100644
--- a/interface/src/Audio.h
+++ b/interface/src/Audio.h
@@ -129,7 +129,7 @@ private:
QString _outputAudioDeviceName;
StDev _stdev;
- QElapsedTimer _timeSinceLastRecieved;
+ QElapsedTimer _timeSinceLastReceived;
float _averagedLatency;
float _measuredJitter;
int16_t _jitterBufferSamples;
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index a7012d838d..5006bec608 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include
@@ -970,6 +971,17 @@ void Menu::goToUser(const QString& user) {
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
}
+/// Open a url, shortcutting any "hifi" scheme URLs to the local application.
+void Menu::openUrl(const QUrl& url) {
+ if (url.scheme() == "hifi") {
+ QString path = url.toString(QUrl::RemoveScheme);
+ path = path.remove(QRegExp("^:?/*"));
+ goTo(path);
+ } else {
+ QDesktopServices::openUrl(url);
+ }
+}
+
void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
QMessageBox msgBox;
msgBox.setText("Both user and location exists with same name");
@@ -1145,23 +1157,22 @@ void Menu::showScriptEditor() {
void Menu::showChat() {
QMainWindow* mainWindow = Application::getInstance()->getWindow();
if (!_chatWindow) {
- mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow());
+ _chatWindow = new ChatWindow(mainWindow);
}
- if (!_chatWindow->toggleViewAction()->isChecked()) {
- const QRect& windowGeometry = mainWindow->geometry();
- _chatWindow->move(windowGeometry.topRight().x() - _chatWindow->width(),
- windowGeometry.topRight().y() + (windowGeometry.height() / 2) - (_chatWindow->height() / 2));
-
- _chatWindow->resize(0, _chatWindow->height());
- _chatWindow->toggleViewAction()->trigger();
+ if (_chatWindow->isHidden()) {
+ _chatWindow->show();
}
}
void Menu::toggleChat() {
#ifdef HAVE_QXMPP
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
- if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) {
- _chatWindow->toggleViewAction()->trigger();
+ if (!_chatAction->isEnabled() && _chatWindow) {
+ if (_chatWindow->isHidden()) {
+ _chatWindow->show();
+ } else {
+ _chatWindow->hide();
+ }
}
#endif
}
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index 09b5fabfc8..88de62a260 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -154,6 +154,7 @@ public slots:
void goTo();
void goToUser(const QString& user);
void pasteToVoxel();
+ void openUrl(const QUrl& url);
void toggleLoginMenuItem();
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index fb547da13e..140756e9d7 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
@@ -1184,6 +1185,8 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
setPosition(newPosition);
emit transformChanged();
+ } else {
+ QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
}
}
diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp
index 8009551b6c..f80c331df4 100644
--- a/interface/src/location/LocationManager.cpp
+++ b/interface/src/location/LocationManager.cpp
@@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include
+
#include "Application.h"
#include "LocationManager.h"
@@ -118,6 +120,8 @@ void LocationManager::checkForMultipleDestinations() {
Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData);
return;
}
+
+ QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
}
}
diff --git a/interface/src/ui/ChatInputArea.cpp b/interface/src/ui/ChatInputArea.cpp
new file mode 100644
index 0000000000..3e8fc84fe2
--- /dev/null
+++ b/interface/src/ui/ChatInputArea.cpp
@@ -0,0 +1,19 @@
+//
+// ChatInputArea.cpp
+// interface/src/ui
+//
+// Created by Ryan Huffman on 4/24/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "ChatInputArea.h"
+
+ChatInputArea::ChatInputArea(QWidget* parent) : QTextEdit(parent) {
+};
+
+void ChatInputArea::insertFromMimeData(const QMimeData* source) {
+ insertPlainText(source->text());
+};
diff --git a/interface/src/ui/ChatInputArea.h b/interface/src/ui/ChatInputArea.h
new file mode 100644
index 0000000000..31d1584df7
--- /dev/null
+++ b/interface/src/ui/ChatInputArea.h
@@ -0,0 +1,27 @@
+//
+// ChatInputArea.h
+// interface/src/ui
+//
+// Created by Ryan Huffman on 4/11/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_ChatInputArea_h
+#define hifi_ChatInputArea_h
+
+#include
+#include
+
+class ChatInputArea : public QTextEdit {
+ Q_OBJECT
+public:
+ ChatInputArea(QWidget* parent);
+
+protected:
+ void insertFromMimeData(const QMimeData* source);
+};
+
+#endif // hifi_ChatInputArea_h
diff --git a/interface/src/ui/ChatMessageArea.cpp b/interface/src/ui/ChatMessageArea.cpp
index f15b788990..1e16a8a2db 100644
--- a/interface/src/ui/ChatMessageArea.cpp
+++ b/interface/src/ui/ChatMessageArea.cpp
@@ -9,13 +9,18 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include "Application.h"
#include "ChatMessageArea.h"
#include
#include
-ChatMessageArea::ChatMessageArea() : QTextBrowser() {
+ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixedHeight(useFixedHeight) {
+ setOpenLinks(false);
+
connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
this, &ChatMessageArea::updateLayout);
+ connect(this, &QTextBrowser::anchorClicked,
+ Menu::getInstance(), &Menu::openUrl);
}
void ChatMessageArea::setHtml(const QString& html) {
@@ -34,7 +39,15 @@ void ChatMessageArea::setHtml(const QString& html) {
}
void ChatMessageArea::updateLayout() {
- setFixedHeight(document()->size().height());
+ if (_useFixedHeight) {
+ setFixedHeight(document()->size().height());
+ updateGeometry();
+ emit sizeChanged(size());
+ }
+}
+
+void ChatMessageArea::setSize(const QSize& size) {
+ setFixedHeight(size.height());
updateGeometry();
}
diff --git a/interface/src/ui/ChatMessageArea.h b/interface/src/ui/ChatMessageArea.h
index 1c49c60b08..57199538fd 100644
--- a/interface/src/ui/ChatMessageArea.h
+++ b/interface/src/ui/ChatMessageArea.h
@@ -19,15 +19,19 @@ const int CHAT_MESSAGE_LINE_HEIGHT = 130;
class ChatMessageArea : public QTextBrowser {
Q_OBJECT
public:
- ChatMessageArea();
+ ChatMessageArea(bool useFixedHeight = true);
virtual void setHtml(const QString& html);
public slots:
void updateLayout();
+ void setSize(const QSize& size);
+
+signals:
+ void sizeChanged(QSize newSize);
protected:
virtual void wheelEvent(QWheelEvent* event);
-
+ bool _useFixedHeight;
};
#endif // hifi_ChatMessageArea_h
diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp
index 635f1f3d10..e0802c6bc5 100644
--- a/interface/src/ui/ChatWindow.cpp
+++ b/interface/src/ui/ChatWindow.cpp
@@ -12,12 +12,10 @@
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#include "Application.h"
#include "FlowLayout.h"
@@ -31,32 +29,40 @@
const int NUM_MESSAGES_TO_TIME_STAMP = 20;
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
+const QRegularExpression regexHifiLinks("([#@]\\S+)");
-ChatWindow::ChatWindow() :
+ChatWindow::ChatWindow(QWidget* parent) :
+ FramelessDialog(parent, 0, POSITION_RIGHT),
ui(new Ui::ChatWindow),
numMessagesAfterLastTimeStamp(0),
_mousePressed(false),
_mouseStartPosition()
{
- ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, false);
- // remove the title bar (see the Qt docs on setTitleBarWidget), but we keep it for undocking
- //
- titleBar = titleBarWidget();
- setTitleBarWidget(new QWidget());
+ ui->setupUi(this);
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
ui->usersWidget->setLayout(flowLayout);
- ui->messagesGridLayout->setColumnStretch(0, 1);
- ui->messagesGridLayout->setColumnStretch(1, 3);
-
ui->messagePlainTextEdit->installEventFilter(this);
+ ui->messagePlainTextEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+
+ QTextCursor cursor(ui->messagePlainTextEdit->textCursor());
+
+ cursor.movePosition(QTextCursor::Start);
+
+ QTextBlockFormat format = cursor.blockFormat();
+ format.setLineHeight(130, QTextBlockFormat::ProportionalHeight);
+
+ cursor.setBlockFormat(format);
+
+ ui->messagePlainTextEdit->setTextCursor(cursor);
if (!AccountManager::getInstance().isLoggedIn()) {
ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others."));
}
-
+
#ifdef HAVE_QXMPP
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
if (xmppClient.isConnected()) {
@@ -89,36 +95,17 @@ ChatWindow::~ChatWindow() {
delete ui;
}
-void ChatWindow::mousePressEvent(QMouseEvent *e) {
- if (e->button() == Qt::LeftButton && isFloating()) {
- _mousePressed = true;
- _mouseStartPosition = e->pos();
- }
-}
-
-void ChatWindow::mouseMoveEvent(QMouseEvent *e) {
- if (_mousePressed) {
- move(mapToParent(e->pos() - _mouseStartPosition));
- }
-}
-
-void ChatWindow::mouseReleaseEvent( QMouseEvent *e ) {
- if ( e->button() == Qt::LeftButton ) {
- _mousePressed = false;
- }
-}
-
void ChatWindow::keyPressEvent(QKeyEvent* event) {
- QDockWidget::keyPressEvent(event);
if (event->key() == Qt::Key_Escape) {
hide();
+ } else {
+ FramelessDialog::keyPressEvent(event);
}
}
void ChatWindow::showEvent(QShowEvent* event) {
- QDockWidget::showEvent(event);
+ FramelessDialog::showEvent(event);
if (!event->spontaneous()) {
- activateWindow();
ui->messagePlainTextEdit->setFocus();
}
}
@@ -141,18 +128,20 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
message.setBody(messageText);
XmppClient::getInstance().getXMPPClient().sendPacket(message);
#endif
- ui->messagePlainTextEdit->document()->clear();
+ QTextCursor cursor = ui->messagePlainTextEdit->textCursor();
+ cursor.select(QTextCursor::Document);
+ cursor.removeSelectedText();
}
return true;
}
- } else {
- if (event->type() != QEvent::MouseButtonRelease) {
- return false;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QVariant userVar = sender->property("user");
+ if (userVar.isValid()) {
+ Menu::getInstance()->goToUser("@" + userVar.toString());
+ return true;
}
- QString user = sender->property("user").toString();
- Menu::getInstance()->goToUser(user);
}
- return false;
+ return FramelessDialog::eventFilter(sender, event);
}
#ifdef HAVE_QXMPP
@@ -175,16 +164,17 @@ void ChatWindow::addTimeStamp() {
timeString.chop(1);
if (!timeString.isEmpty()) {
QLabel* timeLabel = new QLabel(timeString);
- timeLabel->setStyleSheet("color: palette(shadow);"
- "background-color: palette(highlight);"
+ timeLabel->setStyleSheet("color: #333333;"
+ "background-color: white;"
+ "font-size: 14pt;"
"padding: 4px;");
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- timeLabel->setAlignment(Qt::AlignHCenter);
+ timeLabel->setAlignment(Qt::AlignLeft);
- bool atBottom = isAtBottom();
+ bool atBottom = isNearBottom();
- ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2);
- ui->messagesGridLayout->parentWidget()->updateGeometry();
+ ui->messagesVBoxLayout->addWidget(timeLabel);
+ ui->messagesVBoxLayout->parentWidget()->updateGeometry();
Application::processEvents();
numMessagesAfterLastTimeStamp = 0;
@@ -249,6 +239,7 @@ void ChatWindow::participantsChanged() {
"padding-bottom: 2px;"
"padding-left: 2px;"
"border: 1px solid palette(shadow);"
+ "font-size: 14pt;"
"font-weight: bold");
userLabel->setProperty("user", participantName);
userLabel->setCursor(Qt::PointingHandCursor);
@@ -262,15 +253,11 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
return;
}
- QLabel* userLabel = new QLabel(getParticipantName(message.from()));
- userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- userLabel->setStyleSheet("padding: 2px; font-weight: bold");
- userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
+ // Update background if this is a message from the current user
+ bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername();
- ChatMessageArea* messageArea = new ChatMessageArea();
-
- messageArea->setOpenLinks(true);
- messageArea->setOpenExternalLinks(true);
+ // Create message area
+ ChatMessageArea* messageArea = new ChatMessageArea(true);
messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction);
messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -281,22 +268,30 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
"padding-left: 2px;"
"padding-top: 2px;"
"padding-right: 20px;"
+ "margin: 0px;"
+ "color: #333333;"
+ "font-size: 14pt;"
"background-color: rgba(0, 0, 0, 0%);"
"border: 0;");
- bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername();
+ QString userLabel = getParticipantName(message.from());
if (fromSelf) {
- userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea");
- messageArea->setStyleSheet(messageArea->styleSheet() + "; background-color: #e1e8ea");
+ userLabel = "" + userLabel + ": ";
+ messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea");
+ } else {
+ userLabel = "" + userLabel + ": ";
}
- messageArea->setHtml(message.body().replace(regexLinks, "\\1"));
+ messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}");
+ QString messageText = message.body().toHtmlEscaped();
+ messageText = messageText.replace(regexLinks, "\\1");
+ messageText = messageText.replace(regexHifiLinks, "\\1");
+ messageArea->setHtml(userLabel + messageText);
- bool atBottom = isAtBottom();
- ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0);
- ui->messagesGridLayout->addWidget(messageArea, ui->messagesGridLayout->rowCount() - 1, 1);
+ bool atBottom = isNearBottom();
- ui->messagesGridLayout->parentWidget()->updateGeometry();
+ ui->messagesVBoxLayout->addWidget(messageArea);
+ ui->messagesVBoxLayout->parentWidget()->updateGeometry();
Application::processEvents();
if (atBottom || fromSelf) {
@@ -313,26 +308,13 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
#endif
-bool ChatWindow::isAtBottom() {
+bool ChatWindow::isNearBottom() {
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
- return verticalScrollBar->sliderPosition() == verticalScrollBar->maximum();
+ return verticalScrollBar->value() >= verticalScrollBar->maximum() - Ui::AUTO_SCROLL_THRESHOLD;
}
// Scroll chat message area to bottom.
void ChatWindow::scrollToBottom() {
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
- verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());
-}
-
-void ChatWindow::togglePinned() {
- QMainWindow* mainWindow = Application::getInstance()->getWindow();
- mainWindow->removeDockWidget(this);
- if (ui->togglePinnedButton->isChecked()) {
- mainWindow->addDockWidget(ui->togglePinnedButton->isChecked() ? Qt::RightDockWidgetArea : Qt::NoDockWidgetArea, this);
- }
- if (!this->toggleViewAction()->isChecked()) {
- this->toggleViewAction()->trigger();
- }
- this->setFloating(!ui->togglePinnedButton->isChecked());
- setTitleBarWidget(ui->togglePinnedButton->isChecked()?new QWidget():titleBar);
+ verticalScrollBar->setValue(verticalScrollBar->maximum());
}
diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h
index 6a807f9b81..104fbe1746 100644
--- a/interface/src/ui/ChatWindow.h
+++ b/interface/src/ui/ChatWindow.h
@@ -17,6 +17,7 @@
#include
#include
+#include "FramelessDialog.h"
#ifdef HAVE_QXMPP
@@ -26,37 +27,38 @@
#endif
namespace Ui {
+
+
+// Maximum amount the chat can be scrolled up in order to auto scroll.
+const int AUTO_SCROLL_THRESHOLD = 20;
+
+
class ChatWindow;
}
-class ChatWindow : public QDockWidget {
+class ChatWindow : public FramelessDialog {
Q_OBJECT
public:
- ChatWindow();
+ ChatWindow(QWidget* parent);
~ChatWindow();
- virtual void keyPressEvent(QKeyEvent *event);
- virtual void showEvent(QShowEvent* event);
-
- virtual void mousePressEvent(QMouseEvent *e);
- virtual void mouseMoveEvent(QMouseEvent *e);
- virtual void mouseReleaseEvent(QMouseEvent *e);
-
protected:
bool eventFilter(QObject* sender, QEvent* event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void showEvent(QShowEvent* event);
+
private:
#ifdef HAVE_QXMPP
QString getParticipantName(const QString& participant);
#endif
void startTimerForTimeStamps();
void addTimeStamp();
- bool isAtBottom();
+ bool isNearBottom();
void scrollToBottom();
Ui::ChatWindow* ui;
- QWidget* titleBar;
int numMessagesAfterLastTimeStamp;
QDateTime lastMessageStamp;
bool _mousePressed;
@@ -65,7 +67,6 @@ private:
private slots:
void connected();
void timeout();
- void togglePinned();
#ifdef HAVE_QXMPP
void error(QXmppClient::Error error);
void participantsChanged();
diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp
index 18e3bca89a..4919e99db6 100644
--- a/interface/src/ui/FramelessDialog.cpp
+++ b/interface/src/ui/FramelessDialog.cpp
@@ -14,8 +14,13 @@
const int RESIZE_HANDLE_WIDTH = 7;
-FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) :
-QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) {
+FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) :
+ QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
+ _isResizing(false),
+ _resizeInitialWidth(0),
+ _selfHidden(false),
+ _position(position) {
+
setAttribute(Qt::WA_DeleteOnClose);
// handle rezize and move events
@@ -29,29 +34,37 @@ bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) {
switch (event->type()) {
case QEvent::Move:
if (sender == parentWidget()) {
- // move to upper left corner on app move
- move(parentWidget()->geometry().topLeft());
+ resizeAndPosition(false);
}
break;
case QEvent::Resize:
if (sender == parentWidget()) {
- // keep full app height on resizing the app
- setFixedHeight(parentWidget()->size().height());
+ resizeAndPosition(false);
}
break;
case QEvent::WindowStateChange:
if (parentWidget()->isMinimized()) {
- setHidden(true);
- } else {
+ if (isVisible()) {
+ _selfHidden = true;
+ setHidden(true);
+ }
+ } else if (_selfHidden) {
+ _selfHidden = false;
setHidden(false);
}
break;
case QEvent::ApplicationDeactivate:
// hide on minimize and focus lost
- setHidden(true);
+ if (isVisible()) {
+ _selfHidden = true;
+ setHidden(true);
+ }
break;
case QEvent::ApplicationActivate:
- setHidden(false);
+ if (_selfHidden) {
+ _selfHidden = false;
+ setHidden(false);
+ }
break;
default:
break;
@@ -70,21 +83,38 @@ void FramelessDialog::setStyleSheetFile(const QString& fileName) {
}
void FramelessDialog::showEvent(QShowEvent* event) {
- // move to upper left corner
- move(parentWidget()->geometry().topLeft());
+ resizeAndPosition();
+}
+void FramelessDialog::resizeAndPosition(bool resizeParent) {
// keep full app height
setFixedHeight(parentWidget()->size().height());
// resize parrent if width is smaller than this dialog
- if (parentWidget()->size().width() < size().width()) {
+ if (resizeParent && parentWidget()->size().width() < size().width()) {
parentWidget()->resize(size().width(), parentWidget()->size().height());
}
+
+ if (_position == POSITION_LEFT) {
+ // move to upper left corner
+ move(parentWidget()->geometry().topLeft());
+ } else if (_position == POSITION_RIGHT) {
+ // move to upper right corner
+ QPoint pos = parentWidget()->geometry().topRight();
+ pos.setX(pos.x() - size().width());
+ move(pos);
+ }
}
+
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
- if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) {
- _isResizing = true;
- QApplication::setOverrideCursor(Qt::SizeHorCursor);
+ if (mouseEvent->button() == Qt::LeftButton) {
+ bool hitLeft = _position == POSITION_LEFT && abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH;
+ bool hitRight = _position == POSITION_RIGHT && mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH;
+ if (hitLeft || hitRight) {
+ _isResizing = true;
+ _resizeInitialWidth = size().width();
+ QApplication::setOverrideCursor(Qt::SizeHorCursor);
+ }
}
}
@@ -95,6 +125,14 @@ void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
if (_isResizing) {
- resize(mouseEvent->pos().x(), size().height());
+ if (_position == POSITION_LEFT) {
+ resize(mouseEvent->pos().x(), size().height());
+ } else if (_position == POSITION_RIGHT) {
+ setUpdatesEnabled(false);
+ resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height());
+ resizeAndPosition();
+ _resizeInitialWidth = size().width();
+ setUpdatesEnabled(true);
+ }
}
}
diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h
index db9f6dfd6c..828602a5db 100644
--- a/interface/src/ui/FramelessDialog.h
+++ b/interface/src/ui/FramelessDialog.h
@@ -19,7 +19,9 @@ class FramelessDialog : public QDialog {
Q_OBJECT
public:
- FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0);
+ enum Position { POSITION_LEFT, POSITION_RIGHT };
+
+ FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT);
void setStyleSheetFile(const QString& fileName);
protected:
@@ -31,7 +33,12 @@ protected:
bool eventFilter(QObject* sender, QEvent* event);
private:
+ void resizeAndPosition(bool resizeParent = true);
+
bool _isResizing;
+ int _resizeInitialWidth;
+ bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization)
+ Position _position;
};
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 36508e94d1..7a70b743bd 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -19,7 +19,7 @@ const int SCROLL_PANEL_BOTTOM_MARGIN = 30;
const int OK_BUTTON_RIGHT_MARGIN = 30;
const int BUTTONS_TOP_MARGIN = 24;
-PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags) {
+PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags, POSITION_LEFT) {
ui.setupUi(this);
setStyleSheetFile("styles/preferences.qss");
@@ -38,26 +38,34 @@ void PreferencesDialog::accept() {
void PreferencesDialog::setHeadUrl(QString modelUrl) {
ui.faceURLEdit->setText(modelUrl);
- setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
}
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
ui.skeletonURLEdit->setText(modelUrl);
- setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
}
void PreferencesDialog::openHeadModelBrowser() {
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
+ show();
+
ModelsBrowser modelBrowser(Head);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
modelBrowser.browse();
+
+ setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
+ show();
}
void PreferencesDialog::openBodyModelBrowser() {
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
+ show();
+
ModelsBrowser modelBrowser(Skeleton);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
modelBrowser.browse();
+
+ setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
+ show();
}
void PreferencesDialog::openSnapshotLocationBrowser() {
@@ -176,6 +184,7 @@ void PreferencesDialog::savePreferences() {
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
+ Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value());
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
Application::getInstance()->getGLWidget()->height());
diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui
index 0372e00c09..4d223b2665 100644
--- a/interface/ui/chatWindow.ui
+++ b/interface/ui/chatWindow.ui
@@ -1,13 +1,13 @@
ChatWindow
-
+
0
0
400
- 608
+ 440
@@ -16,127 +16,95 @@
238
-
- font-family: Helvetica, Arial, sans-serif;
-
-
- QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable
-
-
- Qt::NoDockWidgetArea
-
Chat
-
-
-
- 0
-
-
- 8
-
-
- 8
-
-
- 8
-
-
- 8
-
- -
-
-
-
- 0
- 0
-
-
-
- Connecting to XMPP...
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- font-weight: bold; color: palette(shadow); margin-bottom: 4px;
-
-
- online now:
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 16
- 16
-
-
-
- Qt::NoFocus
-
-
-
-
-
-
- ../resources/images/pin.svg
- ../resources/images/pinned.svg../resources/images/pin.svg
-
-
- true
-
-
- true
-
-
- false
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 16
- 16
-
-
-
- Qt::NoFocus
-
-
- QPushButton {
+
+ font-family: Helvetica, Arial, sans-serif;
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 0
+
+
+ 8
+
+
+ 8
+
+
+ 8
+
+
+ 8
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Connecting to XMPP...
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ font-weight: bold; color: palette(shadow); margin-bottom: 4px;
+
+
+ online now:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+ Qt::NoFocus
+
+
+ QPushButton {
background-color: rgba( 0, 0, 0, 0% );
border: none;
image: url(../resources/images/close.svg)
@@ -148,50 +116,104 @@ QPushButton:pressed {
border: none;
image: url(../resources/images/close_down.svg)
}
-
-
-
-
-
- true
-
-
-
-
-
- -
-
-
- -
-
-
- margin-top: 12px;
-
-
- Qt::ScrollBarAlwaysOff
-
-
- true
-
-
-
-
- 0
- 0
- 382
- 16
-
+
+
+
+
+
+ true
+
+
+
+
+
+ -
+
+
+ #usersWidget {
+ margin-right: 20px;
+}
+
+
+ -
+
+
+ margin-top: 12px;
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 382
+ 16
+
+
+
+
+ 0
+ 0
+
+
+
+ margin-top: 0px;
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+ -
+
-
+
0
0
-
- margin-top: 0px;
+
+
+ 0
+ 78
+
-
+
+ #chatFrame {
+border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;
+}
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Raised
+
+
+ 0
+
+
0
@@ -204,69 +226,65 @@ QPushButton:pressed {
0
-
- 0
-
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 60
+
+
+
+
+ Helvetica,Arial,sans-serif
+ 14
+
+
+
+
+
+
+ QFrame::NoFrame
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+ true
+
+
+ false
+
+
+
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 60
-
-
-
- border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;
-
-
- QFrame::NoFrame
-
-
- Qt::ScrollBarAlwaysOff
-
-
- QAbstractScrollArea::AdjustToContents
-
-
- true
-
-
-
-
-
+
+
+
+
+
+
+ ChatInputArea
+ QTextEdit
+
+
+
- messagePlainTextEdit
messagesScrollArea
-
- togglePinnedButton
- clicked()
- ChatWindow
- togglePinned()
-
-
- 390
- 42
-
-
- 550
- 42
-
-
-
closeButton
clicked()