mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge remote-tracking branch 'origin/new_video_view'
This commit is contained in:
commit
7117083e86
19
qtox.pro
19
qtox.pro
|
@ -358,14 +358,13 @@ contains(ENABLE_SYSTRAY_GTK_BACKEND, NO) {
|
|||
src/widget/form/loadhistorydialog.h \
|
||||
src/widget/form/setpassworddialog.h \
|
||||
src/widget/form/tabcompleter.h \
|
||||
src/widget/flowlayout.h \
|
||||
src/ipc.h \
|
||||
src/net/autoupdate.h \
|
||||
src/widget/tool/callconfirmwidget.h \
|
||||
src/widget/systemtrayicon.h \
|
||||
src/widget/qrwidget.h \
|
||||
src/widget/systemtrayicon_private.h \
|
||||
src/widget/loginscreen.h
|
||||
src/widget/loginscreen.h \
|
||||
src/ipc.h
|
||||
|
||||
SOURCES += \
|
||||
src/widget/form/addfriendform.cpp \
|
||||
|
@ -385,7 +384,6 @@ contains(ENABLE_SYSTRAY_GTK_BACKEND, NO) {
|
|||
src/widget/form/setpassworddialog.cpp \
|
||||
src/widget/form/tabcompleter.cpp \
|
||||
src/widget/flowlayout.cpp \
|
||||
src/ipc.cpp \
|
||||
src/net/autoupdate.cpp \
|
||||
src/widget/tool/callconfirmwidget.cpp \
|
||||
src/widget/systemtrayicon.cpp \
|
||||
|
@ -427,7 +425,8 @@ contains(ENABLE_SYSTRAY_GTK_BACKEND, NO) {
|
|||
src/persistence/offlinemsgengine.cpp \
|
||||
src/widget/qrwidget.cpp \
|
||||
src/widget/genericchatroomwidget.cpp \
|
||||
src/widget/loginscreen.cpp
|
||||
src/widget/loginscreen.cpp \
|
||||
src/ipc.cpp
|
||||
}
|
||||
|
||||
win32 {
|
||||
|
@ -498,7 +497,10 @@ SOURCES += \
|
|||
src/widget/tool/removefrienddialog.cpp \
|
||||
src/widget/contentlayout.cpp \
|
||||
src/widget/contentdialog.cpp \
|
||||
src/widget/tool/activatedialog.cpp
|
||||
src/widget/tool/activatedialog.cpp \
|
||||
src/widget/tool/movablewidget.cpp \
|
||||
src/video/genericnetcamview.cpp \
|
||||
src/video/groupnetcamview.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/audio/audio.h \
|
||||
|
@ -545,4 +547,7 @@ HEADERS += \
|
|||
src/widget/contentlayout.h \
|
||||
src/widget/contentdialog.h \
|
||||
src/widget/tool/activatedialog.h \
|
||||
src/widget/tool/removefrienddialog.h
|
||||
src/widget/tool/removefrienddialog.h \
|
||||
src/widget/tool/movablewidget.h \
|
||||
src/video/genericnetcamview.h \
|
||||
src/video/groupnetcamview.h
|
||||
|
|
|
@ -295,6 +295,13 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data,
|
|||
alSourcef(call.alSources[peer], AL_GAIN, outputVolume);
|
||||
}
|
||||
|
||||
qreal volume = 0.;
|
||||
int bufsize = samples * 2 * channels;
|
||||
for (int i = 0; i < bufsize; ++i)
|
||||
volume += abs(data[i]);//std::max(volume, data[i]);
|
||||
|
||||
emit groupAudioPlayed(group, peer, volume / bufsize);
|
||||
|
||||
playAudioBuffer(call.alSources[peer], data, samples, channels, sample_rate);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class QMutex;
|
|||
struct Tox;
|
||||
class AudioFilterer;
|
||||
|
||||
class Audio : QObject
|
||||
class Audio : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -81,6 +81,9 @@ public slots:
|
|||
void playGroupAudio(int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate);
|
||||
|
||||
signals:
|
||||
void groupAudioPlayed(int group, int peer, unsigned short volume);
|
||||
|
||||
private:
|
||||
explicit Audio()=default;
|
||||
~Audio();
|
||||
|
|
|
@ -78,6 +78,7 @@ void Core::prepareCall(uint32_t friendId, int32_t callId, ToxAv* toxav, bool vid
|
|||
calls[callId].sendAudioTimer->setSingleShot(true);
|
||||
connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
|
||||
calls[callId].sendAudioTimer->start();
|
||||
|
||||
if (calls[callId].videoEnabled)
|
||||
{
|
||||
calls[callId].videoSource = new CoreVideoSource;
|
||||
|
@ -237,6 +238,7 @@ void Core::cleanupCall(int32_t callId)
|
|||
calls[callId].active = false;
|
||||
disconnect(calls[callId].sendAudioTimer,0,0,0);
|
||||
calls[callId].sendAudioTimer->stop();
|
||||
|
||||
if (calls[callId].videoEnabled)
|
||||
{
|
||||
CameraSource::getInstance().unsubscribe();
|
||||
|
|
|
@ -46,45 +46,21 @@ Group::~Group()
|
|||
widget->deleteLater();
|
||||
}
|
||||
|
||||
/*
|
||||
void Group::addPeer(int peerId, QString name)
|
||||
{
|
||||
if (peers.contains(peerId))
|
||||
qWarning() << "addPeer: peerId already used, overwriting anyway";
|
||||
if (name.isEmpty())
|
||||
peers[peerId] = "<Unknown>";
|
||||
else
|
||||
peers[peerId] = name;
|
||||
nPeers++;
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
}
|
||||
|
||||
void Group::removePeer(int peerId)
|
||||
{
|
||||
peers.remove(peerId);
|
||||
nPeers--;
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
}
|
||||
*/
|
||||
|
||||
void Group::updatePeer(int peerId, QString name)
|
||||
{
|
||||
ToxId id = Core::getInstance()->getGroupPeerToxId(groupId, peerId);
|
||||
QString toxid = id.publicKey;
|
||||
peers[peerId] = name;
|
||||
toxids[toxid] = name;
|
||||
Friend *f = FriendList::findFriend(id);
|
||||
if (f && f->hasAlias())
|
||||
{
|
||||
peers[peerId] = f->getDisplayedName();
|
||||
toxids[toxid] = f->getDisplayedName();
|
||||
}
|
||||
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
emit userListChanged(getGroupWidget());
|
||||
Friend *f = FriendList::findFriend(id);
|
||||
|
||||
if (f != nullptr && f->hasAlias())
|
||||
{
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
emit userListChanged(getGroupWidget());
|
||||
}
|
||||
}
|
||||
|
||||
void Group::setName(const QString& name)
|
||||
|
|
|
@ -54,11 +54,6 @@ public:
|
|||
void setMentionedFlag(int f);
|
||||
int getMentionedFlag() const;
|
||||
|
||||
/*
|
||||
void addPeer(int peerId, QString name);
|
||||
void removePeer(int peerId);
|
||||
*/
|
||||
|
||||
void updatePeer(int peerId, QString newName);
|
||||
void setName(const QString& name);
|
||||
QString getName() const;
|
||||
|
|
|
@ -262,8 +262,8 @@ int main(int argc, char *argv[])
|
|||
logFile = nullptr;
|
||||
#endif
|
||||
|
||||
CameraSource::destroyInstance();
|
||||
Nexus::destroyInstance();
|
||||
CameraSource::destroyInstance();
|
||||
Settings::destroyInstance();
|
||||
qDebug() << "Clean exit with status"<<errorcode;
|
||||
return errorcode;
|
||||
|
|
|
@ -1087,8 +1087,8 @@ QSplitter:handle{
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>284</width>
|
||||
<height>398</height>
|
||||
<width>775</width>
|
||||
<height>284</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5"/>
|
||||
|
|
|
@ -232,6 +232,7 @@ void Settings::loadGlobal()
|
|||
s.beginGroup("Video");
|
||||
videoDev = s.value("videoDev", "").toString();
|
||||
camVideoRes = s.value("camVideoRes",QSize()).toSize();
|
||||
camVideoFPS = s.value("camVideoFPS", 0).toUInt();
|
||||
s.endGroup();
|
||||
|
||||
// Read the embedded DHT bootsrap nodes list if needed
|
||||
|
@ -431,6 +432,7 @@ void Settings::saveGlobal()
|
|||
s.beginGroup("Video");
|
||||
s.setValue("videoDev", videoDev);
|
||||
s.setValue("camVideoRes",camVideoRes);
|
||||
s.setValue("camVideoFPS",camVideoFPS);
|
||||
s.endGroup();
|
||||
}
|
||||
|
||||
|
@ -1220,6 +1222,18 @@ void Settings::setCamVideoRes(QSize newValue)
|
|||
camVideoRes = newValue;
|
||||
}
|
||||
|
||||
unsigned short Settings::getCamVideoFPS() const
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
return camVideoFPS;
|
||||
}
|
||||
|
||||
void Settings::setCamVideoFPS(unsigned short newValue)
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
camVideoFPS = newValue;
|
||||
}
|
||||
|
||||
QString Settings::getFriendAdress(const QString &publicKey) const
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
|
|
@ -163,6 +163,9 @@ public:
|
|||
QSize getCamVideoRes() const;
|
||||
void setCamVideoRes(QSize newValue);
|
||||
|
||||
unsigned short getCamVideoFPS() const;
|
||||
void setCamVideoFPS(unsigned short newValue);
|
||||
|
||||
bool isAnimationEnabled() const;
|
||||
void setAnimationEnabled(bool newValue);
|
||||
|
||||
|
@ -376,6 +379,7 @@ private:
|
|||
// Video
|
||||
QString videoDev;
|
||||
QSize camVideoRes;
|
||||
unsigned short camVideoFPS;
|
||||
|
||||
struct friendProp
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ CameraSource::CameraSource()
|
|||
biglock{false}, freelistLock{false},
|
||||
isOpen{false}, subscriptions{0}
|
||||
{
|
||||
subscriptions = 0;
|
||||
av_register_all();
|
||||
avdevice_register_all();
|
||||
}
|
||||
|
@ -119,7 +120,7 @@ CameraSource::~CameraSource()
|
|||
|
||||
// Free all remaining VideoFrame
|
||||
// Locking must be done precisely this way to avoid races
|
||||
for (int i=0; i<freelist.size(); i++)
|
||||
for (int i = 0; i < freelist.size(); i++)
|
||||
{
|
||||
std::shared_ptr<VideoFrame> vframe = freelist[i].lock();
|
||||
if (!vframe)
|
||||
|
@ -132,8 +133,9 @@ CameraSource::~CameraSource()
|
|||
if (cctxOrig)
|
||||
avcodec_close(cctxOrig);
|
||||
|
||||
for (int i=subscriptions; i; --i)
|
||||
for(int i = 0; i < subscriptions; i++)
|
||||
device->close();
|
||||
|
||||
device = nullptr;
|
||||
// Memfence so the stream thread sees a nullptr device
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
@ -177,6 +179,7 @@ bool CameraSource::subscribe()
|
|||
biglock = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CameraSource::unsubscribe()
|
||||
|
@ -190,7 +193,7 @@ void CameraSource::unsubscribe()
|
|||
|
||||
if (!isOpen)
|
||||
{
|
||||
--subscriptions;
|
||||
subscriptions--;
|
||||
biglock = false;
|
||||
return;
|
||||
}
|
||||
|
@ -202,10 +205,9 @@ void CameraSource::unsubscribe()
|
|||
return;
|
||||
}
|
||||
|
||||
if (--subscriptions == 0)
|
||||
if (subscriptions - 1 == 0)
|
||||
{
|
||||
closeDevice();
|
||||
|
||||
biglock = false;
|
||||
|
||||
// Synchronize with our stream thread
|
||||
|
@ -217,12 +219,12 @@ void CameraSource::unsubscribe()
|
|||
device->close();
|
||||
biglock = false;
|
||||
}
|
||||
subscriptions--;
|
||||
|
||||
}
|
||||
|
||||
bool CameraSource::openDevice()
|
||||
{
|
||||
qDebug() << "Opening device "<<deviceName;
|
||||
|
||||
if (device)
|
||||
{
|
||||
device->open();
|
||||
|
@ -243,15 +245,15 @@ bool CameraSource::openDevice()
|
|||
|
||||
// We need to open the device as many time as we already have subscribers,
|
||||
// otherwise the device could get closed while we still have subscribers
|
||||
for (int i=subscriptions; i>0; i--)
|
||||
for (int i = 0; i < subscriptions; i++)
|
||||
device->open();
|
||||
|
||||
// Find the first video stream
|
||||
for (unsigned i=0; i<device->context->nb_streams; i++)
|
||||
for (unsigned i = 0; i < device->context->nb_streams; i++)
|
||||
{
|
||||
if(device->context->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
|
||||
if(device->context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
videoStreamIndex=i;
|
||||
videoStreamIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -259,8 +261,8 @@ bool CameraSource::openDevice()
|
|||
return false;
|
||||
|
||||
// Get a pointer to the codec context for the video stream
|
||||
cctxOrig=device->context->streams[videoStreamIndex]->codec;
|
||||
codec=avcodec_find_decoder(cctxOrig->codec_id);
|
||||
cctxOrig = device->context->streams[videoStreamIndex]->codec;
|
||||
codec = avcodec_find_decoder(cctxOrig->codec_id);
|
||||
if(!codec)
|
||||
return false;
|
||||
|
||||
|
@ -268,6 +270,7 @@ bool CameraSource::openDevice()
|
|||
cctx = avcodec_alloc_context3(codec);
|
||||
if(avcodec_copy_context(cctx, cctxOrig) != 0)
|
||||
return false;
|
||||
|
||||
cctx->refcounted_frames = 1;
|
||||
|
||||
// Open codec
|
||||
|
@ -286,16 +289,16 @@ bool CameraSource::openDevice()
|
|||
while (!streamFuture.isRunning())
|
||||
QThread::yieldCurrentThread();
|
||||
|
||||
emit deviceOpened();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CameraSource::closeDevice()
|
||||
{
|
||||
qDebug() << "Closing device "<<deviceName;
|
||||
|
||||
// Free all remaining VideoFrame
|
||||
// Locking must be done precisely this way to avoid races
|
||||
for (int i=0; i<freelist.size(); i++)
|
||||
for (int i = 0; i < freelist.size(); i++)
|
||||
{
|
||||
std::shared_ptr<VideoFrame> vframe = freelist[i].lock();
|
||||
if (!vframe)
|
||||
|
@ -396,9 +399,10 @@ void CameraSource::freelistCallback(int freelistIndex)
|
|||
int CameraSource::getFreelistSlotLockless()
|
||||
{
|
||||
int size = freelist.size();
|
||||
for (int i=0; i<size; ++i)
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (freelist[i].expired())
|
||||
return i;
|
||||
freelist.resize(size+(size>>1)+4); // Arbitrary growth strategy, should work well
|
||||
|
||||
freelist.resize(size + (size>>1) + 4); // Arbitrary growth strategy, should work well
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ struct AVCodecContext;
|
|||
class CameraSource : public VideoSource
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static CameraSource& getInstance();
|
||||
static void destroyInstance();
|
||||
|
@ -59,6 +60,9 @@ public:
|
|||
virtual bool subscribe() override;
|
||||
virtual void unsubscribe() override;
|
||||
|
||||
signals:
|
||||
void deviceOpened();
|
||||
|
||||
private:
|
||||
CameraSource();
|
||||
~CameraSource();
|
||||
|
|
69
src/video/genericnetcamview.cpp
Normal file
69
src/video/genericnetcamview.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 "genericnetcamview.h"
|
||||
#include <QBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QFrame>
|
||||
|
||||
GenericNetCamView::GenericNetCamView(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
verLayout = new QVBoxLayout(this);
|
||||
setWindowTitle(tr("Tox video"));
|
||||
|
||||
int spacing = verLayout->spacing();
|
||||
verLayout->setSpacing(0);
|
||||
|
||||
QHBoxLayout* buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->addStretch();
|
||||
button = new QPushButton();
|
||||
buttonLayout->addWidget(button);
|
||||
connect(button, &QPushButton::clicked, this, &GenericNetCamView::showMessageClicked);
|
||||
|
||||
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);
|
||||
|
||||
setShowMessages(false);
|
||||
|
||||
setStyleSheet("NetCamView { background-color: #c1c1c1; }");
|
||||
}
|
||||
|
||||
void GenericNetCamView::setShowMessages(bool show, bool notify)
|
||||
{
|
||||
if (show)
|
||||
{
|
||||
button->setText(tr("Show Messages"));
|
||||
|
||||
if (notify)
|
||||
button->setIcon(QIcon(":/ui/chatArea/info.svg"));
|
||||
}
|
||||
else
|
||||
{
|
||||
button->setText(tr("Hide Messages"));
|
||||
button->setIcon(QIcon());
|
||||
}
|
||||
}
|
49
src/video/genericnetcamview.h
Normal file
49
src/video/genericnetcamview.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 GENERICNETCAMVIEW_H
|
||||
#define GENERICNETCAMVIEW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class VideoSurface;
|
||||
class QPushButton;
|
||||
class QVBoxLayout;
|
||||
|
||||
class GenericNetCamView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GenericNetCamView(QWidget* parent);
|
||||
|
||||
signals:
|
||||
void showMessageClicked();
|
||||
|
||||
public slots:
|
||||
void setShowMessages(bool show, bool notify = false);
|
||||
|
||||
protected:
|
||||
QVBoxLayout* verLayout;
|
||||
VideoSurface* videoSurface;
|
||||
|
||||
private:
|
||||
QPushButton* button;
|
||||
};
|
||||
|
||||
#endif // GENERICNETCAMVIEW_H
|
281
src/video/groupnetcamview.cpp
Normal file
281
src/video/groupnetcamview.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 "groupnetcamview.h"
|
||||
#include "src/widget/tool/croppinglabel.h"
|
||||
#include "src/video/videosurface.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/audio/audio.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/friend.h"
|
||||
#include <QBoxLayout>
|
||||
#include <QScrollArea>
|
||||
#include <QSplitter>
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
|
||||
#include <QDebug>
|
||||
class LabeledVideo : public QFrame
|
||||
{
|
||||
public:
|
||||
LabeledVideo(const QPixmap& avatar, QWidget* parent = 0, bool expanding = true)
|
||||
: QFrame(parent)
|
||||
{
|
||||
qDebug() << "Created expanding? " << expanding;
|
||||
videoSurface = new VideoSurface(avatar, 0, expanding);
|
||||
videoSurface->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
videoSurface->setMinimumHeight(32);
|
||||
|
||||
connect(videoSurface, &VideoSurface::ratioChanged, this, &LabeledVideo::updateSize);
|
||||
label = new CroppingLabel(this);
|
||||
label->setTextFormat(Qt::PlainText);
|
||||
label->setStyleSheet("color: white");
|
||||
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(videoSurface, 1);
|
||||
layout->addWidget(label);
|
||||
}
|
||||
|
||||
~LabeledVideo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VideoSurface* getVideoSurface() const
|
||||
{
|
||||
return videoSurface;
|
||||
}
|
||||
|
||||
void setText(const QString& text)
|
||||
{
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
QString getText() const
|
||||
{
|
||||
return label->text();
|
||||
}
|
||||
|
||||
void setActive(bool active = true)
|
||||
{
|
||||
if (active)
|
||||
setStyleSheet("QFrame { background-color: #414141; border-radius: 10px; }");
|
||||
else
|
||||
setStyleSheet(QString());
|
||||
}
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) final override
|
||||
{
|
||||
qDebug() << "Resize!";
|
||||
updateSize();
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void updateSize()
|
||||
{
|
||||
qDebug() << videoSurface->isExpanding();
|
||||
if (videoSurface->isExpanding())
|
||||
{
|
||||
int width = videoSurface->height() * videoSurface->getRatio();
|
||||
videoSurface->setMinimumWidth(width);
|
||||
videoSurface->setMaximumWidth(width);
|
||||
qDebug() << videoSurface->minimumWidth();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CroppingLabel* label;
|
||||
VideoSurface* videoSurface;
|
||||
bool selected = false;
|
||||
};
|
||||
|
||||
GroupNetCamView::GroupNetCamView(int group, QWidget *parent)
|
||||
: GenericNetCamView(parent)
|
||||
, group(group)
|
||||
{
|
||||
videoLabelSurface = new LabeledVideo(QPixmap(), this, false);
|
||||
videoSurface = videoLabelSurface->getVideoSurface();
|
||||
videoSurface->setMinimumHeight(256);
|
||||
videoSurface->setContentsMargins(6, 6, 6, 0);
|
||||
videoLabelSurface->setContentsMargins(0, 0, 0, 0);
|
||||
videoLabelSurface->layout()->setMargin(0);
|
||||
videoLabelSurface->setStyleSheet("QFrame { background-color: black; }");
|
||||
|
||||
QSplitter* splitter = new QSplitter(Qt::Vertical, this);
|
||||
splitter->setChildrenCollapsible(false);
|
||||
verLayout->insertWidget(0, splitter, 1);
|
||||
splitter->addWidget(videoLabelSurface);
|
||||
splitter->setStyleSheet("QSplitter { background-color: black; } QSplitter::handle { background-color: black; }");
|
||||
|
||||
QScrollArea* scrollArea = new QScrollArea();
|
||||
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scrollArea->setFrameStyle(QFrame::NoFrame);
|
||||
QWidget* widget = new QWidget(nullptr);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
horLayout = new QHBoxLayout(widget);
|
||||
horLayout->addStretch(1);
|
||||
|
||||
selfVideoSurface = new LabeledVideo(Settings::getInstance().getSavedAvatar(Core::getInstance()->getSelfId().toString()), this);
|
||||
horLayout->addWidget(selfVideoSurface);
|
||||
|
||||
horLayout->addStretch(1);
|
||||
splitter->addWidget(scrollArea);
|
||||
scrollArea->setWidget(widget);
|
||||
|
||||
connect(&Audio::getInstance(), &Audio::groupAudioPlayed, this, &GroupNetCamView::groupAudioPlayed);
|
||||
|
||||
QTimer* timer = new QTimer(this);
|
||||
timer->setInterval(1000);
|
||||
connect(timer, &QTimer::timeout, this, &GroupNetCamView::findActivePeer);
|
||||
timer->start();
|
||||
|
||||
connect(Core::getInstance(), &Core::selfAvatarChanged, [this](const QPixmap& pixmap)
|
||||
{
|
||||
selfVideoSurface->getVideoSurface()->setAvatar(pixmap);
|
||||
findActivePeer();
|
||||
});
|
||||
connect(Core::getInstance(), &Core::usernameSet, [this](const QString& username)
|
||||
{
|
||||
selfVideoSurface->setText(username);
|
||||
findActivePeer();
|
||||
});
|
||||
connect(Core::getInstance(), &Core::friendAvatarChanged, this, &GroupNetCamView::friendAvatarChanged);
|
||||
|
||||
selfVideoSurface->setText(Core::getInstance()->getUsername());
|
||||
}
|
||||
|
||||
void GroupNetCamView::clearPeers()
|
||||
{
|
||||
QList<int> keys = videoList.keys();
|
||||
|
||||
for (int &i : keys)
|
||||
removePeer(i);
|
||||
}
|
||||
|
||||
void GroupNetCamView::addPeer(int peer, const QString& name)
|
||||
{
|
||||
QPixmap groupAvatar = Settings::getInstance().getSavedAvatar(Core::getInstance()->getGroupPeerToxId(group, peer).toString());
|
||||
LabeledVideo* labeledVideo = new LabeledVideo(groupAvatar, this);
|
||||
labeledVideo->setText(name);
|
||||
horLayout->insertWidget(horLayout->count() - 1, labeledVideo);
|
||||
PeerVideo peerVideo;
|
||||
peerVideo.video = labeledVideo;
|
||||
videoList.insert(peer, peerVideo);
|
||||
|
||||
findActivePeer();
|
||||
}
|
||||
|
||||
void GroupNetCamView::removePeer(int peer)
|
||||
{
|
||||
auto peerVideo = videoList.find(peer);
|
||||
|
||||
if (peerVideo != videoList.end())
|
||||
{
|
||||
LabeledVideo* labeledVideo = peerVideo.value().video;
|
||||
horLayout->removeWidget(labeledVideo);
|
||||
labeledVideo->deleteLater();
|
||||
videoList.remove(peer);
|
||||
|
||||
findActivePeer();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupNetCamView::setActive(int peer)
|
||||
{
|
||||
if (peer == -1)
|
||||
{
|
||||
videoLabelSurface->setText(selfVideoSurface->getText());
|
||||
activePeer = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
auto peerVideo = videoList.find(peer);
|
||||
|
||||
if (peerVideo != videoList.end())
|
||||
{
|
||||
// When group video exists:
|
||||
// videoSurface->setSource(peerVideo.value()->getVideoSurface()->source);
|
||||
|
||||
auto lastVideo = videoList.find(activePeer);
|
||||
|
||||
if (lastVideo != videoList.end())
|
||||
lastVideo.value().video->setActive(false);
|
||||
|
||||
LabeledVideo *labeledVideo = peerVideo.value().video;
|
||||
videoLabelSurface->setText(labeledVideo->getText());
|
||||
videoLabelSurface->getVideoSurface()->setAvatar(labeledVideo->getVideoSurface()->getAvatar());
|
||||
labeledVideo->setActive();
|
||||
|
||||
activePeer = peer;
|
||||
}
|
||||
}
|
||||
|
||||
void GroupNetCamView::groupAudioPlayed(int Group, int peer, unsigned short volume)
|
||||
{
|
||||
if (group != Group)
|
||||
return;
|
||||
|
||||
auto peerVideo = videoList.find(peer);
|
||||
|
||||
if (peerVideo != videoList.end())
|
||||
peerVideo.value().volume = volume;
|
||||
}
|
||||
|
||||
void GroupNetCamView::findActivePeer()
|
||||
{
|
||||
int candidate = -1;
|
||||
int maximum = 0;
|
||||
|
||||
for (auto peer = videoList.begin(); peer != videoList.end(); ++peer)
|
||||
{
|
||||
if (peer.value().volume > maximum)
|
||||
{
|
||||
maximum = peer.value().volume;
|
||||
candidate = peer.key();
|
||||
}
|
||||
}
|
||||
|
||||
setActive(candidate);
|
||||
}
|
||||
|
||||
void GroupNetCamView::friendAvatarChanged(int FriendId, const QPixmap &pixmap)
|
||||
{
|
||||
Friend* f = FriendList::findFriend(FriendId);
|
||||
|
||||
for (int i = 0; i < Core::getInstance()->getGroupNumberPeers(group); ++i)
|
||||
{
|
||||
if (Core::getInstance()->getGroupPeerToxId(group, i) == f->getToxId())
|
||||
{
|
||||
auto peerVideo = videoList.find(i);
|
||||
|
||||
if (peerVideo != videoList.end())
|
||||
{
|
||||
peerVideo.value().video->getVideoSurface()->setAvatar(pixmap);
|
||||
findActivePeer();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
61
src/video/groupnetcamview.h
Normal file
61
src/video/groupnetcamview.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 GROUPNETCAMVIEW_H
|
||||
#define GROUPNETCAMVIEW_H
|
||||
|
||||
#include "genericnetcamview.h"
|
||||
#include <QMap>
|
||||
|
||||
class LabeledVideo;
|
||||
class QHBoxLayout;
|
||||
|
||||
class GroupNetCamView : public GenericNetCamView
|
||||
{
|
||||
public:
|
||||
GroupNetCamView(int group, QWidget* parent = 0);
|
||||
void clearPeers();
|
||||
void addPeer(int peer, const QString &name);
|
||||
void removePeer(int peer);
|
||||
|
||||
public slots:
|
||||
void groupAudioPlayed(int group, int peer, unsigned short volume);
|
||||
|
||||
private slots:
|
||||
void findActivePeer();
|
||||
void friendAvatarChanged(int FriendId, const QPixmap& pixmap);
|
||||
|
||||
private:
|
||||
struct PeerVideo
|
||||
{
|
||||
LabeledVideo* video;
|
||||
unsigned short volume = 0;
|
||||
};
|
||||
|
||||
void setActive(int peer);
|
||||
|
||||
QHBoxLayout* horLayout;
|
||||
QMap<int, PeerVideo> videoList;
|
||||
LabeledVideo* videoLabelSurface;
|
||||
LabeledVideo* selfVideoSurface;
|
||||
int activePeer;
|
||||
int group;
|
||||
};
|
||||
|
||||
#endif // GROUPNETCAMVIEW_H
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project
|
||||
Copyright © 2014-2015 by The qTox Project
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
|
@ -18,35 +18,97 @@
|
|||
*/
|
||||
|
||||
#include "netcamview.h"
|
||||
#include "camerasource.h"
|
||||
#include "src/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/video/videosurface.h"
|
||||
#include "src/widget/tool/movablewidget.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QBoxLayout>
|
||||
#include <QFrame>
|
||||
|
||||
NetCamView::NetCamView(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, mainLayout(new QHBoxLayout())
|
||||
NetCamView::NetCamView(int friendId, QWidget* parent)
|
||||
: GenericNetCamView(parent)
|
||||
, selfFrame{nullptr}
|
||||
, friendId{friendId}
|
||||
{
|
||||
setLayout(mainLayout);
|
||||
setWindowTitle(tr("Tox video"));
|
||||
setMinimumSize(320,240);
|
||||
QString id = FriendList::findFriend(friendId)->getToxId().toString();
|
||||
videoSurface = new VideoSurface(Settings::getInstance().getSavedAvatar(id), this);
|
||||
videoSurface->setMinimumHeight(256);
|
||||
videoSurface->setContentsMargins(6, 6, 6, 6);
|
||||
|
||||
videoSurface = new VideoSurface(this);
|
||||
verLayout->insertWidget(0, videoSurface, 1);
|
||||
|
||||
mainLayout->addWidget(videoSurface);
|
||||
selfVideoSurface = new VideoSurface(Settings::getInstance().getSavedAvatar(Core::getInstance()->getSelfId().toString()), this, true);
|
||||
selfVideoSurface->setObjectName(QStringLiteral("CamVideoSurface"));
|
||||
selfVideoSurface->setMouseTracking(true);
|
||||
selfVideoSurface->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
selfFrame = new MovableWidget(videoSurface);
|
||||
selfFrame->show();
|
||||
|
||||
QHBoxLayout* frameLayout = new QHBoxLayout(selfFrame);
|
||||
frameLayout->addWidget(selfVideoSurface);
|
||||
frameLayout->setMargin(0);
|
||||
|
||||
updateRatio();
|
||||
connect(selfVideoSurface, &VideoSurface::ratioChanged, this, &NetCamView::updateRatio);
|
||||
|
||||
connect(videoSurface, &VideoSurface::boundaryChanged, [this]()
|
||||
{
|
||||
QRect boundingRect = videoSurface->getBoundingRect();
|
||||
updateFrameSize(boundingRect.size());
|
||||
selfFrame->setBoundary(boundingRect);
|
||||
});
|
||||
|
||||
connect(videoSurface, &VideoSurface::ratioChanged, [this]()
|
||||
{
|
||||
selfFrame->setMinimumWidth(selfFrame->minimumHeight() * selfVideoSurface->getRatio());
|
||||
QRect boundingRect = videoSurface->getBoundingRect();
|
||||
updateFrameSize(boundingRect.size());
|
||||
selfFrame->resetBoundary(boundingRect);
|
||||
});
|
||||
|
||||
connect(Core::getInstance(), &Core::selfAvatarChanged, [this](const QPixmap& pixmap)
|
||||
{
|
||||
selfVideoSurface->setAvatar(pixmap);
|
||||
});
|
||||
|
||||
connect(Core::getInstance(), &Core::friendAvatarChanged, [this](int FriendId, const QPixmap& pixmap)
|
||||
{
|
||||
if (this->friendId == FriendId)
|
||||
videoSurface->setAvatar(pixmap);
|
||||
});
|
||||
|
||||
VideoMode videoMode;
|
||||
QSize videoSize = Settings::getInstance().getCamVideoRes();
|
||||
videoMode.width = videoSize.width();
|
||||
videoMode.height = videoSize.height();
|
||||
qDebug() << "SIZER" << videoSize;
|
||||
videoMode.FPS = Settings::getInstance().getCamVideoFPS();
|
||||
CameraSource::getInstance().open(Settings::getInstance().getVideoDev(), videoMode);
|
||||
}
|
||||
|
||||
void NetCamView::show(VideoSource *source, const QString &title)
|
||||
{
|
||||
setSource(source);
|
||||
setTitle(title);
|
||||
selfVideoSurface->setSource(&CameraSource::getInstance());
|
||||
|
||||
setTitle(title);
|
||||
QWidget::show();
|
||||
}
|
||||
|
||||
void NetCamView::hide()
|
||||
{
|
||||
setSource(nullptr);
|
||||
selfVideoSurface->setSource(nullptr);
|
||||
|
||||
if (selfFrame)
|
||||
selfFrame->deleteLater();
|
||||
|
||||
selfFrame = nullptr;
|
||||
|
||||
QWidget::hide();
|
||||
}
|
||||
|
@ -60,3 +122,25 @@ void NetCamView::setTitle(const QString &title)
|
|||
{
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void NetCamView::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
selfFrame->resetBoundary(videoSurface->getBoundingRect());
|
||||
}
|
||||
|
||||
void NetCamView::updateRatio()
|
||||
{
|
||||
selfFrame->setMinimumWidth(selfFrame->minimumHeight() * selfVideoSurface->getRatio());
|
||||
selfFrame->setRatio(selfVideoSurface->getRatio());
|
||||
}
|
||||
|
||||
void NetCamView::updateFrameSize(QSize size)
|
||||
{
|
||||
selfFrame->setMaximumSize(size.height() / 3, size.width() / 3);
|
||||
|
||||
if (selfFrame->maximumWidth() > selfFrame->maximumHeight())
|
||||
selfFrame->setMaximumWidth(selfFrame->maximumHeight() * selfVideoSurface->getRatio());
|
||||
else
|
||||
selfFrame->setMaximumHeight(selfFrame->maximumWidth() / selfVideoSurface->getRatio());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright © 2014 by The qTox Project
|
||||
Copyright © 2014-2015 by The qTox Project
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
|
@ -20,19 +20,20 @@
|
|||
#ifndef NETCAMVIEW_H
|
||||
#define NETCAMVIEW_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "genericnetcamview.h"
|
||||
|
||||
class QHBoxLayout;
|
||||
struct vpx_image;
|
||||
class VideoSurface;
|
||||
class VideoSource;
|
||||
class QFrame;
|
||||
class MovableWidget;
|
||||
|
||||
class NetCamView : public QWidget
|
||||
class NetCamView : public GenericNetCamView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NetCamView(QWidget *parent=0);
|
||||
NetCamView(int friendId, QWidget *parent=0);
|
||||
|
||||
virtual void show(VideoSource* source, const QString& title);
|
||||
virtual void hide();
|
||||
|
@ -40,9 +41,19 @@ public:
|
|||
void setSource(VideoSource* s);
|
||||
void setTitle(const QString& title);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) final override;
|
||||
|
||||
private slots:
|
||||
void updateRatio();
|
||||
|
||||
private:
|
||||
QHBoxLayout* mainLayout;
|
||||
VideoSurface* videoSurface;
|
||||
void updateFrameSize(QSize size);
|
||||
|
||||
VideoSurface* selfVideoSurface;
|
||||
MovableWidget* selfFrame;
|
||||
int friendId;
|
||||
bool e = false;
|
||||
};
|
||||
|
||||
#endif // NETCAMVIEW_H
|
||||
|
|
|
@ -6,33 +6,49 @@
|
|||
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.
|
||||
(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
|
||||
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
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "videosurface.h"
|
||||
#include "src/video/videoframe.h"
|
||||
#include "src/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/widget/friendwidget.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/widget/style.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
|
||||
VideoSurface::VideoSurface(QWidget* parent)
|
||||
float getSizeRatio(const QSize size)
|
||||
{
|
||||
return size.width() / static_cast<float>(size.height());
|
||||
}
|
||||
|
||||
VideoSurface::VideoSurface(const QPixmap& avatar, QWidget* parent, bool expanding)
|
||||
: QWidget{parent}
|
||||
, source{nullptr}
|
||||
, frameLock{false}
|
||||
, hasSubscribed{false}
|
||||
, hasSubscribed{0}
|
||||
, avatar{avatar}
|
||||
, ratio{1.0f}
|
||||
, expanding{expanding}
|
||||
{
|
||||
|
||||
recalulateBounds();
|
||||
}
|
||||
|
||||
VideoSurface::VideoSurface(VideoSource *source, QWidget* parent)
|
||||
: VideoSurface(parent)
|
||||
VideoSurface::VideoSurface(const QPixmap& avatar, VideoSource *source, QWidget* parent)
|
||||
: VideoSurface(avatar, parent)
|
||||
{
|
||||
setSource(source);
|
||||
}
|
||||
|
@ -42,6 +58,11 @@ VideoSurface::~VideoSurface()
|
|||
unsubscribe();
|
||||
}
|
||||
|
||||
bool VideoSurface::isExpanding() const
|
||||
{
|
||||
return expanding;
|
||||
}
|
||||
|
||||
void VideoSurface::setSource(VideoSource *src)
|
||||
{
|
||||
if (source == src)
|
||||
|
@ -52,70 +73,154 @@ void VideoSurface::setSource(VideoSource *src)
|
|||
subscribe();
|
||||
}
|
||||
|
||||
QRect VideoSurface::getBoundingRect() const
|
||||
{
|
||||
QRect bRect = boundingRect;
|
||||
bRect.setBottomRight(QPoint(boundingRect.bottom() + 1, boundingRect.right() + 1));
|
||||
return boundingRect;
|
||||
}
|
||||
|
||||
float VideoSurface::getRatio() const
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
void VideoSurface::setAvatar(const QPixmap &pixmap)
|
||||
{
|
||||
avatar = pixmap;
|
||||
update();
|
||||
}
|
||||
|
||||
QPixmap VideoSurface::getAvatar() const
|
||||
{
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void VideoSurface::subscribe()
|
||||
{
|
||||
if (source && !hasSubscribed)
|
||||
if (source && hasSubscribed++ == 0)
|
||||
{
|
||||
source->subscribe();
|
||||
hasSubscribed = true;
|
||||
connect(source, &VideoSource::frameAvailable, this, &VideoSurface::onNewFrameAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoSurface::unsubscribe()
|
||||
{
|
||||
if (!source || !hasSubscribed)
|
||||
if (!source || hasSubscribed == 0)
|
||||
return;
|
||||
|
||||
// Fast lock
|
||||
{
|
||||
bool expected = false;
|
||||
while (!frameLock.compare_exchange_weak(expected, true))
|
||||
expected = false;
|
||||
}
|
||||
if (--hasSubscribed != 0)
|
||||
return;
|
||||
|
||||
lock();
|
||||
lastFrame.reset();
|
||||
frameLock = false;
|
||||
unlock();
|
||||
|
||||
ratio = 1.0f;
|
||||
recalulateBounds();
|
||||
emit ratioChanged();
|
||||
emit boundaryChanged();
|
||||
|
||||
source->unsubscribe();
|
||||
hasSubscribed = false;
|
||||
disconnect(source, &VideoSource::frameAvailable, this, &VideoSurface::onNewFrameAvailable);
|
||||
}
|
||||
|
||||
void VideoSurface::onNewFrameAvailable(std::shared_ptr<VideoFrame> newFrame)
|
||||
{
|
||||
// Fast lock
|
||||
QSize newSize;
|
||||
|
||||
lock();
|
||||
lastFrame = newFrame;
|
||||
newSize = lastFrame->getSize();
|
||||
unlock();
|
||||
|
||||
float newRatio = getSizeRatio(newSize);
|
||||
|
||||
if (newRatio != ratio && isVisible())
|
||||
{
|
||||
bool expected = false;
|
||||
while (!frameLock.compare_exchange_weak(expected, true))
|
||||
expected = false;
|
||||
ratio = newRatio;
|
||||
recalulateBounds();
|
||||
emit ratioChanged();
|
||||
emit boundaryChanged();
|
||||
}
|
||||
|
||||
lastFrame = newFrame;
|
||||
frameLock = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void VideoSurface::paintEvent(QPaintEvent*)
|
||||
{
|
||||
// Fast lock
|
||||
{
|
||||
bool expected = false;
|
||||
while (!frameLock.compare_exchange_weak(expected, true))
|
||||
expected = false;
|
||||
}
|
||||
lock();
|
||||
|
||||
QPainter painter(this);
|
||||
painter.fillRect(painter.viewport(), Qt::black);
|
||||
if (lastFrame)
|
||||
{
|
||||
QSize frameSize = lastFrame->getSize();
|
||||
QRect rect = painter.viewport();
|
||||
int width = frameSize.width()*rect.height()/frameSize.height();
|
||||
rect.setLeft((rect.width()-width)/2);
|
||||
rect.setWidth(width);
|
||||
|
||||
QImage frame = lastFrame->toQImage(rect.size());
|
||||
painter.drawImage(rect, frame, frame.rect(), Qt::NoFormatConversion);
|
||||
QImage frame = lastFrame->toQImage(rect().size());
|
||||
painter.drawImage(boundingRect, frame, frame.rect(), Qt::NoFormatConversion);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.fillRect(boundingRect, Qt::white);
|
||||
QPixmap drawnAvatar = avatar;
|
||||
|
||||
if (drawnAvatar.isNull())
|
||||
drawnAvatar = Style::scaleSvgImage(":/img/contact_dark.svg", boundingRect.width(), boundingRect.height());
|
||||
|
||||
painter.drawPixmap(boundingRect, drawnAvatar, drawnAvatar.rect());
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
void VideoSurface::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
recalulateBounds();
|
||||
emit boundaryChanged();
|
||||
}
|
||||
|
||||
void VideoSurface::showEvent(QShowEvent* e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
//emit ratioChanged();
|
||||
}
|
||||
|
||||
void VideoSurface::recalulateBounds()
|
||||
{
|
||||
if (expanding)
|
||||
{
|
||||
boundingRect = contentsRect();
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint pos;
|
||||
QSize size;
|
||||
QSize usableSize = contentsRect().size();
|
||||
int possibleWidth = usableSize.height() * ratio;
|
||||
|
||||
if (possibleWidth > usableSize.width())
|
||||
size = (QSize(usableSize.width(), usableSize.width() / ratio));
|
||||
else
|
||||
size = (QSize(possibleWidth, usableSize.height()));
|
||||
|
||||
pos.setX(width() / 2 - size.width() / 2);
|
||||
pos.setY(height() / 2 - size.height() / 2);
|
||||
boundingRect.setRect(pos.x(), pos.y(), size.width(), size.height());
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void VideoSurface::lock()
|
||||
{
|
||||
// Fast lock
|
||||
bool expected = false;
|
||||
while (!frameLock.compare_exchange_weak(expected, true))
|
||||
expected = false;
|
||||
}
|
||||
|
||||
void VideoSurface::unlock()
|
||||
{
|
||||
frameLock = false;
|
||||
}
|
||||
|
|
|
@ -30,26 +30,45 @@ class VideoSurface : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VideoSurface(QWidget* parent=0);
|
||||
VideoSurface(VideoSource* source, QWidget* parent=0);
|
||||
VideoSurface(const QPixmap& avatar, QWidget* parent = 0, bool expanding = false);
|
||||
VideoSurface(const QPixmap& avatar, VideoSource* source, QWidget* parent = 0);
|
||||
~VideoSurface();
|
||||
|
||||
bool isExpanding() const;
|
||||
void setSource(VideoSource* src); //NULL is a valid option
|
||||
QRect getBoundingRect() const;
|
||||
float getRatio() const;
|
||||
void setAvatar(const QPixmap& pixmap);
|
||||
QPixmap getAvatar() const;
|
||||
|
||||
signals:
|
||||
void ratioChanged();
|
||||
void boundaryChanged();
|
||||
|
||||
protected:
|
||||
void subscribe();
|
||||
void unsubscribe();
|
||||
|
||||
virtual void paintEvent(QPaintEvent * event) final override;
|
||||
virtual void paintEvent(QPaintEvent* event) final override;
|
||||
virtual void resizeEvent(QResizeEvent* event) final override;
|
||||
virtual void showEvent(QShowEvent* event) final override;
|
||||
|
||||
private slots:
|
||||
void onNewFrameAvailable(std::shared_ptr<VideoFrame> newFrame);
|
||||
|
||||
private:
|
||||
void recalulateBounds();
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
QRect boundingRect;
|
||||
VideoSource* source;
|
||||
std::shared_ptr<VideoFrame> lastFrame;
|
||||
std::atomic_bool frameLock; ///< Fast lock for lastFrame
|
||||
bool hasSubscribed;
|
||||
uint8_t hasSubscribed;
|
||||
QPixmap avatar;
|
||||
float ratio;
|
||||
bool expanding;
|
||||
};
|
||||
|
||||
#endif // SELFCAMVIEW_H
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <QTemporaryFile>
|
||||
#include <QGuiApplication>
|
||||
#include <QStyle>
|
||||
#include <QSplitter>
|
||||
#include <cassert>
|
||||
#include "chatform.h"
|
||||
#include "src/core/core.h"
|
||||
|
@ -41,7 +42,6 @@
|
|||
#include "src/core/cstring.h"
|
||||
#include "src/widget/tool/callconfirmwidget.h"
|
||||
#include "src/widget/friendwidget.h"
|
||||
#include "src/video/netcamview.h"
|
||||
#include "src/widget/form/loadhistorydialog.h"
|
||||
#include "src/widget/tool/chattextedit.h"
|
||||
#include "src/widget/widget.h"
|
||||
|
@ -52,10 +52,13 @@
|
|||
#include "src/chatlog/chatlinecontentproxy.h"
|
||||
#include "src/chatlog/content/text.h"
|
||||
#include "src/chatlog/chatlog.h"
|
||||
#include "src/video/netcamview.h"
|
||||
#include "src/persistence/offlinemsgengine.h"
|
||||
#include "src/widget/tool/screenshotgrabber.h"
|
||||
#include "src/widget/tool/flyoutoverlaywidget.h"
|
||||
#include "src/widget/translator.h"
|
||||
#include "src/video/videosource.h"
|
||||
#include "src/video/camerasource.h"
|
||||
|
||||
ChatForm::ChatForm(Friend* chatFriend)
|
||||
: f(chatFriend)
|
||||
|
@ -76,7 +79,6 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
|
||||
typingTimer.setSingleShot(true);
|
||||
|
||||
netcam = nullptr;
|
||||
callDurationTimer = nullptr;
|
||||
disableCallButtonsTimer = nullptr;
|
||||
|
||||
|
@ -88,6 +90,9 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
headTextLayout->addWidget(callDuration, 1, Qt::AlignCenter);
|
||||
callDuration->hide();
|
||||
|
||||
chatWidget->setMinimumHeight(160);
|
||||
connect(this, &GenericChatForm::messageInserted, this, &ChatForm::onMessageInserted);
|
||||
|
||||
loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory()));
|
||||
|
||||
connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend);
|
||||
|
@ -133,7 +138,6 @@ void ChatForm::setStatusMessage(QString newMessage)
|
|||
void ChatForm::onSendTriggered()
|
||||
{
|
||||
SendMessageStr(msgEdit->toPlainText());
|
||||
|
||||
msgEdit->clear();
|
||||
}
|
||||
|
||||
|
@ -251,7 +255,7 @@ void ChatForm::onAvInvite(uint32_t FriendId, int CallId, bool video)
|
|||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvInvite";
|
||||
qDebug() << "onAvInvite, callId: " << CallId;
|
||||
|
||||
callId = CallId;
|
||||
callButton->disconnect();
|
||||
|
@ -302,7 +306,7 @@ void ChatForm::onAvStart(uint32_t FriendId, int CallId, bool video)
|
|||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvStart";
|
||||
qDebug() << "onAvStart, callId: " << CallId;
|
||||
|
||||
audioInputFlag = true;
|
||||
audioOutputFlag = true;
|
||||
|
@ -329,6 +333,7 @@ void ChatForm::onAvStart(uint32_t FriendId, int CallId, bool video)
|
|||
videoButton->setToolTip("");
|
||||
connect(callButton, SIGNAL(clicked()),
|
||||
this, SLOT(onHangupCallTriggered()));
|
||||
hideNetcam();
|
||||
}
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->style()->polish(videoButton);
|
||||
|
@ -348,12 +353,12 @@ void ChatForm::onAvStart(uint32_t FriendId, int CallId, bool video)
|
|||
startCounter();
|
||||
}
|
||||
|
||||
void ChatForm::onAvCancel(uint32_t FriendId, int)
|
||||
void ChatForm::onAvCancel(uint32_t FriendId, int CallId)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvCancel";
|
||||
qDebug() << "onAvCancel, callId: " << CallId;
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
@ -368,27 +373,12 @@ void ChatForm::onAvCancel(uint32_t FriendId, int)
|
|||
QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
void ChatForm::onAvEnd(uint32_t FriendId, int)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvEnd";
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
stopCounter();
|
||||
hideNetcam();
|
||||
}
|
||||
|
||||
void ChatForm::onAvRinging(uint32_t FriendId, int CallId, bool video)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvRinging";
|
||||
qDebug() << "onAvRinging, callId: " << CallId;
|
||||
|
||||
callId = CallId;
|
||||
callButton->disconnect();
|
||||
|
@ -428,7 +418,7 @@ void ChatForm::onAvStarting(uint32_t FriendId, int CallId, bool video)
|
|||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvStarting";
|
||||
qDebug() << "onAvStarting, callId:" << CallId;
|
||||
|
||||
callId = CallId;
|
||||
|
||||
|
@ -460,28 +450,43 @@ void ChatForm::onAvStarting(uint32_t FriendId, int CallId, bool video)
|
|||
startCounter();
|
||||
}
|
||||
|
||||
void ChatForm::onAvEnding(uint32_t FriendId, int)
|
||||
void ChatForm::onAvEnding(uint32_t FriendId, int CallId)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvEnding";
|
||||
qDebug() << "onAvEnding, callId: " << CallId;
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
stopCounter();
|
||||
|
||||
CameraSource::getInstance().unsubscribe();
|
||||
hideNetcam();
|
||||
}
|
||||
|
||||
void ChatForm::onAvRequestTimeout(uint32_t FriendId, int)
|
||||
void ChatForm::onAvEnd(uint32_t FriendId, int CallId)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvRequestTimeout";
|
||||
qDebug() << "onAvEnd, callId: " << CallId;
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
stopCounter();
|
||||
hideNetcam();
|
||||
}
|
||||
|
||||
void ChatForm::onAvRequestTimeout(uint32_t FriendId, int CallId)
|
||||
{
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvRequestTimeout, callId: " << CallId;
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
@ -532,7 +537,7 @@ void ChatForm::onAvMediaChange(uint32_t FriendId, int CallId, bool video)
|
|||
if (FriendId != f->getFriendID() || CallId != callId)
|
||||
return;
|
||||
|
||||
qDebug() << "onAvMediaChange";
|
||||
qDebug() << "onAvMediaChange, callId: " << CallId;
|
||||
|
||||
if (video)
|
||||
showNetcam();
|
||||
|
@ -747,6 +752,14 @@ void ChatForm::onAvatarChange(uint32_t FriendId, const QPixmap &pic)
|
|||
avatar->setPixmap(pic);
|
||||
}
|
||||
|
||||
GenericNetCamView *ChatForm::createNetcam()
|
||||
{
|
||||
qDebug() << "creating netcam";
|
||||
NetCamView* view = new NetCamView(f->getFriendID(), this);
|
||||
view->show(Core::getInstance()->getVideoSourceFromCall(callId), f->getDisplayedName());
|
||||
return view;
|
||||
}
|
||||
|
||||
void ChatForm::dragEnterEvent(QDragEnterEvent *ev)
|
||||
{
|
||||
if (ev->mimeData()->hasUrls())
|
||||
|
@ -943,6 +956,12 @@ void ChatForm::onLoadHistory()
|
|||
}
|
||||
}
|
||||
|
||||
void ChatForm::onMessageInserted()
|
||||
{
|
||||
if (netcam && bodySplitter->sizes()[1] == 0)
|
||||
netcam->setShowMessages(true, true);
|
||||
}
|
||||
|
||||
void ChatForm::startCounter()
|
||||
{
|
||||
if (!callDurationTimer)
|
||||
|
@ -1075,22 +1094,6 @@ void ChatForm::SendMessageStr(QString msg)
|
|||
}
|
||||
}
|
||||
|
||||
void ChatForm::showNetcam()
|
||||
{
|
||||
if (!netcam)
|
||||
netcam = new NetCamView();
|
||||
netcam->show(Core::getInstance()->getVideoSourceFromCall(callId), f->getDisplayedName());
|
||||
}
|
||||
|
||||
void ChatForm::hideNetcam()
|
||||
{
|
||||
if (!netcam)
|
||||
return;
|
||||
netcam->hide();
|
||||
delete netcam;
|
||||
netcam = nullptr;
|
||||
}
|
||||
|
||||
void ChatForm::retranslateUi()
|
||||
{
|
||||
QString volObjectName = volButton->objectName();
|
||||
|
@ -1106,4 +1109,7 @@ void ChatForm::retranslateUi()
|
|||
micButton->setToolTip(tr("Mute microphone"));
|
||||
else if (micObjectName == QStringLiteral("red"))
|
||||
micButton->setToolTip(tr("Unmute microphone"));
|
||||
|
||||
if (netcam)
|
||||
netcam->setShowMessages(chatWidget->isVisible());
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
class Friend;
|
||||
class FileTransferInstance;
|
||||
class NetCamView;
|
||||
class QPixmap;
|
||||
class CallConfirmWidget;
|
||||
class QHideEvent;
|
||||
|
@ -99,13 +98,13 @@ private slots:
|
|||
void onScreenshotClicked();
|
||||
void onScreenshotTaken(const QPixmap &pixmap);
|
||||
void doScreenshot();
|
||||
void onMessageInserted();
|
||||
|
||||
private:
|
||||
void retranslateUi();
|
||||
|
||||
protected:
|
||||
void showNetcam();
|
||||
void hideNetcam();
|
||||
virtual GenericNetCamView* createNetcam() final override;
|
||||
// drag & drop
|
||||
virtual void dragEnterEvent(QDragEnterEvent* ev) final override;
|
||||
virtual void dropEvent(QDropEvent* ev) final override;
|
||||
|
@ -115,7 +114,6 @@ protected:
|
|||
private:
|
||||
Friend* f;
|
||||
CroppingLabel *statusMessageLabel;
|
||||
NetCamView* netcam;
|
||||
int callId;
|
||||
QLabel *callDuration;
|
||||
QTimer *callDurationTimer;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <QDebug>
|
||||
#include <QShortcut>
|
||||
#include <QKeyEvent>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "src/persistence/smileypack.h"
|
||||
#include "src/widget/emoticonswidget.h"
|
||||
|
@ -44,6 +45,7 @@
|
|||
#include "src/widget/contentlayout.h"
|
||||
#include "src/widget/tool/croppinglabel.h"
|
||||
#include <QPushButton>
|
||||
#include "src/video/genericnetcamview.h"
|
||||
|
||||
GenericChatForm::GenericChatForm(QWidget *parent)
|
||||
: QWidget(parent, Qt::Window)
|
||||
|
@ -73,7 +75,8 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
chatWidget = new ChatLog(this);
|
||||
chatWidget->setBusyNotification(ChatMessage::createBusyNotification());
|
||||
|
||||
connect(&Settings::getInstance(), &Settings::emojiFontChanged, this, [this]() { chatWidget->forceRelayout(); });
|
||||
connect(&Settings::getInstance(), &Settings::emojiFontChanged,
|
||||
this, [this]() { chatWidget->forceRelayout(); });
|
||||
|
||||
msgEdit = new ChatTextEdit();
|
||||
|
||||
|
@ -127,8 +130,17 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
micButton->setStyleSheet(micButtonStylesheet);
|
||||
|
||||
setLayout(mainLayout);
|
||||
mainLayout->addWidget(chatWidget);
|
||||
mainLayout->addLayout(mainFootLayout);
|
||||
|
||||
bodySplitter = new QSplitter(Qt::Vertical, this);
|
||||
connect(bodySplitter, &QSplitter::splitterMoved, this, &GenericChatForm::onSplitterMoved);
|
||||
|
||||
QWidget* contentWidget = new QWidget(this);
|
||||
QVBoxLayout* contentLayout = new QVBoxLayout(contentWidget);
|
||||
contentLayout->addWidget(chatWidget);
|
||||
contentLayout->addLayout(mainFootLayout);
|
||||
bodySplitter->addWidget(contentWidget);
|
||||
|
||||
mainLayout->addWidget(bodySplitter);
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
footButtonsSmall->addWidget(emoteButton);
|
||||
|
@ -175,12 +187,16 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
|
||||
menu.addActions(chatWidget->actions());
|
||||
menu.addSeparator();
|
||||
saveChatAction = menu.addAction(QIcon::fromTheme("document-save"), QString(), this, SLOT(onSaveLogClicked()));
|
||||
clearAction = menu.addAction(QIcon::fromTheme("edit-clear"), QString(), this, SLOT(clearChatArea(bool)));
|
||||
saveChatAction = menu.addAction(QIcon::fromTheme("document-save"),
|
||||
QString(), this, SLOT(onSaveLogClicked()));
|
||||
clearAction = menu.addAction(QIcon::fromTheme("edit-clear"),
|
||||
QString(), this, SLOT(clearChatArea(bool)));
|
||||
menu.addSeparator();
|
||||
|
||||
connect(emoteButton, &QPushButton::clicked, this, &GenericChatForm::onEmoteButtonClicked);
|
||||
connect(chatWidget, &ChatLog::customContextMenuRequested, this, &GenericChatForm::onChatContextMenuRequested);
|
||||
connect(emoteButton, &QPushButton::clicked,
|
||||
this, &GenericChatForm::onEmoteButtonClicked);
|
||||
connect(chatWidget, &ChatLog::customContextMenuRequested,
|
||||
this, &GenericChatForm::onChatContextMenuRequested);
|
||||
|
||||
new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_L, this, SLOT(clearChatArea()));
|
||||
|
||||
|
@ -194,6 +210,8 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
|
||||
retranslateUi();
|
||||
Translator::registerHandler(std::bind(&GenericChatForm::retranslateUi, this), this);
|
||||
|
||||
netcam = nullptr;
|
||||
}
|
||||
|
||||
GenericChatForm::~GenericChatForm()
|
||||
|
@ -462,6 +480,7 @@ QString GenericChatForm::resolveToxId(const ToxId &id)
|
|||
void GenericChatForm::insertChatMessage(ChatMessage::Ptr msg)
|
||||
{
|
||||
chatWidget->insertChatlineAtBottom(std::dynamic_pointer_cast<ChatLine>(msg));
|
||||
emit messageInserted();
|
||||
}
|
||||
|
||||
void GenericChatForm::hideEvent(QHideEvent* event)
|
||||
|
@ -511,6 +530,25 @@ bool GenericChatForm::eventFilter(QObject* object, QEvent* event)
|
|||
return false;
|
||||
}
|
||||
|
||||
void GenericChatForm::onSplitterMoved(int, int)
|
||||
{
|
||||
if (netcam)
|
||||
netcam->setShowMessages(bodySplitter->sizes()[1] == 0);
|
||||
}
|
||||
|
||||
void GenericChatForm::onShowMessagesClicked()
|
||||
{
|
||||
if (netcam)
|
||||
{
|
||||
if (bodySplitter->sizes()[1] == 0)
|
||||
bodySplitter->setSizes({1, 1});
|
||||
else
|
||||
bodySplitter->setSizes({1, 0});
|
||||
|
||||
onSplitterMoved(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericChatForm::retranslateUi()
|
||||
{
|
||||
QString callObjectName = callButton->objectName();
|
||||
|
@ -537,3 +575,26 @@ void GenericChatForm::retranslateUi()
|
|||
saveChatAction->setText(tr("Save chat log"));
|
||||
clearAction->setText(tr("Clear displayed messages"));
|
||||
}
|
||||
|
||||
void GenericChatForm::showNetcam()
|
||||
{
|
||||
if (!netcam)
|
||||
netcam = createNetcam();
|
||||
|
||||
connect(netcam, &GenericNetCamView::showMessageClicked,
|
||||
this, &GenericChatForm::onShowMessagesClicked);
|
||||
|
||||
bodySplitter->insertWidget(0, netcam);
|
||||
bodySplitter->setCollapsible(0, false);
|
||||
}
|
||||
|
||||
void GenericChatForm::hideNetcam()
|
||||
{
|
||||
if (!netcam)
|
||||
return;
|
||||
|
||||
netcam->close();
|
||||
netcam->hide();
|
||||
delete netcam;
|
||||
netcam = nullptr;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,12 @@ class MaskablePixmapWidget;
|
|||
class Widget;
|
||||
class FlyoutOverlayWidget;
|
||||
class ContentLayout;
|
||||
class QSplitter;
|
||||
class GenericNetCamView;
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class GenericChatForm : public QWidget
|
||||
{
|
||||
|
@ -67,6 +73,7 @@ signals:
|
|||
void sendMessage(uint32_t, QString);
|
||||
void sendAction(uint32_t, QString);
|
||||
void chatAreaCleared();
|
||||
void messageInserted();
|
||||
|
||||
public slots:
|
||||
void focusInput();
|
||||
|
@ -82,11 +89,16 @@ protected slots:
|
|||
void onSelectAllClicked();
|
||||
void showFileMenu();
|
||||
void hideFileMenu();
|
||||
void onShowMessagesClicked();
|
||||
void onSplitterMoved(int pos, int index);
|
||||
|
||||
private:
|
||||
void retranslateUi();
|
||||
|
||||
protected:
|
||||
void showNetcam();
|
||||
void hideNetcam();
|
||||
virtual GenericNetCamView* createNetcam() = 0;
|
||||
QString resolveToxId(const ToxId &id);
|
||||
void insertChatMessage(ChatMessage::Ptr msg);
|
||||
void adjustFileMenuPosition();
|
||||
|
@ -116,6 +128,8 @@ protected:
|
|||
QDateTime historyBaselineDate = QDateTime::currentDateTime(); // used by HistoryKeeper to load messages from t to historyBaselineDate (excluded)
|
||||
bool audioInputFlag;
|
||||
bool audioOutputFlag;
|
||||
QSplitter* bodySplitter;
|
||||
GenericNetCamView* netcam;
|
||||
};
|
||||
|
||||
#endif // GENERICCHATFORM_H
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "src/persistence/historykeeper.h"
|
||||
#include "src/widget/flowlayout.h"
|
||||
#include "src/widget/translator.h"
|
||||
#include "src/video/groupnetcamview.h"
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QPushButton>
|
||||
|
@ -195,7 +196,14 @@ void GroupChatForm::onUserListChanged()
|
|||
orderizer[names[i]] = peerLabels[i];
|
||||
if (group->isSelfPeerNumber(i))
|
||||
peerLabels[i]->setStyleSheet("QLabel {color : green;}");
|
||||
|
||||
if (netcam && !group->isSelfPeerNumber(i))
|
||||
static_cast<GroupNetCamView*>(netcam)->addPeer(i, names[i]);
|
||||
}
|
||||
|
||||
if (netcam)
|
||||
static_cast<GroupNetCamView*>(netcam)->clearPeers();
|
||||
|
||||
// now alphabetize and add to layout
|
||||
names.sort(Qt::CaseInsensitive);
|
||||
for (unsigned i=0; i<nNames; ++i)
|
||||
|
@ -231,9 +239,24 @@ void GroupChatForm::peerAudioPlaying(int peer)
|
|||
{
|
||||
peerAudioTimers[peer] = new QTimer(this);
|
||||
peerAudioTimers[peer]->setSingleShot(true);
|
||||
connect(peerAudioTimers[peer], &QTimer::timeout, [=]{this->peerLabels[peer]->setStyleSheet("");
|
||||
delete this->peerAudioTimers[peer];
|
||||
this->peerAudioTimers[peer] = nullptr;});
|
||||
connect(peerAudioTimers[peer], &QTimer::timeout, [this, peer]
|
||||
{
|
||||
if (netcam)
|
||||
static_cast<GroupNetCamView*>(netcam)->removePeer(peer);
|
||||
|
||||
if (peer >= peerLabels.size())
|
||||
return;
|
||||
|
||||
peerLabels[peer]->setStyleSheet("");
|
||||
delete peerAudioTimers[peer];
|
||||
peerAudioTimers[peer] = nullptr;
|
||||
});
|
||||
|
||||
if (netcam)
|
||||
{
|
||||
static_cast<GroupNetCamView*>(netcam)->removePeer(peer);
|
||||
static_cast<GroupNetCamView*>(netcam)->addPeer(peer, group->getPeerList()[peer]);
|
||||
}
|
||||
}
|
||||
peerAudioTimers[peer]->start(500);
|
||||
}
|
||||
|
@ -312,6 +335,7 @@ void GroupChatForm::onCallClicked()
|
|||
volButton->style()->polish(volButton);
|
||||
volButton->setToolTip(tr("Mute call"));
|
||||
inCall = true;
|
||||
showNetcam();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -328,9 +352,24 @@ void GroupChatForm::onCallClicked()
|
|||
volButton->style()->polish(volButton);
|
||||
volButton->setToolTip("");
|
||||
inCall = false;
|
||||
hideNetcam();
|
||||
}
|
||||
}
|
||||
|
||||
GenericNetCamView *GroupChatForm::createNetcam()
|
||||
{
|
||||
GroupNetCamView* view = new GroupNetCamView(group->getGroupId(), this);
|
||||
|
||||
QStringList names = group->getPeerList();
|
||||
for (unsigned i=0; i<names.size(); ++i)
|
||||
{
|
||||
if (!group->isSelfPeerNumber(i))
|
||||
static_cast<GroupNetCamView*>(view)->addPeer(i, names[i]);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void GroupChatForm::keyPressEvent(QKeyEvent* ev)
|
||||
{
|
||||
// Push to talk (CTRL+P)
|
||||
|
|
|
@ -49,6 +49,7 @@ private slots:
|
|||
void onCallClicked();
|
||||
|
||||
protected:
|
||||
virtual GenericNetCamView* createNetcam() final override;
|
||||
virtual void keyPressEvent(QKeyEvent* ev) final override;
|
||||
virtual void keyReleaseEvent(QKeyEvent* ev) final override;
|
||||
// drag & drop
|
||||
|
|
|
@ -58,6 +58,8 @@ AVForm::AVForm() :
|
|||
connect(bodyUI->inDevCombobox, qcbxIndexChangedStr, this, &AVForm::onInDevChanged);
|
||||
connect(bodyUI->outDevCombobox, qcbxIndexChangedStr, this, &AVForm::onOutDevChanged);
|
||||
connect(bodyUI->videoDevCombobox, qcbxIndexChangedInt, this, &AVForm::onVideoDevChanged);
|
||||
connect(bodyUI->videoModescomboBox, qcbxIndexChangedInt, this, &AVForm::onVideoModesIndexChanged);
|
||||
|
||||
connect(bodyUI->filterAudio, &QCheckBox::toggled, this, &AVForm::onFilterAudioToggled);
|
||||
connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=](){getAudioInDevices(); getAudioOutDevices();});
|
||||
bodyUI->playbackSlider->setValue(100);
|
||||
|
@ -74,6 +76,7 @@ AVForm::AVForm() :
|
|||
|
||||
AVForm::~AVForm()
|
||||
{
|
||||
killVideoSurface();
|
||||
Translator::unregister(this);
|
||||
delete bodyUI;
|
||||
}
|
||||
|
@ -86,7 +89,7 @@ void AVForm::showEvent(QShowEvent*)
|
|||
getVideoDevices();
|
||||
}
|
||||
|
||||
void AVForm::on_videoModescomboBox_currentIndexChanged(int index)
|
||||
void AVForm::onVideoModesIndexChanged(int index)
|
||||
{
|
||||
if (index<0 || index>=videoModes.size())
|
||||
{
|
||||
|
@ -102,6 +105,7 @@ void AVForm::on_videoModescomboBox_currentIndexChanged(int index)
|
|||
QString devName = videoDeviceList[devIndex].first;
|
||||
VideoMode mode = videoModes[index];
|
||||
Settings::getInstance().setCamVideoRes(QSize(mode.width, mode.height));
|
||||
Settings::getInstance().setCamVideoFPS(mode.FPS);
|
||||
camera.open(devName, mode);
|
||||
}
|
||||
|
||||
|
@ -123,10 +127,11 @@ void AVForm::updateVideoModes(int curIndex)
|
|||
bodyUI->videoModescomboBox->clear();
|
||||
int prefResIndex = -1;
|
||||
QSize prefRes = Settings::getInstance().getCamVideoRes();
|
||||
unsigned short prefFPS = Settings::getInstance().getCamVideoFPS();
|
||||
for (int i=0; i<videoModes.size(); ++i)
|
||||
{
|
||||
VideoMode mode = videoModes[i];
|
||||
if (mode.width==prefRes.width() && mode.height==prefRes.height() && prefResIndex==-1)
|
||||
if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1)
|
||||
prefResIndex = i;
|
||||
QString str;
|
||||
if (mode.height && mode.width)
|
||||
|
@ -176,6 +181,14 @@ void AVForm::updateVideoModes(int curIndex)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoModes.size())
|
||||
{
|
||||
bodyUI->videoModescomboBox->setUpdatesEnabled(false);
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(-1);
|
||||
bodyUI->videoModescomboBox->setUpdatesEnabled(true);
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,29 +205,8 @@ void AVForm::onVideoDevChanged(int index)
|
|||
updateVideoModes(index);
|
||||
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
||||
camera.open(dev);
|
||||
}
|
||||
|
||||
void AVForm::onResProbingFinished(QList<QSize> res)
|
||||
{
|
||||
QSize savedRes = Settings::getInstance().getCamVideoRes();
|
||||
int savedResIndex = -1;
|
||||
bodyUI->videoModescomboBox->clear();
|
||||
bodyUI->videoModescomboBox->blockSignals(true);
|
||||
for (int i=0; i<res.size(); ++i)
|
||||
{
|
||||
QSize& r = res[i];
|
||||
bodyUI->videoModescomboBox->addItem(QString("%1x%2").arg(QString::number(r.width()),QString::number(r.height())), r);
|
||||
if (r == savedRes)
|
||||
savedResIndex = i;
|
||||
}
|
||||
//reset index, otherwise cameras with only one resolution won't get initialized
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(-1);
|
||||
bodyUI->videoModescomboBox->blockSignals(false);
|
||||
|
||||
if (savedResIndex != -1)
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(savedResIndex);
|
||||
else
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(bodyUI->videoModescomboBox->count()-1);
|
||||
killVideoSurface();
|
||||
createVideoSurface();
|
||||
}
|
||||
|
||||
void AVForm::hideEvent(QHideEvent *)
|
||||
|
@ -241,8 +233,6 @@ void AVForm::getVideoDevices()
|
|||
if (device.first == settingsInDev)
|
||||
videoDevIndex = bodyUI->videoDevCombobox->count()-1;
|
||||
}
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->videoDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->videoDevCombobox->setCurrentIndex(videoDevIndex);
|
||||
bodyUI->videoDevCombobox->blockSignals(false);
|
||||
updateVideoModes(videoDevIndex);
|
||||
|
@ -254,37 +244,37 @@ void AVForm::getVideoDevices()
|
|||
void AVForm::getAudioInDevices()
|
||||
{
|
||||
QString settingsInDev = Settings::getInstance().getInDev();
|
||||
int inDevIndex = 0;
|
||||
int inDevIndex = 0;
|
||||
bodyUI->inDevCombobox->clear();
|
||||
const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
if (pDeviceList)
|
||||
{
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->inDevCombobox->blockSignals(true);
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->inDevCombobox->blockSignals(true);
|
||||
while (*pDeviceList)
|
||||
{
|
||||
int len = strlen(pDeviceList);
|
||||
#ifdef Q_OS_WIN
|
||||
QString inDev = QString::fromUtf8(pDeviceList,len);
|
||||
#else
|
||||
QString inDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
QString inDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#endif
|
||||
bodyUI->inDevCombobox->addItem(inDev);
|
||||
if (settingsInDev == inDev)
|
||||
inDevIndex = bodyUI->inDevCombobox->count()-1;
|
||||
inDevIndex = bodyUI->inDevCombobox->count()-1;
|
||||
pDeviceList += len+1;
|
||||
}
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->inDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->inDevCombobox->blockSignals(false);
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->inDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->inDevCombobox->blockSignals(false);
|
||||
}
|
||||
bodyUI->inDevCombobox->setCurrentIndex(inDevIndex);
|
||||
bodyUI->inDevCombobox->setCurrentIndex(inDevIndex);
|
||||
}
|
||||
|
||||
void AVForm::getAudioOutDevices()
|
||||
{
|
||||
QString settingsOutDev = Settings::getInstance().getOutDev();
|
||||
int outDevIndex = 0;
|
||||
int outDevIndex = 0;
|
||||
bodyUI->outDevCombobox->clear();
|
||||
const ALchar *pDeviceList;
|
||||
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
||||
|
@ -293,15 +283,15 @@ void AVForm::getAudioOutDevices()
|
|||
pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
if (pDeviceList)
|
||||
{
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->outDevCombobox->blockSignals(true);
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->outDevCombobox->blockSignals(true);
|
||||
while (*pDeviceList)
|
||||
{
|
||||
int len = strlen(pDeviceList);
|
||||
#ifdef Q_OS_WIN
|
||||
QString outDev = QString::fromUtf8(pDeviceList,len);
|
||||
#else
|
||||
QString outDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
QString outDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#endif
|
||||
bodyUI->outDevCombobox->addItem(outDev);
|
||||
if (settingsOutDev == outDev)
|
||||
|
@ -310,11 +300,11 @@ void AVForm::getAudioOutDevices()
|
|||
}
|
||||
pDeviceList += len+1;
|
||||
}
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->outDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->outDevCombobox->blockSignals(false);
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->outDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->outDevCombobox->blockSignals(false);
|
||||
}
|
||||
bodyUI->outDevCombobox->setCurrentIndex(outDevIndex);
|
||||
bodyUI->outDevCombobox->setCurrentIndex(outDevIndex);
|
||||
}
|
||||
|
||||
void AVForm::onInDevChanged(const QString &deviceDescriptor)
|
||||
|
@ -361,7 +351,7 @@ void AVForm::createVideoSurface()
|
|||
{
|
||||
if (camVideoSurface)
|
||||
return;
|
||||
camVideoSurface = new VideoSurface(bodyUI->CamFrame);
|
||||
camVideoSurface = new VideoSurface(QPixmap(), bodyUI->CamFrame);
|
||||
camVideoSurface->setObjectName(QStringLiteral("CamVideoSurface"));
|
||||
camVideoSurface->setMinimumSize(QSize(160, 120));
|
||||
camVideoSurface->setSource(&camera);
|
||||
|
@ -376,6 +366,7 @@ void AVForm::killVideoSurface()
|
|||
while ((child = bodyUI->gridLayout->takeAt(0)) != 0)
|
||||
delete child;
|
||||
|
||||
camVideoSurface->close();
|
||||
delete camVideoSurface;
|
||||
camVideoSurface = nullptr;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ private:
|
|||
void retranslateUi();
|
||||
|
||||
private slots:
|
||||
void on_videoModescomboBox_currentIndexChanged(int index);
|
||||
|
||||
// audio
|
||||
void onInDevChanged(const QString& deviceDescriptor);
|
||||
|
@ -63,7 +62,7 @@ private slots:
|
|||
|
||||
// camera
|
||||
void onVideoDevChanged(int index);
|
||||
void onResProbingFinished(QList<QSize> res);
|
||||
void onVideoModesIndexChanged(int index);
|
||||
|
||||
virtual void hideEvent(QHideEvent*) final override;
|
||||
virtual void showEvent(QShowEvent*) final override;
|
||||
|
|
|
@ -116,8 +116,8 @@ void NotificationScrollArea::resizeEvent(QResizeEvent *event)
|
|||
|
||||
void NotificationScrollArea::findNextWidget()
|
||||
{
|
||||
GenericChatroomWidget* next = nullptr;
|
||||
int value;
|
||||
GenericChatroomWidget* next = nullptr;
|
||||
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
|
||||
|
||||
// Find the first next, to avoid nullptr.
|
||||
|
@ -151,8 +151,8 @@ void NotificationScrollArea::findNextWidget()
|
|||
|
||||
void NotificationScrollArea::findPreviousWidget()
|
||||
{
|
||||
GenericChatroomWidget* next = nullptr;
|
||||
int value;
|
||||
GenericChatroomWidget* next = nullptr;
|
||||
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
|
||||
|
||||
// Find the first next, to avoid nullptr.
|
||||
|
|
286
src/widget/tool/movablewidget.cpp
Normal file
286
src/widget/tool/movablewidget.cpp
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 "movablewidget.h"
|
||||
#include <QMouseEvent>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
MovableWidget::MovableWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setMinimumHeight(64);
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
|
||||
actualSize = minimumSize();
|
||||
boundaryRect = QRect(0, 0, 0, 0);
|
||||
setRatio(1.0f);
|
||||
resize(minimumSize());
|
||||
actualPos = QPoint(0, 0);
|
||||
}
|
||||
|
||||
void MovableWidget::resetBoundary(QRect newBoundary)
|
||||
{
|
||||
boundaryRect = newBoundary;
|
||||
resize(QSize(round(actualSize.width()), round(actualSize.height())));
|
||||
|
||||
QPoint moveTo = QPoint(round(actualPos.x()), round(actualPos.y()));
|
||||
checkBoundary(moveTo);
|
||||
move(moveTo);
|
||||
actualPos = moveTo;
|
||||
}
|
||||
|
||||
void MovableWidget::setBoundary(QRect newBoundary)
|
||||
{
|
||||
if (boundaryRect.isNull())
|
||||
{
|
||||
boundaryRect = newBoundary;
|
||||
return;
|
||||
}
|
||||
|
||||
float changeX = newBoundary.width() / static_cast<float>(boundaryRect.width());
|
||||
float changeY = newBoundary.height() / static_cast<float>(boundaryRect.height());
|
||||
|
||||
float percentageX = (x() - boundaryRect.x()) / static_cast<float>(boundaryRect.width() - width());
|
||||
float percentageY = (y() - boundaryRect.y()) / static_cast<float>(boundaryRect.height() - height());
|
||||
|
||||
actualSize.setWidth(actualSize.width() * changeX);
|
||||
actualSize.setHeight(actualSize.height() * changeY);
|
||||
|
||||
if (actualSize.width() == 0)
|
||||
actualSize.setWidth(1);
|
||||
|
||||
if (actualSize.height() == 0)
|
||||
actualSize.setHeight(1);
|
||||
|
||||
resize(QSize(round(actualSize.width()), round(actualSize.height())));
|
||||
|
||||
actualPos = QPointF(percentageX * (newBoundary.width() - width()), percentageY * (newBoundary.height() - height()));
|
||||
actualPos += QPointF(newBoundary.topLeft());
|
||||
|
||||
QPoint moveTo = QPoint(round(actualPos.x()), round(actualPos.y()));
|
||||
move(moveTo);
|
||||
|
||||
boundaryRect = newBoundary;
|
||||
|
||||
}
|
||||
|
||||
float MovableWidget::getRatio() const
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
void MovableWidget::setRatio(float r)
|
||||
{
|
||||
ratio = r;
|
||||
resize(width(), width() / ratio);
|
||||
QPoint position = QPoint(actualPos.x(), actualPos.y());
|
||||
checkBoundary(position);
|
||||
move(position);
|
||||
|
||||
actualPos = pos();
|
||||
actualSize = size();
|
||||
}
|
||||
|
||||
void MovableWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
if (!(mode & Resize))
|
||||
mode |= Moving;
|
||||
|
||||
lastPoint = event->globalPos();
|
||||
}
|
||||
}
|
||||
|
||||
void MovableWidget::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (mode & Moving)
|
||||
{
|
||||
QPoint moveTo = pos() - (lastPoint - event->globalPos());
|
||||
checkBoundary(moveTo);
|
||||
|
||||
move(moveTo);
|
||||
lastPoint = event->globalPos();
|
||||
|
||||
actualPos = pos();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(event->buttons() & Qt::LeftButton))
|
||||
{
|
||||
if (event->x() < 6)
|
||||
mode |= ResizeLeft;
|
||||
else
|
||||
mode &= ~ResizeLeft;
|
||||
|
||||
if (event->y() < 6)
|
||||
mode |= ResizeUp;
|
||||
else
|
||||
mode &= ~ResizeUp;
|
||||
|
||||
if (event->x() > width() - 6)
|
||||
mode |= ResizeRight;
|
||||
else
|
||||
mode &= ~ResizeRight;
|
||||
|
||||
if (event->y() > height() - 6)
|
||||
mode |= ResizeDown;
|
||||
else
|
||||
mode &= ~ResizeDown;
|
||||
}
|
||||
|
||||
if (mode & Resize)
|
||||
{
|
||||
const Modes ResizeUpRight = ResizeUp | ResizeRight;
|
||||
const Modes ResizeUpLeft = ResizeUp | ResizeLeft;
|
||||
const Modes ResizeDownRight = ResizeDown | ResizeRight;
|
||||
const Modes ResizeDownLeft = ResizeDown | ResizeLeft;
|
||||
|
||||
if ((mode & ResizeUpRight) == ResizeUpRight || (mode & ResizeDownLeft) == ResizeDownLeft)
|
||||
setCursor(Qt::SizeBDiagCursor);
|
||||
else if ((mode & ResizeUpLeft) == ResizeUpLeft || (mode & ResizeDownRight) == ResizeDownRight)
|
||||
setCursor(Qt::SizeFDiagCursor);
|
||||
else if (mode & (ResizeLeft | ResizeRight))
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
else
|
||||
setCursor(Qt::SizeVerCursor);
|
||||
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
QPoint lastPosition = pos();
|
||||
QPoint displacement = lastPoint - event->globalPos();
|
||||
QSize lastSize = size();
|
||||
|
||||
|
||||
if (mode & ResizeUp)
|
||||
{
|
||||
lastSize.setHeight(height() + displacement.y());
|
||||
|
||||
if (lastSize.height() > maximumHeight())
|
||||
lastPosition.setY(y() - displacement.y() + (lastSize.height() - maximumHeight()));
|
||||
else
|
||||
lastPosition.setY(y() - displacement.y());
|
||||
}
|
||||
|
||||
if (mode & ResizeLeft)
|
||||
{
|
||||
lastSize.setWidth(width() + displacement.x());
|
||||
if (lastSize.width() > maximumWidth())
|
||||
lastPosition.setX(x() - displacement.x() + (lastSize.width() - maximumWidth()));
|
||||
else
|
||||
lastPosition.setX(x() - displacement.x());
|
||||
}
|
||||
|
||||
if (mode & ResizeRight)
|
||||
lastSize.setWidth(width() - displacement.x());
|
||||
|
||||
if (mode & ResizeDown)
|
||||
lastSize.setHeight(height() - displacement.y());
|
||||
|
||||
if (lastSize.height() > maximumHeight())
|
||||
lastSize.setHeight(maximumHeight());
|
||||
|
||||
if (lastSize.width() > maximumWidth())
|
||||
lastSize.setWidth(maximumWidth());
|
||||
|
||||
if (mode & (ResizeLeft | ResizeRight))
|
||||
{
|
||||
if (mode & (ResizeUp | ResizeDown))
|
||||
{
|
||||
int height = lastSize.width() / getRatio();
|
||||
|
||||
if (!(mode & ResizeDown))
|
||||
lastPosition.setY(lastPosition.y() - (height - lastSize.height()));
|
||||
|
||||
resize(lastSize.width(), height);
|
||||
|
||||
if (lastSize.width() < minimumWidth())
|
||||
lastPosition.setX(pos().x());
|
||||
|
||||
if (height < minimumHeight())
|
||||
lastPosition.setY(pos().y());
|
||||
}
|
||||
else
|
||||
{
|
||||
resize(lastSize.width(), lastSize.width() / getRatio());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resize(lastSize.height() * getRatio(), lastSize.height());
|
||||
}
|
||||
|
||||
updateGeometry();
|
||||
|
||||
checkBoundary(lastPosition);
|
||||
|
||||
move(lastPosition);
|
||||
|
||||
lastPoint = event->globalPos();
|
||||
actualSize = size();
|
||||
actualPos = pos();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MovableWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (!(event->buttons() & Qt::LeftButton))
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
void MovableWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if (!(event->buttons() & Qt::LeftButton))
|
||||
return;
|
||||
|
||||
if (!graphicsEffect())
|
||||
{
|
||||
QGraphicsOpacityEffect* opacityEffect = new QGraphicsOpacityEffect(this);
|
||||
opacityEffect->setOpacity(0.5);
|
||||
setGraphicsEffect(opacityEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
setGraphicsEffect(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MovableWidget::checkBoundary(QPoint& point) const
|
||||
{
|
||||
int x1, y1, x2, y2;
|
||||
boundaryRect.getCoords(&x1, &y1, &x2, &y2);
|
||||
|
||||
if (point.x() < boundaryRect.left())
|
||||
point.setX(boundaryRect.left());
|
||||
|
||||
if (point.y() < boundaryRect.top())
|
||||
point.setY(boundaryRect.top());
|
||||
|
||||
if (point.x() + width() > boundaryRect.right() + 1)
|
||||
point.setX(boundaryRect.right() - width() + 1);
|
||||
|
||||
if (point.y() + height() > boundaryRect.bottom() + 1)
|
||||
point.setY(boundaryRect.bottom() - height() + 1);
|
||||
}
|
64
src/widget/tool/movablewidget.h
Normal file
64
src/widget/tool/movablewidget.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright © 2015 by The qTox Project
|
||||
|
||||
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 MOVABLEWIDGET_H
|
||||
#define MOVABLEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class MovableWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
MovableWidget(QWidget* parent);
|
||||
void resetBoundary(QRect newBoundary);
|
||||
void setBoundary(QRect newBoundary);
|
||||
float getRatio() const;
|
||||
void setRatio(float r);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseMoveEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
|
||||
private:
|
||||
void checkBoundary(QPoint& point) const;
|
||||
void checkBoundaryLeft(int &x) const;
|
||||
|
||||
typedef uint8_t Modes;
|
||||
|
||||
enum Mode : Modes
|
||||
{
|
||||
Moving = 0x01,
|
||||
ResizeLeft = 0x02,
|
||||
ResizeRight = 0x04,
|
||||
ResizeUp = 0x08,
|
||||
ResizeDown = 0x10,
|
||||
Resize = ResizeLeft | ResizeRight | ResizeUp | ResizeDown
|
||||
};
|
||||
|
||||
Modes mode = 0;
|
||||
QPoint lastPoint;
|
||||
QRect boundaryRect;
|
||||
QSizeF actualSize;
|
||||
QPointF actualPos;
|
||||
float ratio;
|
||||
};
|
||||
|
||||
#endif // MOVABLEWIDGET_H
|
|
@ -1507,7 +1507,8 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
|
|||
}
|
||||
else if (change == TOX_CHAT_CHANGE_PEER_NAME) // core overwrites old name before telling us it changed...
|
||||
{
|
||||
g->updatePeer(peernumber,Nexus::getCore()->getGroupPeerName(groupnumber, peernumber));
|
||||
qDebug() << "UPDATING PEER";
|
||||
g->updatePeer(peernumber, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user