Merge branch 'master' of https://github.com/highfidelity/hifi into improved_undo

This commit is contained in:
Atlante45 2014-04-25 11:41:43 -07:00
commit 860766fb49
20 changed files with 494 additions and 565 deletions

View file

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="44px"
height="44px"
viewBox="0 0 44 44"
version="1.1"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="close.svg">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Slice 1</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview14"
showgrid="false"
inkscape:zoom="3.7926636"
inkscape:cx="57.156875"
inkscape:cy="33.978935"
inkscape:window-x="536"
inkscape:window-y="258"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<title
id="title4">Slice 1</title>
<description
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs
id="defs8" />
<g
id="Page-1"
sketch:type="MSPage"
transform="translate(0.52733383,0.52733392)"
style="fill:none;stroke:none" />
<rect
id="rect2993"
width="5.7796612"
height="26.101694"
x="19.730724"
y="16.374792"
ry="3.371469" />
<rect
id="rect2995"
width="35.423729"
height="2.9830508"
x="4.6290293"
y="2.3917408"
ry="1.4915254" />
<rect
id="rect2999"
width="31.135593"
height="21.067797"
x="6.6798768"
y="4.0697069"
ry="1.4915254" />
<rect
style="fill:#ff0000"
id="rect3003"
width="27.779657"
height="17.711861"
x="8.171401"
y="5.3747911"
ry="0.46610171" />
<rect
style="fill:#999999"
id="rect3011"
width="3.1694915"
height="13.983051"
x="21.035809"
y="25.883266"
ry="0.46610171" />
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="44px"
height="44px"
viewBox="0 0 44 44"
version="1.1"
id="svg2"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="pin.svg">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Slice 1</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1058"
id="namedview14"
showgrid="false"
inkscape:zoom="3.7926636"
inkscape:cx="39.754857"
inkscape:cy="33.978935"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<title
id="title4">Slice 1</title>
<description
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs
id="defs8" />
<g
id="Page-1"
sketch:type="MSPage"
transform="translate(0.52733383,0.52733392)"
style="fill:none;stroke:none" />
<rect
style="fill:#b3b3b3"
id="rect3013"
width="43.768692"
height="44.296078"
x="0.26366693"
y="-0.032378189"
ry="0.46610171" />
<rect
id="rect2993"
width="5.7796612"
height="26.101694"
x="19.730724"
y="16.374792"
ry="3.371469" />
<rect
id="rect2995"
width="35.423729"
height="2.9830508"
x="4.6290293"
y="2.3917408"
ry="1.4915254" />
<rect
id="rect2999"
width="31.135593"
height="21.067797"
x="6.6798768"
y="4.0697069"
ry="1.4915254" />
<rect
style="fill:#ff0000"
id="rect3003"
width="27.779657"
height="17.711861"
x="8.171401"
y="5.3747911"
ry="0.46610171" />
<rect
style="fill:#999999"
id="rect3011"
width="3.1694915"
height="13.983051"
x="21.035809"
y="25.883266"
ry="0.46610171" />
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -3520,35 +3520,30 @@ void Application::parseVersionXml() {
QString operatingSystem("ubuntu"); QString operatingSystem("ubuntu");
#endif #endif
QString releaseDate;
QString releaseNotes;
QString latestVersion; QString latestVersion;
QUrl downloadUrl; QUrl downloadUrl;
QString releaseNotes("Unavailable");
QObject* sender = QObject::sender(); QObject* sender = QObject::sender();
QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender)); QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
while (!xml.atEnd() && !xml.hasError()) { while (!xml.atEnd() && !xml.hasError()) {
QXmlStreamReader::TokenType token = xml.readNext(); if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) {
while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) {
if (token == QXmlStreamReader::StartElement) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") {
if (xml.name() == "ReleaseDate") { xml.readNext();
latestVersion = xml.text().toString();
}
if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "url") {
xml.readNext();
downloadUrl = QUrl(xml.text().toString());
}
xml.readNext(); 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) { if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) {
new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl); new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl);
} }

View file

@ -16,6 +16,7 @@
#include <time.h> #include <time.h>
#include <QApplication> #include <QApplication>
#include <QMainWindow>
#include <QAction> #include <QAction>
#include <QHash> #include <QHash>
#include <QImage> #include <QImage>

View file

@ -644,10 +644,10 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
const int NUM_INITIAL_PACKETS_DISCARD = 3; const int NUM_INITIAL_PACKETS_DISCARD = 3;
const int STANDARD_DEVIATION_SAMPLE_COUNT = 500; const int STANDARD_DEVIATION_SAMPLE_COUNT = 500;
_timeSinceLastRecieved.start();
_totalPacketsReceived++; _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) // Discard first few received packets for computing jitter (often they pile up on start)
if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) { if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) {
@ -1265,7 +1265,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo)
// setup a procedural audio output device // setup a procedural audio output device
_proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); _proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
_timeSinceLastRecieved.start(); _timeSinceLastReceived.start();
// setup spatial audio ringbuffer // setup spatial audio ringbuffer
int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount(); int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount();

View file

@ -129,7 +129,7 @@ private:
QString _outputAudioDeviceName; QString _outputAudioDeviceName;
StDev _stdev; StDev _stdev;
QElapsedTimer _timeSinceLastRecieved; QElapsedTimer _timeSinceLastReceived;
float _averagedLatency; float _averagedLatency;
float _measuredJitter; float _measuredJitter;
int16_t _jitterBufferSamples; int16_t _jitterBufferSamples;

View file

@ -27,6 +27,7 @@
#include <QSlider> #include <QSlider>
#include <QUuid> #include <QUuid>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QDesktopServices>
#include <AccountManager.h> #include <AccountManager.h>
#include <XmppClient.h> #include <XmppClient.h>
@ -970,6 +971,17 @@ void Menu::goToUser(const QString& user) {
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); 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) { void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setText("Both user and location exists with same name"); msgBox.setText("Both user and location exists with same name");
@ -1145,23 +1157,22 @@ void Menu::showScriptEditor() {
void Menu::showChat() { void Menu::showChat() {
QMainWindow* mainWindow = Application::getInstance()->getWindow(); QMainWindow* mainWindow = Application::getInstance()->getWindow();
if (!_chatWindow) { if (!_chatWindow) {
mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); _chatWindow = new ChatWindow(mainWindow);
} }
if (!_chatWindow->toggleViewAction()->isChecked()) { if (_chatWindow->isHidden()) {
const QRect& windowGeometry = mainWindow->geometry(); _chatWindow->show();
_chatWindow->move(windowGeometry.topRight().x() - _chatWindow->width(),
windowGeometry.topRight().y() + (windowGeometry.height() / 2) - (_chatWindow->height() / 2));
_chatWindow->resize(0, _chatWindow->height());
_chatWindow->toggleViewAction()->trigger();
} }
} }
void Menu::toggleChat() { void Menu::toggleChat() {
#ifdef HAVE_QXMPP #ifdef HAVE_QXMPP
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) { if (!_chatAction->isEnabled() && _chatWindow) {
_chatWindow->toggleViewAction()->trigger(); if (_chatWindow->isHidden()) {
_chatWindow->show();
} else {
_chatWindow->hide();
}
} }
#endif #endif
} }

View file

@ -154,6 +154,7 @@ public slots:
void goTo(); void goTo();
void goToUser(const QString& user); void goToUser(const QString& user);
void pasteToVoxel(); void pasteToVoxel();
void openUrl(const QUrl& url);
void toggleLoginMenuItem(); void toggleLoginMenuItem();

View file

@ -12,6 +12,7 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <QMessageBox>
#include <QBuffer> #include <QBuffer>
#include <glm/gtx/norm.hpp> #include <glm/gtx/norm.hpp>
@ -1184,6 +1185,8 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) {
coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER;
setPosition(newPosition); setPosition(newPosition);
emit transformChanged(); emit transformChanged();
} else {
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
} }
} }

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QMessageBox>
#include "Application.h" #include "Application.h"
#include "LocationManager.h" #include "LocationManager.h"
@ -118,6 +120,8 @@ void LocationManager::checkForMultipleDestinations() {
Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData); Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData);
return; return;
} }
QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found.");
} }
} }

View file

@ -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());
};

View file

@ -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 <QTextBrowser>
#include <QMimeData>
class ChatInputArea : public QTextEdit {
Q_OBJECT
public:
ChatInputArea(QWidget* parent);
protected:
void insertFromMimeData(const QMimeData* source);
};
#endif // hifi_ChatInputArea_h

View file

@ -9,13 +9,18 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "Application.h"
#include "ChatMessageArea.h" #include "ChatMessageArea.h"
#include <QAbstractTextDocumentLayout> #include <QAbstractTextDocumentLayout>
#include <QWheelEvent> #include <QWheelEvent>
ChatMessageArea::ChatMessageArea() : QTextBrowser() { ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixedHeight(useFixedHeight) {
setOpenLinks(false);
connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
this, &ChatMessageArea::updateLayout); this, &ChatMessageArea::updateLayout);
connect(this, &QTextBrowser::anchorClicked,
Menu::getInstance(), &Menu::openUrl);
} }
void ChatMessageArea::setHtml(const QString& html) { void ChatMessageArea::setHtml(const QString& html) {
@ -34,7 +39,15 @@ void ChatMessageArea::setHtml(const QString& html) {
} }
void ChatMessageArea::updateLayout() { 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(); updateGeometry();
} }

View file

@ -19,15 +19,19 @@ const int CHAT_MESSAGE_LINE_HEIGHT = 130;
class ChatMessageArea : public QTextBrowser { class ChatMessageArea : public QTextBrowser {
Q_OBJECT Q_OBJECT
public: public:
ChatMessageArea(); ChatMessageArea(bool useFixedHeight = true);
virtual void setHtml(const QString& html); virtual void setHtml(const QString& html);
public slots: public slots:
void updateLayout(); void updateLayout();
void setSize(const QSize& size);
signals:
void sizeChanged(QSize newSize);
protected: protected:
virtual void wheelEvent(QWheelEvent* event); virtual void wheelEvent(QWheelEvent* event);
bool _useFixedHeight;
}; };
#endif // hifi_ChatMessageArea_h #endif // hifi_ChatMessageArea_h

View file

@ -12,12 +12,10 @@
#include <QGridLayout> #include <QGridLayout>
#include <QFrame> #include <QFrame>
#include <QLayoutItem> #include <QLayoutItem>
#include <QMainWindow>
#include <QPalette> #include <QPalette>
#include <QScrollBar> #include <QScrollBar>
#include <QSizePolicy> #include <QSizePolicy>
#include <QTimer> #include <QTimer>
#include <QWidget>
#include "Application.h" #include "Application.h"
#include "FlowLayout.h" #include "FlowLayout.h"
@ -31,32 +29,40 @@
const int NUM_MESSAGES_TO_TIME_STAMP = 20; const int NUM_MESSAGES_TO_TIME_STAMP = 20;
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); 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), ui(new Ui::ChatWindow),
numMessagesAfterLastTimeStamp(0), numMessagesAfterLastTimeStamp(0),
_mousePressed(false), _mousePressed(false),
_mouseStartPosition() _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 ui->setupUi(this);
//
titleBar = titleBarWidget();
setTitleBarWidget(new QWidget());
FlowLayout* flowLayout = new FlowLayout(0, 4, 4); FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
ui->usersWidget->setLayout(flowLayout); ui->usersWidget->setLayout(flowLayout);
ui->messagesGridLayout->setColumnStretch(0, 1);
ui->messagesGridLayout->setColumnStretch(1, 3);
ui->messagePlainTextEdit->installEventFilter(this); 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()) { if (!AccountManager::getInstance().isLoggedIn()) {
ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others.")); ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others."));
} }
#ifdef HAVE_QXMPP #ifdef HAVE_QXMPP
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
if (xmppClient.isConnected()) { if (xmppClient.isConnected()) {
@ -89,36 +95,17 @@ ChatWindow::~ChatWindow() {
delete ui; 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) { void ChatWindow::keyPressEvent(QKeyEvent* event) {
QDockWidget::keyPressEvent(event);
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
hide(); hide();
} else {
FramelessDialog::keyPressEvent(event);
} }
} }
void ChatWindow::showEvent(QShowEvent* event) { void ChatWindow::showEvent(QShowEvent* event) {
QDockWidget::showEvent(event); FramelessDialog::showEvent(event);
if (!event->spontaneous()) { if (!event->spontaneous()) {
activateWindow();
ui->messagePlainTextEdit->setFocus(); ui->messagePlainTextEdit->setFocus();
} }
} }
@ -141,18 +128,20 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
message.setBody(messageText); message.setBody(messageText);
XmppClient::getInstance().getXMPPClient().sendPacket(message); XmppClient::getInstance().getXMPPClient().sendPacket(message);
#endif #endif
ui->messagePlainTextEdit->document()->clear(); QTextCursor cursor = ui->messagePlainTextEdit->textCursor();
cursor.select(QTextCursor::Document);
cursor.removeSelectedText();
} }
return true; return true;
} }
} else { } else if (event->type() == QEvent::MouseButtonRelease) {
if (event->type() != QEvent::MouseButtonRelease) { QVariant userVar = sender->property("user");
return false; 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 #ifdef HAVE_QXMPP
@ -175,16 +164,17 @@ void ChatWindow::addTimeStamp() {
timeString.chop(1); timeString.chop(1);
if (!timeString.isEmpty()) { if (!timeString.isEmpty()) {
QLabel* timeLabel = new QLabel(timeString); QLabel* timeLabel = new QLabel(timeString);
timeLabel->setStyleSheet("color: palette(shadow);" timeLabel->setStyleSheet("color: #333333;"
"background-color: palette(highlight);" "background-color: white;"
"font-size: 14pt;"
"padding: 4px;"); "padding: 4px;");
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 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->messagesVBoxLayout->addWidget(timeLabel);
ui->messagesGridLayout->parentWidget()->updateGeometry(); ui->messagesVBoxLayout->parentWidget()->updateGeometry();
Application::processEvents(); Application::processEvents();
numMessagesAfterLastTimeStamp = 0; numMessagesAfterLastTimeStamp = 0;
@ -249,6 +239,7 @@ void ChatWindow::participantsChanged() {
"padding-bottom: 2px;" "padding-bottom: 2px;"
"padding-left: 2px;" "padding-left: 2px;"
"border: 1px solid palette(shadow);" "border: 1px solid palette(shadow);"
"font-size: 14pt;"
"font-weight: bold"); "font-weight: bold");
userLabel->setProperty("user", participantName); userLabel->setProperty("user", participantName);
userLabel->setCursor(Qt::PointingHandCursor); userLabel->setCursor(Qt::PointingHandCursor);
@ -262,15 +253,11 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
return; return;
} }
QLabel* userLabel = new QLabel(getParticipantName(message.from())); // Update background if this is a message from the current user
userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername();
userLabel->setStyleSheet("padding: 2px; font-weight: bold");
userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
ChatMessageArea* messageArea = new ChatMessageArea(); // Create message area
ChatMessageArea* messageArea = new ChatMessageArea(true);
messageArea->setOpenLinks(true);
messageArea->setOpenExternalLinks(true);
messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction); messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction);
messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -281,22 +268,30 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
"padding-left: 2px;" "padding-left: 2px;"
"padding-top: 2px;" "padding-top: 2px;"
"padding-right: 20px;" "padding-right: 20px;"
"margin: 0px;"
"color: #333333;"
"font-size: 14pt;"
"background-color: rgba(0, 0, 0, 0%);" "background-color: rgba(0, 0, 0, 0%);"
"border: 0;"); "border: 0;");
bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername(); QString userLabel = getParticipantName(message.from());
if (fromSelf) { if (fromSelf) {
userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea"); userLabel = "<b style=\"color: #4a6f91\">" + userLabel + ": </b>";
messageArea->setStyleSheet(messageArea->styleSheet() + "; background-color: #e1e8ea"); messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea");
} else {
userLabel = "<b>" + userLabel + ": </b>";
} }
messageArea->setHtml(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>")); messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}");
QString messageText = message.body().toHtmlEscaped();
messageText = messageText.replace(regexLinks, "<a href=\"\\1\">\\1</a>");
messageText = messageText.replace(regexHifiLinks, "<a href=\"hifi://\\1\">\\1</a>");
messageArea->setHtml(userLabel + messageText);
bool atBottom = isAtBottom(); bool atBottom = isNearBottom();
ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0);
ui->messagesGridLayout->addWidget(messageArea, ui->messagesGridLayout->rowCount() - 1, 1);
ui->messagesGridLayout->parentWidget()->updateGeometry(); ui->messagesVBoxLayout->addWidget(messageArea);
ui->messagesVBoxLayout->parentWidget()->updateGeometry();
Application::processEvents(); Application::processEvents();
if (atBottom || fromSelf) { if (atBottom || fromSelf) {
@ -313,26 +308,13 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
#endif #endif
bool ChatWindow::isAtBottom() { bool ChatWindow::isNearBottom() {
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); 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. // Scroll chat message area to bottom.
void ChatWindow::scrollToBottom() { void ChatWindow::scrollToBottom() {
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum()); verticalScrollBar->setValue(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);
} }

View file

@ -17,6 +17,7 @@
#include <QTimer> #include <QTimer>
#include <Application.h> #include <Application.h>
#include "FramelessDialog.h"
#ifdef HAVE_QXMPP #ifdef HAVE_QXMPP
@ -26,37 +27,38 @@
#endif #endif
namespace Ui { 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;
} }
class ChatWindow : public QDockWidget { class ChatWindow : public FramelessDialog {
Q_OBJECT Q_OBJECT
public: public:
ChatWindow(); ChatWindow(QWidget* parent);
~ChatWindow(); ~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: protected:
bool eventFilter(QObject* sender, QEvent* event); bool eventFilter(QObject* sender, QEvent* event);
virtual void keyPressEvent(QKeyEvent *event);
virtual void showEvent(QShowEvent* event);
private: private:
#ifdef HAVE_QXMPP #ifdef HAVE_QXMPP
QString getParticipantName(const QString& participant); QString getParticipantName(const QString& participant);
#endif #endif
void startTimerForTimeStamps(); void startTimerForTimeStamps();
void addTimeStamp(); void addTimeStamp();
bool isAtBottom(); bool isNearBottom();
void scrollToBottom(); void scrollToBottom();
Ui::ChatWindow* ui; Ui::ChatWindow* ui;
QWidget* titleBar;
int numMessagesAfterLastTimeStamp; int numMessagesAfterLastTimeStamp;
QDateTime lastMessageStamp; QDateTime lastMessageStamp;
bool _mousePressed; bool _mousePressed;
@ -65,7 +67,6 @@ private:
private slots: private slots:
void connected(); void connected();
void timeout(); void timeout();
void togglePinned();
#ifdef HAVE_QXMPP #ifdef HAVE_QXMPP
void error(QXmppClient::Error error); void error(QXmppClient::Error error);
void participantsChanged(); void participantsChanged();

View file

@ -14,8 +14,13 @@
const int RESIZE_HANDLE_WIDTH = 7; const int RESIZE_HANDLE_WIDTH = 7;
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) : FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) :
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) { QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
_isResizing(false),
_resizeInitialWidth(0),
_selfHidden(false),
_position(position) {
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
// handle rezize and move events // handle rezize and move events
@ -29,29 +34,37 @@ bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) {
switch (event->type()) { switch (event->type()) {
case QEvent::Move: case QEvent::Move:
if (sender == parentWidget()) { if (sender == parentWidget()) {
// move to upper left corner on app move resizeAndPosition(false);
move(parentWidget()->geometry().topLeft());
} }
break; break;
case QEvent::Resize: case QEvent::Resize:
if (sender == parentWidget()) { if (sender == parentWidget()) {
// keep full app height on resizing the app resizeAndPosition(false);
setFixedHeight(parentWidget()->size().height());
} }
break; break;
case QEvent::WindowStateChange: case QEvent::WindowStateChange:
if (parentWidget()->isMinimized()) { if (parentWidget()->isMinimized()) {
setHidden(true); if (isVisible()) {
} else { _selfHidden = true;
setHidden(true);
}
} else if (_selfHidden) {
_selfHidden = false;
setHidden(false); setHidden(false);
} }
break; break;
case QEvent::ApplicationDeactivate: case QEvent::ApplicationDeactivate:
// hide on minimize and focus lost // hide on minimize and focus lost
setHidden(true); if (isVisible()) {
_selfHidden = true;
setHidden(true);
}
break; break;
case QEvent::ApplicationActivate: case QEvent::ApplicationActivate:
setHidden(false); if (_selfHidden) {
_selfHidden = false;
setHidden(false);
}
break; break;
default: default:
break; break;
@ -70,21 +83,38 @@ void FramelessDialog::setStyleSheetFile(const QString& fileName) {
} }
void FramelessDialog::showEvent(QShowEvent* event) { void FramelessDialog::showEvent(QShowEvent* event) {
// move to upper left corner resizeAndPosition();
move(parentWidget()->geometry().topLeft()); }
void FramelessDialog::resizeAndPosition(bool resizeParent) {
// keep full app height // keep full app height
setFixedHeight(parentWidget()->size().height()); setFixedHeight(parentWidget()->size().height());
// resize parrent if width is smaller than this dialog // 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()); 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) { void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) { if (mouseEvent->button() == Qt::LeftButton) {
_isResizing = true; bool hitLeft = _position == POSITION_LEFT && abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH;
QApplication::setOverrideCursor(Qt::SizeHorCursor); 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) { void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
if (_isResizing) { 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);
}
} }
} }

View file

@ -19,7 +19,9 @@ class FramelessDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: 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); void setStyleSheetFile(const QString& fileName);
protected: protected:
@ -31,7 +33,12 @@ protected:
bool eventFilter(QObject* sender, QEvent* event); bool eventFilter(QObject* sender, QEvent* event);
private: private:
void resizeAndPosition(bool resizeParent = true);
bool _isResizing; bool _isResizing;
int _resizeInitialWidth;
bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization)
Position _position;
}; };

View file

@ -19,7 +19,7 @@ const int SCROLL_PANEL_BOTTOM_MARGIN = 30;
const int OK_BUTTON_RIGHT_MARGIN = 30; const int OK_BUTTON_RIGHT_MARGIN = 30;
const int BUTTONS_TOP_MARGIN = 24; 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); ui.setupUi(this);
setStyleSheetFile("styles/preferences.qss"); setStyleSheetFile("styles/preferences.qss");
@ -38,26 +38,34 @@ void PreferencesDialog::accept() {
void PreferencesDialog::setHeadUrl(QString modelUrl) { void PreferencesDialog::setHeadUrl(QString modelUrl) {
ui.faceURLEdit->setText(modelUrl); ui.faceURLEdit->setText(modelUrl);
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
} }
void PreferencesDialog::setSkeletonUrl(QString modelUrl) { void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
ui.skeletonURLEdit->setText(modelUrl); ui.skeletonURLEdit->setText(modelUrl);
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
} }
void PreferencesDialog::openHeadModelBrowser() { void PreferencesDialog::openHeadModelBrowser() {
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
show();
ModelsBrowser modelBrowser(Head); ModelsBrowser modelBrowser(Head);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl); connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
modelBrowser.browse(); modelBrowser.browse();
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
show();
} }
void PreferencesDialog::openBodyModelBrowser() { void PreferencesDialog::openBodyModelBrowser() {
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
show();
ModelsBrowser modelBrowser(Skeleton); ModelsBrowser modelBrowser(Skeleton);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl); connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
modelBrowser.browse(); modelBrowser.browse();
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
show();
} }
void PreferencesDialog::openSnapshotLocationBrowser() { void PreferencesDialog::openSnapshotLocationBrowser() {
@ -176,6 +184,7 @@ void PreferencesDialog::savePreferences() {
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value()); Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value());
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(), Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
Application::getInstance()->getGLWidget()->height()); Application::getInstance()->getGLWidget()->height());

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>ChatWindow</class> <class>ChatWindow</class>
<widget class="QDockWidget" name="ChatWindow"> <widget class="QDialog" name="ChatWindow">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>400</width>
<height>608</height> <height>440</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -16,127 +16,95 @@
<height>238</height> <height>238</height>
</size> </size>
</property> </property>
<property name="styleSheet">
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::NoDockWidgetArea</set>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Chat</string> <string>Chat</string>
</property> </property>
<widget class="QWidget" name="dockWidgetContents"> <property name="styleSheet">
<layout class="QVBoxLayout" name="verticalLayout"> <string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
<property name="spacing"> </property>
<number>0</number> <layout class="QGridLayout" name="gridLayout">
</property> <property name="leftMargin">
<property name="leftMargin"> <number>0</number>
<number>8</number> </property>
</property> <property name="topMargin">
<property name="topMargin"> <number>0</number>
<number>8</number> </property>
</property> <property name="rightMargin">
<property name="rightMargin"> <number>0</number>
<number>8</number> </property>
</property> <property name="bottomMargin">
<property name="bottomMargin"> <number>0</number>
<number>8</number> </property>
</property> <item row="0" column="0">
<item> <layout class="QVBoxLayout" name="verticalLayout">
<widget class="QLabel" name="connectingToXMPPLabel"> <property name="spacing">
<property name="sizePolicy"> <number>0</number>
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> </property>
<horstretch>0</horstretch> <property name="leftMargin">
<verstretch>0</verstretch> <number>8</number>
</sizepolicy> </property>
</property> <property name="topMargin">
<property name="text"> <number>8</number>
<string>Connecting to XMPP...</string> </property>
</property> <property name="rightMargin">
<property name="alignment"> <number>8</number>
<set>Qt::AlignCenter</set> </property>
</property> <property name="bottomMargin">
</widget> <number>8</number>
</item> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <widget class="QLabel" name="connectingToXMPPLabel">
<item> <property name="sizePolicy">
<widget class="QLabel" name="numOnlineLabel"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<property name="sizePolicy"> <horstretch>0</horstretch>
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <verstretch>0</verstretch>
<horstretch>0</horstretch> </sizepolicy>
<verstretch>0</verstretch> </property>
</sizepolicy> <property name="text">
</property> <string>Connecting to XMPP...</string>
<property name="styleSheet"> </property>
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string> <property name="alignment">
</property> <set>Qt::AlignCenter</set>
<property name="text"> </property>
<string> online now:</string> </widget>
</property> </item>
</widget> <item>
</item> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QPushButton" name="togglePinnedButton"> <widget class="QLabel" name="numOnlineLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximumSize"> <property name="styleSheet">
<size> <string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
<width>16</width> </property>
<height>16</height> <property name="text">
</size> <string> online now:</string>
</property> </property>
<property name="focusPolicy"> </widget>
<enum>Qt::NoFocus</enum> </item>
</property> <item>
<property name="text"> <widget class="QPushButton" name="closeButton">
<string/> <property name="sizePolicy">
</property> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<property name="icon"> <horstretch>0</horstretch>
<iconset> <verstretch>0</verstretch>
<normaloff>../resources/images/pin.svg</normaloff> </sizepolicy>
<normalon>../resources/images/pinned.svg</normalon>../resources/images/pin.svg</iconset> </property>
</property> <property name="maximumSize">
<property name="checkable"> <size>
<bool>true</bool> <width>16</width>
</property> <height>16</height>
<property name="checked"> </size>
<bool>true</bool> </property>
</property> <property name="focusPolicy">
<property name="default"> <enum>Qt::NoFocus</enum>
<bool>false</bool> </property>
</property> <property name="styleSheet">
<property name="flat"> <string notr="true">QPushButton {
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
background-color: rgba( 0, 0, 0, 0% ); background-color: rgba( 0, 0, 0, 0% );
border: none; border: none;
image: url(../resources/images/close.svg) image: url(../resources/images/close.svg)
@ -148,50 +116,104 @@ QPushButton:pressed {
border: none; border: none;
image: url(../resources/images/close_down.svg) image: url(../resources/images/close_down.svg)
}</string> }</string>
</property> </property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="flat"> <property name="flat">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QWidget" name="usersWidget" native="true"/> <widget class="QWidget" name="usersWidget" native="true">
</item> <property name="styleSheet">
<item> <string notr="true">#usersWidget {
<widget class="QScrollArea" name="messagesScrollArea"> margin-right: 20px;
<property name="styleSheet"> }</string>
<string notr="true">margin-top: 12px;</string>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>16</height>
</rect>
</property> </property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="messagesScrollArea">
<property name="styleSheet">
<string notr="true">margin-top: 12px;</string>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>16</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">margin-top: 0px;</string>
</property>
<layout class="QVBoxLayout" name="messagesVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QFrame" name="chatFrame">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="styleSheet"> <property name="minimumSize">
<string notr="true">margin-top: 0px;</string> <size>
<width>0</width>
<height>78</height>
</size>
</property> </property>
<layout class="QGridLayout" name="messagesGridLayout"> <property name="styleSheet">
<string notr="true">#chatFrame {
border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;
}</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -204,69 +226,65 @@ QPushButton:pressed {
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="spacing"> <item>
<number>0</number> <widget class="ChatInputArea" name="messagePlainTextEdit">
</property> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="font">
<font>
<family>Helvetica,Arial,sans-serif</family>
<pointsize>14</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </item>
</item> </layout>
<item> </item>
<widget class="QPlainTextEdit" name="messagePlainTextEdit"> </layout>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ChatInputArea</class>
<extends>QTextEdit</extends>
<header>ui/ChatInputArea.h</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>messagePlainTextEdit</tabstop>
<tabstop>messagesScrollArea</tabstop> <tabstop>messagesScrollArea</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections> <connections>
<connection>
<sender>togglePinnedButton</sender>
<signal>clicked()</signal>
<receiver>ChatWindow</receiver>
<slot>togglePinned()</slot>
<hints>
<hint type="sourcelabel">
<x>390</x>
<y>42</y>
</hint>
<hint type="destinationlabel">
<x>550</x>
<y>42</y>
</hint>
</hints>
</connection>
<connection> <connection>
<sender>closeButton</sender> <sender>closeButton</sender>
<signal>clicked()</signal> <signal>clicked()</signal>