Show remote calls full screen with camera picture in picture
This commit is contained in:
1 parent
4a7d64b2aa
commit
434b59b1c7
2 files changed
+110
-18
No files matched your search
@@ -16,6 +16,8 @@
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QCloseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <cstring>
|
||||
@@ -142,8 +144,8 @@ static QWidget* wrapWithCaption(QWidget* btn, const QString& caption, QLabel** c
|
||||
CallWindow::CallWindow(QWidget* parent)
|
||||
: QWidget(parent, Qt::Window) {
|
||||
setWindowTitle(QCoreApplication::translate("ChatGui", "Call"));
|
||||
resize(640, 800);
|
||||
setMinimumSize(400, 600);
|
||||
resize(520, 520);
|
||||
setMinimumSize(420, 360);
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
|
||||
m_avatarLabel = new QLabel(this);
|
||||
@@ -188,7 +190,12 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
"QComboBox { border: 1px solid palette(mid); border-radius: 4px;"
|
||||
" padding: 6px 10px; font-size: 13px; background: palette(base); }");
|
||||
|
||||
QVBoxLayout* lay = new QVBoxLayout(this);
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(12, 12, 12, 12); root->addStretch(1);
|
||||
m_panel = new QWidget(this); m_panel->setObjectName("callPanel"); m_panel->setMaximumWidth(640);
|
||||
m_panel->setStyleSheet("QWidget#callPanel { background: palette(window); border-radius: 12px; }");
|
||||
root->addWidget(m_panel, 0, Qt::AlignHCenter | Qt::AlignBottom);
|
||||
QVBoxLayout* lay = new QVBoxLayout(m_panel);
|
||||
lay->setContentsMargins(16, 20, 16, 16);
|
||||
lay->setSpacing(8);
|
||||
lay->addWidget(m_avatarLabel, 0, Qt::AlignHCenter);
|
||||
@@ -199,12 +206,19 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
lay->addWidget(m_bgpPathLabel);
|
||||
lay->addWidget(m_statsLabel);
|
||||
m_video = new CallVideoEngine(this);
|
||||
m_videoImage = new QLabel(this); m_videoImage->setMinimumHeight(180); m_videoImage->setAlignment(Qt::AlignCenter);
|
||||
lay->addWidget(m_videoImage, 1);
|
||||
m_localPreview = new QLabel(this); m_localPreview->setAlignment(Qt::AlignCenter); m_localPreview->hide();
|
||||
lay->addWidget(m_localPreview, 0, Qt::AlignHCenter);
|
||||
m_videoStatus = new QLabel(this); m_videoStatus->setWordWrap(true); lay->addWidget(m_videoStatus);
|
||||
m_videoControls = new QWidget(this); auto* videoLayout = new QVBoxLayout(m_videoControls);
|
||||
videoLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_videoEnabled = new QCheckBox(tr("Send video"), this); videoLayout->addWidget(m_videoEnabled);
|
||||
auto* actions = new QHBoxLayout();
|
||||
m_videoEnabled = new QCheckBox(tr("Send video"), this); actions->addWidget(m_videoEnabled);
|
||||
actions->addStretch(1);
|
||||
m_settingsBtn = new QPushButton(tr("Call settings"), this); m_settingsBtn->setCheckable(true); actions->addWidget(m_settingsBtn);
|
||||
m_fullScreenBtn = new QPushButton(tr("Full screen"), this); actions->addWidget(m_fullScreenBtn);
|
||||
lay->addLayout(actions);
|
||||
connect(m_settingsBtn, &QPushButton::toggled, this, [this] { updateVideoPresentation(); });
|
||||
connect(m_fullScreenBtn, &QPushButton::clicked, this, &CallWindow::toggleFullScreen);
|
||||
auto* modes = new QHBoxLayout();
|
||||
m_camera = new QComboBox(this);
|
||||
for (const auto& camera : CallVideoEngine::cameras()) m_camera->addItem(camera.first, camera.second);
|
||||
@@ -224,9 +238,22 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
};
|
||||
connect(m_videoMin, &QSpinBox::editingFinished, this, updateRange);
|
||||
connect(m_videoMax, &QSpinBox::editingFinished, this, updateRange);
|
||||
connect(m_video, &CallVideoEngine::statusChanged, m_videoStatus, &QLabel::setText);
|
||||
connect(m_video, &CallVideoEngine::statusChanged, this, [this](const QString& text) {
|
||||
m_videoStatus->setText(text); m_videoStatus->setVisible(m_state == Active && !text.isEmpty());
|
||||
});
|
||||
connect(m_video, &CallVideoEngine::imageChanged, this, [this](const QImage& image) {
|
||||
m_videoImage->setPixmap(image.isNull() ? QPixmap() : QPixmap::fromImage(image).scaled(m_videoImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
bool changed = m_remoteImage.isNull() != image.isNull(); m_remoteImage = image;
|
||||
if (changed) updateVideoPresentation();
|
||||
update();
|
||||
});
|
||||
connect(m_video, &CallVideoEngine::localImageChanged, this, [this](const QImage& image) {
|
||||
bool changed = m_localImage.isNull() != image.isNull(); m_localImage = image;
|
||||
if (!image.isNull()) {
|
||||
QSize size = image.size().scaled(200, 150, Qt::KeepAspectRatio); m_localPreview->setFixedSize(size);
|
||||
m_localPreview->setPixmap(QPixmap::fromImage(image).scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
} else m_localPreview->clear();
|
||||
if (changed) updateVideoPresentation();
|
||||
update();
|
||||
});
|
||||
auto* videoTimer = new QTimer(this); videoTimer->setInterval(100);
|
||||
connect(videoTimer, &QTimer::timeout, this, [this] {
|
||||
@@ -237,7 +264,6 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
m_videoMin->setValue(status.minimum_bps / 1000); m_videoMax->setValue(status.maximum_bps / 1000); m_videoRangeReady = true;
|
||||
}
|
||||
}); videoTimer->start();
|
||||
lay->addStretch(1);
|
||||
|
||||
m_acceptCell = wrapWithCaption(m_acceptBtn, QCoreApplication::translate("ChatGui", "Accept"));
|
||||
m_declineCell = wrapWithCaption(m_declineBtn, QCoreApplication::translate("ChatGui", "Decline"));
|
||||
@@ -253,8 +279,7 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
btn->addWidget(m_muteCell);
|
||||
btn->addStretch(1);
|
||||
lay->addLayout(btn);
|
||||
lay->addStretch(1);
|
||||
lay->addWidget(m_deviceCombo);
|
||||
videoLayout->addWidget(m_deviceCombo);
|
||||
|
||||
connect(m_acceptBtn, &QPushButton::clicked, this, &CallWindow::onAccept);
|
||||
connect(m_declineBtn, &QPushButton::clicked, this, &CallWindow::onDecline);
|
||||
@@ -278,7 +303,7 @@ void CallWindow::setPeerName(const QString& name) {
|
||||
|
||||
void CallWindow::setBgpPath(const QString& path) {
|
||||
m_bgpPathLabel->setText(path);
|
||||
m_bgpPathLabel->setVisible(!path.isEmpty());
|
||||
m_bgpPathLabel->setVisible(!path.isEmpty() && m_settingsBtn->isChecked());
|
||||
}
|
||||
|
||||
void CallWindow::setConnectionType(uint8_t type, quint64 nextHop) {
|
||||
@@ -344,10 +369,66 @@ void CallWindow::updateButtons() {
|
||||
m_declineCell->setVisible(m_state == Incoming);
|
||||
m_hangupCell->setVisible(m_state == Outgoing || m_state == Ringing || m_state == Active);
|
||||
m_muteCell->setVisible(m_state == Active);
|
||||
m_deviceCombo->setVisible(m_state == Active);
|
||||
m_videoControls->setVisible(m_state == Active);
|
||||
m_videoImage->setVisible(m_state == Active);
|
||||
m_videoStatus->setVisible(m_state == Active);
|
||||
updateVideoPresentation();
|
||||
}
|
||||
|
||||
void CallWindow::leaveFullScreen() {
|
||||
if (!isFullScreen()) return;
|
||||
showNormal();
|
||||
if (!m_windowGeometry.isEmpty()) restoreGeometry(m_windowGeometry);
|
||||
}
|
||||
|
||||
void CallWindow::toggleFullScreen() {
|
||||
if (m_remoteImage.isNull()) return;
|
||||
if (isFullScreen()) leaveFullScreen();
|
||||
else { m_windowGeometry = saveGeometry(); showFullScreen(); }
|
||||
m_fullScreenBtn->setText(isFullScreen() ? tr("Exit full screen") : tr("Full screen"));
|
||||
}
|
||||
|
||||
void CallWindow::updateVideoPresentation() {
|
||||
bool receiving = m_state == Active && !m_remoteImage.isNull();
|
||||
if (receiving != m_receivingVideo) {
|
||||
m_receivingVideo = receiving;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call video presentation remote=%d local=%d", receiving, !m_localImage.isNull());
|
||||
if (receiving) {
|
||||
m_settingsBtn->setChecked(false); m_windowGeometry = saveGeometry(); showFullScreen();
|
||||
} else leaveFullScreen();
|
||||
}
|
||||
bool active = m_state == Active, settings = active && m_settingsBtn->isChecked();
|
||||
m_localPreview->setVisible(active && !receiving && !m_localImage.isNull());
|
||||
m_avatarLabel->setVisible(!receiving); m_statusLabel->setVisible(!receiving);
|
||||
m_connectionLabel->setVisible(settings); m_bgpPathLabel->setVisible(settings && !m_bgpPathLabel->text().isEmpty());
|
||||
m_statsLabel->setVisible(settings && !m_statsLabel->text().isEmpty());
|
||||
m_videoEnabled->setVisible(active); m_settingsBtn->setVisible(active);
|
||||
m_videoControls->setVisible(settings); m_fullScreenBtn->setVisible(receiving);
|
||||
m_fullScreenBtn->setText(isFullScreen() ? tr("Exit full screen") : tr("Full screen"));
|
||||
m_videoStatus->setVisible(active && !m_videoStatus->text().isEmpty());
|
||||
update();
|
||||
}
|
||||
|
||||
void CallWindow::paintEvent(QPaintEvent* event) {
|
||||
QWidget::paintEvent(event);
|
||||
if (!m_receivingVideo) return;
|
||||
QPainter painter(this); painter.fillRect(rect(), Qt::black); painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
QSize remote = m_remoteImage.size().scaled(size(), Qt::KeepAspectRatio);
|
||||
painter.drawImage(QRect(QPoint((width() - remote.width()) / 2, (height() - remote.height()) / 2), remote), m_remoteImage);
|
||||
if (!m_localImage.isNull()) {
|
||||
QSize preview = m_localImage.size().scaled(qMin(240, width() / 4), qMin(180, height() / 4), Qt::KeepAspectRatio);
|
||||
QRect target(QPoint(width() - preview.width() - 20, 20), preview);
|
||||
painter.setPen(QPen(Qt::white, 2)); painter.drawRect(target.adjusted(-1, -1, 1, 1));
|
||||
painter.drawImage(target, m_localImage);
|
||||
}
|
||||
}
|
||||
|
||||
void CallWindow::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Escape && isFullScreen()) { toggleFullScreen(); event->accept(); return; }
|
||||
if (event->key() == Qt::Key_F11 && m_receivingVideo) { toggleFullScreen(); event->accept(); return; }
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void CallWindow::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::LeftButton && m_receivingVideo) { toggleFullScreen(); event->accept(); return; }
|
||||
QWidget::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void CallWindow::applyVideo() {
|
||||
|
||||
Reference in new issue
Block a user