1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor: Extract head widget from GenericChatForm

Also fix #2749
This commit is contained in:
Diadlo 2017-10-26 08:59:06 +03:00
parent 511b8af954
commit ba1581005b
No known key found for this signature in database
GPG Key ID: 5AF9F2E29107C727
8 changed files with 453 additions and 283 deletions

View File

@ -325,6 +325,8 @@ set(${PROJECT_NAME}_SOURCES
src/widget/about/aboutfriendform.h
src/widget/categorywidget.cpp
src/widget/categorywidget.h
src/widget/chatformheader.cpp
src/widget/chatformheader.h
src/widget/circlewidget.cpp
src/widget/circlewidget.h
src/widget/contentdialog.cpp

View 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);
}
}

View 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

View File

@ -33,6 +33,7 @@
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include "src/video/netcamview.h"
#include "src/widget/chatformheader.h"
#include "src/widget/form/loadhistorydialog.h"
#include "src/widget/maskablepixmapwidget.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 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 ");
QString statusToString(const Status status)
@ -118,9 +114,9 @@ ChatForm::ChatForm(Friend* chatFriend)
, callDuration(new QLabel(this))
, 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->setObjectName("statusLabel");
@ -129,7 +125,6 @@ ChatForm::ChatForm(Friend* chatFriend)
statusMessageLabel->setTextFormat(Qt::PlainText);
statusMessageLabel->setContextMenuPolicy(Qt::CustomContextMenu);
callConfirm = nullptr;
offlineEngine = new OfflineMsgEngine(f);
typingTimer.setSingleShot(true);
@ -139,10 +134,10 @@ ChatForm::ChatForm(Friend* chatFriend)
chatWidget->setTypingNotification(ChatMessage::createTypingNotification());
chatWidget->setMinimumHeight(CHAT_WIDGET_MIN_HEIGHT);
headTextLayout->addWidget(statusMessageLabel);
headTextLayout->addStretch();
callDuration = new QLabel();
headTextLayout->addWidget(callDuration, 1, Qt::AlignCenter);
headWidget->addWidget(statusMessageLabel);
headWidget->addStretch();
headWidget->addWidget(callDuration, 1, Qt::AlignCenter);
callDuration->hide();
loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory()));
@ -171,10 +166,10 @@ ChatForm::ChatForm(Friend* chatFriend)
connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
connect(screenshotButton, &QPushButton::clicked, this, &ChatForm::onScreenshotClicked);
connect(callButton, &QAbstractButton::clicked, this, &ChatForm::onCallTriggered);
connect(videoButton, &QAbstractButton::clicked, this, &ChatForm::onVideoCallTriggered);
connect(micButton, &QAbstractButton::clicked, this, &ChatForm::onMicMuteToggle);
connect(volButton, &QAbstractButton::clicked, this, &ChatForm::onVolMuteToggle);
connect(headWidget, &ChatFormHeader::callTriggered, this, &ChatForm::onCallTriggered);
connect(headWidget, &ChatFormHeader::videoCallTriggered, this, &ChatForm::onVideoCallTriggered);
connect(headWidget, &ChatFormHeader::micMuteToggle, this, &ChatForm::onMicMuteToggle);
connect(headWidget, &ChatFormHeader::volMuteToggle, this, &ChatForm::onVolMuteToggle);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
@ -192,9 +187,8 @@ ChatForm::ChatForm(Friend* chatFriend)
isTyping = false;
});
connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName) {
nameLabel->setText(newName);
emit aliasChanged(newName);
connect(headWidget, &ChatFormHeader::nameChanged, this, [=](const QString& newName) {
f->setAlias(newName);
});
updateCallButtons();
@ -335,7 +329,6 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
return;
}
callConfirm = new CallConfirmWidget(video ? videoButton : callButton);
QString displayedName = f->getDisplayedName();
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
ChatMessage::INFO,
@ -351,10 +344,9 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
Q_ARG(uint32_t, friendId), Q_ARG(bool, video));
onAvStart(friendId, video);
} else {
callConfirm->show();
CallConfirmWidget* confirmData = callConfirm.data();
connect(confirmData, &CallConfirmWidget::accepted, this, [this, video]{ onAnswerCallTriggered(video); });
connect(confirmData, &CallConfirmWidget::rejected, this, &ChatForm::onRejectCallTriggered);
headWidget->showCallConfirm(video);
connect(headWidget, &ChatFormHeader::callAccepted, this, &ChatForm::onAnswerCallTriggered);
connect(headWidget, &ChatFormHeader::callRejected, this, &ChatForm::onRejectCallTriggered);
auto msg = ChatMessage::createChatInfoMessage(tr("%1 calling").arg(displayedName),
ChatMessage::INFO, QDateTime::currentDateTime());
insertChatMessage(msg);
@ -385,8 +377,6 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
return;
}
delete callConfirm;
// Fixes an OS X bug with ending a call while in full screen
if (netcam && netcam->isFullScreen()) {
netcam->showNormal();
@ -399,10 +389,7 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
void ChatForm::showOutgoingCall(bool video)
{
QPushButton* btn = video ? videoButton : callButton;
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"));
headWidget->showOutgoingCall(video);
addSystemInfoMessage(tr("Calling %1").arg(f->getDisplayedName()), ChatMessage::INFO,
QDateTime::currentDateTime());
emit outgoingNotification();
@ -411,7 +398,7 @@ void ChatForm::showOutgoingCall(bool video)
void ChatForm::onAnswerCallTriggered(bool video)
{
delete callConfirm;
headWidget->removeCallConfirm();
uint32_t friendId = f->getId();
emit acceptCall(friendId);
@ -429,7 +416,7 @@ void ChatForm::onAnswerCallTriggered(bool video)
void ChatForm::onRejectCallTriggered()
{
delete callConfirm;
headWidget->removeCallConfirm();
emit rejectCall(f->getId());
}
@ -461,32 +448,10 @@ void ChatForm::onVideoCallTriggered()
void ChatForm::updateCallButtons()
{
CoreAV* av = Core::getInstance()->getAv();
bool audio = av->isCallActive(f);
bool video = av->isCallVideoEnabled(f);
callButton->setEnabled(audio && !video);
videoButton->setEnabled(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));
const bool audio = av->isCallActive(f);
const bool video = av->isCallVideoEnabled(f);
const bool online = f->getStatus() != Status::Offline;
headWidget->updateCallButtons(online, audio, video);
updateMuteMicButton();
updateMuteVolButton();
}
@ -584,7 +549,7 @@ void ChatForm::onAvatarChange(uint32_t friendId, const QPixmap& pic)
return;
}
avatar->setPixmap(pic);
headWidget->setAvatar(pic);
}
GenericNetCamView* ChatForm::createNetcam()
@ -653,7 +618,7 @@ void ChatForm::onAvatarRemoved(uint32_t friendId)
return;
}
avatar->setPixmap(QPixmap(":/img/contact_dark.svg"));
headWidget->setAvatar(QPixmap(":/img/contact_dark.svg"));
}
void ChatForm::clearChatArea(bool notInForm)
@ -849,35 +814,17 @@ void ChatForm::onCopyStatusMessage()
void ChatForm::updateMuteMicButton()
{
const CoreAV* av = Core::getInstance()->getAv();
micButton->setEnabled(av->isCallActive(f));
if (micButton->isEnabled()) {
bool active = av->isCallActive(f);
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));
headWidget->updateMuteMicButton(active, inputMuted);
}
void ChatForm::updateMuteVolButton()
{
const CoreAV* av = Core::getInstance()->getAv();
volButton->setEnabled(av->isCallActive(f));
if (volButton->isEnabled()) {
bool active = av->isCallActive(f);
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));
headWidget->updateMuteVolButton(active, outputMuted);
}
void ChatForm::startCounter()
@ -929,26 +876,15 @@ void ChatForm::setFriendTyping(bool isTyping)
void ChatForm::show(ContentLayout* contentLayout)
{
GenericChatForm::show(contentLayout);
if (callConfirm) {
callConfirm->show();
}
}
void ChatForm::showEvent(QShowEvent* event)
{
if (callConfirm) {
callConfirm->show();
}
GenericChatForm::showEvent(event);
}
void ChatForm::hideEvent(QHideEvent* event)
{
if (callConfirm) {
callConfirm->hide();
}
GenericChatForm::hideEvent(event);
}
@ -1006,8 +942,6 @@ void ChatForm::SendMessageStr(QString msg)
void ChatForm::retranslateUi()
{
QString volObjectName = volButton->objectName();
QString micObjectName = micButton->objectName();
loadHistoryAction->setText(tr("Load chat history..."));
copyStatusAction->setText(tr("Copy"));
exportChatAction->setText(tr("Export to file"));

View File

@ -57,7 +57,6 @@ public:
static const QString ACTION_PREFIX;
signals:
void aliasChanged(const QString& alias);
void incomingNotification(uint32_t friendId);
void outgoingNotification();
void rejectCall(uint32_t friendId);
@ -134,7 +133,6 @@ private:
QAction* exportChatAction;
QHash<uint, FileTransferInstance*> ftransWidgets;
QPointer<CallConfirmWidget> callConfirm;
bool isTyping;
};

View File

@ -29,6 +29,7 @@
#include "src/persistence/settings.h"
#include "src/persistence/smileypack.h"
#include "src/video/genericnetcamview.h"
#include "src/widget/chatformheader.h"
#include "src/widget/contentdialog.h"
#include "src/widget/contentlayout.h"
#include "src/widget/emoticonswidget.h"
@ -57,16 +58,10 @@
#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 short FOOT_BUTTONS_SPACING = 2;
static const short MESSAGE_EDIT_HEIGHT = 50;
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"};
/**
@ -115,22 +110,12 @@ GenericChatForm::GenericChatForm(QWidget* parent)
, audioOutputFlag(false)
{
curRow = 0;
headWidget = new QWidget();
headWidget = new ChatFormHeader();
nameLabel = new CroppingLabel();
nameLabel->setObjectName("nameLabel");
nameLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
nameLabel->setEditable(true);
nameLabel->setTextFormat(Qt::PlainText);
QHBoxLayout* mainFootLayout = new QHBoxLayout();
avatar = new MaskablePixmapWidget(this, AVATAR_SIZE, ":/img/avatar_mask.svg");
QHBoxLayout *mainFootLayout = new QHBoxLayout(), *headLayout = new QHBoxLayout();
QVBoxLayout *mainLayout = new QVBoxLayout(), *footButtonsSmall = new QVBoxLayout(),
*micButtonsLayout = new QVBoxLayout();
headTextLayout = new QVBoxLayout();
QGridLayout* buttonsLayout = new QGridLayout();
QVBoxLayout* mainLayout = new QVBoxLayout();
QVBoxLayout* footButtonsSmall = new QVBoxLayout();
chatWidget = new ChatLog(this);
chatWidget->setBusyNotification(ChatMessage::createBusyNotification());
@ -149,16 +134,6 @@ GenericChatForm::GenericChatForm(QWidget* parent)
fileButton = 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
// and call here to set tooltips.
@ -180,15 +155,6 @@ GenericChatForm::GenericChatForm(QWidget* parent)
SET_STYLESHEET(fileButton);
SET_STYLESHEET(screenshotButton);
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);
@ -213,37 +179,12 @@ GenericChatForm::GenericChatForm(QWidget* parent)
mainFootLayout->addWidget(sendButton);
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
// https://bugreports.qt-project.org/browse/QTBUG-14591
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
fileButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
screenshotButton->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.addSeparator();
@ -324,9 +265,7 @@ QDate GenericChatForm::getLatestDate() const
void GenericChatForm::setName(const QString& newName)
{
nameLabel->setText(newName);
nameLabel->setToolTip(
Qt::convertFromPlainText(newName, Qt::WhiteSpaceNormal)); // for overlength names
headWidget->setName(newName);
}
void GenericChatForm::show(ContentLayout* contentLayout)
@ -709,23 +648,6 @@ void GenericChatForm::copyLink()
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"));
emoteButton->setToolTip(tr("Smileys"));
fileButton->setToolTip(tr("Send file(s)"));

View File

@ -32,6 +32,7 @@
* - Even a different font is not enough TODO #1307 ~~zetok
*/
class ChatFormHeader;
class ChatLog;
class ChatTextEdit;
class ContentLayout;
@ -56,7 +57,7 @@ class GenericChatForm : public QWidget
Q_OBJECT
public:
explicit GenericChatForm(QWidget* parent = nullptr);
~GenericChatForm();
~GenericChatForm() override;
void setName(const QString& newName);
virtual void show() final
@ -138,28 +139,19 @@ protected:
QMenu menu;
QPushButton* callButton;
QPushButton* emoteButton;
QPushButton* fileButton;
QPushButton* screenshotButton;
QPushButton* sendButton;
QPushButton* videoButton;
QSplitter* bodySplitter;
QToolButton* volButton;
QToolButton* micButton;
QVBoxLayout* headTextLayout;
QWidget* headWidget;
ChatFormHeader* headWidget;
ChatLog* chatWidget;
ChatTextEdit* msgEdit;
CroppingLabel* nameLabel;
FlyoutOverlayWidget* fileFlyout;
GenericNetCamView* netcam;
MaskablePixmapWidget* avatar;
Widget* parent;
};

View File

@ -26,6 +26,7 @@
#include "src/friendlist.h"
#include "src/model/group.h"
#include "src/video/groupnetcamview.h"
#include "src/widget/chatformheader.h"
#include "src/widget/flowlayout.h"
#include "src/widget/form/chatform.h"
#include "src/widget/groupwidget.h"
@ -77,46 +78,40 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
tabber = new TabCompleter(msgEdit, group);
fileButton->setEnabled(false);
ChatFormHeader::Mode mode = ChatFormHeader::Mode::None;
if (group->isAvGroupchat()) {
videoButton->setEnabled(false);
videoButton->setObjectName("grey");
} else {
videoButton->setVisible(false);
callButton->setVisible(false);
volButton->setVisible(false);
micButton->setVisible(false);
mode = ChatFormHeader::Mode::Audio;
}
nameLabel->setText(group->getName());
headWidget->setMode(mode);
setName(group->getName());
nusersLabel->setFont(Style::getFont(Style::Medium));
nusersLabel->setObjectName("statusLabel");
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");
namesListLayout = new FlowLayout(0, 5, 0);
headTextLayout->addWidget(nusersLabel);
headTextLayout->addLayout(namesListLayout);
headTextLayout->addStretch();
headWidget->addWidget(nusersLabel);
headWidget->addLayout(namesListLayout);
headWidget->addStretch();
nameLabel->setMinimumHeight(12);
//nameLabel->setMinimumHeight(12);
nusersLabel->setMinimumHeight(12);
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
connect(callButton, &QPushButton::clicked, this, &GroupChatForm::onCallClicked);
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName) {
if (!newName.isEmpty()) {
nameLabel->setText(newName);
connect(headWidget, &ChatFormHeader::callTriggered, this, &GroupChatForm::onCallClicked);
connect(headWidget, &ChatFormHeader::micMuteToggle, this, &GroupChatForm::onMicMuteToggle);
connect(headWidget, &ChatFormHeader::volMuteToggle, this, &GroupChatForm::onVolMuteToggle);
connect(headWidget, &ChatFormHeader::nameChanged, this, [=](const QString& newName) {
chatGroup->setName(newName);
}
});
connect(group, &Group::userListChanged, this, &GroupChatForm::onUserListChanged);
@ -169,19 +164,9 @@ void GroupChatForm::onUserListChanged()
// Enable or disable call button
const int peersCount = group->getPeersCount();
if (peersCount > 1 && group->isAvGroupchat()) {
// don't set button to green if call running
if (!inCall) {
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("");
const bool online = peersCount > 1;
headWidget->updateCallButtons(online, inCall);
if (!online || !group->isAvGroupchat()) {
Core::getInstance()->getAv()->leaveGroupCall(group->getId());
hideNetcam();
}
@ -294,17 +279,10 @@ void GroupChatForm::onMicMuteToggle()
{
if (audioInputFlag) {
CoreAV* av = Core::getInstance()->getAv();
if (micButton->objectName() == "red") {
av->muteCallInput(group, false);
micButton->setObjectName("green");
micButton->setToolTip(tr("Mute microphone"));
} else {
av->muteCallInput(group, true);
micButton->setObjectName("red");
micButton->setToolTip(tr("Unmute microphone"));
}
Style::repolish(micButton);
const bool oldMuteState = av->isGroupCallInputMuted(group);
const bool newMute = !oldMuteState;
av->muteCallInput(group, newMute);
headWidget->updateMuteMicButton(inCall, newMute);
}
}
@ -312,53 +290,39 @@ void GroupChatForm::onVolMuteToggle()
{
if (audioOutputFlag) {
CoreAV* av = Core::getInstance()->getAv();
if (volButton->objectName() == "red") {
av->muteCallOutput(group, false);
volButton->setObjectName("green");
volButton->setToolTip(tr("Mute call"));
} else {
av->muteCallOutput(group, true);
volButton->setObjectName("red");
volButton->setToolTip(tr("Unmute call"));
}
Style::repolish(volButton);
const bool oldMuteState = av->isGroupCallOutputMuted(group);
const bool newMute = !oldMuteState;
av->muteCallOutput(group, newMute);
headWidget->updateMuteVolButton(inCall, newMute);
}
}
void GroupChatForm::onCallClicked()
{
CoreAV* av = Core::getInstance()->getAv();
if (!inCall) {
Core::getInstance()->getAv()->joinGroupCall(group->getId());
av->joinGroupCall(group->getId());
audioInputFlag = 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;
showNetcam();
} else {
Core::getInstance()->getAv()->leaveGroupCall(group->getId());
av->leaveGroupCall(group->getId());
audioInputFlag = 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;
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()
@ -378,13 +342,7 @@ void GroupChatForm::keyPressEvent(QKeyEvent* ev)
{
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
CoreAV* av = Core::getInstance()->getAv();
if (!av->isGroupCallInputMuted(group)) {
av->muteCallInput(group, false);
micButton->setObjectName("green");
micButton->style()->polish(micButton);
Style::repolish(micButton);
}
onMicMuteToggle();
}
if (msgEdit->hasFocus())
@ -395,13 +353,7 @@ void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
{
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
CoreAV* av = Core::getInstance()->getAv();
if (av->isGroupCallInputMuted(group)) {
av->muteCallInput(group, true);
micButton->setObjectName("red");
micButton->style()->polish(micButton);
Style::repolish(micButton);
}
onMicMuteToggle();
}
if (msgEdit->hasFocus())