2014-07-07 00:19:45 +08:00
|
|
|
/*
|
2019-06-24 22:01:18 +08:00
|
|
|
Copyright © 2014-2019 by The qTox Project Contributors
|
2015-06-06 09:40:08 +08:00
|
|
|
|
2014-07-07 00:19:45 +08:00
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
2014-07-07 00:19:45 +08:00
|
|
|
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.
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
|
|
qTox is distributed in the hope that it will be useful,
|
2014-07-07 00:19:45 +08:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2015-06-06 09:40:08 +08:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2014-07-07 00:19:45 +08:00
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
2014-07-07 00:19:45 +08:00
|
|
|
*/
|
|
|
|
|
2014-06-30 10:39:43 +08:00
|
|
|
#include "netcamview.h"
|
2015-07-23 02:50:39 +08:00
|
|
|
#include "camerasource.h"
|
2017-02-26 19:52:45 +08:00
|
|
|
#include "src/core/core.h"
|
2016-12-19 10:26:26 +08:00
|
|
|
#include "src/friendlist.h"
|
2018-06-30 18:10:46 +08:00
|
|
|
#include "src/model/friend.h"
|
2017-02-26 19:52:45 +08:00
|
|
|
#include "src/nexus.h"
|
|
|
|
#include "src/persistence/profile.h"
|
|
|
|
#include "src/persistence/settings.h"
|
2016-12-19 10:26:26 +08:00
|
|
|
#include "src/video/videosurface.h"
|
|
|
|
#include "src/widget/tool/movablewidget.h"
|
2020-01-26 15:29:26 +08:00
|
|
|
#include "src/widget/style.h"
|
|
|
|
|
|
|
|
#include <QApplication>
|
2015-07-23 02:50:39 +08:00
|
|
|
#include <QBoxLayout>
|
2020-01-26 15:29:26 +08:00
|
|
|
#include <QScreen>
|
2015-08-13 21:31:15 +08:00
|
|
|
#include <QFrame>
|
2017-02-26 19:52:45 +08:00
|
|
|
#include <QLabel>
|
2020-01-26 15:29:26 +08:00
|
|
|
#include <QCloseEvent>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
const auto BTN_STATE_NONE = QVariant("none");
|
|
|
|
const auto BTN_STATE_RED = QVariant("red");
|
|
|
|
const int BTN_PANEL_HEIGHT = 55;
|
|
|
|
const int BTN_PANEL_WIDTH = 250;
|
|
|
|
const auto BTN_STYLE_SHEET_PATH = QStringLiteral("chatForm/fullScreenButtons.css");
|
|
|
|
}
|
2014-06-30 10:39:43 +08:00
|
|
|
|
2019-04-16 15:40:14 +08:00
|
|
|
NetCamView::NetCamView(ToxPk friendPk, QWidget* parent)
|
2020-01-26 15:29:26 +08:00
|
|
|
: selfFrame{nullptr}
|
2019-04-16 15:40:14 +08:00
|
|
|
, friendPk{friendPk}
|
2016-07-27 06:18:57 +08:00
|
|
|
, e(false)
|
2014-06-30 10:39:43 +08:00
|
|
|
{
|
2020-01-26 15:29:26 +08:00
|
|
|
verLayout = new QVBoxLayout(this);
|
|
|
|
setWindowTitle(tr("Tox video"));
|
|
|
|
|
|
|
|
buttonLayout = new QHBoxLayout();
|
|
|
|
|
|
|
|
toggleMessagesButton = new QPushButton();
|
|
|
|
enterFullScreenButton = new QPushButton();
|
|
|
|
enterFullScreenButton->setText(tr("Full Screen"));
|
|
|
|
|
|
|
|
buttonLayout->addStretch();
|
|
|
|
buttonLayout->addWidget(toggleMessagesButton);
|
|
|
|
buttonLayout->addWidget(enterFullScreenButton);
|
|
|
|
|
|
|
|
connect(toggleMessagesButton, &QPushButton::clicked, this, &NetCamView::showMessageClicked);
|
|
|
|
connect(enterFullScreenButton, &QPushButton::clicked, this, &NetCamView::toggleFullScreen);
|
|
|
|
|
|
|
|
verLayout->addLayout(buttonLayout);
|
|
|
|
verLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
|
|
|
setShowMessages(false);
|
|
|
|
|
|
|
|
setStyleSheet("NetCamView { background-color: #c1c1c1; }");
|
|
|
|
buttonPanel = new QFrame(this);
|
|
|
|
buttonPanel->setStyleSheet(Style::getStylesheet(BTN_STYLE_SHEET_PATH));
|
|
|
|
buttonPanel->setGeometry(0, 0, BTN_PANEL_WIDTH, BTN_PANEL_HEIGHT);
|
|
|
|
|
|
|
|
QHBoxLayout* buttonPanelLayout = new QHBoxLayout(buttonPanel);
|
|
|
|
buttonPanelLayout->setContentsMargins(20, 0, 20, 0);
|
|
|
|
|
|
|
|
videoPreviewButton = createButton("videoPreviewButton", "none");
|
|
|
|
videoPreviewButton->setToolTip(tr("Toggle video preview"));
|
|
|
|
|
|
|
|
volumeButton = createButton("volButtonFullScreen", "none");
|
|
|
|
volumeButton->setToolTip(tr("Mute audio"));
|
|
|
|
|
|
|
|
microphoneButton = createButton("micButtonFullScreen", "none");
|
|
|
|
microphoneButton->setToolTip(tr("Mute microphone"));
|
|
|
|
|
|
|
|
endVideoButton = createButton("videoButtonFullScreen", "none");
|
|
|
|
endVideoButton->setToolTip(tr("End video call"));
|
|
|
|
|
|
|
|
exitFullScreenButton = createButton("exitFullScreenButton", "none");
|
|
|
|
exitFullScreenButton->setToolTip(tr("Exit full screen"));
|
|
|
|
|
2020-01-26 15:34:01 +08:00
|
|
|
connect(videoPreviewButton, &QPushButton::clicked, this, &NetCamView::toggleVideoPreview);
|
2020-01-26 15:29:26 +08:00
|
|
|
connect(volumeButton, &QPushButton::clicked, this, &NetCamView::volMuteToggle);
|
|
|
|
connect(microphoneButton, &QPushButton::clicked, this, &NetCamView::micMuteToggle);
|
|
|
|
connect(endVideoButton, &QPushButton::clicked, this, &NetCamView::endVideoCall);
|
|
|
|
connect(exitFullScreenButton, &QPushButton::clicked, this, &NetCamView::toggleFullScreen);
|
|
|
|
|
|
|
|
buttonPanelLayout->addStretch();
|
|
|
|
buttonPanelLayout->addWidget(videoPreviewButton);
|
|
|
|
buttonPanelLayout->addWidget(volumeButton);
|
|
|
|
buttonPanelLayout->addWidget(microphoneButton);
|
|
|
|
buttonPanelLayout->addWidget(endVideoButton);
|
|
|
|
buttonPanelLayout->addWidget(exitFullScreenButton);
|
|
|
|
buttonPanelLayout->addStretch();
|
|
|
|
|
2017-10-27 09:55:49 +08:00
|
|
|
videoSurface = new VideoSurface(Nexus::getProfile()->loadAvatar(friendPk), this);
|
2015-08-13 21:31:15 +08:00
|
|
|
videoSurface->setMinimumHeight(256);
|
2015-08-12 02:01:49 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
verLayout->insertWidget(0, videoSurface, 1);
|
2015-08-12 02:01:49 +08:00
|
|
|
|
2015-12-06 02:08:28 +08:00
|
|
|
selfVideoSurface = new VideoSurface(Nexus::getProfile()->loadAvatar(), this, true);
|
2015-08-12 02:01:49 +08:00
|
|
|
selfVideoSurface->setObjectName(QStringLiteral("CamVideoSurface"));
|
|
|
|
selfVideoSurface->setMouseTracking(true);
|
2015-08-13 21:31:15 +08:00
|
|
|
selfVideoSurface->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
2014-07-12 21:21:24 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
selfFrame = new MovableWidget(videoSurface);
|
|
|
|
selfFrame->show();
|
|
|
|
|
2015-08-12 02:01:49 +08:00
|
|
|
QHBoxLayout* frameLayout = new QHBoxLayout(selfFrame);
|
|
|
|
frameLayout->addWidget(selfVideoSurface);
|
|
|
|
frameLayout->setMargin(0);
|
2015-07-21 05:57:46 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
updateRatio();
|
2017-02-26 19:52:45 +08:00
|
|
|
connections +=
|
|
|
|
connect(selfVideoSurface, &VideoSurface::ratioChanged, this, &NetCamView::updateRatio);
|
2015-08-13 21:31:15 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
connections += connect(videoSurface, &VideoSurface::boundaryChanged, [this]() {
|
2015-08-19 01:40:11 +08:00
|
|
|
QRect boundingRect = videoSurface->getBoundingRect();
|
|
|
|
updateFrameSize(boundingRect.size());
|
|
|
|
selfFrame->setBoundary(boundingRect);
|
2015-08-13 21:31:15 +08:00
|
|
|
});
|
2015-07-22 02:38:43 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
connections += connect(videoSurface, &VideoSurface::ratioChanged, [this]() {
|
2015-08-19 01:40:11 +08:00
|
|
|
selfFrame->setMinimumWidth(selfFrame->minimumHeight() * selfVideoSurface->getRatio());
|
|
|
|
QRect boundingRect = videoSurface->getBoundingRect();
|
|
|
|
updateFrameSize(boundingRect.size());
|
|
|
|
selfFrame->resetBoundary(boundingRect);
|
2015-08-13 21:31:15 +08:00
|
|
|
});
|
2015-08-19 05:44:34 +08:00
|
|
|
|
2017-05-07 03:59:46 +08:00
|
|
|
connections += connect(Nexus::getProfile(), &Profile::selfAvatarChanged,
|
2017-02-26 19:52:45 +08:00
|
|
|
[this](const QPixmap& pixmap) { selfVideoSurface->setAvatar(pixmap); });
|
2015-08-20 00:42:54 +08:00
|
|
|
|
2017-10-27 09:55:49 +08:00
|
|
|
connections += connect(Nexus::getProfile(), &Profile::friendAvatarChanged,
|
|
|
|
[this](ToxPk friendPk, const QPixmap& pixmap) {
|
|
|
|
if (this->friendPk == friendPk)
|
2017-02-26 19:52:45 +08:00
|
|
|
videoSurface->setAvatar(pixmap);
|
|
|
|
});
|
2015-08-20 00:42:54 +08:00
|
|
|
|
2016-06-19 03:44:31 +08:00
|
|
|
QRect videoSize = Settings::getInstance().getCamVideoRes();
|
2015-08-20 00:42:54 +08:00
|
|
|
qDebug() << "SIZER" << videoSize;
|
2014-06-30 10:39:43 +08:00
|
|
|
}
|
2014-09-16 01:51:25 +08:00
|
|
|
|
2015-12-16 04:19:10 +08:00
|
|
|
NetCamView::~NetCamView()
|
|
|
|
{
|
|
|
|
for (QMetaObject::Connection conn : connections)
|
|
|
|
disconnect(conn);
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void NetCamView::show(VideoSource* source, const QString& title)
|
2014-10-16 21:37:48 +08:00
|
|
|
{
|
|
|
|
setSource(source);
|
2015-08-13 21:31:15 +08:00
|
|
|
selfVideoSurface->setSource(&CameraSource::getInstance());
|
2014-10-16 21:37:48 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
setTitle(title);
|
2014-10-16 21:37:48 +08:00
|
|
|
QWidget::show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::hide()
|
|
|
|
{
|
|
|
|
setSource(nullptr);
|
2015-08-12 02:01:49 +08:00
|
|
|
selfVideoSurface->setSource(nullptr);
|
2014-10-16 21:37:48 +08:00
|
|
|
|
2015-07-23 02:50:39 +08:00
|
|
|
if (selfFrame)
|
|
|
|
selfFrame->deleteLater();
|
|
|
|
|
|
|
|
selfFrame = nullptr;
|
|
|
|
|
2014-10-16 21:37:48 +08:00
|
|
|
QWidget::hide();
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void NetCamView::setSource(VideoSource* s)
|
2014-09-16 01:51:25 +08:00
|
|
|
{
|
2014-10-15 20:46:01 +08:00
|
|
|
videoSurface->setSource(s);
|
2014-09-16 01:51:25 +08:00
|
|
|
}
|
2014-10-16 21:37:48 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void NetCamView::setTitle(const QString& title)
|
2014-10-16 21:37:48 +08:00
|
|
|
{
|
|
|
|
setWindowTitle(title);
|
|
|
|
}
|
2015-07-21 05:57:46 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void NetCamView::showEvent(QShowEvent* event)
|
2015-08-13 21:31:15 +08:00
|
|
|
{
|
2015-10-18 16:46:57 +08:00
|
|
|
Q_UNUSED(event);
|
2015-08-13 21:31:15 +08:00
|
|
|
selfFrame->resetBoundary(videoSurface->getBoundingRect());
|
2015-07-22 02:38:43 +08:00
|
|
|
}
|
2015-07-21 05:57:46 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
void NetCamView::updateRatio()
|
2015-07-23 02:50:39 +08:00
|
|
|
{
|
2015-08-19 01:40:11 +08:00
|
|
|
selfFrame->setMinimumWidth(selfFrame->minimumHeight() * selfVideoSurface->getRatio());
|
|
|
|
selfFrame->setRatio(selfVideoSurface->getRatio());
|
|
|
|
}
|
2015-07-23 02:50:39 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
void NetCamView::updateFrameSize(QSize size)
|
|
|
|
{
|
|
|
|
selfFrame->setMaximumSize(size.height() / 3, size.width() / 3);
|
2015-08-13 21:31:15 +08:00
|
|
|
|
2015-08-19 01:40:11 +08:00
|
|
|
if (selfFrame->maximumWidth() > selfFrame->maximumHeight())
|
|
|
|
selfFrame->setMaximumWidth(selfFrame->maximumHeight() * selfVideoSurface->getRatio());
|
|
|
|
else
|
|
|
|
selfFrame->setMaximumHeight(selfFrame->maximumWidth() / selfVideoSurface->getRatio());
|
2015-07-21 05:57:46 +08:00
|
|
|
}
|
2018-03-05 15:07:10 +08:00
|
|
|
|
2020-01-26 15:29:26 +08:00
|
|
|
QSize NetCamView::getSurfaceMinSize()
|
|
|
|
{
|
|
|
|
QSize surfaceSize = videoSurface->minimumSize();
|
|
|
|
QSize buttonSize = toggleMessagesButton->size();
|
|
|
|
QSize panelSize(0, 45);
|
|
|
|
|
|
|
|
return surfaceSize + buttonSize + panelSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::setShowMessages(bool show, bool notify)
|
|
|
|
{
|
|
|
|
if (!show) {
|
|
|
|
toggleMessagesButton->setText(tr("Hide messages"));
|
|
|
|
toggleMessagesButton->setIcon(QIcon());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleMessagesButton->setText(tr("Show messages"));
|
|
|
|
|
|
|
|
if (notify) {
|
|
|
|
toggleMessagesButton->setIcon(QIcon(Style::getImagePath("chatArea/info.svg")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::toggleFullScreen()
|
|
|
|
{
|
|
|
|
if (isFullScreen()) {
|
|
|
|
exitFullScreen();
|
|
|
|
} else {
|
|
|
|
enterFullScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::enterFullScreen()
|
|
|
|
{
|
|
|
|
setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
|
|
|
|
showFullScreen();
|
|
|
|
enterFullScreenButton->hide();
|
|
|
|
toggleMessagesButton->hide();
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
|
|
|
const auto screenSize = QGuiApplication::screenAt(this->pos())->geometry();
|
|
|
|
#else
|
|
|
|
const QRect screenSize = QApplication::desktop()->screenGeometry(this);
|
|
|
|
#endif
|
|
|
|
buttonPanel->setGeometry((screenSize.width() / 2) - buttonPanel->width() / 2,
|
|
|
|
screenSize.height() - BTN_PANEL_HEIGHT - 25, BTN_PANEL_WIDTH, BTN_PANEL_HEIGHT);
|
|
|
|
buttonPanel->show();
|
|
|
|
buttonPanel->activateWindow();
|
|
|
|
buttonPanel->raise();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::exitFullScreen()
|
|
|
|
{
|
|
|
|
setWindowFlags(Qt::Widget);
|
|
|
|
showNormal();
|
|
|
|
buttonPanel->hide();
|
|
|
|
enterFullScreenButton->show();
|
|
|
|
toggleMessagesButton->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::endVideoCall()
|
|
|
|
{
|
|
|
|
toggleFullScreen();
|
|
|
|
emit videoCallEnd();
|
|
|
|
}
|
|
|
|
|
2020-01-26 15:34:01 +08:00
|
|
|
void NetCamView::toggleVideoPreview()
|
2020-01-26 15:29:26 +08:00
|
|
|
{
|
|
|
|
toggleButtonState(videoPreviewButton);
|
2020-01-26 15:34:01 +08:00
|
|
|
if (selfFrame->isHidden()) {
|
|
|
|
selfFrame->show();
|
|
|
|
} else {
|
|
|
|
selfFrame->hide();
|
|
|
|
}
|
2020-01-26 15:29:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QPushButton* NetCamView::createButton(const QString& name, const QString& state)
|
|
|
|
{
|
|
|
|
QPushButton* btn = new QPushButton();
|
|
|
|
btn->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
|
|
|
btn->setObjectName(name);
|
|
|
|
btn->setProperty("state", QVariant(state));
|
|
|
|
btn->setStyleSheet(Style::getStylesheet(BTN_STYLE_SHEET_PATH));
|
|
|
|
|
|
|
|
return btn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::updateMuteVolButton(bool isMuted)
|
|
|
|
{
|
|
|
|
updateButtonState(volumeButton, !isMuted);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::updateMuteMicButton(bool isMuted)
|
|
|
|
{
|
|
|
|
updateButtonState(microphoneButton, !isMuted);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::toggleButtonState(QPushButton* btn)
|
|
|
|
{
|
|
|
|
if (btn->property("state") == BTN_STATE_RED) {
|
|
|
|
btn->setProperty("state", BTN_STATE_NONE);
|
|
|
|
} else {
|
|
|
|
btn->setProperty("state", BTN_STATE_RED);
|
|
|
|
}
|
|
|
|
|
|
|
|
btn->setStyleSheet(Style::getStylesheet(BTN_STYLE_SHEET_PATH));
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::updateButtonState(QPushButton* btn, bool active)
|
|
|
|
{
|
|
|
|
if (active) {
|
|
|
|
btn->setProperty("state", BTN_STATE_NONE);
|
|
|
|
} else {
|
|
|
|
btn->setProperty("state", BTN_STATE_RED);
|
|
|
|
}
|
|
|
|
|
|
|
|
btn->setStyleSheet(Style::getStylesheet(BTN_STYLE_SHEET_PATH));
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::keyPressEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
int key = event->key();
|
|
|
|
if (key == Qt::Key_Escape && isFullScreen()) {
|
|
|
|
exitFullScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetCamView::closeEvent(QCloseEvent *event)
|
|
|
|
{
|
|
|
|
exitFullScreen();
|
|
|
|
event->ignore();
|
|
|
|
}
|