From d6df8883e399b95a55c5a5870497c1dcd45a3917 Mon Sep 17 00:00:00 2001 From: tox-user <32248732+tox-user@users.noreply.github.com> Date: Mon, 5 Mar 2018 07:07:10 +0000 Subject: [PATCH] feat(chat): full screen video chat Implements #2922 and #2514. This change adds: - a button for enabling full screen mode - a panel with buttons for controlling the chat in full screen mode - a button to toggle video preview - new icons fix(chat): fix buttons in full screen video call feat(chat): add hotkey for exiting full screen video fix(chat): use screen res to position button panel fix(chat): dont remove video widget on window close --- res.qrc | 7 + src/video/genericnetcamview.cpp | 190 +++++++++++++++++++++++---- src/video/genericnetcamview.h | 30 ++++- src/video/netcamview.cpp | 10 +- src/video/netcamview.h | 1 + src/widget/form/chatform.cpp | 10 ++ ui/chatForm/exitFullScreenButton.svg | 42 ++++++ ui/chatForm/fullScreenButtons.css | 78 +++++++++++ ui/chatForm/micButtonRed.svg | 67 ++++++++++ ui/chatForm/videoButtonRed.svg | 29 ++++ ui/chatForm/videoPreview.svg | 42 ++++++ ui/chatForm/videoPreviewRed.svg | 41 ++++++ ui/chatForm/volButtonRed.svg | 61 +++++++++ 13 files changed, 584 insertions(+), 24 deletions(-) create mode 100644 ui/chatForm/exitFullScreenButton.svg create mode 100644 ui/chatForm/fullScreenButtons.css create mode 100644 ui/chatForm/micButtonRed.svg create mode 100644 ui/chatForm/videoButtonRed.svg create mode 100644 ui/chatForm/videoPreview.svg create mode 100644 ui/chatForm/videoPreviewRed.svg create mode 100644 ui/chatForm/volButtonRed.svg diff --git a/res.qrc b/res.qrc index d6a18972a..da45a6b57 100644 --- a/res.qrc +++ b/res.qrc @@ -53,10 +53,16 @@ ui/chatArea/scrollBarLeftArrow.svg ui/chatArea/scrollBarRightArrow.svg ui/chatForm/buttons.css + ui/chatForm/fullScreenButtons.css ui/chatForm/callButton.svg ui/chatForm/micButton.svg + ui/chatForm/micButtonRed.svg ui/chatForm/videoButton.svg + ui/chatForm/videoButtonRed.svg ui/chatForm/volButton.svg + ui/chatForm/volButtonRed.svg + ui/chatForm/videoPreview.svg + ui/chatForm/videoPreviewRed.svg ui/chatForm/emoteButton.svg ui/chatForm/fileButton.svg ui/chatForm/screenshotButton.svg @@ -64,6 +70,7 @@ ui/chatForm/searchHideButton.svg ui/chatForm/searchUpButton.svg ui/chatForm/sendButton.svg + ui/chatForm/exitFullScreenButton.svg ui/emoticonWidget/dot_page.svg ui/emoticonWidget/dot_page_current.svg ui/emoticonWidget/dot_page_hover.svg diff --git a/src/video/genericnetcamview.cpp b/src/video/genericnetcamview.cpp index 69af582d0..7b7db2091 100644 --- a/src/video/genericnetcamview.cpp +++ b/src/video/genericnetcamview.cpp @@ -19,9 +19,21 @@ #include "genericnetcamview.h" +#include #include -#include +#include +#include #include +#include + +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(":/ui/chatForm/fullScreenButtons.css"); +} GenericNetCamView::GenericNetCamView(QWidget* parent) : QWidget(parent) @@ -29,35 +41,66 @@ GenericNetCamView::GenericNetCamView(QWidget* parent) verLayout = new QVBoxLayout(this); setWindowTitle(tr("Tox video")); - int spacing = verLayout->spacing(); - verLayout->setSpacing(0); + buttonLayout = new QHBoxLayout(); + + toggleMessagesButton = new QPushButton(); + enterFullScreenButton = new QPushButton(); + enterFullScreenButton->setText(tr("Full Screen")); - QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->addStretch(); - button = new QPushButton(); - buttonLayout->addWidget(button); - buttonLayout->setSizeConstraint(QLayout::SetMinimumSize); - connect(button, &QPushButton::clicked, this, &GenericNetCamView::showMessageClicked); + buttonLayout->addWidget(toggleMessagesButton); + buttonLayout->addWidget(enterFullScreenButton); + + connect(toggleMessagesButton, &QPushButton::clicked, this, &GenericNetCamView::showMessageClicked); + connect(enterFullScreenButton, &QPushButton::clicked, this, &GenericNetCamView::toggleFullScreen); - verLayout->addSpacing(spacing); verLayout->addLayout(buttonLayout); - verLayout->addSpacing(spacing); - - QFrame* lineFrame = new QFrame(this); - lineFrame->setStyleSheet("border: 1px solid #c1c1c1;"); - lineFrame->setFrameShape(QFrame::HLine); - lineFrame->setMaximumHeight(1); - verLayout->addWidget(lineFrame); + 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")); + + connect(videoPreviewButton, &QPushButton::clicked, this, &GenericNetCamView::toggleVideoPreview); + connect(volumeButton, &QPushButton::clicked, this, &GenericNetCamView::volMuteToggle); + connect(microphoneButton, &QPushButton::clicked, this, &GenericNetCamView::micMuteToggle); + connect(endVideoButton, &QPushButton::clicked, this, &GenericNetCamView::endVideoCall); + connect(exitFullScreenButton, &QPushButton::clicked, this, &GenericNetCamView::toggleFullScreen); + + buttonPanelLayout->addStretch(); + buttonPanelLayout->addWidget(videoPreviewButton); + buttonPanelLayout->addWidget(volumeButton); + buttonPanelLayout->addWidget(microphoneButton); + buttonPanelLayout->addWidget(endVideoButton); + buttonPanelLayout->addWidget(exitFullScreenButton); + buttonPanelLayout->addStretch(); } QSize GenericNetCamView::getSurfaceMinSize() { QSize surfaceSize = videoSurface->minimumSize(); - QSize buttonSize = button->size(); + QSize buttonSize = toggleMessagesButton->size(); QSize panelSize(0, 45); return surfaceSize + buttonSize + panelSize; @@ -66,13 +109,116 @@ QSize GenericNetCamView::getSurfaceMinSize() void GenericNetCamView::setShowMessages(bool show, bool notify) { if (!show) { - button->setText(tr("Hide Messages")); - button->setIcon(QIcon()); + toggleMessagesButton->setText(tr("Hide Messages")); + toggleMessagesButton->setIcon(QIcon()); return; } - button->setText(tr("Show Messages")); + toggleMessagesButton->setText(tr("Show Messages")); - if (notify) - button->setIcon(QIcon(":/ui/chatArea/info.svg")); + if (notify) { + toggleMessagesButton->setIcon(QIcon(":/ui/chatArea/info.svg")); + } +} + +void GenericNetCamView::toggleFullScreen() +{ + if (isFullScreen()) { + exitFullScreen(); + } else { + enterFullScreen(); + } +} + +void GenericNetCamView::enterFullScreen() +{ + setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::FramelessWindowHint); + showFullScreen(); + enterFullScreenButton->hide(); + toggleMessagesButton->hide(); + + const auto screenSize = QApplication::desktop()->screenGeometry(this); + 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 GenericNetCamView::exitFullScreen() +{ + setWindowFlags(Qt::Widget); + showNormal(); + buttonPanel->hide(); + enterFullScreenButton->show(); + toggleMessagesButton->show(); +} + +void GenericNetCamView::endVideoCall() +{ + toggleFullScreen(); + emit videoCallEnd(); +} + +void GenericNetCamView::toggleVideoPreview() +{ + toggleButtonState(videoPreviewButton); + emit videoPreviewToggle(); +} + +QPushButton *GenericNetCamView::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 GenericNetCamView::updateMuteVolButton(bool isMuted) +{ + updateButtonState(volumeButton, !isMuted); +} + +void GenericNetCamView::updateMuteMicButton(bool isMuted) +{ + updateButtonState(microphoneButton, !isMuted); +} + +void GenericNetCamView::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 GenericNetCamView::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 GenericNetCamView::keyPressEvent(QKeyEvent *event) +{ + int key = event->key(); + if (key == Qt::Key_Escape && isFullScreen()) { + exitFullScreen(); + } +} + +void GenericNetCamView::closeEvent(QCloseEvent *event) +{ + exitFullScreen(); + event->ignore(); } diff --git a/src/video/genericnetcamview.h b/src/video/genericnetcamview.h index d141037eb..272afd15e 100644 --- a/src/video/genericnetcamview.h +++ b/src/video/genericnetcamview.h @@ -20,11 +20,13 @@ #ifndef GENERICNETCAMVIEW_H #define GENERICNETCAMVIEW_H +#include #include #include #include #include "src/video/videosurface.h" +#include "src/widget/style.h" class GenericNetCamView : public QWidget { @@ -35,16 +37,42 @@ public: signals: void showMessageClicked(); + void videoCallEnd(); + void volMuteToggle(); + void micMuteToggle(); + void videoPreviewToggle(); public slots: void setShowMessages(bool show, bool notify = false); + void updateMuteVolButton(bool isMuted); + void updateMuteMicButton(bool isMuted); protected: QVBoxLayout* verLayout; VideoSurface* videoSurface; private: - QPushButton* button; + QHBoxLayout* buttonLayout = nullptr; + QPushButton* toggleMessagesButton = nullptr; + QPushButton* enterFullScreenButton = nullptr; + QFrame* buttonPanel = nullptr; + QPushButton* videoPreviewButton = nullptr; + QPushButton* volumeButton = nullptr; + QPushButton* microphoneButton = nullptr; + QPushButton* endVideoButton = nullptr; + QPushButton* exitFullScreenButton = nullptr; + +private: + QPushButton* createButton(const QString& name, const QString& state); + void toggleFullScreen(); + void enterFullScreen(); + void exitFullScreen(); + void endVideoCall(); + void toggleVideoPreview(); + void toggleButtonState(QPushButton* btn); + void updateButtonState(QPushButton* btn, bool active); + void keyPressEvent(QKeyEvent *event) override; + void closeEvent(QCloseEvent *event) override; }; #endif // GENERICNETCAMVIEW_H diff --git a/src/video/netcamview.cpp b/src/video/netcamview.cpp index ffb79fdc2..10a6f27e3 100644 --- a/src/video/netcamview.cpp +++ b/src/video/netcamview.cpp @@ -40,7 +40,6 @@ NetCamView::NetCamView(int friendId, QWidget* parent) const ToxPk pk = FriendList::findFriend(friendId)->getPublicKey(); videoSurface = new VideoSurface(Nexus::getProfile()->loadAvatar(pk), this); videoSurface->setMinimumHeight(256); - videoSurface->setContentsMargins(6, 6, 6, 6); verLayout->insertWidget(0, videoSurface, 1); @@ -145,3 +144,12 @@ void NetCamView::updateFrameSize(QSize size) else selfFrame->setMaximumHeight(selfFrame->maximumWidth() / selfVideoSurface->getRatio()); } + +void NetCamView::toggleVideoPreview() +{ + if (selfFrame->isHidden()) { + selfFrame->show(); + } else { + selfFrame->hide(); + } +} diff --git a/src/video/netcamview.h b/src/video/netcamview.h index 4e8f3449c..a76c44a67 100644 --- a/src/video/netcamview.h +++ b/src/video/netcamview.h @@ -42,6 +42,7 @@ public: void setSource(VideoSource* s); void setTitle(const QString& title); + void toggleVideoPreview(); protected: void showEvent(QShowEvent* event) final override; diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 492a8d895..f57875f16 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -626,6 +626,10 @@ GenericNetCamView* ChatForm::createNetcam() CoreAV* av = Core::getInstance()->getAv(); VideoSource* source = av->getVideoSourceFromCall(friendId); view->show(source, f->getDisplayedName()); + connect(view, &GenericNetCamView::videoCallEnd, this, &ChatForm::onVideoCallTriggered); + connect(view, &GenericNetCamView::volMuteToggle, this, &ChatForm::onVolMuteToggle); + connect(view, &GenericNetCamView::micMuteToggle, this, &ChatForm::onMicMuteToggle); + connect(view, &GenericNetCamView::videoPreviewToggle, view, &NetCamView::toggleVideoPreview); return view; } @@ -907,6 +911,9 @@ void ChatForm::updateMuteMicButton() bool active = av->isCallActive(f); bool inputMuted = av->isCallInputMuted(f); headWidget->updateMuteMicButton(active, inputMuted); + if (netcam) { + netcam->updateMuteMicButton(inputMuted); + } } void ChatForm::updateMuteVolButton() @@ -915,6 +922,9 @@ void ChatForm::updateMuteVolButton() bool active = av->isCallActive(f); bool outputMuted = av->isCallOutputMuted(f); headWidget->updateMuteVolButton(active, outputMuted); + if (netcam) { + netcam->updateMuteVolButton(outputMuted); + } } void ChatForm::startCounter() diff --git a/ui/chatForm/exitFullScreenButton.svg b/ui/chatForm/exitFullScreenButton.svg new file mode 100644 index 000000000..6e7159f0a --- /dev/null +++ b/ui/chatForm/exitFullScreenButton.svg @@ -0,0 +1,42 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/ui/chatForm/fullScreenButtons.css b/ui/chatForm/fullScreenButtons.css new file mode 100644 index 000000000..da0596378 --- /dev/null +++ b/ui/chatForm/fullScreenButtons.css @@ -0,0 +1,78 @@ +QFrame +{ + background-color: rgba(50, 50, 50, 0.6); + border-radius: 20px; +} + +QAbstractButton +{ + background-color: transparent; + background-repeat: none; + background-position: center; + border: none; + border-radius: 5px; +} + +QAbstractButton:hover +{ + background-color: rgba(255,255,255, 0.2); +} + +QAbstractButton:pressed +{ + background-color: rgba(0,0,0, 0.2); +} + +QAbstractButton#volButtonFullScreen +{ + background-image: url(":/ui/chatForm/volButton.svg"); + width: 11px; + height: 9px; + padding: 12px; +} + +QAbstractButton#micButtonFullScreen +{ + background-image: url(":/ui/chatForm/micButton.svg"); + width: 11px; + height: 9px; + padding: 12px; +} + +QAbstractButton#videoButtonFullScreen +{ + background-image: url(":/ui/chatForm/videoButtonRed.svg"); + width: 37px; + height: 33px; +} + +QAbstractButton#videoPreviewButton +{ + background-image: url(":/ui/chatForm/videoPreview.svg"); + width: 13px; + height: 13px; + padding: 10px; +} + +QAbstractButton#exitFullScreenButton +{ + background-image: url(":/ui/chatForm/exitFullScreenButton.svg"); + width: 30px; + height: 30px; + padding: 1px; +} + +QAbstractButton#volButtonFullScreen[state="red"] +{ + background-image: url(":/ui/chatForm/volButtonRed.svg"); +} + +QAbstractButton#micButtonFullScreen[state="red"] +{ + background-image: url(":/ui/chatForm/micButtonRed.svg"); +} + +QAbstractButton#videoPreviewButton[state="red"] +{ + background-image: url(":/ui/chatForm/videoPreviewRed.svg"); +} diff --git a/ui/chatForm/micButtonRed.svg b/ui/chatForm/micButtonRed.svg new file mode 100644 index 000000000..8a8979014 --- /dev/null +++ b/ui/chatForm/micButtonRed.svg @@ -0,0 +1,67 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/ui/chatForm/videoButtonRed.svg b/ui/chatForm/videoButtonRed.svg new file mode 100644 index 000000000..c292b1b33 --- /dev/null +++ b/ui/chatForm/videoButtonRed.svg @@ -0,0 +1,29 @@ + + + +image/svg+xml diff --git a/ui/chatForm/videoPreview.svg b/ui/chatForm/videoPreview.svg new file mode 100644 index 000000000..be8ffeb00 --- /dev/null +++ b/ui/chatForm/videoPreview.svg @@ -0,0 +1,42 @@ + + + +image/svg+xml diff --git a/ui/chatForm/videoPreviewRed.svg b/ui/chatForm/videoPreviewRed.svg new file mode 100644 index 000000000..ec7501430 --- /dev/null +++ b/ui/chatForm/videoPreviewRed.svg @@ -0,0 +1,41 @@ + + + +image/svg+xml diff --git a/ui/chatForm/volButtonRed.svg b/ui/chatForm/volButtonRed.svg new file mode 100644 index 000000000..5934f4539 --- /dev/null +++ b/ui/chatForm/volButtonRed.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + + + +