mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
parent
511b8af954
commit
ba1581005b
|
@ -325,6 +325,8 @@ set(${PROJECT_NAME}_SOURCES
|
||||||
src/widget/about/aboutfriendform.h
|
src/widget/about/aboutfriendform.h
|
||||||
src/widget/categorywidget.cpp
|
src/widget/categorywidget.cpp
|
||||||
src/widget/categorywidget.h
|
src/widget/categorywidget.h
|
||||||
|
src/widget/chatformheader.cpp
|
||||||
|
src/widget/chatformheader.h
|
||||||
src/widget/circlewidget.cpp
|
src/widget/circlewidget.cpp
|
||||||
src/widget/circlewidget.h
|
src/widget/circlewidget.h
|
||||||
src/widget/contentdialog.cpp
|
src/widget/contentdialog.cpp
|
||||||
|
|
274
src/widget/chatformheader.cpp
Normal file
274
src/widget/chatformheader.cpp
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2017 by The qTox Project Contributors
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "chatformheader.h"
|
||||||
|
|
||||||
|
#include "src/widget/maskablepixmapwidget.h"
|
||||||
|
#include "src/widget/style.h"
|
||||||
|
#include "src/widget/tool/callconfirmwidget.h"
|
||||||
|
#include "src/widget/tool/croppinglabel.h"
|
||||||
|
#include "src/widget/translator.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
|
static const QSize AVATAR_SIZE{40, 40};
|
||||||
|
static const QSize CALL_BUTTONS_SIZE{50, 40};
|
||||||
|
static const QSize VOL_MIC_BUTTONS_SIZE{22, 18};
|
||||||
|
static const short HEAD_LAYOUT_SPACING = 5;
|
||||||
|
static const short MIC_BUTTONS_LAYOUT_SPACING = 4;
|
||||||
|
static const short BUTTONS_LAYOUT_HOR_SPACING = 4;
|
||||||
|
static const QString Green = QStringLiteral("green");
|
||||||
|
|
||||||
|
#define STYLE_SHEET(x) Style::getStylesheet(":/ui/" #x "/" #x ".css")
|
||||||
|
#define SET_STYLESHEET(x) (x)->setStyleSheet(STYLE_SHEET(x))
|
||||||
|
|
||||||
|
ChatFormHeader::ChatFormHeader(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, mode{Mode::AV}
|
||||||
|
{
|
||||||
|
QHBoxLayout* headLayout = new QHBoxLayout();
|
||||||
|
avatar = new MaskablePixmapWidget(this, AVATAR_SIZE, ":/img/avatar_mask.svg");
|
||||||
|
|
||||||
|
nameLabel = new CroppingLabel();
|
||||||
|
nameLabel->setObjectName("nameLabel");
|
||||||
|
nameLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
|
||||||
|
nameLabel->setEditable(true);
|
||||||
|
nameLabel->setTextFormat(Qt::PlainText);
|
||||||
|
connect(nameLabel, &CroppingLabel::editFinished, this, &ChatFormHeader::onNameChanged);
|
||||||
|
|
||||||
|
headTextLayout = new QVBoxLayout();
|
||||||
|
headTextLayout->addStretch();
|
||||||
|
headTextLayout->addWidget(nameLabel);
|
||||||
|
headTextLayout->addStretch();
|
||||||
|
|
||||||
|
micButton = new QToolButton();
|
||||||
|
micButton->setFixedSize(VOL_MIC_BUTTONS_SIZE);
|
||||||
|
micButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
|
SET_STYLESHEET(micButton);
|
||||||
|
connect(micButton, &QPushButton::clicked, this, &ChatFormHeader::micMuteToggle);
|
||||||
|
|
||||||
|
volButton = new QToolButton();
|
||||||
|
volButton->setFixedSize(VOL_MIC_BUTTONS_SIZE);
|
||||||
|
volButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
|
SET_STYLESHEET(volButton);
|
||||||
|
connect(volButton, &QPushButton::clicked, this, &ChatFormHeader::volMuteToggle);
|
||||||
|
|
||||||
|
callButton = new QPushButton();
|
||||||
|
callButton->setFixedSize(CALL_BUTTONS_SIZE);
|
||||||
|
callButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
|
SET_STYLESHEET(callButton);
|
||||||
|
connect(callButton, &QPushButton::clicked, this, &ChatFormHeader::callTriggered);
|
||||||
|
|
||||||
|
videoButton = new QPushButton();
|
||||||
|
videoButton->setFixedSize(CALL_BUTTONS_SIZE);
|
||||||
|
videoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
|
SET_STYLESHEET(videoButton);
|
||||||
|
connect(videoButton, &QPushButton::clicked, this, &ChatFormHeader::videoCallTriggered);
|
||||||
|
|
||||||
|
QVBoxLayout* micButtonsLayout = new QVBoxLayout();
|
||||||
|
micButtonsLayout->setSpacing(MIC_BUTTONS_LAYOUT_SPACING);
|
||||||
|
micButtonsLayout->addWidget(micButton, Qt::AlignTop | Qt::AlignRight);
|
||||||
|
micButtonsLayout->addWidget(volButton, Qt::AlignTop | Qt::AlignRight);
|
||||||
|
|
||||||
|
QGridLayout* buttonsLayout = new QGridLayout();
|
||||||
|
buttonsLayout->addLayout(micButtonsLayout, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignRight);
|
||||||
|
buttonsLayout->addWidget(callButton, 0, 1, 2, 1, Qt::AlignTop);
|
||||||
|
buttonsLayout->addWidget(videoButton, 0, 2, 2, 1, Qt::AlignTop);
|
||||||
|
buttonsLayout->setVerticalSpacing(0);
|
||||||
|
buttonsLayout->setHorizontalSpacing(BUTTONS_LAYOUT_HOR_SPACING);
|
||||||
|
|
||||||
|
headLayout->addWidget(avatar);
|
||||||
|
headLayout->addSpacing(HEAD_LAYOUT_SPACING);
|
||||||
|
headLayout->addLayout(headTextLayout);
|
||||||
|
headLayout->addLayout(buttonsLayout);
|
||||||
|
|
||||||
|
setLayout(headLayout);
|
||||||
|
|
||||||
|
updateCallButtons(false, false, false);
|
||||||
|
updateMuteMicButton(false, false);
|
||||||
|
updateMuteVolButton(false, false);
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
Translator::registerHandler(std::bind(&ChatFormHeader::retranslateUi, this), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatFormHeader::~ChatFormHeader()
|
||||||
|
{
|
||||||
|
delete callConfirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::setName(const QString& newName)
|
||||||
|
{
|
||||||
|
nameLabel->setText(newName);
|
||||||
|
// for overlength names
|
||||||
|
nameLabel->setToolTip(Qt::convertFromPlainText(newName, Qt::WhiteSpaceNormal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::setMode(ChatFormHeader::Mode mode)
|
||||||
|
{
|
||||||
|
this->mode = mode;
|
||||||
|
if (mode == Mode::None) {
|
||||||
|
callButton->hide();
|
||||||
|
videoButton->hide();
|
||||||
|
volButton->hide();
|
||||||
|
micButton->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::retranslateUi()
|
||||||
|
{
|
||||||
|
const QString callObjectName = callButton->objectName();
|
||||||
|
const QString videoObjectName = videoButton->objectName();
|
||||||
|
|
||||||
|
if (callObjectName == QStringLiteral("green")) {
|
||||||
|
callButton->setToolTip(tr("Start audio call"));
|
||||||
|
} else if (callObjectName == QStringLiteral("yellow")) {
|
||||||
|
callButton->setToolTip(tr("Accept audio call"));
|
||||||
|
} else if (callObjectName == QStringLiteral("red")) {
|
||||||
|
callButton->setToolTip(tr("End audio call"));
|
||||||
|
} else if (callObjectName.isEmpty()) {
|
||||||
|
callButton->setToolTip(QString{});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoObjectName == QStringLiteral("green")) {
|
||||||
|
videoButton->setToolTip(tr("Start video call"));
|
||||||
|
} else if (videoObjectName == QStringLiteral("yellow")) {
|
||||||
|
videoButton->setToolTip(tr("Accept video call"));
|
||||||
|
} else if (videoObjectName == QStringLiteral("red")) {
|
||||||
|
videoButton->setToolTip(tr("End video call"));
|
||||||
|
} else if (videoObjectName.isEmpty()) {
|
||||||
|
videoButton->setToolTip(QString{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::showOutgoingCall(bool video)
|
||||||
|
{
|
||||||
|
QPushButton* btn = video ? videoButton : callButton;
|
||||||
|
btn->setObjectName("yellow");
|
||||||
|
btn->setStyleSheet(video ? STYLE_SHEET(videoButton) : STYLE_SHEET(callButton));
|
||||||
|
btn->setToolTip(video ? tr("Cancel video call") : tr("Cancel audio call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::showCallConfirm(bool video)
|
||||||
|
{
|
||||||
|
callConfirm = new CallConfirmWidget(video ? videoButton : callButton);
|
||||||
|
callConfirm->show();
|
||||||
|
CallConfirmWidget* confirmData = callConfirm.data();
|
||||||
|
connect(confirmData, &CallConfirmWidget::accepted, this, [this, video]{
|
||||||
|
emit callAccepted(video);
|
||||||
|
});
|
||||||
|
connect(confirmData, &CallConfirmWidget::rejected, this, &ChatFormHeader::callRejected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::removeCallConfirm()
|
||||||
|
{
|
||||||
|
delete callConfirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::updateCallButtons(bool online, bool audio, bool video)
|
||||||
|
{
|
||||||
|
callButton->setEnabled(audio && !video);
|
||||||
|
videoButton->setEnabled(video);
|
||||||
|
if (audio) {
|
||||||
|
callButton->setObjectName(!video ? "red" : "");
|
||||||
|
callButton->setToolTip(!video ? tr("End audio call") : tr("Can't start audio call"));
|
||||||
|
|
||||||
|
videoButton->setObjectName(video ? "red" : "");
|
||||||
|
videoButton->setToolTip(video ? tr("End video call") : tr("Can't start video call"));
|
||||||
|
} else {
|
||||||
|
const bool audioAvaliable = online && (mode & Mode::Audio);
|
||||||
|
callButton->setEnabled(audioAvaliable);
|
||||||
|
callButton->setObjectName(audioAvaliable ? "green" : "");
|
||||||
|
callButton->setToolTip(audioAvaliable ? tr("Start audio call") : tr("Can't start audio call"));
|
||||||
|
|
||||||
|
const bool videoAvaliable = online && (mode & Mode::Video);
|
||||||
|
videoButton->setEnabled(videoAvaliable);
|
||||||
|
videoButton->setObjectName(videoAvaliable ? "green" : "");
|
||||||
|
videoButton->setToolTip(videoAvaliable ? tr("Start video call") : tr("Can't start video call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
callButton->setStyleSheet(STYLE_SHEET(callButton));
|
||||||
|
videoButton->setStyleSheet(STYLE_SHEET(videoButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::updateMuteMicButton(bool active, bool inputMuted)
|
||||||
|
{
|
||||||
|
micButton->setEnabled(active);
|
||||||
|
if (micButton->isEnabled()) {
|
||||||
|
micButton->setObjectName(inputMuted ? "red" : "green");
|
||||||
|
micButton->setToolTip(inputMuted ? tr("Unmute microphone") : tr("Mute microphone"));
|
||||||
|
} else {
|
||||||
|
micButton->setObjectName("");
|
||||||
|
micButton->setToolTip(tr("Microphone can be muted only during a call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
micButton->setStyleSheet(STYLE_SHEET(micButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::updateMuteVolButton(bool active, bool outputMuted)
|
||||||
|
{
|
||||||
|
volButton->setEnabled(active);
|
||||||
|
if (volButton->isEnabled()) {
|
||||||
|
volButton->setObjectName(outputMuted ? "red" : "green");
|
||||||
|
volButton->setToolTip(outputMuted ? tr("Unmute call") : tr("Mute call"));
|
||||||
|
} else {
|
||||||
|
volButton->setObjectName("");
|
||||||
|
volButton->setToolTip(tr("Sound can be disabled only during a call"));
|
||||||
|
}
|
||||||
|
|
||||||
|
volButton->setStyleSheet(STYLE_SHEET(volButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::setAvatar(const QPixmap &img)
|
||||||
|
{
|
||||||
|
avatar->setPixmap(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ChatFormHeader::getAvatarSize() const
|
||||||
|
{
|
||||||
|
return QSize{avatar->width(), avatar->height()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::addWidget(QWidget* widget, int stretch, Qt::Alignment alignment)
|
||||||
|
{
|
||||||
|
headTextLayout->addWidget(widget, stretch, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::addLayout(QLayout* layout)
|
||||||
|
{
|
||||||
|
headTextLayout->addLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::addStretch()
|
||||||
|
{
|
||||||
|
headTextLayout->addStretch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFormHeader::onNameChanged(const QString& name)
|
||||||
|
{
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
nameLabel->setText(name);
|
||||||
|
emit nameChanged(name);
|
||||||
|
}
|
||||||
|
}
|
96
src/widget/chatformheader.h
Normal file
96
src/widget/chatformheader.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
Copyright © 2017 by The qTox Project Contributors
|
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CHAT_FORM_HEADER
|
||||||
|
#define CHAT_FORM_HEADER
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class MaskablePixmapWidget;
|
||||||
|
class QVBoxLayout;
|
||||||
|
class CroppingLabel;
|
||||||
|
class QPushButton;
|
||||||
|
class QToolButton;
|
||||||
|
class CallConfirmWidget;
|
||||||
|
|
||||||
|
class ChatFormHeader : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum Mode {
|
||||||
|
None = 0,
|
||||||
|
Audio = 1,
|
||||||
|
Video = 2,
|
||||||
|
AV = Audio | Video
|
||||||
|
};
|
||||||
|
|
||||||
|
ChatFormHeader(QWidget* parent = nullptr);
|
||||||
|
~ChatFormHeader() override;
|
||||||
|
|
||||||
|
void setName(const QString& newName);
|
||||||
|
void setMode(Mode mode);
|
||||||
|
|
||||||
|
void showOutgoingCall(bool video);
|
||||||
|
void showCallConfirm(bool video);
|
||||||
|
void removeCallConfirm();
|
||||||
|
|
||||||
|
void updateCallButtons(bool online, bool audio, bool video = false);
|
||||||
|
void updateMuteMicButton(bool active, bool inputMuted);
|
||||||
|
void updateMuteVolButton(bool active, bool outputMuted);
|
||||||
|
|
||||||
|
void setAvatar(const QPixmap& img);
|
||||||
|
QSize getAvatarSize() const;
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
|
void addWidget(QWidget* widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment());
|
||||||
|
void addLayout(QLayout* layout);
|
||||||
|
void addStretch();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void callTriggered();
|
||||||
|
void videoCallTriggered();
|
||||||
|
void micMuteToggle();
|
||||||
|
void volMuteToggle();
|
||||||
|
|
||||||
|
void nameChanged(const QString& name);
|
||||||
|
|
||||||
|
void callAccepted(bool video);
|
||||||
|
void callRejected();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onNameChanged(const QString& name);
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mode mode;
|
||||||
|
MaskablePixmapWidget* avatar;
|
||||||
|
QVBoxLayout* headTextLayout;
|
||||||
|
CroppingLabel* nameLabel;
|
||||||
|
|
||||||
|
QPushButton* callButton;
|
||||||
|
QPushButton* videoButton;
|
||||||
|
|
||||||
|
QToolButton* volButton;
|
||||||
|
QToolButton* micButton;
|
||||||
|
|
||||||
|
QPointer<CallConfirmWidget> callConfirm;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHAT_FORM_HEADER
|
|
@ -33,6 +33,7 @@
|
||||||
#include "src/persistence/profile.h"
|
#include "src/persistence/profile.h"
|
||||||
#include "src/persistence/settings.h"
|
#include "src/persistence/settings.h"
|
||||||
#include "src/video/netcamview.h"
|
#include "src/video/netcamview.h"
|
||||||
|
#include "src/widget/chatformheader.h"
|
||||||
#include "src/widget/form/loadhistorydialog.h"
|
#include "src/widget/form/loadhistorydialog.h"
|
||||||
#include "src/widget/maskablepixmapwidget.h"
|
#include "src/widget/maskablepixmapwidget.h"
|
||||||
#include "src/widget/style.h"
|
#include "src/widget/style.h"
|
||||||
|
@ -58,11 +59,6 @@ static const int DELIVER_OFFLINE_MESSAGES_DELAY = 250;
|
||||||
static const int SCREENSHOT_GRABBER_OPENING_DELAY = 500;
|
static const int SCREENSHOT_GRABBER_OPENING_DELAY = 500;
|
||||||
static const int TYPING_NOTIFICATION_DURATION = 3000;
|
static const int TYPING_NOTIFICATION_DURATION = 3000;
|
||||||
|
|
||||||
static const QString CALL_BTN_STYLESHEET = QStringLiteral(":/ui/callButton/callButton.css");
|
|
||||||
static const QString MIC_BTN_STYLESHEET = QStringLiteral(":/ui/micButton/micButton.css");
|
|
||||||
static const QString VIDEO_BTN_STYLESHEET = QStringLiteral(":/ui/videoButton/videoButton.css");
|
|
||||||
static const QString VOL_BTN_STYLESHEET = QStringLiteral(":/ui/volButton/volButton.css");
|
|
||||||
|
|
||||||
const QString ChatForm::ACTION_PREFIX = QStringLiteral("/me ");
|
const QString ChatForm::ACTION_PREFIX = QStringLiteral("/me ");
|
||||||
|
|
||||||
QString statusToString(const Status status)
|
QString statusToString(const Status status)
|
||||||
|
@ -118,9 +114,9 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
, callDuration(new QLabel(this))
|
, callDuration(new QLabel(this))
|
||||||
, isTyping(false)
|
, isTyping(false)
|
||||||
{
|
{
|
||||||
nameLabel->setText(f->getDisplayedName());
|
setName(f->getDisplayedName());
|
||||||
|
|
||||||
avatar->setPixmap(QPixmap(":/img/contact_dark.svg"));
|
headWidget->setAvatar(QPixmap(":/img/contact_dark.svg"));
|
||||||
|
|
||||||
statusMessageLabel = new CroppingLabel();
|
statusMessageLabel = new CroppingLabel();
|
||||||
statusMessageLabel->setObjectName("statusLabel");
|
statusMessageLabel->setObjectName("statusLabel");
|
||||||
|
@ -129,7 +125,6 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
statusMessageLabel->setTextFormat(Qt::PlainText);
|
statusMessageLabel->setTextFormat(Qt::PlainText);
|
||||||
statusMessageLabel->setContextMenuPolicy(Qt::CustomContextMenu);
|
statusMessageLabel->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
callConfirm = nullptr;
|
|
||||||
offlineEngine = new OfflineMsgEngine(f);
|
offlineEngine = new OfflineMsgEngine(f);
|
||||||
|
|
||||||
typingTimer.setSingleShot(true);
|
typingTimer.setSingleShot(true);
|
||||||
|
@ -139,10 +134,10 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
chatWidget->setTypingNotification(ChatMessage::createTypingNotification());
|
chatWidget->setTypingNotification(ChatMessage::createTypingNotification());
|
||||||
chatWidget->setMinimumHeight(CHAT_WIDGET_MIN_HEIGHT);
|
chatWidget->setMinimumHeight(CHAT_WIDGET_MIN_HEIGHT);
|
||||||
|
|
||||||
headTextLayout->addWidget(statusMessageLabel);
|
|
||||||
headTextLayout->addStretch();
|
|
||||||
callDuration = new QLabel();
|
callDuration = new QLabel();
|
||||||
headTextLayout->addWidget(callDuration, 1, Qt::AlignCenter);
|
headWidget->addWidget(statusMessageLabel);
|
||||||
|
headWidget->addStretch();
|
||||||
|
headWidget->addWidget(callDuration, 1, Qt::AlignCenter);
|
||||||
callDuration->hide();
|
callDuration->hide();
|
||||||
|
|
||||||
loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory()));
|
loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory()));
|
||||||
|
@ -171,10 +166,10 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
|
connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
|
||||||
connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
|
connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
|
||||||
connect(screenshotButton, &QPushButton::clicked, this, &ChatForm::onScreenshotClicked);
|
connect(screenshotButton, &QPushButton::clicked, this, &ChatForm::onScreenshotClicked);
|
||||||
connect(callButton, &QAbstractButton::clicked, this, &ChatForm::onCallTriggered);
|
connect(headWidget, &ChatFormHeader::callTriggered, this, &ChatForm::onCallTriggered);
|
||||||
connect(videoButton, &QAbstractButton::clicked, this, &ChatForm::onVideoCallTriggered);
|
connect(headWidget, &ChatFormHeader::videoCallTriggered, this, &ChatForm::onVideoCallTriggered);
|
||||||
connect(micButton, &QAbstractButton::clicked, this, &ChatForm::onMicMuteToggle);
|
connect(headWidget, &ChatFormHeader::micMuteToggle, this, &ChatForm::onMicMuteToggle);
|
||||||
connect(volButton, &QAbstractButton::clicked, this, &ChatForm::onVolMuteToggle);
|
connect(headWidget, &ChatFormHeader::volMuteToggle, this, &ChatForm::onVolMuteToggle);
|
||||||
|
|
||||||
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
|
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
|
||||||
connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
|
connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
|
||||||
|
@ -192,9 +187,8 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
isTyping = false;
|
isTyping = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName) {
|
connect(headWidget, &ChatFormHeader::nameChanged, this, [=](const QString& newName) {
|
||||||
nameLabel->setText(newName);
|
f->setAlias(newName);
|
||||||
emit aliasChanged(newName);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
updateCallButtons();
|
updateCallButtons();
|
||||||
|
@ -335,7 +329,6 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callConfirm = new CallConfirmWidget(video ? videoButton : callButton);
|
|
||||||
QString displayedName = f->getDisplayedName();
|
QString displayedName = f->getDisplayedName();
|
||||||
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
|
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
|
||||||
ChatMessage::INFO,
|
ChatMessage::INFO,
|
||||||
|
@ -351,10 +344,9 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
|
||||||
Q_ARG(uint32_t, friendId), Q_ARG(bool, video));
|
Q_ARG(uint32_t, friendId), Q_ARG(bool, video));
|
||||||
onAvStart(friendId, video);
|
onAvStart(friendId, video);
|
||||||
} else {
|
} else {
|
||||||
callConfirm->show();
|
headWidget->showCallConfirm(video);
|
||||||
CallConfirmWidget* confirmData = callConfirm.data();
|
connect(headWidget, &ChatFormHeader::callAccepted, this, &ChatForm::onAnswerCallTriggered);
|
||||||
connect(confirmData, &CallConfirmWidget::accepted, this, [this, video]{ onAnswerCallTriggered(video); });
|
connect(headWidget, &ChatFormHeader::callRejected, this, &ChatForm::onRejectCallTriggered);
|
||||||
connect(confirmData, &CallConfirmWidget::rejected, this, &ChatForm::onRejectCallTriggered);
|
|
||||||
auto msg = ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
|
auto msg = ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
|
||||||
ChatMessage::INFO, QDateTime::currentDateTime());
|
ChatMessage::INFO, QDateTime::currentDateTime());
|
||||||
insertChatMessage(msg);
|
insertChatMessage(msg);
|
||||||
|
@ -385,8 +377,6 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete callConfirm;
|
|
||||||
|
|
||||||
// Fixes an OS X bug with ending a call while in full screen
|
// Fixes an OS X bug with ending a call while in full screen
|
||||||
if (netcam && netcam->isFullScreen()) {
|
if (netcam && netcam->isFullScreen()) {
|
||||||
netcam->showNormal();
|
netcam->showNormal();
|
||||||
|
@ -399,10 +389,7 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
|
||||||
|
|
||||||
void ChatForm::showOutgoingCall(bool video)
|
void ChatForm::showOutgoingCall(bool video)
|
||||||
{
|
{
|
||||||
QPushButton* btn = video ? videoButton : callButton;
|
headWidget->showOutgoingCall(video);
|
||||||
btn->setObjectName("yellow");
|
|
||||||
btn->setStyleSheet(Style::getStylesheet(video ? VIDEO_BTN_STYLESHEET : CALL_BTN_STYLESHEET));
|
|
||||||
btn->setToolTip(video ? tr("Cancel video call") : tr("Cancel audio call"));
|
|
||||||
addSystemInfoMessage(tr("Calling %1").arg(f->getDisplayedName()), ChatMessage::INFO,
|
addSystemInfoMessage(tr("Calling %1").arg(f->getDisplayedName()), ChatMessage::INFO,
|
||||||
QDateTime::currentDateTime());
|
QDateTime::currentDateTime());
|
||||||
emit outgoingNotification();
|
emit outgoingNotification();
|
||||||
|
@ -411,7 +398,7 @@ void ChatForm::showOutgoingCall(bool video)
|
||||||
|
|
||||||
void ChatForm::onAnswerCallTriggered(bool video)
|
void ChatForm::onAnswerCallTriggered(bool video)
|
||||||
{
|
{
|
||||||
delete callConfirm;
|
headWidget->removeCallConfirm();
|
||||||
uint32_t friendId = f->getId();
|
uint32_t friendId = f->getId();
|
||||||
emit acceptCall(friendId);
|
emit acceptCall(friendId);
|
||||||
|
|
||||||
|
@ -429,7 +416,7 @@ void ChatForm::onAnswerCallTriggered(bool video)
|
||||||
|
|
||||||
void ChatForm::onRejectCallTriggered()
|
void ChatForm::onRejectCallTriggered()
|
||||||
{
|
{
|
||||||
delete callConfirm;
|
headWidget->removeCallConfirm();
|
||||||
emit rejectCall(f->getId());
|
emit rejectCall(f->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,32 +448,10 @@ void ChatForm::onVideoCallTriggered()
|
||||||
void ChatForm::updateCallButtons()
|
void ChatForm::updateCallButtons()
|
||||||
{
|
{
|
||||||
CoreAV* av = Core::getInstance()->getAv();
|
CoreAV* av = Core::getInstance()->getAv();
|
||||||
bool audio = av->isCallActive(f);
|
const bool audio = av->isCallActive(f);
|
||||||
bool video = av->isCallVideoEnabled(f);
|
const bool video = av->isCallVideoEnabled(f);
|
||||||
callButton->setEnabled(audio && !video);
|
const bool online = f->getStatus() != Status::Offline;
|
||||||
videoButton->setEnabled(video);
|
headWidget->updateCallButtons(online, audio, video);
|
||||||
if (audio) {
|
|
||||||
videoButton->setObjectName(video ? "red" : "");
|
|
||||||
videoButton->setToolTip(video ? tr("End video call") : tr("Can't start video call"));
|
|
||||||
|
|
||||||
callButton->setObjectName(!video ? "red" : "");
|
|
||||||
callButton->setToolTip(!video ? tr("End audio call") : tr("Can't start audio call"));
|
|
||||||
} else {
|
|
||||||
const Status fs = f->getStatus();
|
|
||||||
bool online = fs != Status::Offline;
|
|
||||||
callButton->setEnabled(online);
|
|
||||||
videoButton->setEnabled(online);
|
|
||||||
|
|
||||||
QString color = online ? "green" : "";
|
|
||||||
callButton->setObjectName(color);
|
|
||||||
callButton->setToolTip(online ? tr("Start audio call") : tr("Can't start audio call"));
|
|
||||||
|
|
||||||
videoButton->setObjectName(color);
|
|
||||||
videoButton->setToolTip(online ? tr("Start video call") : tr("Can't start video call"));
|
|
||||||
}
|
|
||||||
|
|
||||||
callButton->setStyleSheet(Style::getStylesheet(CALL_BTN_STYLESHEET));
|
|
||||||
videoButton->setStyleSheet(Style::getStylesheet(VIDEO_BTN_STYLESHEET));
|
|
||||||
updateMuteMicButton();
|
updateMuteMicButton();
|
||||||
updateMuteVolButton();
|
updateMuteVolButton();
|
||||||
}
|
}
|
||||||
|
@ -584,7 +549,7 @@ void ChatForm::onAvatarChange(uint32_t friendId, const QPixmap& pic)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
avatar->setPixmap(pic);
|
headWidget->setAvatar(pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericNetCamView* ChatForm::createNetcam()
|
GenericNetCamView* ChatForm::createNetcam()
|
||||||
|
@ -653,7 +618,7 @@ void ChatForm::onAvatarRemoved(uint32_t friendId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
avatar->setPixmap(QPixmap(":/img/contact_dark.svg"));
|
headWidget->setAvatar(QPixmap(":/img/contact_dark.svg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::clearChatArea(bool notInForm)
|
void ChatForm::clearChatArea(bool notInForm)
|
||||||
|
@ -849,35 +814,17 @@ void ChatForm::onCopyStatusMessage()
|
||||||
void ChatForm::updateMuteMicButton()
|
void ChatForm::updateMuteMicButton()
|
||||||
{
|
{
|
||||||
const CoreAV* av = Core::getInstance()->getAv();
|
const CoreAV* av = Core::getInstance()->getAv();
|
||||||
|
bool active = av->isCallActive(f);
|
||||||
micButton->setEnabled(av->isCallActive(f));
|
bool inputMuted = av->isCallInputMuted(f);
|
||||||
if (micButton->isEnabled()) {
|
headWidget->updateMuteMicButton(active, inputMuted);
|
||||||
bool inputMuted = av->isCallInputMuted(f);
|
|
||||||
micButton->setObjectName(inputMuted ? "red" : "green");
|
|
||||||
micButton->setToolTip(inputMuted ? tr("Unmute microphone") : tr("Mute microphone"));
|
|
||||||
} else {
|
|
||||||
micButton->setObjectName("");
|
|
||||||
micButton->setToolTip(tr("Microphone can be muted only during a call"));
|
|
||||||
}
|
|
||||||
|
|
||||||
micButton->setStyleSheet(Style::getStylesheet(MIC_BTN_STYLESHEET));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::updateMuteVolButton()
|
void ChatForm::updateMuteVolButton()
|
||||||
{
|
{
|
||||||
const CoreAV* av = Core::getInstance()->getAv();
|
const CoreAV* av = Core::getInstance()->getAv();
|
||||||
|
bool active = av->isCallActive(f);
|
||||||
volButton->setEnabled(av->isCallActive(f));
|
bool outputMuted = av->isCallOutputMuted(f);
|
||||||
if (volButton->isEnabled()) {
|
headWidget->updateMuteVolButton(active, outputMuted);
|
||||||
bool outputMuted = av->isCallOutputMuted(f);
|
|
||||||
volButton->setObjectName(outputMuted ? "red" : "green");
|
|
||||||
volButton->setToolTip(outputMuted ? tr("Unmute call") : tr("Mute call"));
|
|
||||||
} else {
|
|
||||||
volButton->setObjectName("");
|
|
||||||
volButton->setToolTip(tr("Sound can be disabled only during a call"));
|
|
||||||
}
|
|
||||||
|
|
||||||
volButton->setStyleSheet(Style::getStylesheet(VOL_BTN_STYLESHEET));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::startCounter()
|
void ChatForm::startCounter()
|
||||||
|
@ -929,26 +876,15 @@ void ChatForm::setFriendTyping(bool isTyping)
|
||||||
void ChatForm::show(ContentLayout* contentLayout)
|
void ChatForm::show(ContentLayout* contentLayout)
|
||||||
{
|
{
|
||||||
GenericChatForm::show(contentLayout);
|
GenericChatForm::show(contentLayout);
|
||||||
if (callConfirm) {
|
|
||||||
callConfirm->show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::showEvent(QShowEvent* event)
|
void ChatForm::showEvent(QShowEvent* event)
|
||||||
{
|
{
|
||||||
if (callConfirm) {
|
|
||||||
callConfirm->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericChatForm::showEvent(event);
|
GenericChatForm::showEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::hideEvent(QHideEvent* event)
|
void ChatForm::hideEvent(QHideEvent* event)
|
||||||
{
|
{
|
||||||
if (callConfirm) {
|
|
||||||
callConfirm->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericChatForm::hideEvent(event);
|
GenericChatForm::hideEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,8 +942,6 @@ void ChatForm::SendMessageStr(QString msg)
|
||||||
|
|
||||||
void ChatForm::retranslateUi()
|
void ChatForm::retranslateUi()
|
||||||
{
|
{
|
||||||
QString volObjectName = volButton->objectName();
|
|
||||||
QString micObjectName = micButton->objectName();
|
|
||||||
loadHistoryAction->setText(tr("Load chat history..."));
|
loadHistoryAction->setText(tr("Load chat history..."));
|
||||||
copyStatusAction->setText(tr("Copy"));
|
copyStatusAction->setText(tr("Copy"));
|
||||||
exportChatAction->setText(tr("Export to file"));
|
exportChatAction->setText(tr("Export to file"));
|
||||||
|
|
|
@ -57,7 +57,6 @@ public:
|
||||||
static const QString ACTION_PREFIX;
|
static const QString ACTION_PREFIX;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void aliasChanged(const QString& alias);
|
|
||||||
void incomingNotification(uint32_t friendId);
|
void incomingNotification(uint32_t friendId);
|
||||||
void outgoingNotification();
|
void outgoingNotification();
|
||||||
void rejectCall(uint32_t friendId);
|
void rejectCall(uint32_t friendId);
|
||||||
|
@ -134,7 +133,6 @@ private:
|
||||||
QAction* exportChatAction;
|
QAction* exportChatAction;
|
||||||
|
|
||||||
QHash<uint, FileTransferInstance*> ftransWidgets;
|
QHash<uint, FileTransferInstance*> ftransWidgets;
|
||||||
QPointer<CallConfirmWidget> callConfirm;
|
|
||||||
bool isTyping;
|
bool isTyping;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "src/persistence/settings.h"
|
#include "src/persistence/settings.h"
|
||||||
#include "src/persistence/smileypack.h"
|
#include "src/persistence/smileypack.h"
|
||||||
#include "src/video/genericnetcamview.h"
|
#include "src/video/genericnetcamview.h"
|
||||||
|
#include "src/widget/chatformheader.h"
|
||||||
#include "src/widget/contentdialog.h"
|
#include "src/widget/contentdialog.h"
|
||||||
#include "src/widget/contentlayout.h"
|
#include "src/widget/contentlayout.h"
|
||||||
#include "src/widget/emoticonswidget.h"
|
#include "src/widget/emoticonswidget.h"
|
||||||
|
@ -57,16 +58,10 @@
|
||||||
|
|
||||||
#define SET_STYLESHEET(x) (x)->setStyleSheet(Style::getStylesheet(":/ui/" #x "/" #x ".css"))
|
#define SET_STYLESHEET(x) (x)->setStyleSheet(Style::getStylesheet(":/ui/" #x "/" #x ".css"))
|
||||||
|
|
||||||
static const QSize AVATAR_SIZE{40, 40};
|
|
||||||
static const QSize CALL_BUTTONS_SIZE{50, 40};
|
|
||||||
static const QSize VOL_MIC_BUTTONS_SIZE{22, 18};
|
|
||||||
static const QSize FILE_FLYOUT_SIZE{24, 24};
|
static const QSize FILE_FLYOUT_SIZE{24, 24};
|
||||||
static const short FOOT_BUTTONS_SPACING = 2;
|
static const short FOOT_BUTTONS_SPACING = 2;
|
||||||
static const short MESSAGE_EDIT_HEIGHT = 50;
|
static const short MESSAGE_EDIT_HEIGHT = 50;
|
||||||
static const short MAIN_FOOT_LAYOUT_SPACING = 5;
|
static const short MAIN_FOOT_LAYOUT_SPACING = 5;
|
||||||
static const short MIC_BUTTONS_LAYOUT_SPACING = 4;
|
|
||||||
static const short HEAD_LAYOUT_SPACING = 5;
|
|
||||||
static const short BUTTONS_LAYOUT_HOR_SPACING = 4;
|
|
||||||
static const QString FONT_STYLE[]{"normal", "italic", "oblique"};
|
static const QString FONT_STYLE[]{"normal", "italic", "oblique"};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,22 +110,12 @@ GenericChatForm::GenericChatForm(QWidget* parent)
|
||||||
, audioOutputFlag(false)
|
, audioOutputFlag(false)
|
||||||
{
|
{
|
||||||
curRow = 0;
|
curRow = 0;
|
||||||
headWidget = new QWidget();
|
headWidget = new ChatFormHeader();
|
||||||
|
|
||||||
nameLabel = new CroppingLabel();
|
QHBoxLayout* mainFootLayout = new QHBoxLayout();
|
||||||
nameLabel->setObjectName("nameLabel");
|
|
||||||
nameLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
|
|
||||||
nameLabel->setEditable(true);
|
|
||||||
nameLabel->setTextFormat(Qt::PlainText);
|
|
||||||
|
|
||||||
avatar = new MaskablePixmapWidget(this, AVATAR_SIZE, ":/img/avatar_mask.svg");
|
QVBoxLayout* mainLayout = new QVBoxLayout();
|
||||||
QHBoxLayout *mainFootLayout = new QHBoxLayout(), *headLayout = new QHBoxLayout();
|
QVBoxLayout* footButtonsSmall = new QVBoxLayout();
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout(), *footButtonsSmall = new QVBoxLayout(),
|
|
||||||
*micButtonsLayout = new QVBoxLayout();
|
|
||||||
headTextLayout = new QVBoxLayout();
|
|
||||||
|
|
||||||
QGridLayout* buttonsLayout = new QGridLayout();
|
|
||||||
|
|
||||||
chatWidget = new ChatLog(this);
|
chatWidget = new ChatLog(this);
|
||||||
chatWidget->setBusyNotification(ChatMessage::createBusyNotification());
|
chatWidget->setBusyNotification(ChatMessage::createBusyNotification());
|
||||||
|
@ -149,16 +134,6 @@ GenericChatForm::GenericChatForm(QWidget* parent)
|
||||||
fileButton = new QPushButton();
|
fileButton = new QPushButton();
|
||||||
screenshotButton = new QPushButton;
|
screenshotButton = new QPushButton;
|
||||||
|
|
||||||
callButton = new QPushButton();
|
|
||||||
callButton->setFixedSize(CALL_BUTTONS_SIZE);
|
|
||||||
videoButton = new QPushButton();
|
|
||||||
videoButton->setFixedSize(CALL_BUTTONS_SIZE);
|
|
||||||
|
|
||||||
volButton = new QToolButton();
|
|
||||||
volButton->setFixedSize(VOL_MIC_BUTTONS_SIZE);
|
|
||||||
micButton = new QToolButton();
|
|
||||||
micButton->setFixedSize(VOL_MIC_BUTTONS_SIZE);
|
|
||||||
|
|
||||||
// TODO: Make updateCallButtons (see ChatForm) abstract
|
// TODO: Make updateCallButtons (see ChatForm) abstract
|
||||||
// and call here to set tooltips.
|
// and call here to set tooltips.
|
||||||
|
|
||||||
|
@ -180,15 +155,6 @@ GenericChatForm::GenericChatForm(QWidget* parent)
|
||||||
SET_STYLESHEET(fileButton);
|
SET_STYLESHEET(fileButton);
|
||||||
SET_STYLESHEET(screenshotButton);
|
SET_STYLESHEET(screenshotButton);
|
||||||
SET_STYLESHEET(emoteButton);
|
SET_STYLESHEET(emoteButton);
|
||||||
SET_STYLESHEET(callButton);
|
|
||||||
SET_STYLESHEET(videoButton);
|
|
||||||
SET_STYLESHEET(volButton);
|
|
||||||
SET_STYLESHEET(micButton);
|
|
||||||
|
|
||||||
callButton->setObjectName("green");
|
|
||||||
videoButton->setObjectName("green");
|
|
||||||
volButton->setObjectName("grey");
|
|
||||||
micButton->setObjectName("grey");
|
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
@ -213,37 +179,12 @@ GenericChatForm::GenericChatForm(QWidget* parent)
|
||||||
mainFootLayout->addWidget(sendButton);
|
mainFootLayout->addWidget(sendButton);
|
||||||
mainFootLayout->setSpacing(0);
|
mainFootLayout->setSpacing(0);
|
||||||
|
|
||||||
headTextLayout->addStretch();
|
|
||||||
headTextLayout->addWidget(nameLabel);
|
|
||||||
headTextLayout->addStretch();
|
|
||||||
|
|
||||||
micButtonsLayout->setSpacing(MIC_BUTTONS_LAYOUT_SPACING);
|
|
||||||
micButtonsLayout->addWidget(micButton, Qt::AlignTop | Qt::AlignRight);
|
|
||||||
micButtonsLayout->addWidget(volButton, Qt::AlignTop | Qt::AlignRight);
|
|
||||||
|
|
||||||
buttonsLayout->addLayout(micButtonsLayout, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignRight);
|
|
||||||
buttonsLayout->addWidget(callButton, 0, 1, 2, 1, Qt::AlignTop);
|
|
||||||
buttonsLayout->addWidget(videoButton, 0, 2, 2, 1, Qt::AlignTop);
|
|
||||||
buttonsLayout->setVerticalSpacing(0);
|
|
||||||
buttonsLayout->setHorizontalSpacing(BUTTONS_LAYOUT_HOR_SPACING);
|
|
||||||
|
|
||||||
headLayout->addWidget(avatar);
|
|
||||||
headLayout->addSpacing(HEAD_LAYOUT_SPACING);
|
|
||||||
headLayout->addLayout(headTextLayout);
|
|
||||||
headLayout->addLayout(buttonsLayout);
|
|
||||||
|
|
||||||
headWidget->setLayout(headLayout);
|
|
||||||
|
|
||||||
// Fix for incorrect layouts on OS X as per
|
// Fix for incorrect layouts on OS X as per
|
||||||
// https://bugreports.qt-project.org/browse/QTBUG-14591
|
// https://bugreports.qt-project.org/browse/QTBUG-14591
|
||||||
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
fileButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
fileButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
screenshotButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
screenshotButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
emoteButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
emoteButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
micButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
|
||||||
volButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
|
||||||
callButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
|
||||||
videoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
|
||||||
|
|
||||||
menu.addActions(chatWidget->actions());
|
menu.addActions(chatWidget->actions());
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
@ -324,9 +265,7 @@ QDate GenericChatForm::getLatestDate() const
|
||||||
|
|
||||||
void GenericChatForm::setName(const QString& newName)
|
void GenericChatForm::setName(const QString& newName)
|
||||||
{
|
{
|
||||||
nameLabel->setText(newName);
|
headWidget->setName(newName);
|
||||||
nameLabel->setToolTip(
|
|
||||||
Qt::convertFromPlainText(newName, Qt::WhiteSpaceNormal)); // for overlength names
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::show(ContentLayout* contentLayout)
|
void GenericChatForm::show(ContentLayout* contentLayout)
|
||||||
|
@ -709,23 +648,6 @@ void GenericChatForm::copyLink()
|
||||||
|
|
||||||
void GenericChatForm::retranslateUi()
|
void GenericChatForm::retranslateUi()
|
||||||
{
|
{
|
||||||
QString callObjectName = callButton->objectName();
|
|
||||||
QString videoObjectName = videoButton->objectName();
|
|
||||||
|
|
||||||
if (callObjectName == QStringLiteral("green"))
|
|
||||||
callButton->setToolTip(tr("Start audio call"));
|
|
||||||
else if (callObjectName == QStringLiteral("yellow"))
|
|
||||||
callButton->setToolTip(tr("Accept audio call"));
|
|
||||||
else if (callObjectName == QStringLiteral("red"))
|
|
||||||
callButton->setToolTip(tr("End audio call"));
|
|
||||||
|
|
||||||
if (videoObjectName == QStringLiteral("green"))
|
|
||||||
videoButton->setToolTip(tr("Start video call"));
|
|
||||||
else if (videoObjectName == QStringLiteral("yellow"))
|
|
||||||
videoButton->setToolTip(tr("Accept video call"));
|
|
||||||
else if (videoObjectName == QStringLiteral("red"))
|
|
||||||
videoButton->setToolTip(tr("End video call"));
|
|
||||||
|
|
||||||
sendButton->setToolTip(tr("Send message"));
|
sendButton->setToolTip(tr("Send message"));
|
||||||
emoteButton->setToolTip(tr("Smileys"));
|
emoteButton->setToolTip(tr("Smileys"));
|
||||||
fileButton->setToolTip(tr("Send file(s)"));
|
fileButton->setToolTip(tr("Send file(s)"));
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
* - Even a different font is not enough – TODO #1307 ~~zetok
|
* - Even a different font is not enough – TODO #1307 ~~zetok
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class ChatFormHeader;
|
||||||
class ChatLog;
|
class ChatLog;
|
||||||
class ChatTextEdit;
|
class ChatTextEdit;
|
||||||
class ContentLayout;
|
class ContentLayout;
|
||||||
|
@ -56,7 +57,7 @@ class GenericChatForm : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit GenericChatForm(QWidget* parent = nullptr);
|
explicit GenericChatForm(QWidget* parent = nullptr);
|
||||||
~GenericChatForm();
|
~GenericChatForm() override;
|
||||||
|
|
||||||
void setName(const QString& newName);
|
void setName(const QString& newName);
|
||||||
virtual void show() final
|
virtual void show() final
|
||||||
|
@ -138,28 +139,19 @@ protected:
|
||||||
|
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
|
|
||||||
QPushButton* callButton;
|
|
||||||
QPushButton* emoteButton;
|
QPushButton* emoteButton;
|
||||||
QPushButton* fileButton;
|
QPushButton* fileButton;
|
||||||
QPushButton* screenshotButton;
|
QPushButton* screenshotButton;
|
||||||
QPushButton* sendButton;
|
QPushButton* sendButton;
|
||||||
QPushButton* videoButton;
|
|
||||||
|
|
||||||
QSplitter* bodySplitter;
|
QSplitter* bodySplitter;
|
||||||
|
|
||||||
QToolButton* volButton;
|
ChatFormHeader* headWidget;
|
||||||
QToolButton* micButton;
|
|
||||||
|
|
||||||
QVBoxLayout* headTextLayout;
|
|
||||||
|
|
||||||
QWidget* headWidget;
|
|
||||||
|
|
||||||
ChatLog* chatWidget;
|
ChatLog* chatWidget;
|
||||||
ChatTextEdit* msgEdit;
|
ChatTextEdit* msgEdit;
|
||||||
CroppingLabel* nameLabel;
|
|
||||||
FlyoutOverlayWidget* fileFlyout;
|
FlyoutOverlayWidget* fileFlyout;
|
||||||
GenericNetCamView* netcam;
|
GenericNetCamView* netcam;
|
||||||
MaskablePixmapWidget* avatar;
|
|
||||||
Widget* parent;
|
Widget* parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "src/friendlist.h"
|
#include "src/friendlist.h"
|
||||||
#include "src/model/group.h"
|
#include "src/model/group.h"
|
||||||
#include "src/video/groupnetcamview.h"
|
#include "src/video/groupnetcamview.h"
|
||||||
|
#include "src/widget/chatformheader.h"
|
||||||
#include "src/widget/flowlayout.h"
|
#include "src/widget/flowlayout.h"
|
||||||
#include "src/widget/form/chatform.h"
|
#include "src/widget/form/chatform.h"
|
||||||
#include "src/widget/groupwidget.h"
|
#include "src/widget/groupwidget.h"
|
||||||
|
@ -77,46 +78,40 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
|
||||||
tabber = new TabCompleter(msgEdit, group);
|
tabber = new TabCompleter(msgEdit, group);
|
||||||
|
|
||||||
fileButton->setEnabled(false);
|
fileButton->setEnabled(false);
|
||||||
|
ChatFormHeader::Mode mode = ChatFormHeader::Mode::None;
|
||||||
if (group->isAvGroupchat()) {
|
if (group->isAvGroupchat()) {
|
||||||
videoButton->setEnabled(false);
|
mode = ChatFormHeader::Mode::Audio;
|
||||||
videoButton->setObjectName("grey");
|
|
||||||
} else {
|
|
||||||
videoButton->setVisible(false);
|
|
||||||
callButton->setVisible(false);
|
|
||||||
volButton->setVisible(false);
|
|
||||||
micButton->setVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nameLabel->setText(group->getName());
|
headWidget->setMode(mode);
|
||||||
|
setName(group->getName());
|
||||||
|
|
||||||
nusersLabel->setFont(Style::getFont(Style::Medium));
|
nusersLabel->setFont(Style::getFont(Style::Medium));
|
||||||
nusersLabel->setObjectName("statusLabel");
|
nusersLabel->setObjectName("statusLabel");
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
||||||
avatar->setPixmap(Style::scaleSvgImage(":/img/group_dark.svg", avatar->width(), avatar->height()));
|
const QSize& size = headWidget->getAvatarSize();
|
||||||
|
headWidget->setAvatar(Style::scaleSvgImage(":/img/group_dark.svg", size.width(), size.height()));
|
||||||
|
|
||||||
msgEdit->setObjectName("group");
|
msgEdit->setObjectName("group");
|
||||||
|
|
||||||
namesListLayout = new FlowLayout(0, 5, 0);
|
namesListLayout = new FlowLayout(0, 5, 0);
|
||||||
headTextLayout->addWidget(nusersLabel);
|
headWidget->addWidget(nusersLabel);
|
||||||
headTextLayout->addLayout(namesListLayout);
|
headWidget->addLayout(namesListLayout);
|
||||||
headTextLayout->addStretch();
|
headWidget->addStretch();
|
||||||
|
|
||||||
nameLabel->setMinimumHeight(12);
|
//nameLabel->setMinimumHeight(12);
|
||||||
nusersLabel->setMinimumHeight(12);
|
nusersLabel->setMinimumHeight(12);
|
||||||
|
|
||||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||||
connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
|
connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
|
||||||
connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
|
connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
|
||||||
connect(callButton, &QPushButton::clicked, this, &GroupChatForm::onCallClicked);
|
connect(headWidget, &ChatFormHeader::callTriggered, this, &GroupChatForm::onCallClicked);
|
||||||
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
|
connect(headWidget, &ChatFormHeader::micMuteToggle, this, &GroupChatForm::onMicMuteToggle);
|
||||||
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
connect(headWidget, &ChatFormHeader::volMuteToggle, this, &GroupChatForm::onVolMuteToggle);
|
||||||
connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName) {
|
connect(headWidget, &ChatFormHeader::nameChanged, this, [=](const QString& newName) {
|
||||||
if (!newName.isEmpty()) {
|
chatGroup->setName(newName);
|
||||||
nameLabel->setText(newName);
|
|
||||||
chatGroup->setName(newName);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
connect(group, &Group::userListChanged, this, &GroupChatForm::onUserListChanged);
|
connect(group, &Group::userListChanged, this, &GroupChatForm::onUserListChanged);
|
||||||
|
|
||||||
|
@ -169,19 +164,9 @@ void GroupChatForm::onUserListChanged()
|
||||||
|
|
||||||
// Enable or disable call button
|
// Enable or disable call button
|
||||||
const int peersCount = group->getPeersCount();
|
const int peersCount = group->getPeersCount();
|
||||||
if (peersCount > 1 && group->isAvGroupchat()) {
|
const bool online = peersCount > 1;
|
||||||
// don't set button to green if call running
|
headWidget->updateCallButtons(online, inCall);
|
||||||
if (!inCall) {
|
if (!online || !group->isAvGroupchat()) {
|
||||||
callButton->setEnabled(true);
|
|
||||||
callButton->setObjectName("green");
|
|
||||||
callButton->style()->polish(callButton);
|
|
||||||
callButton->setToolTip(tr("Start audio call"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
callButton->setEnabled(false);
|
|
||||||
callButton->setObjectName("grey");
|
|
||||||
callButton->style()->polish(callButton);
|
|
||||||
callButton->setToolTip("");
|
|
||||||
Core::getInstance()->getAv()->leaveGroupCall(group->getId());
|
Core::getInstance()->getAv()->leaveGroupCall(group->getId());
|
||||||
hideNetcam();
|
hideNetcam();
|
||||||
}
|
}
|
||||||
|
@ -294,17 +279,10 @@ void GroupChatForm::onMicMuteToggle()
|
||||||
{
|
{
|
||||||
if (audioInputFlag) {
|
if (audioInputFlag) {
|
||||||
CoreAV* av = Core::getInstance()->getAv();
|
CoreAV* av = Core::getInstance()->getAv();
|
||||||
if (micButton->objectName() == "red") {
|
const bool oldMuteState = av->isGroupCallInputMuted(group);
|
||||||
av->muteCallInput(group, false);
|
const bool newMute = !oldMuteState;
|
||||||
micButton->setObjectName("green");
|
av->muteCallInput(group, newMute);
|
||||||
micButton->setToolTip(tr("Mute microphone"));
|
headWidget->updateMuteMicButton(inCall, newMute);
|
||||||
} else {
|
|
||||||
av->muteCallInput(group, true);
|
|
||||||
micButton->setObjectName("red");
|
|
||||||
micButton->setToolTip(tr("Unmute microphone"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Style::repolish(micButton);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,53 +290,39 @@ void GroupChatForm::onVolMuteToggle()
|
||||||
{
|
{
|
||||||
if (audioOutputFlag) {
|
if (audioOutputFlag) {
|
||||||
CoreAV* av = Core::getInstance()->getAv();
|
CoreAV* av = Core::getInstance()->getAv();
|
||||||
if (volButton->objectName() == "red") {
|
const bool oldMuteState = av->isGroupCallOutputMuted(group);
|
||||||
av->muteCallOutput(group, false);
|
const bool newMute = !oldMuteState;
|
||||||
volButton->setObjectName("green");
|
av->muteCallOutput(group, newMute);
|
||||||
volButton->setToolTip(tr("Mute call"));
|
headWidget->updateMuteVolButton(inCall, newMute);
|
||||||
} else {
|
|
||||||
av->muteCallOutput(group, true);
|
|
||||||
volButton->setObjectName("red");
|
|
||||||
volButton->setToolTip(tr("Unmute call"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Style::repolish(volButton);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onCallClicked()
|
void GroupChatForm::onCallClicked()
|
||||||
{
|
{
|
||||||
|
CoreAV* av = Core::getInstance()->getAv();
|
||||||
if (!inCall) {
|
if (!inCall) {
|
||||||
Core::getInstance()->getAv()->joinGroupCall(group->getId());
|
av->joinGroupCall(group->getId());
|
||||||
audioInputFlag = true;
|
audioInputFlag = true;
|
||||||
audioOutputFlag = true;
|
audioOutputFlag = true;
|
||||||
callButton->setObjectName("red");
|
|
||||||
callButton->style()->polish(callButton);
|
|
||||||
callButton->setToolTip(tr("End audio call"));
|
|
||||||
micButton->setObjectName("green");
|
|
||||||
micButton->style()->polish(micButton);
|
|
||||||
micButton->setToolTip(tr("Mute microphone"));
|
|
||||||
volButton->setObjectName("green");
|
|
||||||
volButton->style()->polish(volButton);
|
|
||||||
volButton->setToolTip(tr("Mute call"));
|
|
||||||
inCall = true;
|
inCall = true;
|
||||||
showNetcam();
|
showNetcam();
|
||||||
} else {
|
} else {
|
||||||
Core::getInstance()->getAv()->leaveGroupCall(group->getId());
|
av->leaveGroupCall(group->getId());
|
||||||
audioInputFlag = false;
|
audioInputFlag = false;
|
||||||
audioOutputFlag = false;
|
audioOutputFlag = false;
|
||||||
callButton->setObjectName("green");
|
|
||||||
callButton->style()->polish(callButton);
|
|
||||||
callButton->setToolTip(tr("Start audio call"));
|
|
||||||
micButton->setObjectName("grey");
|
|
||||||
micButton->style()->polish(micButton);
|
|
||||||
micButton->setToolTip("");
|
|
||||||
volButton->setObjectName("grey");
|
|
||||||
volButton->style()->polish(volButton);
|
|
||||||
volButton->setToolTip("");
|
|
||||||
inCall = false;
|
inCall = false;
|
||||||
hideNetcam();
|
hideNetcam();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int peersCount = group->getPeersCount();
|
||||||
|
const bool online = peersCount > 1;
|
||||||
|
headWidget->updateCallButtons(online, inCall);
|
||||||
|
|
||||||
|
const bool inMute = av->isGroupCallInputMuted(group);
|
||||||
|
headWidget->updateMuteMicButton(inCall, inMute);
|
||||||
|
|
||||||
|
const bool outMute = av->isGroupCallOutputMuted(group);
|
||||||
|
headWidget->updateMuteVolButton(inCall, outMute);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericNetCamView* GroupChatForm::createNetcam()
|
GenericNetCamView* GroupChatForm::createNetcam()
|
||||||
|
@ -378,13 +342,7 @@ void GroupChatForm::keyPressEvent(QKeyEvent* ev)
|
||||||
{
|
{
|
||||||
// Push to talk (CTRL+P)
|
// Push to talk (CTRL+P)
|
||||||
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
|
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
|
||||||
CoreAV* av = Core::getInstance()->getAv();
|
onMicMuteToggle();
|
||||||
if (!av->isGroupCallInputMuted(group)) {
|
|
||||||
av->muteCallInput(group, false);
|
|
||||||
micButton->setObjectName("green");
|
|
||||||
micButton->style()->polish(micButton);
|
|
||||||
Style::repolish(micButton);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgEdit->hasFocus())
|
if (msgEdit->hasFocus())
|
||||||
|
@ -395,13 +353,7 @@ void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
|
||||||
{
|
{
|
||||||
// Push to talk (CTRL+P)
|
// Push to talk (CTRL+P)
|
||||||
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
|
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
|
||||||
CoreAV* av = Core::getInstance()->getAv();
|
onMicMuteToggle();
|
||||||
if (av->isGroupCallInputMuted(group)) {
|
|
||||||
av->muteCallInput(group, true);
|
|
||||||
micButton->setObjectName("red");
|
|
||||||
micButton->style()->polish(micButton);
|
|
||||||
Style::repolish(micButton);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgEdit->hasFocus())
|
if (msgEdit->hasFocus())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user