diff --git a/README.md b/README.md
index 9609fee0c..6264fbf25 100644
--- a/README.md
+++ b/README.md
@@ -15,31 +15,73 @@ However, it is not a fork.
- Tox DNS
- Translations in various languages
-
Requirements
+
Downloads
-This client runs on Windows, Linux and Mac natively, but is not build regularly for Linux
-Linux users will have to compile the source code themselves if they want the latest updates.
+This client runs on Windows, Linux and Mac natively. Windows download
-Mac download
-Linux download (12st July 2014 20:30 GMT)
-Note that the Linux download has not been tested and may not be up to date.
+Mac download
+Linux download (click "Last successful artifacts")
Screenshots
Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features
-
Compiling
-Compiling toxgui requires Qt 5.2 with the Qt Multimedia module and a C++11 compatible compiler.
-It also requires the toxcore and toxav libraries.
+
Compiling on GNU-Linux
+
Acquiring dependencies
+Compiling qTox requires several dependencies, however these are easily installable
+with your system's package manager. The step-by-step instructions assume Debian-style apt, but
+it should be easy enough to get equivalent packages with yum or pacman.
-To compile, first clone or download the qTox repository and open a terminal in the qTox folder.
-Then run the script bootstrap.sh (for Linux and Mac) or bootsrap.bat (for Windows) to download an up-to-date toxcore.
-And finally run the commands "qmake" and "make" to start building qTox.
+First, we need Qt 5.2 with a C++11 compatible compiler:
+```bash
+sudo apt-get install build-essential qt5-qmake qt5-default
+```
+toxcore and toxav, the client-agnostic network code for Tox, has several dependencies
+of its own (see its installation guide for more details):
+```bash
+sudo apt-get install libtool autotools-dev automake checkinstall check git yasm libopus-dev libvpx-dev
+```
-
+
+Having acquired all the dependencies, the following commands should get and compile qTox:
+
+```bash
+wget -O qtox.tgz https://github.com/tux3/qTox/archive/master.tar.gz
+tar xvf qtox.tgz
+cd qTox-master
+./bootstrap.sh # This will automagically download and compile libsodium, toxcore, and toxav
+qmake
+make # Should compile to "qtox"
+```
+
+And that's it!
+
+
Building packages
+
+qTox now has the experimental and probably-dodgy ability to package itself (in .deb
+form natively, and .rpm form with alien).
+
+After installing the required dependencies, run `bootstrap.sh` and then run the
+`buildPackages.sh` script, found in the tools folder. It will automatically get the
+packages necessary for building .debs, so be prepared to type your password for sudo.
+
+
OSX Easy Install
+
+Since https://github.com/ReDetection/homebrew-qtox you can easily install qtox with homebrew
+```bash
+brew install --HEAD ReDetection/qtox/qtox
+```
+
+
OSX Full Install Guide
This guide is intended for people who wish to use an existing or new ProjectTox-Core installation separate to the bundled installation with qTox, if you do not wish to use a separate installation you can skip to the section titled 'Final Steps'.
diff --git a/audiobuffer.cpp b/audiobuffer.cpp
deleted file mode 100644
index 9ca0960bb..000000000
--- a/audiobuffer.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- Copyright (C) 2014 by Project Tox
-
- This file is part of qTox, a Qt-based graphical interface for Tox.
-
- This program 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.
- This program 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 COPYING file for more details.
-*/
-
-#include "audiobuffer.h"
-
-AudioBuffer::AudioBuffer() :
- QIODevice(0)
-{
- open(QIODevice::ReadWrite);
-}
-
-AudioBuffer::~AudioBuffer()
-{
- close();
-}
-
-qint64 AudioBuffer::readData(char *data, qint64 len)
-{
- qint64 total;
- bufferMutex.lock();
- try {
- total = qMin((qint64)buffer.size(), len);
- memcpy(data, buffer.constData(), total);
- buffer = buffer.mid(total);
- }
- catch (...)
- {
- bufferMutex.unlock();
- return 0;
- }
- bufferMutex.unlock();
- return total;
-}
-
-qint64 AudioBuffer::writeData(const char* data, qint64 len)
-{
- bufferMutex.lock();
- try {
- buffer.append(data, len);
- }
- catch (...)
- {
- bufferMutex.unlock();
- return 0;
- }
- bufferMutex.unlock();
- return len;
-}
-
-qint64 AudioBuffer::bytesAvailable() const
-{
- bufferMutex.lock();
- long long size = buffer.size() + QIODevice::bytesAvailable();
- bufferMutex.unlock();
- return size;
-}
-
-qint64 AudioBuffer::bufferSize() const
-{
- bufferMutex.lock();
- long long size = buffer.size();
- bufferMutex.unlock();
- return size;
-}
-
-void AudioBuffer::clear()
-{
- bufferMutex.lock();
- buffer.clear();
- bufferMutex.unlock();
-}
diff --git a/bootstrap.sh b/bootstrap.sh
index cc25129f8..2f7067fb6 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -10,8 +10,10 @@ INSTALL_DIR=libs
# just for convenience
BASE_DIR=${SCRIPT_DIR}/${INSTALL_DIR}
+SODIUM_VER=0.7.0
+
# directory names of cloned repositories
-SODIUM_DIR=libsodium-0.5.0
+SODIUM_DIR=libsodium-$SODIUM_VER
TOX_CORE_DIR=libtoxcore-latest
# this boolean describes whether the installation of
@@ -19,6 +21,8 @@ TOX_CORE_DIR=libtoxcore-latest
# the default value is 'false' and will be set to 'true'
# if this script gets the parameter -t or --tox
TOX_ONLY=false
+GLOBAL=false
+KEEP=false
if [ -z "$BASE_DIR" ]; then
echo "internal error detected!"
@@ -41,9 +45,16 @@ fi
########## check input parameters ##########
-if [ $# -ge 1 ] ; then
+while [ $# -ge 1 ] ; do
if [ ${1} = "-t" -o ${1} = "--tox" ] ; then
TOX_ONLY=true
+ shift
+ elif [ ${1} = "-g" -o ${1} = "--global" ] ; then
+ GLOBAL=true
+ shift
+ elif [ ${1} = "-k" -o ${1} = "--keep" ]; then
+ KEEP=true
+ shift
else
if [ ${1} != "-h" -a ${1} != "--help" ] ; then
echo "[ERROR] Unknown parameter \"${1}\""
@@ -54,21 +65,26 @@ if [ $# -ge 1 ] ; then
echo "Use this script to install/update libsodium and libtoxcore in ${INSTALL_DIR}"
echo ""
echo "usage:"
- echo " ${0} [-t|--tox|-h|--help]"
+ echo " ${0} [-t|--tox|-h|--help|-g|--global|-k|--keep]"
echo ""
echo "parameters:"
- echo " -h|--help: displays this help"
- echo " -t|--tox : only install/update libtoxcore"
- echo " requires an already installed libsodium"
+ echo " -h|--help : displays this help"
+ echo " -t|--tox : only install/update libtoxcore"
+ echo " requires an already installed libsodium"
+ echo " -g|--global: installs libtox* and libsodium globally"
+ echo " (also disables local configure prefixes)"
+ echo " -k|--keep : does not delete the build directories afterwards"
echo ""
echo "example usages:"
echo " ${0} -- to install libsodium and libtoxcore"
echo " ${0} -t -- to update already installed libtoxcore"
exit 1
fi
-fi
-
+done
+echo "Tox only: $TOX_ONLY"
+echo "Global : $GLOBAL"
+echo "Keep : $KEEP"
############### prepare step ###############
# create BASE_DIR directory if necessary
@@ -83,17 +99,29 @@ rm -rf ${BASE_DIR}/${TOX_CORE_DIR}
############### install step ###############
-# clone current master of libsodium and switch to version 0.5.0
+# clone current master of libsodium and switch to version $SODIUM_VER
# afterwards install libsodium to INSTALL_DIR
# skip the installation if TOX_ONLY is true
if [[ $TOX_ONLY = "false" ]]; then
git clone git://github.com/jedisct1/libsodium.git ${BASE_DIR}/${SODIUM_DIR}
pushd ${BASE_DIR}/${SODIUM_DIR}
- git checkout tags/0.5.0
+ git checkout tags/$SODIUM_VER
./autogen.sh
- ./configure --prefix=${BASE_DIR}/
+
+ if [[ $GLOBAL = "false" ]]; then
+ ./configure --prefix=${BASE_DIR}/
+ else
+ ./configure
+ fi
+
make -j2 check
- make install
+
+ if [[ $GLOBAL = "false" ]]; then
+ make install
+ else
+ sudo make install
+ fi
+
popd
fi
@@ -103,14 +131,25 @@ fi
git clone https://github.com/irungentoo/toxcore.git ${BASE_DIR}/${TOX_CORE_DIR}
pushd ${BASE_DIR}/${TOX_CORE_DIR}
./autogen.sh
-./configure --prefix=${BASE_DIR}/ --with-libsodium-headers=${BASE_DIR}/include --with-libsodium-libs=${BASE_DIR}/lib
+if [[ $GLOBAL = "false" ]]; then
+ ./configure --prefix=${BASE_DIR}/ --with-libsodium-headers=${BASE_DIR}/include --with-libsodium-libs=${BASE_DIR}/lib
+else
+ ./configure
+fi
+
make -j2
-make install
+
+if [[ $GLOBAL = "false" ]]; then
+ make install
+else
+ sudo make install
+fi
+
popd
-
-
############### cleanup step ###############
# remove cloned repositories
-rm -rf ${BASE_DIR}/${SODIUM_DIR}
-rm -rf ${BASE_DIR}/${TOX_CORE_DIR}
+if [[ $KEEP = "false" ]]; then
+ rm -rf ${BASE_DIR}/${SODIUM_DIR}
+ rm -rf ${BASE_DIR}/${TOX_CORE_DIR}
+fi
diff --git a/core.cpp b/core.cpp
index 2403dcc2b..fbba751c0 100644
--- a/core.cpp
+++ b/core.cpp
@@ -20,6 +20,9 @@
#include "settings.h"
#include "widget/widget.h"
+#include
+#include
+
#include
#include
#include
@@ -33,10 +36,6 @@ const QString Core::CONFIG_FILE_NAME = "data";
const QString Core::TOX_EXT = ".tox";
QList Core::fileSendQueue;
QList Core::fileRecvQueue;
-ToxCall Core::calls[TOXAV_MAX_CALLS];
-const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
-uint8_t* Core::videobuf;
-int Core::videoBusyness;
Core::Core(Camera* cam, QThread *coreThread) :
tox(nullptr), camera(cam)
@@ -48,8 +47,6 @@ Core::Core(Camera* cam, QThread *coreThread) :
toxTimer->setSingleShot(true);
//saveTimer = new QTimer(this);
//saveTimer->start(TOX_SAVE_INTERVAL);
- //fileTimer = new QTimer(this);
- //fileTimer->start(TOX_FILE_INTERVAL);
bootstrapTimer = new QTimer(this);
bootstrapTimer->start(TOX_BOOTSTRAP_INTERVAL);
connect(toxTimer, &QTimer::timeout, this, &Core::process);
@@ -63,11 +60,32 @@ Core::Core(Camera* cam, QThread *coreThread) :
{
calls[i].sendAudioTimer = new QTimer();
calls[i].sendVideoTimer = new QTimer();
- calls[i].audioBuffer.moveToThread(coreThread);
calls[i].sendAudioTimer->moveToThread(coreThread);
calls[i].sendVideoTimer->moveToThread(coreThread);
connect(calls[i].sendVideoTimer, &QTimer::timeout, [this,i](){sendCallVideo(i);});
}
+
+ // OpenAL init
+ alOutDev = alcOpenDevice(nullptr);
+ if (!alOutDev)
+ {
+ qWarning() << "Core: Cannot open output audio device";
+ }
+ else
+ {
+ alContext=alcCreateContext(alOutDev,nullptr);
+ if (!alcMakeContextCurrent(alContext))
+ {
+ qWarning() << "Core: Cannot create output audio context";
+ alcCloseDevice(alOutDev);
+ }
+ else
+ alGenSources(1, &alMainSource);
+ }
+ alInDev = alcCaptureOpenDevice(NULL,av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16,
+ (av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
+ if (!alInDev)
+ qWarning() << "Core: Cannot open input audio device";
}
Core::~Core()
@@ -83,6 +101,16 @@ Core::~Core()
delete[] videobuf;
videobuf=nullptr;
}
+
+ if (alContext)
+ {
+ alcMakeContextCurrent(nullptr);
+ alcDestroyContext(alContext);
+ }
+ if (alOutDev)
+ alcCloseDevice(alOutDev);
+ if (alInDev)
+ alcCaptureCloseDevice(alInDev);
}
void Core::start()
@@ -93,12 +121,36 @@ void Core::start()
qDebug() << "Core starting with IPv6 enabled";
else
qWarning() << "Core starting with IPv6 disabled. LAN discovery may not work properly.";
- tox = tox_new(enableIPv6);
+
+ Tox_Options toxOptions;
+ toxOptions.ipv6enabled = enableIPv6;
+ toxOptions.udp_disabled = 0;
+ toxOptions.proxy_enabled = false;
+ toxOptions.proxy_address[0] = 0;
+ toxOptions.proxy_port = 0;
+
+ tox = tox_new(&toxOptions);
if (tox == nullptr)
{
- qCritical() << "Tox core failed to start";
- emit failedToStart();
- return;
+ if (enableIPv6) // Fallback to IPv4
+ {
+ toxOptions.ipv6enabled = false;
+ tox = tox_new(&toxOptions);
+ if (tox == nullptr)
+ {
+ qCritical() << "Tox core failed to start";
+ emit failedToStart();
+ return;
+ }
+ else
+ qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery may not work properly.";
+ }
+ else
+ {
+ qCritical() << "Tox core failed to start";
+ emit failedToStart();
+ return;
+ }
}
toxav = toxav_new(tox, TOXAV_MAX_CALLS);
@@ -109,6 +161,8 @@ void Core::start()
return;
}
+ qsrand(time(nullptr));
+
// where do we find the data file?
QString path;
{ // read data from whose profile?
@@ -153,8 +207,8 @@ void Core::start()
toxav_register_callstate_callback(toxav, onAvRequestTimeout, av_OnRequestTimeout, this);
toxav_register_callstate_callback(toxav, onAvPeerTimeout, av_OnPeerTimeout, this);
- toxav_register_audio_recv_callback(toxav, playCallAudio);
- toxav_register_video_recv_callback(toxav, playCallVideo);
+ toxav_register_audio_recv_callback(toxav, playCallAudio, this);
+ toxav_register_video_recv_callback(toxav, playCallVideo, this);
uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(tox, friendAddress);
@@ -261,7 +315,7 @@ void Core::onFileSendRequestCallback(Tox*, int32_t friendnumber, uint8_t filenum
fileRecvQueue.append(file);
emit static_cast(core)->fileReceiveRequested(fileRecvQueue.last());
}
-void Core::onFileControlCallback(Tox*, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
+void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
uint8_t control_type, const uint8_t*, uint16_t, void *core)
{
ToxFile* file{nullptr};
@@ -292,12 +346,15 @@ void Core::onFileControlCallback(Tox*, int32_t friendnumber, uint8_t receive_sen
qWarning("Core::onFileControlCallback: No such file in queue");
return;
}
- if (control_type == TOX_FILECONTROL_ACCEPT && receive_send == 1)
+ if (receive_send == 1 && control_type == TOX_FILECONTROL_ACCEPT)
{
file->status = ToxFile::TRANSMITTING;
emit static_cast(core)->fileTransferAccepted(*file);
qDebug() << "Core: File control callback, file accepted";
- file->sendFuture = QtConcurrent::run(sendAllFileData, static_cast(core), file);
+ file->sendTimer = new QTimer(static_cast(core));
+ connect(file->sendTimer, &QTimer::timeout, std::bind(sendAllFileData,static_cast(core), file));
+ file->sendTimer->setSingleShot(true);
+ file->sendTimer->start(TOX_FILE_INTERVAL);
}
else if (receive_send == 1 && control_type == TOX_FILECONTROL_KILL)
{
@@ -305,8 +362,26 @@ void Core::onFileControlCallback(Tox*, int32_t friendnumber, uint8_t receive_sen
.arg(file->fileNum).arg(file->friendId);
file->status = ToxFile::STOPPED;
emit static_cast(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
- file->sendFuture.waitForFinished(); // Wait for sendAllFileData to return before deleting the ToxFile
- removeFileFromQueue(true, file->friendId, file->fileNum);
+ // Wait for sendAllFileData to return before deleting the ToxFile, we MUST ensure this or we'll use after free
+ if (file->sendTimer)
+ {
+ QThread::msleep(1);
+ qApp->processEvents();
+ if (file->sendTimer)
+ {
+ delete file->sendTimer;
+ file->sendTimer = nullptr;
+ }
+ }
+ removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
+ }
+ else if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED)
+ {
+ qDebug() << QString("Core::onFileControlCallback: Transfer of file %1 to friend %2 is complete")
+ .arg(file->fileNum).arg(file->friendId);
+ file->status = ToxFile::STOPPED;
+ emit static_cast(core)->fileTransferFinished(*file);
+ removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
}
else if (receive_send == 0 && control_type == TOX_FILECONTROL_KILL)
{
@@ -314,7 +389,7 @@ void Core::onFileControlCallback(Tox*, int32_t friendnumber, uint8_t receive_sen
.arg(file->fileNum).arg(file->friendId);
file->status = ToxFile::STOPPED;
emit static_cast(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::RECEIVING);
- removeFileFromQueue(false, file->friendId, file->fileNum);
+ removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
}
else if (receive_send == 0 && control_type == TOX_FILECONTROL_FINISHED)
{
@@ -322,7 +397,9 @@ void Core::onFileControlCallback(Tox*, int32_t friendnumber, uint8_t receive_sen
.arg(file->fileNum).arg(file->friendId);
file->status = ToxFile::STOPPED;
emit static_cast(core)->fileTransferFinished(*file);
- removeFileFromQueue(false, file->friendId, file->fileNum);
+ // confirm receive is complete
+ tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
+ removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
}
else
{
@@ -376,6 +453,19 @@ void Core::requestFriendship(const QString& friendAddress, const QString& messag
if (friendId < 0) {
emit failedToAddFriend(userId);
} else {
+ // Update our friendAddresses
+ bool found=false;
+ QList& friendAddresses = Settings::getInstance().friendAddresses;
+ for (QString& addr : friendAddresses)
+ {
+ if (addr.toUpper().contains(friendAddress))
+ {
+ addr = friendAddress;
+ found = true;
+ }
+ }
+ if (!found)
+ friendAddresses.append(friendAddress);
emit friendAdded(friendId, userId);
}
saveConfiguration();
@@ -445,7 +535,7 @@ void Core::pauseResumeFileSend(int friendId, int fileNum)
}
if (!file)
{
- qWarning("Core::cancelFileSend: No such file in queue");
+ qWarning("Core::pauseResumeFileSend: No such file in queue");
return;
}
if (file->status == ToxFile::TRANSMITTING)
@@ -515,7 +605,7 @@ void Core::cancelFileSend(int friendId, int fileNum)
file->status = ToxFile::STOPPED;
emit fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
- file->sendFuture.waitForFinished(); // Wait until sendAllFileData returns before deleting
+ while (file->sendTimer) QThread::msleep(1); // Wait until sendAllFileData returns before deleting
removeFileFromQueue(true, friendId, fileNum);
}
@@ -696,25 +786,36 @@ void Core::onFileTransferFinished(ToxFile file)
void Core::bootstrapDht()
{
- qDebug() << "Core: Bootstraping DHT";
const Settings& s = Settings::getInstance();
QList dhtServerList = s.getDhtServerList();
- static int j = 0;
- int i=0;
int listSize = dhtServerList.size();
- while (i<5)
+ static int j = qrand() % listSize, n=0;
+
+ // We couldn't connect after trying 6 different nodes, let's try something else
+ if (n>3)
+ {
+ qDebug() << "Core: We're having trouble connecting to the DHT, slowing down";
+ bootstrapTimer->setInterval(TOX_BOOTSTRAP_INTERVAL*(n-1));
+ }
+ else
+ qDebug() << "Core: Connecting to the DHT ...";
+
+ int i=0;
+ while (i < (2 - (n>3)))
{
const Settings::DhtServer& dhtServer = dhtServerList[j % listSize];
if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(),
- 0, qToBigEndian(dhtServer.port), CUserId(dhtServer.userId).data()) == 1)
+ qToBigEndian(dhtServer.port), CUserId(dhtServer.userId).data()) == 1)
qDebug() << QString("Core: Bootstraping from ")+dhtServer.name+QString(", addr ")+dhtServer.address.toLatin1().data()
+QString(", port ")+QString().setNum(dhtServer.port);
else
qDebug() << "Core: Error bootstraping from "+dhtServer.name;
+ tox_do(tox);
j++;
i++;
+ n++;
}
}
@@ -825,7 +926,7 @@ void Core::saveConfiguration(const QString& path)
qWarning() << "Core::saveConfiguration: Tox not started, aborting!";
return;
}
-
+
QSaveFile configurationFile(path);
if (!configurationFile.open(QIODevice::WriteOnly)) {
qCritical() << "File " << path << " cannot be opened";
@@ -840,8 +941,10 @@ void Core::saveConfiguration(const QString& path)
configurationFile.write(reinterpret_cast(data), fileSize);
configurationFile.commit();
delete[] data;
- //configurationFile.close();
}
+
+ qDebug() << "Core: writing settings";
+ Settings::getInstance().save();
}
void Core::loadFriends()
@@ -981,486 +1084,85 @@ void Core::removeFileFromQueue(bool sendQueue, int friendId, int fileId)
void Core::sendAllFileData(Core *core, ToxFile* file)
{
- while (file->bytesSent < file->filesize)
+ if (file->status == ToxFile::PAUSED)
{
- if (file->status == ToxFile::PAUSED)
- {
- QThread::sleep(5);
- continue;
- }
- else if (file->status == ToxFile::STOPPED)
- {
- qWarning("Core::sendAllFileData: File is stopped");
- return;
- }
- emit core->fileTransferInfo(file->friendId, file->fileNum, file->filesize, file->bytesSent, ToxFile::SENDING);
- qApp->processEvents();
- long long chunkSize = tox_file_data_size(core->tox, file->friendId);
- if (chunkSize == -1)
- {
- qWarning("Core::fileHeartbeat: Error getting preffered chunk size, aborting file send");
- file->status = ToxFile::STOPPED;
- emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
- tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
- removeFileFromQueue(true, file->friendId, file->fileNum);
- return;
- }
- qDebug() << "chunkSize: " << chunkSize;
- chunkSize = std::min(chunkSize, file->filesize);
- uint8_t* data = new uint8_t[chunkSize];
- file->file->seek(file->bytesSent);
- int readSize = file->file->read((char*)data, chunkSize);
- if (readSize == -1)
- {
- qWarning() << QString("Core::sendAllFileData: Error reading from file: %1").arg(file->file->errorString());
- delete[] data;
- QThread::msleep(5);
- continue;
- }
- else if (readSize == 0)
- {
- qWarning() << QString("Core::sendAllFileData: Nothing to read from file: %1").arg(file->file->errorString());
- delete[] data;
- QThread::msleep(5);
- continue;
- }
- if (tox_file_send_data(core->tox, file->friendId, file->fileNum, data, readSize) == -1)
- {
- //qWarning("Core::fileHeartbeat: Error sending data chunk");
- core->process();
- delete[] data;
- QThread::msleep(5);
- continue;
- }
+ file->sendTimer->start(5+TOX_FILE_INTERVAL);
+ return;
+ }
+ else if (file->status == ToxFile::STOPPED)
+ {
+ qWarning("Core::sendAllFileData: File is stopped");
+ file->sendTimer->disconnect();
+ delete file->sendTimer;
+ file->sendTimer = nullptr;
+ return;
+ }
+ emit core->fileTransferInfo(file->friendId, file->fileNum, file->filesize, file->bytesSent, ToxFile::SENDING);
+ qApp->processEvents();
+ long long chunkSize = tox_file_data_size(core->tox, file->friendId);
+ if (chunkSize == -1)
+ {
+ qWarning("Core::fileHeartbeat: Error getting preffered chunk size, aborting file send");
+ file->status = ToxFile::STOPPED;
+ emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
+ tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
+ removeFileFromQueue(true, file->friendId, file->fileNum);
+ return;
+ }
+ //qDebug() << "chunkSize: " << chunkSize;
+ chunkSize = std::min(chunkSize, file->filesize);
+ uint8_t* data = new uint8_t[chunkSize];
+ file->file->seek(file->bytesSent);
+ int readSize = file->file->read((char*)data, chunkSize);
+ if (readSize == -1)
+ {
+ qWarning() << QString("Core::sendAllFileData: Error reading from file: %1").arg(file->file->errorString());
delete[] data;
- file->bytesSent += readSize;
- //qDebug() << QString("Core::fileHeartbeat: sent %1/%2 bytes").arg(file->bytesSent).arg(file->fileData.size());
- }
- qDebug("Core::fileHeartbeat: Transfer finished");
- tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
- file->status = ToxFile::STOPPED;
- emit core->fileTransferFinished(*file);
- removeFileFromQueue(true, file->friendId, file->fileNum);
-}
-
-void Core::onAvInvite(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV invite";
+ file->status = ToxFile::STOPPED;
+ emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
+ tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
+ removeFileFromQueue(true, file->friendId, file->fileNum);
return;
}
-
- int transType = toxav_get_peer_transmission_type(toxav, call_index, 0);
- if (transType == TypeVideo)
+ else if (readSize == 0)
{
- qDebug() << QString("Core: AV invite from %1 with video").arg(friendId);
- emit static_cast(core)->avInvite(friendId, call_index, true);
+ qWarning() << QString("Core::sendAllFileData: Nothing to read from file: %1").arg(file->file->errorString());
+ delete[] data;
+ file->status = ToxFile::STOPPED;
+ emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
+ tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
+ removeFileFromQueue(true, file->friendId, file->fileNum);
+ return;
+ }
+ if (tox_file_send_data(core->tox, file->friendId, file->fileNum, data, readSize) == -1)
+ {
+ //qWarning("Core::fileHeartbeat: Error sending data chunk");
+ //core->process();
+ delete[] data;
+ //QThread::msleep(1);
+ file->sendTimer->start(1+TOX_FILE_INTERVAL);
+ return;
+ }
+ delete[] data;
+ file->bytesSent += readSize;
+ //qDebug() << QString("Core::fileHeartbeat: sent %1/%2 bytes").arg(file->bytesSent).arg(file->fileData.size());
+
+ if (file->bytesSent < file->filesize)
+ {
+ file->sendTimer->start(TOX_FILE_INTERVAL);
+ return;
}
else
{
- qDebug() << QString("Core: AV invite from %1 without video").arg(friendId);
- emit static_cast(core)->avInvite(friendId, call_index, false);
+ //qDebug("Core: File transfer finished");
+ file->sendTimer->disconnect();
+ delete file->sendTimer;
+ file->sendTimer = nullptr;
+ tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
+ //emit core->fileTransferFinished(*file);
}
}
-void Core::onAvStart(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV start";
- return;
- }
-
- int transType = toxav_get_peer_transmission_type(toxav, call_index, 0);
- if (transType == TypeVideo)
- {
- qDebug() << QString("Core: AV start from %1 with video").arg(friendId);
- prepareCall(friendId, call_index, toxav, true);
- emit static_cast(core)->avStart(friendId, call_index, true);
- }
- else
- {
- qDebug() << QString("Core: AV start from %1 without video").arg(friendId);
- prepareCall(friendId, call_index, toxav, false);
- emit static_cast(core)->avStart(friendId, call_index, false);
- }
-}
-
-void Core::onAvCancel(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV cancel";
- return;
- }
- qDebug() << QString("Core: AV cancel from %1").arg(friendId);
-
- emit static_cast(core)->avCancel(friendId, call_index);
-}
-
-void Core::onAvReject(void*, int32_t, void*)
-{
- qDebug() << "Core: AV reject";
-}
-
-void Core::onAvEnd(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV end";
- return;
- }
- qDebug() << QString("Core: AV end from %1").arg(friendId);
-
- cleanupCall(call_index);
-
- emit static_cast(core)->avEnd(friendId, call_index);
-}
-
-void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV ringing";
- return;
- }
-
- if (calls[call_index].videoEnabled)
- {
- qDebug() << QString("Core: AV ringing with %1 with video").arg(friendId);
- emit static_cast(core)->avRinging(friendId, call_index, true);
- }
- else
- {
- qDebug() << QString("Core: AV ringing with %1 without video").arg(friendId);
- emit static_cast(core)->avRinging(friendId, call_index, false);
- }
-}
-
-void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV starting";
- return;
- }
- int transType = toxav_get_peer_transmission_type(toxav, call_index, 0);
- if (transType == TypeVideo)
- {
- qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
- prepareCall(friendId, call_index, toxav, true);
- emit static_cast(core)->avStarting(friendId, call_index, true);
- }
- else
- {
- qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
- prepareCall(friendId, call_index, toxav, false);
- emit static_cast(core)->avStarting(friendId, call_index, false);
- }
-}
-
-void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV ending";
- return;
- }
- qDebug() << QString("Core: AV ending from %1").arg(friendId);
-
- cleanupCall(call_index);
-
- emit static_cast(core)->avEnding(friendId, call_index);
-}
-
-void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV request timeout";
- return;
- }
- qDebug() << QString("Core: AV request timeout with %1").arg(friendId);
-
- cleanupCall(call_index);
-
- emit static_cast(core)->avRequestTimeout(friendId, call_index);
-}
-
-void Core::onAvPeerTimeout(void* _toxav, int32_t call_index, void* core)
-{
- ToxAv* toxav = static_cast(_toxav);
-
- int friendId = toxav_get_peer_id(toxav, call_index, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV peer timeout";
- return;
- }
- qDebug() << QString("Core: AV peer timeout with %1").arg(friendId);
-
- cleanupCall(call_index);
-
- emit static_cast(core)->avPeerTimeout(friendId, call_index);
-}
-
-void Core::onAvMediaChange(void*, int32_t, void*)
-{
- // HALP, PLS COMPLETE MEH
-}
-
-void Core::answerCall(int callId)
-{
- int friendId = toxav_get_peer_id(toxav, callId, 0);
- if (friendId < 0)
- {
- qWarning() << "Core: Received invalid AV answer peer ID";
- return;
- }
- int transType = toxav_get_peer_transmission_type(toxav, callId, 0);
- if (transType == TypeVideo)
- {
- qDebug() << QString("Core: answering call %1 with video").arg(callId);
- toxav_answer(toxav, callId, TypeVideo);
- }
- else
- {
- qDebug() << QString("Core: answering call %1 without video").arg(callId);
- toxav_answer(toxav, callId, TypeAudio);
- }
-}
-
-void Core::hangupCall(int callId)
-{
- qDebug() << QString("Core: hanging up call %1").arg(callId);
- calls[callId].active = false;
- toxav_hangup(toxav, callId);
-}
-
-void Core::startCall(int friendId, bool video)
-{
- int callId;
- if (video)
- {
- qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
- toxav_call(toxav, &callId, friendId, TypeVideo, TOXAV_RINGING_TIME);
- calls[callId].videoEnabled=true;
- }
- else
- {
- qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
- toxav_call(toxav, &callId, friendId, TypeAudio, TOXAV_RINGING_TIME);
- calls[callId].videoEnabled=false;
- }
-}
-
-void Core::cancelCall(int callId, int friendId)
-{
- qDebug() << QString("Core: Cancelling call with %1").arg(friendId);
- calls[callId].active = false;
- toxav_cancel(toxav, callId, friendId, 0);
-}
-
-void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled)
-{
- qDebug() << QString("Core: preparing call %1").arg(callId);
- calls[callId].callId = callId;
- calls[callId].friendId = friendId;
- calls[callId].codecSettings = av_DefaultSettings;
- calls[callId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
- calls[callId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
- calls[callId].videoEnabled = videoEnabled;
- toxav_prepare_transmission(toxav, callId, &calls[callId].codecSettings, videoEnabled);
-
- // Prepare output
- QAudioFormat format;
- format.setSampleRate(calls[callId].codecSettings.audio_sample_rate);
- format.setChannelCount(calls[callId].codecSettings.audio_channels);
- format.setSampleSize(16);
- format.setCodec("audio/pcm");
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setSampleType(QAudioFormat::SignedInt);
- if (!QAudioDeviceInfo::defaultOutputDevice().isFormatSupported(format))
- {
- calls[callId].audioOutput = nullptr;
- qWarning() << "Core: Raw audio format not supported by output backend, cannot play audio.";
- }
- else if (calls[callId].audioOutput==nullptr)
- {
- calls[callId].audioOutput = new QAudioOutput(format);
- calls[callId].audioOutput->setBufferSize(1900*30); // Make this bigger to get less underflows, but more latency
- calls[callId].audioOutput->start(&calls[callId].audioBuffer);
- int error = calls[callId].audioOutput->error();
- if (error != QAudio::NoError)
- {
- qWarning() << QString("Core: Error %1 when starting audio output").arg(error);
- }
- }
-
- // Start input
- if (!QAudioDeviceInfo::defaultInputDevice().isFormatSupported(format))
- {
- calls[callId].audioInput = nullptr;
- qWarning() << "Default input format not supported, cannot record audio";
- }
- else if (calls[callId].audioInput==nullptr)
- {
- calls[callId].audioInput = new QAudioInput(format);
- calls[callId].audioInputDevice = calls[callId].audioInput->start();
- }
-
- // Go
- calls[callId].active = true;
-
- if (calls[callId].audioInput != nullptr)
- {
- calls[callId].sendAudioTimer->setInterval(2);
- calls[callId].sendAudioTimer->setSingleShot(true);
- connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
- calls[callId].sendAudioTimer->start();
- }
-
- if (calls[callId].videoEnabled)
- {
- calls[callId].sendVideoTimer->setInterval(50);
- calls[callId].sendVideoTimer->setSingleShot(true);
- calls[callId].sendVideoTimer->start();
-
- Widget::getInstance()->getCamera()->suscribe();
- }
-}
-
-void Core::cleanupCall(int callId)
-{
- qDebug() << QString("Core: cleaning up call %1").arg(callId);
- calls[callId].active = false;
- disconnect(calls[callId].sendAudioTimer,0,0,0);
- calls[callId].sendAudioTimer->stop();
- calls[callId].sendVideoTimer->stop();
- if (calls[callId].audioOutput != nullptr)
- {
- calls[callId].audioOutput->stop();
- }
- if (calls[callId].audioInput != nullptr)
- {
- calls[callId].audioInput->stop();
- }
- if (calls[callId].videoEnabled)
- Widget::getInstance()->getCamera()->unsuscribe();
- calls[callId].audioBuffer.clear();
-}
-
-void Core::playCallAudio(ToxAv*, int32_t callId, int16_t *data, int length)
-{
- if (!calls[callId].active)
- return;
- calls[callId].audioBuffer.write((char*)data, length*2);
- int state = calls[callId].audioOutput->state();
- if (state != QAudio::ActiveState)
- {
- qDebug() << QString("Core: Audio state is %1").arg(state);
- calls[callId].audioOutput->start(&calls[callId].audioBuffer);
- }
- int error = calls[callId].audioOutput->error();
- if (error != QAudio::NoError)
- qWarning() << QString("Core::playCallAudio: Error: %1").arg(error);
-}
-
-void Core::sendCallAudio(int callId, ToxAv* toxav)
-{
- if (!calls[callId].active)
- return;
- int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
- uint8_t buf[framesize*2], dest[framesize*2];
- int bytesReady = calls[callId].audioInput->bytesReady();
- if (bytesReady >= framesize*2)
- {
- calls[callId].audioInputDevice->read((char*)buf, framesize*2);
- int result = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize);
- if (result < 0)
- {
- qWarning() << QString("Core: Unable to prepare audio frame, error %1").arg(result);
- calls[callId].sendAudioTimer->start();
- return;
- }
- result = toxav_send_audio(toxav, callId, dest, result);
- if (result < 0)
- {
- qWarning() << QString("Core: Unable to send audio frame, error %1").arg(result);
- calls[callId].sendAudioTimer->start();
- return;
- }
- calls[callId].sendAudioTimer->start();
- }
- else
- calls[callId].sendAudioTimer->start();
-}
-
-void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img)
-{
- if (!calls[callId].active || !calls[callId].videoEnabled)
- return;
-
- if (videoBusyness >= 1)
- qWarning() << "Core: playCallVideo: Busy, dropping current frame";
- else
- emit Widget::getInstance()->getCore()->videoFrameReceived(img);
- vpx_img_free(img);
-}
-
-void Core::sendCallVideo(int callId)
-{
- if (!calls[callId].active || !calls[callId].videoEnabled)
- return;
-
- vpx_image frame = camera->getLastVPXImage();
- if (frame.w && frame.h)
- {
- int result;
- if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
- {
- qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
- vpx_img_free(&frame);
- calls[callId].sendVideoTimer->start();
- return;
- }
-
- if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
- qDebug() << QString("Core: toxav_send_video error: %1").arg(result);
-
- vpx_img_free(&frame);
- }
- else
- qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)");
-
- calls[callId].sendVideoTimer->start();
-}
-
void Core::groupInviteFriend(int friendId, int groupId)
{
tox_invite_friend(tox, friendId, groupId);
@@ -1471,12 +1173,18 @@ void Core::createGroup()
emit emptyGroupCreated(tox_add_groupchat(tox));
}
-void Core::increaseVideoBusyness()
+QString Core::getFriendAddress(int friendNumber) const
{
- videoBusyness++;
-}
+ // If we don't know the full address of the client, return just the id, otherwise get the full address
+ uint8_t rawid[TOX_CLIENT_ID_SIZE];
+ tox_get_client_id(tox, friendNumber, rawid);
+ QByteArray data((char*)rawid,TOX_CLIENT_ID_SIZE);
+ QString id = data.toHex().toUpper();
-void Core::decreaseVideoBusyness()
-{
- videoBusyness--;
+ QList& friendAddresses = Settings::getInstance().friendAddresses;
+ for (QString addr : friendAddresses)
+ if (addr.toUpper().contains(id))
+ return addr;
+
+ return id;
}
diff --git a/core.h b/core.h
index 9ba3e2778..5de02e7f7 100644
--- a/core.h
+++ b/core.h
@@ -17,11 +17,17 @@
#ifndef CORE_HPP
#define CORE_HPP
-#include "audiobuffer.h"
-
#include
#include
+#if defined(__APPLE__) && defined(__MACH__)
+ #include
+ #include
+#else
+ #include
+ #include
+#endif
+
#include
#include
#include
@@ -30,16 +36,12 @@
#include
#include
#include
-#include
-#include
-#include
-#include
#define TOXAV_MAX_CALLS 16
#define GROUPCHAT_MAX_SIZE 32
#define TOX_SAVE_INTERVAL 30*1000
-#define TOX_FILE_INTERVAL 20
-#define TOX_BOOTSTRAP_INTERVAL 10*1000
+#define TOX_FILE_INTERVAL 0
+#define TOX_BOOTSTRAP_INTERVAL 5*1000
#define TOXAV_RINGING_TIME 15
// TODO: Put that in the settings
@@ -76,7 +78,7 @@ struct ToxFile
ToxFile()=default;
ToxFile(int FileNum, int FriendId, QByteArray FileName, QString FilePath, FileDirection Direction)
: fileNum(FileNum), friendId(FriendId), fileName{FileName}, filePath{FilePath}, file{new QFile(filePath)},
- bytesSent{0}, filesize{0}, status{STOPPED}, direction{Direction} {}
+ bytesSent{0}, filesize{0}, status{STOPPED}, direction{Direction}, sendTimer{nullptr} {}
~ToxFile(){}
void setFilePath(QString path) {filePath=path; file->setFileName(path);}
bool open(bool write) {return write?file->open(QIODevice::ReadWrite):file->open(QIODevice::ReadOnly);}
@@ -90,22 +92,20 @@ struct ToxFile
long long filesize;
FileStatus status;
FileDirection direction;
- QFuture sendFuture;
+ QTimer* sendTimer;
};
struct ToxCall
{
public:
- AudioBuffer audioBuffer;
- QAudioOutput* audioOutput;
- QAudioInput* audioInput;
- QIODevice* audioInputDevice;
- ToxAvCodecSettings codecSettings;
+ ToxAvCSettings codecSettings;
QTimer *sendAudioTimer, *sendVideoTimer;
int callId;
int friendId;
bool videoEnabled;
bool active;
+ bool muteMic;
+ ALuint alSource;
};
class Core : public QObject
@@ -120,6 +120,7 @@ public:
int getGroupNumberPeers(int groupId) const;
QString getGroupPeerName(int groupId, int peerId) const;
QList getGroupPeerNames(int groupId) const;
+ QString getFriendAddress(int friendNumber) const;
int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key) const;
void quitGroupChat(int groupId) const;
void dispatchVideoFrame(vpx_image img) const;
@@ -173,6 +174,8 @@ public slots:
void startCall(int friendId, bool video=false);
void cancelCall(int callId, int friendId);
+ void micMuteToggle(int callId);
+
signals:
void connected();
void disconnected();
@@ -239,7 +242,7 @@ signals:
void avEnding(int friendId, int callIndex);
void avRequestTimeout(int friendId, int callIndex);
void avPeerTimeout(int friendId, int callIndex);
- void avMediaChange(int friendId, int callIndex);
+ void avMediaChange(int friendId, int callIndex, bool videoEnabled);
void videoFrameReceived(vpx_image* frame);
@@ -271,21 +274,22 @@ private:
static void onAvEnding(void* toxav, int32_t call_index, void* core);
static void onAvRequestTimeout(void* toxav, int32_t call_index, void* core);
static void onAvPeerTimeout(void* toxav, int32_t call_index, void* core);
- static void onAvMediaChange(void* toxav, int32_t call_index, void* core);
+ static void onAvMediaChange(void *toxav, int32_t call_index, void* core);
static void prepareCall(int friendId, int callId, ToxAv *toxav, bool videoEnabled);
static void cleanupCall(int callId);
- static void playCallAudio(ToxAv *toxav, int32_t callId, int16_t *data, int length); // Callback
+ static void playCallAudio(ToxAv *toxav, int32_t callId, int16_t *data, int samples, void *user_data); // Callback
static void sendCallAudio(int callId, ToxAv* toxav);
- static void playCallVideo(ToxAv* toxav, int32_t callId, vpx_image_t* img);
+ static void playAudioBuffer(int callId, int16_t *data, int samples, unsigned channels, int sampleRate);
+ static void playCallVideo(ToxAv* toxav, int32_t callId, vpx_image_t* img, void *user_data);
void sendCallVideo(int callId);
void checkConnection();
void onBootstrapTimer();
void loadFriends();
- static void sendAllFileData(Core* core, ToxFile* file);
+ static void sendAllFileData(Core* core, ToxFile* file);
static void removeFileFromQueue(bool sendQueue, int friendId, int fileId);
void checkLastOnline(int friendId);
@@ -307,6 +311,11 @@ private:
static const int videobufsize;
static uint8_t* videobuf;
static int videoBusyness; // Used to know when to drop frames
+
+ static ALCdevice* alOutDev, *alInDev;
+ static ALCcontext* alContext;
+public:
+ static ALuint alMainSource;
};
#endif // CORE_HPP
diff --git a/coreav.cpp b/coreav.cpp
new file mode 100644
index 000000000..2a3ce7a67
--- /dev/null
+++ b/coreav.cpp
@@ -0,0 +1,540 @@
+/*
+ Copyright (C) 2013 by Maxim Biro
+
+ This file is part of Tox Qt GUI.
+
+ This program is free 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "core.h"
+#include "widget/widget.h"
+
+ToxCall Core::calls[TOXAV_MAX_CALLS];
+const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
+uint8_t* Core::videobuf;
+int Core::videoBusyness;
+
+ALCdevice* Core::alOutDev, *Core::alInDev;
+ALCcontext* Core::alContext;
+ALuint Core::alMainSource;
+
+void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled)
+{
+ qDebug() << QString("Core: preparing call %1").arg(callId);
+ calls[callId].callId = callId;
+ calls[callId].friendId = friendId;
+ calls[callId].muteMic = false;
+ // the following three lines are also now redundant from startCall, but are
+ // necessary there for outbound and here for inbound
+ calls[callId].codecSettings = av_DefaultSettings;
+ calls[callId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
+ calls[callId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
+ calls[callId].videoEnabled = videoEnabled;
+ toxav_prepare_transmission(toxav, callId, av_jbufdc, av_VADd, videoEnabled);
+
+ // Audio
+ alGenSources(1, &calls[callId].alSource);
+ alcCaptureStart(alInDev);
+
+ // Go
+ calls[callId].active = true;
+ calls[callId].sendAudioTimer->setInterval(5);
+ calls[callId].sendAudioTimer->setSingleShot(true);
+ connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
+ calls[callId].sendAudioTimer->start();
+ calls[callId].sendVideoTimer->setInterval(50);
+ calls[callId].sendVideoTimer->setSingleShot(true);
+ if (calls[callId].videoEnabled)
+ {
+ calls[callId].sendVideoTimer->start();
+ Widget::getInstance()->getCamera()->suscribe();
+ }
+}
+
+void Core::onAvMediaChange(void* toxav, int32_t callId, void* core)
+{
+ ToxAvCSettings settings;
+ toxav_get_peer_csettings((ToxAv*)toxav, callId, 0, &settings);
+ int friendId = toxav_get_peer_id((ToxAv*)toxav, callId, 0);
+
+ qWarning() << "Core: Received media change from friend "<stop();
+ Widget::getInstance()->getCamera()->unsuscribe();
+ emit ((Core*)core)->avMediaChange(friendId, callId, false);
+ }
+ else
+ {
+ Widget::getInstance()->getCamera()->suscribe();
+ calls[callId].videoEnabled = true;
+ calls[callId].sendVideoTimer->start();
+ emit ((Core*)core)->avMediaChange(friendId, callId, true);
+ }
+}
+
+void Core::answerCall(int callId)
+{
+ int friendId = toxav_get_peer_id(toxav, callId, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV answer peer ID";
+ return;
+ }
+
+ ToxAvCSettings* transSettings = new ToxAvCSettings;
+ int err = toxav_get_peer_csettings(toxav, callId, 0, transSettings);
+ if (err != ErrorNone)
+ {
+ qWarning() << "Core::answerCall: error getting call settings";
+ delete transSettings;
+ return;
+ }
+
+ if (transSettings->call_type == TypeVideo)
+ {
+ qDebug() << QString("Core: answering call %1 with video").arg(callId);
+ toxav_answer(toxav, callId, transSettings);
+ }
+ else
+ {
+ qDebug() << QString("Core: answering call %1 without video").arg(callId);
+ toxav_answer(toxav, callId, transSettings);
+ }
+
+ delete transSettings;
+}
+
+void Core::hangupCall(int callId)
+{
+ qDebug() << QString("Core: hanging up call %1").arg(callId);
+ calls[callId].active = false;
+ toxav_hangup(toxav, callId);
+}
+
+void Core::startCall(int friendId, bool video)
+{
+ int callId;
+ ToxAvCSettings cSettings = av_DefaultSettings;
+ cSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
+ cSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
+ if (video)
+ {
+ qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
+ cSettings.call_type = TypeVideo;
+ toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
+ calls[callId].videoEnabled=true;
+ }
+ else
+ {
+ qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
+ cSettings.call_type = TypeAudio;
+ toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
+ calls[callId].videoEnabled=false;
+ }
+}
+
+void Core::cancelCall(int callId, int friendId)
+{
+ qDebug() << QString("Core: Cancelling call with %1").arg(friendId);
+ calls[callId].active = false;
+ toxav_cancel(toxav, callId, friendId, 0);
+}
+
+void Core::cleanupCall(int callId)
+{
+ qDebug() << QString("Core: cleaning up call %1").arg(callId);
+ calls[callId].active = false;
+ disconnect(calls[callId].sendAudioTimer,0,0,0);
+ calls[callId].sendAudioTimer->stop();
+ calls[callId].sendVideoTimer->stop();
+ if (calls[callId].videoEnabled)
+ Widget::getInstance()->getCamera()->unsuscribe();
+ alcCaptureStop(alInDev);
+}
+
+void Core::playCallAudio(ToxAv* toxav, int32_t callId, int16_t *data, int samples, void *user_data)
+{
+ Q_UNUSED(user_data);
+
+ if (!calls[callId].active)
+ return;
+
+ ToxAvCSettings dest;
+ if(toxav_get_peer_csettings(toxav, callId, 0, &dest) == 0)
+ playAudioBuffer(callId, data, samples, dest.audio_channels, dest.audio_sample_rate);
+}
+
+void Core::sendCallAudio(int callId, ToxAv* toxav)
+{
+ if (!calls[callId].active)
+ return;
+
+ if (calls[callId].muteMic)
+ {
+ calls[callId].sendAudioTimer->start();
+ return;
+ }
+
+ int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
+ uint8_t buf[framesize*2], dest[framesize*2];
+
+ bool frame = false;
+ ALint samples;
+ alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
+ if(samples >= framesize)
+ {
+ alcCaptureSamples(alInDev, buf, framesize);
+ frame = 1;
+ }
+
+ if(frame)
+ {
+ int r;
+ if((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
+ {
+ qDebug() << "Core: toxav_prepare_audio_frame error";
+ calls[callId].sendAudioTimer->start();
+ return;
+ }
+
+ if((r = toxav_send_audio(toxav, callId, dest, r)) < 0)
+ qDebug() << "Core: toxav_send_audio error";
+ }
+ calls[callId].sendAudioTimer->start();
+}
+
+void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img, void *user_data)
+{
+ Q_UNUSED(user_data);
+
+ if (!calls[callId].active || !calls[callId].videoEnabled)
+ return;
+
+ if (videoBusyness >= 1)
+ qWarning() << "Core: playCallVideo: Busy, dropping current frame";
+ else
+ emit Widget::getInstance()->getCore()->videoFrameReceived(img);
+ vpx_img_free(img);
+}
+
+void Core::sendCallVideo(int callId)
+{
+ if (!calls[callId].active || !calls[callId].videoEnabled)
+ return;
+
+ vpx_image frame = camera->getLastVPXImage();
+ if (frame.w && frame.h)
+ {
+ int result;
+ if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
+ {
+ qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
+ vpx_img_free(&frame);
+ calls[callId].sendVideoTimer->start();
+ return;
+ }
+
+ if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
+ qDebug() << QString("Core: toxav_send_video error: %1").arg(result);
+
+ vpx_img_free(&frame);
+ }
+ else
+ {
+ qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)");
+ }
+
+ calls[callId].sendVideoTimer->start();
+}
+
+
+void Core::increaseVideoBusyness()
+{
+ videoBusyness++;
+}
+
+void Core::decreaseVideoBusyness()
+{
+ videoBusyness--;
+}
+
+void Core::micMuteToggle(int callId)
+{
+ calls[callId].muteMic = !calls[callId].muteMic;
+}
+
+void Core::onAvCancel(void* _toxav, int32_t callId, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, callId, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV cancel";
+ return;
+ }
+ qDebug() << QString("Core: AV cancel from %1").arg(friendId);
+
+ calls[callId].active = false;
+
+ emit static_cast(core)->avCancel(friendId, callId);
+}
+
+void Core::onAvReject(void*, int32_t, void*)
+{
+ qDebug() << "Core: AV reject";
+}
+
+void Core::onAvEnd(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV end";
+ return;
+ }
+ qDebug() << QString("Core: AV end from %1").arg(friendId);
+
+ cleanupCall(call_index);
+
+ emit static_cast(core)->avEnd(friendId, call_index);
+}
+
+void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV ringing";
+ return;
+ }
+
+ if (calls[call_index].videoEnabled)
+ {
+ qDebug() << QString("Core: AV ringing with %1 with video").arg(friendId);
+ emit static_cast(core)->avRinging(friendId, call_index, true);
+ }
+ else
+ {
+ qDebug() << QString("Core: AV ringing with %1 without video").arg(friendId);
+ emit static_cast(core)->avRinging(friendId, call_index, false);
+ }
+}
+
+void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV starting";
+ return;
+ }
+
+ ToxAvCSettings* transSettings = new ToxAvCSettings;
+ int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
+ if (err != ErrorNone)
+ {
+ qWarning() << "Core::onAvStarting: error getting call type";
+ delete transSettings;
+ return;
+ }
+
+ if (transSettings->call_type == TypeVideo)
+ {
+ qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
+ prepareCall(friendId, call_index, toxav, true);
+ emit static_cast(core)->avStarting(friendId, call_index, true);
+ }
+ else
+ {
+ qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
+ prepareCall(friendId, call_index, toxav, false);
+ emit static_cast(core)->avStarting(friendId, call_index, false);
+ }
+
+ delete transSettings;
+}
+
+void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV ending";
+ return;
+ }
+ qDebug() << QString("Core: AV ending from %1").arg(friendId);
+
+ cleanupCall(call_index);
+
+ emit static_cast(core)->avEnding(friendId, call_index);
+}
+
+void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV request timeout";
+ return;
+ }
+ qDebug() << QString("Core: AV request timeout with %1").arg(friendId);
+
+ cleanupCall(call_index);
+
+ emit static_cast(core)->avRequestTimeout(friendId, call_index);
+}
+
+void Core::onAvPeerTimeout(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV peer timeout";
+ return;
+ }
+ qDebug() << QString("Core: AV peer timeout with %1").arg(friendId);
+
+ cleanupCall(call_index);
+
+ emit static_cast(core)->avPeerTimeout(friendId, call_index);
+}
+
+
+void Core::onAvInvite(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV invite";
+ return;
+ }
+
+ ToxAvCSettings* transSettings = new ToxAvCSettings;
+ int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
+ if (err != ErrorNone)
+ {
+ qWarning() << "Core::onAvInvite: error getting call type";
+ delete transSettings;
+ return;
+ }
+
+ if (transSettings->call_type == TypeVideo)
+ {
+ qDebug() << QString("Core: AV invite from %1 with video").arg(friendId);
+ emit static_cast(core)->avInvite(friendId, call_index, true);
+ }
+ else
+ {
+ qDebug() << QString("Core: AV invite from %1 without video").arg(friendId);
+ emit static_cast(core)->avInvite(friendId, call_index, false);
+ }
+
+ delete transSettings;
+}
+
+void Core::onAvStart(void* _toxav, int32_t call_index, void* core)
+{
+ ToxAv* toxav = static_cast(_toxav);
+
+ int friendId = toxav_get_peer_id(toxav, call_index, 0);
+ if (friendId < 0)
+ {
+ qWarning() << "Core: Received invalid AV start";
+ return;
+ }
+
+ ToxAvCSettings* transSettings = new ToxAvCSettings;
+ int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
+ if (err != ErrorNone)
+ {
+ qWarning() << "Core::onAvStart: error getting call type";
+ delete transSettings;
+ return;
+ }
+
+ if (transSettings->call_type == TypeVideo)
+ {
+ qDebug() << QString("Core: AV start from %1 with video").arg(friendId);
+ prepareCall(friendId, call_index, toxav, true);
+ emit static_cast(core)->avStart(friendId, call_index, true);
+ }
+ else
+ {
+ qDebug() << QString("Core: AV start from %1 without video").arg(friendId);
+ prepareCall(friendId, call_index, toxav, false);
+ emit static_cast(core)->avStart(friendId, call_index, false);
+ }
+
+ delete transSettings;
+}
+
+// This function's logic was shamelessly stolen from uTox
+void Core::playAudioBuffer(int callId, int16_t *data, int samples, unsigned channels, int sampleRate)
+{
+ if(!channels || channels > 2)
+ {
+ qWarning() << "Core::playAudioBuffer: trying to play on "< Sat, 30 Aug 2014 23:27:47 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 000000000..ec635144f
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 000000000..ef73726b7
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,14 @@
+Source: qtox
+Maintainer: John Smith
+Section: misc
+Priority: optional
+Standards-Version: 3.9.5
+Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, qt5-default, libopenal-dev, libopencv-dev, libopus-dev
+
+Package: qtox
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Tox client
+ qTox is a powerful Tox client that follows the Tox design guidelines.
+ Tox is a decentralized and encrypted replacement for Skype, supporting
+ chats, audio, and video calls.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 000000000..6770976a6
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,28 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: qtox
+Upstream-Contact: John Smith
+Source: https://github.com/tux3/qTox
+
+Files: *
+Copyright: 2014 John Smith
+License: GPL-3+
+ This program is free 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.
+ .
+ This program 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 this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 3 can be found in the file
+ `/usr/share/common-licenses/GPL-3'.
diff --git a/debian/rules b/debian/rules
new file mode 100644
index 000000000..6815966a4
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,6 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/qmake.mk
+
+QMAKE=qmake STATICPKG=YES
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 000000000..163aaf8d8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/friend.cpp b/friend.cpp
index b024d2dda..ec8dd3860 100644
--- a/friend.cpp
+++ b/friend.cpp
@@ -23,7 +23,7 @@ Friend::Friend(int FriendId, QString UserId)
{
widget = new FriendWidget(friendId, userId);
chatForm = new ChatForm(this);
- hasNewMessages = 0;
+ hasNewEvents = 0;
friendStatus = Status::Offline;
}
diff --git a/friend.h b/friend.h
index 8730ae435..8a3a2427a 100644
--- a/friend.h
+++ b/friend.h
@@ -36,7 +36,7 @@ public:
int friendId;
QString userId;
ChatForm* chatForm;
- int hasNewMessages;
+ int hasNewEvents;
Status friendStatus;
QPixmap avatar;
};
diff --git a/friendlist.cpp b/friendlist.cpp
index 08ecb903d..6547c408c 100644
--- a/friendlist.cpp
+++ b/friendlist.cpp
@@ -17,6 +17,7 @@
#include "friend.h"
#include "friendlist.h"
#include
+#include
QList FriendList::friendList;
diff --git a/main.cpp b/main.cpp
index f61cbadf4..d2d34b138 100644
--- a/main.cpp
+++ b/main.cpp
@@ -58,7 +58,6 @@ int main(int argc, char *argv[])
* Most cameras use YUYV, implement YUYV -> YUV240
* Sending large files (~380MB) "restarts" after ~10MB. Goes back to 0%, consumes twice as much ram (reloads the file?)
* => Don't load the whole file at once, load small chunks (25MB?) when needed, then free them and load the next
- * Sort the friend list by status, online first then busy then offline
* Don't do anything if a friend is disconnected, don't print to the chat
* Changing online/away/busy/offline by clicking the bubble
* /me action messages
diff --git a/mainwindow.ui b/mainwindow.ui
new file mode 100644
index 000000000..7f9cd12c5
--- /dev/null
+++ b/mainwindow.ui
@@ -0,0 +1,3262 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 716
+ 543
+
+
+
+
+ 640
+ 420
+
+
+
+ qTox
+
+
+
+ :/img/icon.png:/img/icon.png
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 23
+
+
+
+
+ 16777215
+ 23
+
+
+
+
+ 4
+
+
+ 5
+
+
+ 0
+
+
+ 1
+
+
+ 0
+
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+ QToolButton::InstantPopup
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 15
+ 1
+
+
+
+
+
+
+
+
+ 100
+ 22
+
+
+
+
+ 16777215
+ 22
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Minimum
+
+
+
+ 134
+ 20
+
+
+
+
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+
+ 22
+ 22
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ QSplitter{
+ color: rgb(255, 255, 255);
+ background-color: rgb(255, 255, 255);
+ alternate-background-color: rgb(255, 255, 255);
+ border-color: rgb(255, 255, 255);
+ gridline-color: rgb(255, 255, 255);
+ selection-color: rgb(255, 255, 255);
+ selection-background-color: rgb(255, 255, 255);
+}
+QSplitter:handle{
+ color: rgb(255, 255, 255);
+ background-color: rgb(255, 255, 255);
+}
+
+
+ Qt::Horizontal
+
+
+ 6
+
+
+ false
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+ true
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+ 0
+
+
+
+
+
+ 40
+ 40
+
+
+
+
+ 40
+ 40
+
+
+
+
+
+
+ :/img/contact.png
+
+
+ true
+
+
+
+
+
+
+ 0
+
+
+
+
+ true
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 240
+ 240
+ 240
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+
+
+ 11
+ 75
+ true
+
+
+
+ Your name
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+
+
+ 8
+
+
+
+ Your status
+
+
+
+
+
+
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 10
+ 20
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 40
+
+
+
+ Qt::NoFocus
+
+
+
+
+
+
+ 10
+ 10
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Qt::LeftToRight
+
+
+ true
+
+
+ QFrame::NoFrame
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 263
+ 373
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 42
+ 42
+ 42
+
+
+
+
+
+
+ 35
+ 35
+ 35
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 18
+ 18
+ 18
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 14
+ 14
+ 14
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 28
+ 28
+ 28
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+ true
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+ 55
+ 35
+
+
+
+
+ 55
+ 35
+
+
+
+ Qt::NoFocus
+
+
+ Add friends
+
+
+
+
+
+
+ :/img/add.png:/img/add.png
+
+
+ true
+
+
+
+
+
+
+
+ 55
+ 35
+
+
+
+ Qt::NoFocus
+
+
+ Create a group chat
+
+
+
+
+
+
+ :/img/group.png:/img/group.png
+
+
+ true
+
+
+
+
+
+
+
+ 55
+ 35
+
+
+
+
+ 55
+ 35
+
+
+
+ Qt::NoFocus
+
+
+ View completed file transfers
+
+
+
+
+
+
+ :/img/transfer.png:/img/transfer.png
+
+
+ true
+
+
+
+
+
+
+
+ 55
+ 35
+
+
+
+
+ 55
+ 35
+
+
+
+ Qt::NoFocus
+
+
+ Change your settings
+
+
+
+
+
+
+ :/img/settings.png:/img/settings.png
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 170
+ 170
+ 170
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 170
+ 170
+ 170
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 170
+ 170
+ 170
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ 255
+ 255
+ 255
+
+
+
+
+
+
+ 255
+ 255
+ 220
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+ true
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 60
+
+
+
+
+ 16777215
+ 60
+
+
+
+ true
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 16777215
+ 1
+
+
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+
+
+ 193
+ 193
+ 193
+
+
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+
+ QFrame::HLine
+
+
+ QFrame::Plain
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 375
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+ 0
+ 0
+ 716
+ 23
+
+
+
+
+
+
+ Close
+
+
+ Ctrl+Q
+
+
+
+
+
+ AdjustingScrollArea
+ QScrollArea
+ widget/adjustingscrollarea.h
+ 1
+
+
+ CroppingLabel
+ QLabel
+ widget/croppinglabel.h
+
+
+
+
+
+
+
diff --git a/qtox.pro b/qtox.pro
index e12cc4cd1..679e6d17e 100644
--- a/qtox.pro
+++ b/qtox.pro
@@ -20,12 +20,13 @@
# See the COPYING file for more details.
-QT += core gui network multimedia multimediawidgets
+QT += core gui network xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtox
TEMPLATE = app
-FORMS += widget.ui
+FORMS += \
+ mainwindow.ui
CONFIG += c++11
TRANSLATIONS = translations/de.ts \
@@ -35,16 +36,33 @@ TRANSLATIONS = translations/de.ts \
RESOURCES += res.qrc
-target.path = /usr/local/bin
-INSTALLS += target
-
-INCLUDEPATH += libs/include
-win32 {
- LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread
+contains(JENKINS,YES) {
+ INCLUDEPATH += ./libs/include/
} else {
- LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx
+ INCLUDEPATH += libs/include
}
+# Rules for Windows, Mac OSX, and Linux
+win32 {
+ LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libopenal32.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread -liphlpapi
+} macx {
+ LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui
+} else {
+ # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
+ contains(STATICPKG, YES) {
+ target.path = /usr/bin
+ INSTALLS += target
+ LIBS += -L$$PWD/libs/lib/ -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -Wl,-Bdynamic -lopus -lvpx -lopenal -lopencv_core -lopencv_highgui
+ } else {
+ LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lvpx -lopenal -lopencv_core -lopencv_highgui
+ }
+
+ contains(JENKINS, YES) {
+ LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a -lopencv_core -lopencv_highgui -lopenal
+ }
+}
+
+
#### Static linux build
#LIBS += -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -lvpx -lopus \
# -lgstbase-0.10 -lgstreamer-0.10 -lgmodule-2.0 -lgstaudio-0.10 -lxml2 \
@@ -61,10 +79,6 @@ HEADERS += widget/form/addfriendform.h \
widget/form/settingsform.h \
widget/form/filesform.h \
widget/tool/chattextedit.h \
- widget/tool/copyableelidelabel.h \
- widget/tool/editablelabelwidget.h \
- widget/tool/elidelabel.h \
- widget/tool/esclineedit.h \
widget/tool/friendrequestdialog.h \
widget/filetransfertwidget.h \
widget/friendwidget.h \
@@ -78,12 +92,16 @@ HEADERS += widget/form/addfriendform.h \
friendlist.h \
cdata.h \
cstring.h \
- audiobuffer.h \
widget/selfcamview.h \
- widget/videosurface.h \
widget/camera.h \
widget/netcamview.h \
- widget/tool/clickablelabel.h
+ smileypack.h \
+ widget/emoticonswidget.h \
+ style.h \
+ widget/adjustingscrollarea.h \
+ widget/croppinglabel.h \
+ widget/friendlistwidget.h \
+ widget/genericchatroomwidget.h
SOURCES += \
widget/form/addfriendform.cpp \
@@ -92,10 +110,6 @@ SOURCES += \
widget/form/settingsform.cpp \
widget/form/filesform.cpp \
widget/tool/chattextedit.cpp \
- widget/tool/copyableelidelabel.cpp \
- widget/tool/editablelabelwidget.cpp \
- widget/tool/elidelabel.cpp \
- widget/tool/esclineedit.cpp \
widget/tool/friendrequestdialog.cpp \
widget/filetransfertwidget.cpp \
widget/friendwidget.cpp \
@@ -110,9 +124,14 @@ SOURCES += \
settings.cpp \
cdata.cpp \
cstring.cpp \
- audiobuffer.cpp \
widget/selfcamview.cpp \
- widget/videosurface.cpp \
widget/camera.cpp \
widget/netcamview.cpp \
- widget/tool/clickablelabel.cpp
+ smileypack.cpp \
+ widget/emoticonswidget.cpp \
+ style.cpp \
+ widget/adjustingscrollarea.cpp \
+ widget/croppinglabel.cpp \
+ widget/friendlistwidget.cpp \
+ coreav.cpp \
+ widget/genericchatroomwidget.cpp
diff --git a/res.qrc b/res.qrc
index cb2fa192b..f413e0209 100644
--- a/res.qrc
+++ b/res.qrc
@@ -111,5 +111,18 @@
ui/statusButton/menu_indicator.pngtranslations/de.qmtranslations/it.qm
+ ui/emoticonWidget/dot_page.png
+ ui/emoticonWidget/dot_page_current.png
+ ui/emoticonWidget/emoticonWidget.css
+ ui/emoticonWidget/dot_page_hover.png
+ ui/volButton/volButton.png
+ ui/volButton/volButtonHover.png
+ ui/volButton/volButtonPressed.png
+ ui/micButton/micButton.png
+ ui/micButton/micButtonDisabled.png
+ ui/micButton/micButtonHover.png
+ ui/micButton/micButtonPressed.png
+ ui/micButton/micButton.css
+ ui/volButton/volButton.css
diff --git a/res/settings.ini b/res/settings.ini
index e1420de5b..25d126190 100644
--- a/res/settings.ini
+++ b/res/settings.ini
@@ -1,5 +1,5 @@
[DHT%20Server]
-dhtServerList\size=16
+dhtServerList\size=9
dhtServerList\1\name=stqism
dhtServerList\1\userId=951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
dhtServerList\1\address=192.254.75.98
@@ -12,55 +12,27 @@ dhtServerList\3\name=stal
dhtServerList\3\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
dhtServerList\3\address=23.226.230.47
dhtServerList\3\port=33445
-dhtServerList\4\name=ChauffeR
-dhtServerList\4\userId=4FD54CFD426A338399767E56FD0F44F5E35FA8C38C8E87C8DC3FEAC0160F8E1
-dhtServerList\4\address=37.187.20.216
+dhtServerList\4\name=aitjcize
+dhtServerList\4\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
+dhtServerList\4\address=54.199.139.199
dhtServerList\4\port=33445
-dhtServerList\5\name=aitjcize
-dhtServerList\5\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
-dhtServerList\5\address=54.199.139.199
+dhtServerList\5\name=astonex
+dhtServerList\5\userId=B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
+dhtServerList\5\address=37.59.102.176
dhtServerList\5\port=33445
-dhtServerList\6\name=astonex
-dhtServerList\6\userId=7F31BFC93B8E4016A902144D0B110C3EA97CB7D43F1C4D21BCAE998A7C838821
-dhtServerList\6\address=109.169.46.133
+dhtServerList\6\name=nurupo
+dhtServerList\6\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
+dhtServerList\6\address=192.210.149.121
dhtServerList\6\port=33445
-dhtServerList\7\name=nurupo
-dhtServerList\7\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
-dhtServerList\7\address=192.210.149.121
+dhtServerList\7\name=mousey
+dhtServerList\7\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331
+dhtServerList\7\address=37.187.46.132
dhtServerList\7\port=33445
-dhtServerList\8\name=mousey
-dhtServerList\8\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331
-dhtServerList\8\address=37.187.46.132
+dhtServerList\8\name=Proplex
+dhtServerList\8\userId=7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111
+dhtServerList\8\address=107.161.17.51
dhtServerList\8\port=33445
-dhtServerList\9\name=zlacki NL
-dhtServerList\9\userId=CC2B02636A2ADBC2871D6EC57C5E9589D4FD5E6F98A14743A4B949914CF26D39
-dhtServerList\9\address=5.39.218.35
+dhtServerList\9\name=SylvieLorxu
+dhtServerList\9\userId=4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
+dhtServerList\9\address=178.21.112.187
dhtServerList\9\port=33445
-dhtServerList\10\name=zlacki RU #2
-dhtServerList\10\userId=AE27E1E72ADA3DC423C60EEBACA241456174048BE76A283B41AD32D953182D49
-dhtServerList\10\address=193.107.16.73
-dhtServerList\10\port=33445
-dhtServerList\11\name=platos
-dhtServerList\11\userId=B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E
-dhtServerList\11\address=66.175.223.88
-dhtServerList\11\port=33445
-dhtServerList\12\name=JmanGuy
-dhtServerList\12\userId=20C797E098701A848B07D0384222416B0EFB60D08CECB925B860CAEAAB572067
-dhtServerList\12\address=66.74.15.98
-dhtServerList\12\port=33445
-dhtServerList\13\name=anonymous
-dhtServerList\13\userId=5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
-dhtServerList\13\address=192.184.81.118
-dhtServerList\13\port=33445
-dhtServerList\14\name=benwaffle
-dhtServerList\14\userId=8E6667FF967EA30B3DC3DB57A4B533152476E7AAE090158B9C2D9DF58ECC7B78
-dhtServerList\14\address=192.3.30.132
-dhtServerList\14\port=33445
-dhtServerList\15\name=zlacki RU #1
-dhtServerList\15\userId=D59F99384592DE4C8AB9D534D5197DB90F4755CC9E975ED0C565E18468A1445B
-dhtServerList\15\address=31.192.105.19
-dhtServerList\15\port=33445
-dhtServerList\16\name=zlacki US
-dhtServerList\16\userId=9430A83211A7AD1C294711D069D587028CA0B4782FA43CB9B30008247A43C944
-dhtServerList\16\address=69.42.220.58
-dhtServerList\16\port=33445
diff --git a/settings.cpp b/settings.cpp
index 96eb9ae15..434236d4e 100644
--- a/settings.cpp
+++ b/settings.cpp
@@ -15,6 +15,8 @@
*/
#include "settings.h"
+#include "smileypack.h"
+#include "widget/widget.h"
#include
#include
@@ -22,6 +24,7 @@
#include
#include
#include
+#include
const QString Settings::FILENAME = "settings.ini";
bool Settings::makeToxPortable{false};
@@ -53,7 +56,7 @@ void Settings::load()
if (portableSettings.exists())
makeToxPortable=true;
- QString filePath = getSettingsDirPath() + '/' + FILENAME;
+ QString filePath = QDir(getSettingsDirPath()).filePath(FILENAME);
//if no settings file exist -- use the default one
QFile file(filePath);
@@ -77,6 +80,16 @@ void Settings::load()
s.endArray();
s.endGroup();
+ friendAddresses.clear();
+ s.beginGroup("Friends");
+ int size = s.beginReadArray("fullAddresses");
+ for (int i = 0; i < size; i ++) {
+ s.setArrayIndex(i);
+ friendAddresses.append(s.value("addr").toString());
+ }
+ s.endArray();
+ s.endGroup();
+
s.beginGroup("General");
enableIPv6 = s.value("enableIPv6", true).toBool();
useTranslations = s.value("useTranslations", true).toBool();
@@ -93,7 +106,7 @@ void Settings::load()
s.beginGroup("GUI");
enableSmoothAnimation = s.value("smoothAnimation", true).toBool();
- smileyPack = s.value("smileyPack").toByteArray();
+ smileyPack = s.value("smileyPack", QString()).toString();
customEmojiFont = s.value("customEmojiFont", true).toBool();
emojiFontFamily = s.value("emojiFontFamily", "DejaVu Sans").toString();
emojiFontPointSize = s.value("emojiFontPointSize", QApplication::font().pointSize()).toInt();
@@ -101,18 +114,30 @@ void Settings::load()
secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt();
timestampFormat = s.value("timestampFormat", "hh:mm").toString();
minimizeOnClose = s.value("minimizeOnClose", false).toBool();
+ useNativeStyle = s.value("nativeStyle", false).toBool();
+ useNativeDecoration = s.value("nativeDecoration", true).toBool();
+ s.endGroup();
+
+ s.beginGroup("State");
+ windowGeometry = s.value("windowGeometry", QByteArray()).toByteArray();
+ windowState = s.value("windowState", QByteArray()).toByteArray();
+ splitterState = s.value("splitterState", QByteArray()).toByteArray();
s.endGroup();
s.beginGroup("Privacy");
typingNotification = s.value("typingNotification", false).toBool();
s.endGroup();
+ // try to set a smiley pack if none is selected
+ if (!SmileyPack::isValid(smileyPack) && !SmileyPack::listSmileyPacks().isEmpty())
+ smileyPack = SmileyPack::listSmileyPacks()[0].second;
+
loaded = true;
}
void Settings::save()
{
- QString filePath = getSettingsDirPath() + '/' + FILENAME;
+ QString filePath = QDir(getSettingsDirPath()).filePath(FILENAME);
save(filePath);
}
@@ -134,6 +159,15 @@ void Settings::save(QString path)
s.endArray();
s.endGroup();
+ s.beginGroup("Friends");
+ s.beginWriteArray("fullAddresses", friendAddresses.size());
+ for (int i = 0; i < friendAddresses.size(); i ++) {
+ s.setArrayIndex(i);
+ s.setValue("addr", friendAddresses[i]);
+ }
+ s.endArray();
+ s.endGroup();
+
s.beginGroup("General");
s.setValue("enableIPv6", enableIPv6);
s.setValue("useTranslations",useTranslations);
@@ -158,6 +192,14 @@ void Settings::save(QString path)
s.setValue("secondColumnHandlePosFromRight", secondColumnHandlePosFromRight);
s.setValue("timestampFormat", timestampFormat);
s.setValue("minimizeOnClose", minimizeOnClose);
+ s.setValue("nativeStyle", useNativeStyle);
+ s.setValue("nativeDecoration", useNativeDecoration);
+ s.endGroup();
+
+ s.beginGroup("State");
+ s.setValue("windowGeometry", windowGeometry);
+ s.setValue("windowState", windowState);
+ s.setValue("splitterState", splitterState);
s.endGroup();
s.beginGroup("Privacy");
@@ -174,7 +216,7 @@ QString Settings::getSettingsDirPath()
#ifdef Q_OS_WIN
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
#else
- return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + '/' + "tox" + '/';
+ return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QDir::separator() + "tox");
#endif
}
@@ -208,6 +250,8 @@ void Settings::setMakeToxPortable(bool newValue)
{
makeToxPortable = newValue;
save(FILENAME); // Commit to the portable file that we don't want to use it
+ if (!newValue) // Update the new file right now if not already done
+ save();
}
QString Settings::getCurrentProfile() const
@@ -270,12 +314,12 @@ void Settings::setAnimationEnabled(bool newValue)
enableSmoothAnimation = newValue;
}
-QByteArray Settings::getSmileyPack() const
+QString Settings::getSmileyPack() const
{
return smileyPack;
}
-void Settings::setSmileyPack(const QByteArray &value)
+void Settings::setSmileyPack(const QString &value)
{
smileyPack = value;
emit smileyPackChanged();
@@ -345,6 +389,56 @@ void Settings::setEmojiFontFamily(const QString &value)
emit emojiFontChanged();
}
+bool Settings::getUseNativeStyle() const
+{
+ return useNativeStyle;
+}
+
+void Settings::setUseNativeStyle(bool value)
+{
+ useNativeStyle = value;
+}
+
+bool Settings::getUseNativeDecoration() const
+{
+ return useNativeDecoration;
+}
+
+void Settings::setUseNativeDecoration(bool value)
+{
+ useNativeDecoration = value;
+}
+
+QByteArray Settings::getWindowGeometry() const
+{
+ return windowGeometry;
+}
+
+void Settings::setWindowGeometry(const QByteArray &value)
+{
+ windowGeometry = value;
+}
+
+QByteArray Settings::getWindowState() const
+{
+ return windowState;
+}
+
+void Settings::setWindowState(const QByteArray &value)
+{
+ windowState = value;
+}
+
+QByteArray Settings::getSplitterState() const
+{
+ return splitterState;
+}
+
+void Settings::setSplitterState(const QByteArray &value)
+{
+ splitterState = value;
+}
+
bool Settings::isMinimizeOnCloseEnabled() const
{
return minimizeOnClose;
diff --git a/settings.h b/settings.h
index 3ad240bc7..322ccea94 100644
--- a/settings.h
+++ b/settings.h
@@ -86,8 +86,8 @@ public:
bool isAnimationEnabled() const;
void setAnimationEnabled(bool newValue);
- QByteArray getSmileyPack() const;
- void setSmileyPack(const QByteArray &value);
+ QString getSmileyPack() const;
+ void setSmileyPack(const QString &value);
bool isCurstomEmojiFont() const;
void setCurstomEmojiFont(bool value);
@@ -115,16 +115,31 @@ public:
bool isTypingNotificationEnabled() const;
void setTypingNotification(bool enabled);
-private:
- Settings();
- Settings(Settings &settings) = delete;
- Settings& operator=(const Settings&) = delete;
+ bool getUseNativeStyle() const;
+ void setUseNativeStyle(bool value);
+ bool getUseNativeDecoration() const;
+ void setUseNativeDecoration(bool value);
+
+ QByteArray getWindowGeometry() const;
+ void setWindowGeometry(const QByteArray &value);
+
+ QByteArray getWindowState() const;
+ void setWindowState(const QByteArray &value);
+
+ QByteArray getSplitterState() const;
+ void setSplitterState(const QByteArray &value);
+
+public:
+ QList friendAddresses;
void save();
void save(QString path);
void load();
-
+private:
+ Settings();
+ Settings(Settings &settings) = delete;
+ Settings& operator=(const Settings&) = delete;
static const QString FILENAME;
@@ -146,11 +161,16 @@ private:
// GUI
bool enableSmoothAnimation;
- QByteArray smileyPack;
+ QString smileyPack;
bool customEmojiFont;
QString emojiFontFamily;
int emojiFontPointSize;
bool minimizeOnClose;
+ bool useNativeStyle;
+ bool useNativeDecoration;
+ QByteArray windowGeometry;
+ QByteArray windowState;
+ QByteArray splitterState;
// ChatView
int firstColumnHandlePos;
diff --git a/smileypack.cpp b/smileypack.cpp
new file mode 100644
index 000000000..cca56583c
--- /dev/null
+++ b/smileypack.cpp
@@ -0,0 +1,199 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "smileypack.h"
+#include "settings.h"
+
+#include
+#include
+#include
+#include
+
+SmileyPack::SmileyPack()
+{
+ load(Settings::getInstance().getSmileyPack());
+ connect(&Settings::getInstance(), &Settings::smileyPackChanged, this, &SmileyPack::onSmileyPackChanged);
+}
+
+SmileyPack& SmileyPack::getInstance()
+{
+ static SmileyPack smileyPack;
+ return smileyPack;
+}
+
+QList > SmileyPack::listSmileyPacks(const QString &path)
+{
+ QList > smileyPacks;
+
+ QDir dir(path);
+ foreach (const QString& subdirectory, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
+ {
+ dir.cd(subdirectory);
+
+ QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files);
+ if (entries.size() > 0) // does it contain a file called emoticons.xml?
+ {
+ QString packageName = dir.dirName();
+ QString relPath = QDir(QCoreApplication::applicationDirPath()).relativeFilePath(entries[0].absoluteFilePath());
+ smileyPacks << QPair(packageName, relPath);
+ }
+
+ dir.cdUp();
+ }
+
+ return smileyPacks;
+}
+
+bool SmileyPack::isValid(const QString &filename)
+{
+ return QFile(filename).exists();
+}
+
+bool SmileyPack::load(const QString& filename)
+{
+ // discard old data
+ filenameTable.clear();
+ imgCache.clear();
+ emoticons.clear();
+ path.clear();
+
+ // open emoticons.xml
+ QFile xmlFile(filename);
+ if(!xmlFile.open(QIODevice::ReadOnly))
+ return false; // cannot open file
+
+ /* parse the cfg file
+ * sample:
+ *
+ *
+ *
+ * :)
+ * :-)
+ *
+ *
+ * :(
+ * :-(
+ *
+ *
+ */
+
+ path = QFileInfo(filename).absolutePath();
+
+ QDomDocument doc;
+ doc.setContent(xmlFile.readAll());
+
+ QDomNodeList emoticonElements = doc.elementsByTagName("emoticon");
+ for (int i = 0; i < emoticonElements.size(); ++i)
+ {
+ QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
+ QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
+
+ QStringList emoticonSet; // { ":)", ":-)" } etc.
+
+ while (!stringElement.isNull())
+ {
+ QString emoticon = stringElement.text();
+ filenameTable.insert(emoticon, file);
+ emoticonSet.push_back(emoticon);
+ cacheSmiley(file); // preload all smileys
+
+ stringElement = stringElement.nextSibling().toElement();
+ }
+ emoticons.push_back(emoticonSet);
+ }
+
+ // success!
+ return true;
+}
+
+QString SmileyPack::smileyfied(QString msg)
+{
+ QRegExp exp("\\S+"); // matches words
+
+ int index = msg.indexOf(exp);
+
+ // if a word is key of a smiley, replace it by its corresponding image in Rich Text
+ while (index >= 0)
+ {
+ QString key = exp.cap();
+ if (filenameTable.contains(key))
+ {
+ QString imgRichText = getAsRichText(key);
+
+ msg.replace(index, key.length(), imgRichText);
+ index += imgRichText.length() - key.length();
+ }
+ index = msg.indexOf(exp, index + key.length());
+ }
+
+ return msg;
+}
+
+QList SmileyPack::getEmoticons() const
+{
+ return emoticons;
+}
+
+QString SmileyPack::getAsRichText(const QString &key)
+{
+ return "";
+}
+
+QIcon SmileyPack::getAsIcon(const QString &key)
+{
+ QPixmap pm;
+ pm.loadFromData(getCachedSmiley(key), "PNG");
+
+ return QIcon(pm);
+}
+
+void SmileyPack::cacheSmiley(const QString &name)
+{
+ QSize size(16, 16); // TODO: adapt to text size
+ QString filename = QDir(path).filePath(name);
+ QImage img(filename);
+
+ if (!img.isNull())
+ {
+ QImage scaledImg = img.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+
+ QByteArray scaledImgData;
+ QBuffer buffer(&scaledImgData);
+ scaledImg.save(&buffer, "PNG");
+
+ imgCache.insert(name, scaledImgData);
+ }
+}
+
+QByteArray SmileyPack::getCachedSmiley(const QString &key)
+{
+ // valid key?
+ if (!filenameTable.contains(key))
+ return QByteArray();
+
+ // cache it if needed
+ QString file = filenameTable.value(key);
+ if (!imgCache.contains(file)) {
+ cacheSmiley(file);
+ }
+
+ return imgCache.value(file);
+}
+
+void SmileyPack::onSmileyPackChanged()
+{
+ load(Settings::getInstance().getSmileyPack());
+}
diff --git a/smileypack.h b/smileypack.h
new file mode 100644
index 000000000..9f4ea31ba
--- /dev/null
+++ b/smileypack.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#ifndef SMILEYPACK_H
+#define SMILEYPACK_H
+
+#include
+#include
+#include
+#include
+
+#define SMILEYPACK_DEFAULT_PATH "./smileys"
+
+//maps emoticons to smileys
+class SmileyPack : public QObject
+{
+ Q_OBJECT
+public:
+ static SmileyPack& getInstance();
+ static QList> listSmileyPacks(const QString& path = SMILEYPACK_DEFAULT_PATH);
+ static bool isValid(const QString& filename);
+
+ bool load(const QString &filename);
+ QString smileyfied(QString msg);
+ QList getEmoticons() const;
+ QString getAsRichText(const QString& key);
+ QIcon getAsIcon(const QString& key);
+
+private slots:
+ void onSmileyPackChanged();
+
+private:
+ SmileyPack();
+ SmileyPack(SmileyPack&) = delete;
+ SmileyPack& operator=(const SmileyPack&) = delete;
+
+ void cacheSmiley(const QString& name);
+ QByteArray getCachedSmiley(const QString& key);
+
+ QHash filenameTable; // matches an emoticon to its corresponding smiley ie. ":)" -> "happy.png"
+ QHash imgCache; // (scaled) representation of a smiley ie. "happy.png" -> data
+ QList emoticons; // {{ ":)", ":-)" }, {":(", ...}, ... }
+ QString path; // directory containing the cfg and image files
+};
+
+#endif // SMILEYPACK_H
diff --git a/smileys/default/angry.png b/smileys/default/angry.png
new file mode 100644
index 000000000..e096ce5ff
Binary files /dev/null and b/smileys/default/angry.png differ
diff --git a/smileys/default/cool.png b/smileys/default/cool.png
new file mode 100644
index 000000000..9c5f1b13a
Binary files /dev/null and b/smileys/default/cool.png differ
diff --git a/smileys/default/crying.png b/smileys/default/crying.png
new file mode 100644
index 000000000..b03be57a4
Binary files /dev/null and b/smileys/default/crying.png differ
diff --git a/smileys/default/emoticons.xml b/smileys/default/emoticons.xml
new file mode 100644
index 000000000..d1fe8c715
--- /dev/null
+++ b/smileys/default/emoticons.xml
@@ -0,0 +1,85 @@
+
+
+
+ 😊
+ :)
+ :-)
+
+
+
+ 😎
+ 8-)
+ 8)
+
+
+
+ 😲
+ :O
+ :-O
+
+
+
+ 😋
+ :p
+ :P
+
+
+
+ 😕
+ :/
+ :-/
+
+
+
+ 😉
+ ;)
+ ;-)
+
+
+
+ 😖
+ :(
+ :-(
+
+
+
+ 😢
+ ;(
+ ;-(
+
+
+
+ 😃
+ :D
+ :-D
+
+
+
+ 😐
+ :|
+ :-|
+
+
+
+ 😄
+ ;D
+ ;-D
+
+
+
+ 😠
+ :@
+
+
+
+ 😨
+ D:
+
+
+
+ 😆
+ xD
+ XD
+
+
+
diff --git a/smileys/default/happy.png b/smileys/default/happy.png
new file mode 100644
index 000000000..bddcc567b
Binary files /dev/null and b/smileys/default/happy.png differ
diff --git a/smileys/default/laugh.png b/smileys/default/laugh.png
new file mode 100644
index 000000000..163b0c4c7
Binary files /dev/null and b/smileys/default/laugh.png differ
diff --git a/smileys/default/laugh_closed_eyes.png b/smileys/default/laugh_closed_eyes.png
new file mode 100644
index 000000000..fc294a510
Binary files /dev/null and b/smileys/default/laugh_closed_eyes.png differ
diff --git a/smileys/default/plain.png b/smileys/default/plain.png
new file mode 100644
index 000000000..3916b06c6
Binary files /dev/null and b/smileys/default/plain.png differ
diff --git a/smileys/default/raw.svg b/smileys/default/raw.svg
new file mode 100644
index 000000000..8ca952f95
--- /dev/null
+++ b/smileys/default/raw.svg
@@ -0,0 +1,889 @@
+
+
+
+
diff --git a/smileys/default/sad.png b/smileys/default/sad.png
new file mode 100644
index 000000000..1fdd9909d
Binary files /dev/null and b/smileys/default/sad.png differ
diff --git a/smileys/default/scared.png b/smileys/default/scared.png
new file mode 100644
index 000000000..c8a904977
Binary files /dev/null and b/smileys/default/scared.png differ
diff --git a/smileys/default/smile.png b/smileys/default/smile.png
new file mode 100644
index 000000000..b13fa01d2
Binary files /dev/null and b/smileys/default/smile.png differ
diff --git a/smileys/default/stunned.png b/smileys/default/stunned.png
new file mode 100644
index 000000000..cbdbaa6c4
Binary files /dev/null and b/smileys/default/stunned.png differ
diff --git a/smileys/default/tongue.png b/smileys/default/tongue.png
new file mode 100644
index 000000000..946419fc1
Binary files /dev/null and b/smileys/default/tongue.png differ
diff --git a/smileys/default/uncertain.png b/smileys/default/uncertain.png
new file mode 100644
index 000000000..d6cdddbed
Binary files /dev/null and b/smileys/default/uncertain.png differ
diff --git a/smileys/default/wink.png b/smileys/default/wink.png
new file mode 100644
index 000000000..ab5858c2d
Binary files /dev/null and b/smileys/default/wink.png differ
diff --git a/style.cpp b/style.cpp
new file mode 100644
index 000000000..609dcc277
--- /dev/null
+++ b/style.cpp
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "style.h"
+#include "settings.h"
+
+#include
+#include
+
+QString Style::get(const QString &filename)
+{
+ if (!Settings::getInstance().getUseNativeStyle())
+ {
+ QFile file(filename);
+ if (file.open(QFile::ReadOnly | QFile::Text))
+ return file.readAll();
+ else
+ qWarning() << "Style " << filename << " not found";
+ }
+
+ return QString();
+}
diff --git a/widget/tool/clickablelabel.cpp b/style.h
similarity index 78%
rename from widget/tool/clickablelabel.cpp
rename to style.h
index 9e61becff..77a09ce25 100644
--- a/widget/tool/clickablelabel.cpp
+++ b/style.h
@@ -14,14 +14,17 @@
See the COPYING file for more details.
*/
-#include "clickablelabel.h"
+#ifndef STYLE_H
+#define STYLE_H
-ClickableLabel::ClickableLabel(QWidget *parent) :
- QLabel(parent)
-{
-}
+#include
-void ClickableLabel::mousePressEvent(QMouseEvent*)
+class Style
{
- emit clicked();
-}
+public:
+ static QString get(const QString& filename);
+private:
+ Style();
+};
+
+#endif // STYLE_H
diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh
new file mode 100755
index 000000000..d0ec345c0
--- /dev/null
+++ b/tools/buildPackages.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+# Config (Update me if needed !)
+VERSION_UPSTREAM="0.01pre-alpha"
+VERSION_PACKAGE="1"
+PACKAGENAME="qtox"
+UPSTREAM_URL="https://github.com/tux3/qTox/archive/master.tar.gz"
+
+# Make some vars for convenience
+VERNAME=$PACKAGENAME"_"$VERSION_UPSTREAM
+FULLVERNAME=$VERNAME"-"$VERSION_PACKAGE
+ARCHIVENAME=$VERNAME".orig.tar.gz"
+
+# ARCHIVENAME > FULLVERNAME > VERNAME = PACKAGENAME+UPVER
+
+# Get some args
+OPT_SUDO=true
+OPT_APT=true
+OPT_KEEP=false
+while [ $# -ge 1 ] ; do
+ if [ ${1} = "-s" -o ${1} = "--no-sudo" ] ; then
+ OPT_SUDO=false
+ shift
+ elif [ ${1} = "-a" -o ${1} = "--no-apt" ] ; then
+ OPT_APT=false
+ shift
+ elif [ ${1} = "-k" -o ${1} = "--keep" ]; then
+ OPT_KEEP=true
+ shift
+ else
+ if [ ${1} != "-h" -a ${1} != "--help" ] ; then
+ echo "[ERROR] Unknown parameter \"${1}\""
+ echo ""
+ fi
+
+ # print help
+ echo "Use this script to build qTox packages for Debian and Red Hat families"
+ echo ""
+ echo "usage:"
+ echo " ${0} [-h|--help|-k|--keep|-s|--no-sudo|-a|--no-apt]"
+ echo ""
+ echo "parameters:"
+ echo " -h|--help : displays this help"
+ echo " -s|--no-sudo: disables using sudo for apt and alien"
+ echo " -a|--no-apt : disables apt-get (used for build deps) entirely"
+ echo " -k|--keep : does not delete the build files afterwards"
+ echo ""
+ echo "example usages:"
+ echo " ${0} -- build packages, cleaning up trash and running sudo alien and apt-get"
+ echo " ${0} -s -k -- build packages, keeping build files and non-sudo alien and apt-get"
+ exit 1
+ fi
+done
+
+# Get the requried tools if needed
+if [[ $OPT_APT = "true" ]]; then
+ echo "Installing missing tools (if any)..."
+ if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then
+ sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential
+ else
+ apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential
+ fi
+fi
+
+mkdir -p .packages
+cd .packages
+
+# Cleanup
+rm -r $VERNAME 2> /dev/null
+rm $ARCHIVENAME 2> /dev/null
+
+# Fectch sources and layout directories
+wget -O $ARCHIVENAME $UPSTREAM_URL
+tar xvf $ARCHIVENAME 2> /dev/null # Extracts to qTox-master
+mv qTox-master $VERNAME
+#tar cz $VERNAME > $ARCHIVENAME
+
+# Build packages
+cd $VERNAME
+debuild -us -uc
+cd ..
+
+# alien warns that it should probably be run as root...
+if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then
+ sudo alien ./$FULLVERNAME*.deb -r
+else
+ alien ./$FULLVERNAME*.deb -r
+fi
+
+mv *.deb ..
+mv -f *.rpm ..
+
+if [[ $OPT_KEEP = "false" ]]; then
+ rm -r *
+fi
+
+cd ..
+rmdir .packages 2> /dev/null # fails if non empty
diff --git a/translations/de.ts b/translations/de.ts
index 63b4dada9..ab61ba9ad 100644
--- a/translations/de.ts
+++ b/translations/de.ts
@@ -1,75 +1,75 @@
-
+AddFriendForm
-
+ Freunde hinzufügen
-
+ Tox ID of the person you're sending a friend request toTox ID
-
+ The message you send in friend requestsNachricht
-
+ Freundschaftseinladung versenden
-
+ Default message in friend requests if the field is left blank. Write something appropriate!Lass uns Toxen!
-
+ Tox ID of the friend you're sending a friend request toBitte gib eine gültige Tox ID ein
-
+ The DNS gives the Tox ID associated to toxme.se addresses
-
+ The DNS gives the Tox ID associated to toxme.se addressesFehler beim Auflösen des DNS
-
+ Error with the DNSUnererwartete Anzahl von Texteinträgen
-
+ Error with the DNSUnerwartete Anzahl von Werten innerhalb des Texteintrages
-
+ Error with the DNSDer DNS Eintrag enthält keine gültige TOX ID
-
-
+
+ Error with the DNSDer DNS Eintrag enthält keine gültige TOX ID
@@ -78,12 +78,12 @@
Camera
-
+ Kamerafehler
-
+ Kameraformat %1 wird nicht unterstützt. Die Kamera kann nicht verwendet werden
@@ -91,13 +91,13 @@
ChatForm
-
+ Datei versenden
-
-
+
+ Chatverlauf speichern
@@ -113,11 +113,42 @@
FileTransfertWidget
-
+ Title of the file saving dialogDatei speichern
+
+
+
+ Title of permissions popup
+
+
+
+
+
+ text of permissions popup
+
+
+
+
+ FilesForm
+
+
+
+ "Headline" of the window
+
+
+
+
+
+
+
+
+
+
+
+ FriendRequestDialog
@@ -158,19 +189,19 @@
FriendWidget
-
+ Menu to copy the Tox ID of that friendTox ID kopieren
-
+ Menu to invite a friend in a groupchatIn Gruppe einladen
-
+ Menu to remove the friend from our friendlistFreund entfernen
@@ -179,23 +210,23 @@
GroupChatForm
-
+ Number of users in chat%1 Personen im Chat
-
+ <Unbekannt>
-
+ %1 Personen im Chat
-
+ Chatverlauf speichern
@@ -203,28 +234,76 @@
GroupWidget
-
-
+
+ %1 Personen im Chat
-
-
+
+ 0 Personen im Chat
-
+ Menu to quit a groupchatGruppe verlassen
+
+ MainWindow
+
+
+
+
+
+
+
+
+ Dein Name
+
+
+
+
+ Dein Status
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Schließen
+
+
+
+
+ Strg+Q
+
+SelfCamView
-
+ Title of the window to test the video/webcamTox Video testen
@@ -233,83 +312,105 @@
SettingsForm
-
+ "Headline" of the windowEinstellungen
-
+ Username/nickBenutzername
-
+ Status messageStatus
-
+
+
+ Click on this text to copy TID to clipboard
+
+
+
+ Text on a button to test the video/webcamVideo testen
-
+ Text on a checkbox to enable IPv6IPv6 aktivieren (empfohlen)
-
+ Text on a checkbox to enable translations
+
+
+
+ Text on a checkbox to make qTox a portable application
+
+
+
+
+
+ describes makeToxPortable checkbox
+
+
+
+
+
+ Text on smiley pack label
+
+ Widget
-
- Tox
+ Tox
-
- Dein Name
+ Dein Name
-
- Dein Status
+ Dein Status
-
- Schließen
+ Schließen
-
- Strg+Q
+ Strg+Q
+ Button to set your status to 'Online'
- Online
+ Online
+ Button to set your status to 'Away'
- Abwesend
+ Abwesend
+ Button to set your status to 'Busy'
- Beschäftigt
+ Beschäftigt
diff --git a/translations/fr.ts b/translations/fr.ts
index 3851b7684..435d022c7 100644
--- a/translations/fr.ts
+++ b/translations/fr.ts
@@ -1,75 +1,75 @@
-
+AddFriendForm
-
+ Ajouter des amis
-
+ Tox ID of the person you're sending a friend request toID Tox
-
+ The message you send in friend requestsMessage
-
+ Envoyer la demande d'ami
-
+ Default message in friend requests if the field is left blank. Write something appropriate!Je souhaiterais vous ajouter à mes contacts
-
+ Tox ID of the friend you're sending a friend request toMerci de remplir un ID Tox valide
-
+ The DNS gives the Tox ID associated to toxme.se addresses
-
+ The DNS gives the Tox ID associated to toxme.se addressesErreur en consultant le serveur DNS
-
+ Error with the DNSNombre d'entrées texte innatendu
-
+ Error with the DNSNombre d'entrées numériques dans l'entrée texte innatendu
-
+ Error with the DNSLa réponse DNS ne contient aucun ID Tox
-
-
+
+ Error with the DNSLa réponse DNS ne contient pas d'ID Tox valide
@@ -78,12 +78,12 @@
Camera
-
+ Erreur de caméra
-
+ Format %1 de la caméra non supporté, impossible de l'utiliser
@@ -91,13 +91,13 @@
ChatForm
-
+ Envoyer un fichier
-
-
+
+ Sauvegarder l'historique de conversation
@@ -113,11 +113,42 @@
FileTransfertWidget
-
+ Title of the file saving dialogSauvegarder un fichier
+
+
+
+ Title of permissions popup
+
+
+
+
+
+ text of permissions popup
+
+
+
+
+ FilesForm
+
+
+
+ "Headline" of the window
+
+
+
+
+
+
+
+
+
+
+
+ FriendRequestDialog
@@ -158,19 +189,19 @@
FriendWidget
-
+ Menu to copy the Tox ID of that friendCopier l'ID ami
-
+ Menu to invite a friend in a groupchatInviter dans un groupe
-
+ Menu to remove the friend from our friendlistSupprimer ami
@@ -179,23 +210,23 @@
GroupChatForm
-
+ Number of users in chat%1 personnes
-
+ <Inconnu>
-
+ %1 personnes
-
+ Sauvegarder l'historique de conversation
@@ -203,28 +234,76 @@
GroupWidget
-
-
+
+ %1 personnes
-
-
+
+ 0 personnes
-
+ Menu to quit a groupchatQuitter le groupe
+
+ MainWindow
+
+
+
+
+
+
+
+
+ Votre nom
+
+
+
+
+ Votre status
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fermer
+
+
+
+
+ Ctrl+Q
+
+SelfCamView
-
+ Title of the window to test the video/webcamTest vidéo Tox
@@ -233,83 +312,105 @@
SettingsForm
-
+ "Headline" of the windowConfiguration
-
+ Username/nickNom
-
+ Status messageStatus
-
+
+
+ Click on this text to copy TID to clipboard
+
+
+
+ Text on a button to test the video/webcamTester la vidéo
-
+ Text on a checkbox to enable IPv6Activer IPv6 (recommandé)
-
+ Text on a checkbox to enable translations
+
+
+
+ Text on a checkbox to make qTox a portable application
+
+
+
+
+
+ describes makeToxPortable checkbox
+
+
+
+
+
+ Text on smiley pack label
+
+ Widget
-
- Tox
+ Tox
-
- Votre nom
+ Votre nom
-
- Votre status
+ Votre status
-
- Fermer
+ Fermer
-
- Ctrl+Q
+ Ctrl+Q
+ Button to set your status to 'Online'
- Connecté
+ Connecté
+ Button to set your status to 'Away'
- Indisponnible
+ Indisponnible
+ Button to set your status to 'Busy'
- Occupé
+ Occupé
diff --git a/translations/it.qm b/translations/it.qm
index d8c42654a..ea977d5d6 100644
Binary files a/translations/it.qm and b/translations/it.qm differ
diff --git a/translations/it.ts b/translations/it.ts
index cde73cd0f..7ada13790 100644
--- a/translations/it.ts
+++ b/translations/it.ts
@@ -1,6 +1,6 @@
-
+AddFriendForm
@@ -26,50 +26,50 @@
Invia richiesta d'amicizia
-
+ Default message in friend requests if the field is left blank. Write something appropriate!Permettimi di aggiungerti alla mia lista contatti
-
+ Tox ID of the friend you're sending a friend request toInserisci un Tox ID valido
-
+ The DNS gives the Tox ID associated to toxme.se addressesQuesto indirizzo non esiste
-
+ The DNS gives the Tox ID associated to toxme.se addressesErrore nel consultare il server DNS
-
+ Error with the DNSNumero inaspettato di text-records
-
+ Error with the DNSNumero inaspettato di valori nel text-record
-
+ Error with the DNSLa risposta del server DNS non contiene nessun Tox ID
-
-
+
+ Error with the DNSLa risposta del server DNS non contiene un Tox ID valido
@@ -91,13 +91,13 @@
ChatForm
-
+ Invia un file
-
-
+
+ Salva il log della chat
@@ -113,11 +113,23 @@
FileTransfertWidget
-
+ Title of the file saving dialogSalva file
+
+
+
+ Title of permissions popup
+ Errore
+
+
+
+
+ text of permissions popup
+ Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio.
+ FilesForm
@@ -125,15 +137,15 @@
"Headline" of the window
- Files inviati
+ Files Trasferiti
-
+ Ricevuti
-
+ Inviati
@@ -177,19 +189,19 @@
FriendWidget
-
+ Menu to copy the Tox ID of that friendCopia Tox ID del contatto
-
+ Menu to invite a friend in a groupchatInvita nel gruppo
-
+ Menu to remove the friend from our friendlistRimuovi contatto
@@ -198,23 +210,23 @@
GroupChatForm
-
+ Number of users in chat%1 utenti in chat
-
+ <Sconosciuto>
-
+ %1 utenti in chat
-
+ Salva il log della chat
@@ -223,23 +235,71 @@
GroupWidget
-
+ %1 utenti in chat
-
+ 0 utenti in chat
-
+ Menu to quit a groupchatEsci dal gruppo
+
+ MainWindow
+
+
+
+ qTox
+
+
+
+
+ qTox User
+
+
+
+
+ Toxin on qTox
+
+
+
+
+ Aggiungi contatto
+
+
+
+
+ Crea un gruppo
+
+
+
+
+ Visualizza i trasferimenti completati
+
+
+
+
+ Cambia le impostazioni
+
+
+
+
+ Chiudi
+
+
+
+
+ Ctrl+Q
+
+SelfCamView
@@ -252,115 +312,129 @@
SettingsForm
-
+ "Headline" of the windowImpostazioni
-
+ Username/nickNome
-
+ Status messageStato
-
+ Click on this text to copy TID to clipboard(clicca qui per copiare)
-
+ Text on a button to test the video/webcamProva la webcam
-
+ Text on a checkbox to enable IPv6Abilita IPv6 (consigliato)
-
+ Text on a checkbox to enable translationsAbilita traduzioni
-
+ Text on a checkbox to make qTox a portable applicationRendi qTox portabile
+
+
+
+ describes makeToxPortable checkbox
+ Slava le impostazioni nella directory di lavoro corrente, invece della directory di default
+
+
+
+
+ Text on smiley pack label
+ Emoticons
+
+
+
+ Scegli pacchetto emoticons
+ Widget
-
- Tox
+ Tox
-
- Tox User
+ Tox User
-
- Toxin on qTox
+ Toxin on qTox
-
- Aggiungi contatto
+ Aggiungi contatto
-
- Crea un gruppo
+ Crea un gruppo
+
+
+
+ Visualizza i trasferimenti completati
-
- (bottone attualmente inattivo)
+ (bottone attualmente inattivo)
-
- Cambia le impostazioni
+ Cambia le impostazioni
-
- Chiudi
+ Chiudi
-
- Ctrl+Q
+ Ctrl+Q
+ Button to set your status to 'Online'
- Online
+ Online
+ Button to set your status to 'Away'
- Assente
+ Assente
+ Button to set your status to 'Busy'
- Occupato
+ Occupato
diff --git a/translations/ru.ts b/translations/ru.ts
index 2ce21d900..1e2118770 100644
--- a/translations/ru.ts
+++ b/translations/ru.ts
@@ -27,51 +27,51 @@
Отправить запрос на добавление в друзья
-
+ Default message in friend requests if the field is left blank. Write something appropriate!Вот таким нехитрым и незамысловатым образом решаются сложные переводчиские проблемыДобавь меня, а?
-
+ Tox ID of the friend you're sending a friend request toПожалуйста, введите корректный Tox ID
-
+ The DNS gives the Tox ID associated to toxme.se addressesНет такого адреса
-
+ The DNS gives the Tox ID associated to toxme.se addressesОшибка при просмотре DNS
-
+ Error with the DNSНепредвиденное количество текстовых записей
-
+ Error with the DNSНепредвиденное количество значений в текстовой записи
-
+ Error with the DNSВ ответе DNS ни одного Tox ID
-
-
+
+ Error with the DNSОтвет DNS не содержит корректных Tox ID
@@ -93,13 +93,13 @@
ChatForm
-
+ Отправить файл
-
-
+
+ Сохранить лог чата
@@ -115,11 +115,23 @@
FileTransfertWidget
-
+ Title of the file saving dialogСохранить файл
+
+
+
+ Title of permissions popup
+
+
+
+
+
+ text of permissions popup
+
+ FilesForm
@@ -130,12 +142,12 @@
Переданные файлы
-
+ Загрузки
-
+ Выгрузки
@@ -181,19 +193,19 @@
FriendWidget
-
+ Menu to copy the Tox ID of that friendКопировать ID друга
-
+ Menu to invite a friend in a groupchatПригласить в группу
-
+ Menu to remove the friend from our friendlistУдалить друга
@@ -202,23 +214,23 @@
GroupChatForm
-
+ Number of users in chat%1 пользователей в чате
-
+ <Неизвестно>
-
+ %1 пользователей в чате
-
+ Сохранить лог чата
@@ -226,24 +238,72 @@
GroupWidget
-
+ Menu to quit a groupchatПокинуть группу
-
+ %1 пользователей в чате
-
+ Ни одного пользователя в чате
+
+ MainWindow
+
+
+
+
+
+
+
+
+ Ваше имя
+
+
+
+
+ Ваш статус
+
+
+
+
+ Добавить друзей
+
+
+
+
+ Создать групповой чат
+
+
+
+
+
+
+
+
+
+ Изменить ваши настройки
+
+
+
+
+ Закрыть
+
+
+
+
+ Ctrl+Q
+
+SelfCamView
@@ -256,117 +316,123 @@
SettingsForm
-
+ "Headline" of the windowПользовательские настройки
-
+ Username/nickИмя
-
+ Status messageСтатус
-
+ Click on this text to copy TID to clipboard(нажмите здесь чтобы скопировать)
-
+ Text on a button to test the video/webcamПроверить видео
-
+ Text on a checkbox to enable IPv6Включить IPv6 (рекомендуется)
-
+ Text on a checkbox to enable translationsТак гораздо понятнее, чем «использовать переводы»Русскоязычный интерфейс
-
+ Text on a checkbox to make qTox a portable applicationПортативный режим
+
+
+
+ describes makeToxPortable checkbox
+
+
+
+
+
+ Text on smiley pack label
+
+ Widget
-
- Tox
+ Tox
-
- Ваше имя
+ Ваше имя
-
- Ваш статус
+ Ваш статус
-
- Добавить друзей
+ Добавить друзей
-
- Создать групповой чат
+ Создать групповой чат
-
- (кнопка на данный момент неактивна)
+ (кнопка на данный момент неактивна)
-
- Изменить ваши настройки
+ Изменить ваши настройки
-
- Закрыть
+ Закрыть
-
- Ctrl+Q
+ Ctrl+Q
+ Button to set your status to 'Online'
- В сети
+ В сети
+ Button to set your status to 'Away'Вероятно, это не столь долгое путешествие
- Отошёл
+ Отошёл
+ Button to set your status to 'Busy'
- Занят
+ Занят
diff --git a/ui/emoticonWidget/dot_page.png b/ui/emoticonWidget/dot_page.png
new file mode 100644
index 000000000..c7c2aa172
Binary files /dev/null and b/ui/emoticonWidget/dot_page.png differ
diff --git a/ui/emoticonWidget/dot_page_current.png b/ui/emoticonWidget/dot_page_current.png
new file mode 100644
index 000000000..aa101903a
Binary files /dev/null and b/ui/emoticonWidget/dot_page_current.png differ
diff --git a/ui/emoticonWidget/dot_page_hover.png b/ui/emoticonWidget/dot_page_hover.png
new file mode 100644
index 000000000..1c23931b9
Binary files /dev/null and b/ui/emoticonWidget/dot_page_hover.png differ
diff --git a/ui/emoticonWidget/emoticonWidget.css b/ui/emoticonWidget/emoticonWidget.css
new file mode 100644
index 000000000..a1aab7de3
--- /dev/null
+++ b/ui/emoticonWidget/emoticonWidget.css
@@ -0,0 +1,40 @@
+QPushButton
+{
+ background-color: transparent;
+ background-repeat: none;
+ border: none;
+ width: 18px;
+ height: 18px;
+}
+
+QRadioButton::indicator
+{
+ width: 10px;
+ height: 10px;
+}
+
+QRadioButton::indicator::unchecked
+{
+ image: url(:/ui/emoticonWidget/dot_page.png);
+}
+
+QRadioButton::indicator:unchecked:hover
+{
+ image: url(:/ui/emoticonWidget/dot_page_hover.png);
+}
+
+QRadioButton::indicator:unchecked:pressed
+{
+ image: url(:/ui/emoticonWidget/dot_page_hover.png);
+}
+
+QRadioButton::indicator::checked
+{
+ image: url(:/ui/emoticonWidget/dot_page_current.png);
+}
+
+QMenu
+{
+ background-color: rgb(240,240,240); /* sets background of the menu */
+ border: 1px solid;
+}
diff --git a/ui/friendList/friendList.css b/ui/friendList/friendList.css
index 42bf69cc1..55b39e1e6 100644
--- a/ui/friendList/friendList.css
+++ b/ui/friendList/friendList.css
@@ -1,34 +1,34 @@
QScrollArea {
- background: #414141!important;
+ background: #414141;
}
QScrollBar:vertical {
- background: #414141!important;
- width: 14px!important;
- margin-top: 2px!important;
- margin-bottom: 2px!important;
+ background: transparent;
+ width: 14px;
+ margin-top: 2px;
+ margin-bottom: 2px;
}
QScrollBar:handle:vertical {
- background: #1c1c1c!important;
- min-height: 20px!important;
- border-radius: 3px!important;
- margin-left: 3px!important;
- margin-right: 1px!important;
+ background: rgba(18, 18, 18, 204);
+ min-height: 20px;
+ border-radius: 3px;
+ margin-left: 3px;
+ margin-right: 1px;
}
QScrollBar:handle:vertical:hover {
- background: #2d2d2d!important;
+ background: rgba(35, 35, 35, 204);
}
QScrollBar:handle:vertical:pressed {
- background: #171717!important;
+ background: rgba(13, 13, 13, 204);
}
-QScrollBar:add-line:vertical {height: 0px!important;subcontrol-position: bottom!important;subcontrol-origin: margin!important;}
+QScrollBar:add-line:vertical {height: 0px;subcontrol-position: bottom;subcontrol-origin: margin;}
-QScrollBar:sub-line:vertical {height: 0px!important;subcontrol-position: top!important;subcontrol-origin: margin!important;}
+QScrollBar:sub-line:vertical {height: 0px;subcontrol-position: top;subcontrol-origin: margin;}
QScrollBar:add-page:vertical, QScrollBar::sub-page:vertical {
- background: none!important;
+ background: none;
}
diff --git a/ui/micButton/micButton.css b/ui/micButton/micButton.css
new file mode 100644
index 000000000..ec784ae7a
--- /dev/null
+++ b/ui/micButton/micButton.css
@@ -0,0 +1,38 @@
+QPushButton#green
+{
+ background-color: transparent;
+ background-image: url(":/ui/micButton/micButton.png");
+ background-repeat: none;
+ border: none;
+ width: 25px;
+ height: 20px;
+}
+
+QPushButton#green:hover
+{
+ background-image:url(":/ui/micButton/micButtonHover.png");
+}
+
+QPushButton#red
+{
+ background-color: transparent;
+ background-image: url(":/ui/micButton/micButtonPressed.png");
+ background-repeat: none;
+ border: none;
+ width: 25px;
+ height: 20px;
+}
+
+QPushButton#grey
+{
+ background-color: transparent;
+ background-image: url(":/ui/micButton/micButtonDisabled.png");
+ background-repeat: none;
+ border: none;
+ width: 25px;
+ height: 20px;
+}
+
+QPushButton:focus {
+ outline: none;
+}
diff --git a/ui/micButton/micButton.png b/ui/micButton/micButton.png
new file mode 100644
index 000000000..7f0cf0c4d
Binary files /dev/null and b/ui/micButton/micButton.png differ
diff --git a/ui/micButton/micButtonDisabled.png b/ui/micButton/micButtonDisabled.png
new file mode 100644
index 000000000..9cb38c9be
Binary files /dev/null and b/ui/micButton/micButtonDisabled.png differ
diff --git a/ui/micButton/micButtonHover.png b/ui/micButton/micButtonHover.png
new file mode 100644
index 000000000..462337253
Binary files /dev/null and b/ui/micButton/micButtonHover.png differ
diff --git a/ui/micButton/micButtonPressed.png b/ui/micButton/micButtonPressed.png
new file mode 100644
index 000000000..cf46b7cf6
Binary files /dev/null and b/ui/micButton/micButtonPressed.png differ
diff --git a/ui/volButton/volButton.css b/ui/volButton/volButton.css
new file mode 100644
index 000000000..066d9ae66
--- /dev/null
+++ b/ui/volButton/volButton.css
@@ -0,0 +1,23 @@
+QPushButton#green
+{
+ background-color: transparent;
+ background-image: url(":/ui/volButton/volButton.png");
+ background-repeat: none;
+ border: none;
+ width: 25px;
+ height: 20px;
+}
+
+QPushButton#green:hover
+{
+ background-image: url(":/ui/volButton/volButtonHover.png");
+}
+
+QPushButton#green:pressed
+{
+ background-image: url(":/ui/volButton/volButtonPressed.png");
+}
+
+QPushButton:focus {
+ outline: none;
+}
diff --git a/ui/volButton/volButton.png b/ui/volButton/volButton.png
new file mode 100644
index 000000000..994fcce4f
Binary files /dev/null and b/ui/volButton/volButton.png differ
diff --git a/ui/volButton/volButtonHover.png b/ui/volButton/volButtonHover.png
new file mode 100644
index 000000000..e6422b7f8
Binary files /dev/null and b/ui/volButton/volButtonHover.png differ
diff --git a/ui/volButton/volButtonPressed.png b/ui/volButton/volButtonPressed.png
new file mode 100644
index 000000000..fc9b67a27
Binary files /dev/null and b/ui/volButton/volButtonPressed.png differ
diff --git a/widget.ui b/widget.ui
deleted file mode 100644
index 0364da3d8..000000000
--- a/widget.ui
+++ /dev/null
@@ -1,3357 +0,0 @@
-
-
-
-
- Widget
-
-
-
- 0
- 0
- 640
- 320
-
-
-
-
- 640
- 320
-
-
-
-
- 16777215
- 16777215
-
-
-
- Tox
-
-
-
- :/img/icon.png:/img/icon.png
-
-
-
- 2
-
-
- 1
-
-
- 2
-
-
- 2
-
-
- 0
-
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 23
-
-
-
-
- 16777215
- 23
-
-
-
-
- 4
-
-
- 5
-
-
- 0
-
-
- 1
-
-
- 0
-
-
-
-
-
- 16
- 16
-
-
-
-
- 16
- 16
-
-
-
-
- 16
- 16
-
-
-
- QToolButton::InstantPopup
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 15
- 1
-
-
-
-
-
-
-
-
- 100
- 22
-
-
-
-
- 16777215
- 22
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 134
- 20
-
-
-
-
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
- true
-
-
-
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
- true
-
-
-
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
-
- 22
- 22
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
- true
-
-
- false
-
-
- QSplitter{
- color: rgb(255, 255, 255);
- background-color: rgb(255, 255, 255);
- alternate-background-color: rgb(255, 255, 255);
- border-color: rgb(255, 255, 255);
- gridline-color: rgb(255, 255, 255);
- selection-color: rgb(255, 255, 255);
- selection-background-color: rgb(255, 255, 255);
-}
-QSplitter:handle{
- color: rgb(255, 255, 255);
- background-color: rgb(255, 255, 255);
-}
-
-
- Qt::Horizontal
-
-
- false
-
-
-
-
- 0
- 0
-
-
-
-
- 225
- 0
-
-
-
-
- 1920
- 16777215
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
- true
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
- 225
- 60
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
- true
-
-
-
-
-
- 0
-
-
-
-
-
- 40
- 40
-
-
-
-
- 40
- 40
-
-
-
-
-
-
- :/img/contact.png
-
-
- true
-
-
-
-
-
-
- 0
-
-
-
-
- true
-
-
-
- 1
- 0
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 240
- 240
- 240
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
-
-
- 11
- 75
- true
-
-
-
- Your name
-
-
-
-
-
-
-
- 1
- 0
-
-
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
-
-
- 8
-
-
-
- Your status
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 10
- 20
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 20
- 40
-
-
-
- Qt::NoFocus
-
-
-
-
-
-
- 10
- 10
-
-
-
- false
-
-
- false
-
-
- false
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 225
- 0
-
-
-
- Qt::RightToLeft
-
-
- true
-
-
- QFrame::NoFrame
-
-
- Qt::ScrollBarAlwaysOff
-
-
- true
-
-
-
-
- 0
- 0
- 256
- 199
-
-
-
-
-
-
-
-
- true
-
-
-
- 0
- 0
-
-
-
-
- 225
- 35
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 42
- 42
- 42
-
-
-
-
-
-
- 35
- 35
- 35
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 18
- 18
- 18
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 14
- 14
- 14
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 28
- 28
- 28
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
- true
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- 55
- 35
-
-
-
-
- 55
- 35
-
-
-
- Qt::NoFocus
-
-
- Add friends
-
-
-
-
-
-
- :/img/add.png:/img/add.png
-
-
- true
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Maximum
-
-
-
- 500
- 20
-
-
-
-
-
-
-
-
- 55
- 35
-
-
-
- Qt::NoFocus
-
-
- Create a group chat
-
-
-
-
-
-
- :/img/group.png:/img/group.png
-
-
- true
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Maximum
-
-
-
- 500
- 20
-
-
-
-
-
-
-
-
- 55
- 35
-
-
-
-
- 55
- 35
-
-
-
- Qt::NoFocus
-
-
- View completed file transfers
-
-
-
-
-
-
- :/img/transfer.png:/img/transfer.png
-
-
- true
-
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Maximum
-
-
-
- 500
- 20
-
-
-
-
-
-
-
-
- 55
- 35
-
-
-
-
- 55
- 35
-
-
-
- Qt::NoFocus
-
-
- Change your settings
-
-
-
-
-
-
- :/img/settings.png:/img/settings.png
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
- 1
- 0
-
-
-
-
- 375
- 0
-
-
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 170
- 170
- 170
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 170
- 170
- 170
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 170
- 170
- 170
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- 255
- 255
- 255
-
-
-
-
-
-
- 255
- 255
- 220
-
-
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
-
- true
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 60
-
-
-
-
- 16777215
- 60
-
-
-
- true
-
-
-
-
-
-
-
- 0
- 1
-
-
-
-
- 16777215
- 1
-
-
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
-
-
- 193
- 193
- 193
-
-
-
-
-
-
-
-
- 127
- 127
- 127
-
-
-
-
-
-
-
- QFrame::HLine
-
-
- QFrame::Plain
-
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 375
- 0
-
-
-
-
-
-
-
-
-
-
-
- Close
-
-
- Ctrl+Q
-
-
-
-
-
-
- EditableLabelWidget
- QLabel
- widget/tool/editablelabelwidget.h
-
-
-
-
-
-
-
- actionClose
- triggered()
- Widget
- close()
-
-
- -1
- -1
-
-
- 69
- 61
-
-
-
-
-
diff --git a/widget/adjustingscrollarea.cpp b/widget/adjustingscrollarea.cpp
new file mode 100644
index 000000000..bb273fa90
--- /dev/null
+++ b/widget/adjustingscrollarea.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "adjustingscrollarea.h"
+
+#include
+#include
+#include
+#include
+
+AdjustingScrollArea::AdjustingScrollArea(QWidget *parent) :
+ QScrollArea(parent)
+{
+
+}
+
+void AdjustingScrollArea::resizeEvent(QResizeEvent *ev)
+{
+ updateGeometry();
+ QScrollArea::resizeEvent(ev);
+}
+
+QSize AdjustingScrollArea::sizeHint() const
+{
+ if (widget())
+ {
+ int scrollbarWidth = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0;
+ return widget()->sizeHint() + QSize(scrollbarWidth, 0);
+ }
+
+ return QScrollArea::sizeHint();
+}
diff --git a/widget/tool/clickablelabel.h b/widget/adjustingscrollarea.h
similarity index 67%
rename from widget/tool/clickablelabel.h
rename to widget/adjustingscrollarea.h
index db475ee1c..a1645cbba 100644
--- a/widget/tool/clickablelabel.h
+++ b/widget/adjustingscrollarea.h
@@ -14,23 +14,23 @@
See the COPYING file for more details.
*/
-#ifndef CLICKABLELABEL_H
-#define CLICKABLELABEL_H
+#ifndef ADJUSTINGSCROLLAREA_H
+#define ADJUSTINGSCROLLAREA_H
-#include
+#include
-class ClickableLabel : public QLabel
+class AdjustingScrollArea : public QScrollArea
{
Q_OBJECT
public:
- explicit ClickableLabel(QWidget *parent = 0);
+ explicit AdjustingScrollArea(QWidget *parent = 0);
+ virtual void resizeEvent(QResizeEvent *ev);
+ virtual QSize sizeHint() const override;
signals:
- void clicked();
-protected:
- void mousePressEvent ( QMouseEvent * event );
+public slots:
};
-#endif // CLICKABLELABEL_H
+#endif // ADJUSTINGSCROLLAREA_H
diff --git a/widget/camera.cpp b/widget/camera.cpp
index 7c8c5582c..e4a6010c7 100644
--- a/widget/camera.cpp
+++ b/widget/camera.cpp
@@ -15,59 +15,13 @@
*/
#include "camera.h"
-#include
#include
-#include
-#include
-static inline void fromYCbCrToRGB(
- uint8_t Y, uint8_t Cb, uint8_t Cr,
- uint8_t& R, uint8_t& G, uint8_t& B)
-{
- int r = Y + ((1436 * (Cr - 128)) >> 10),
- g = Y - ((354 * (Cb - 128) + 732 * (Cr - 128)) >> 10),
- b = Y + ((1814 * (Cb - 128)) >> 10);
-
- if(r < 0) {
- r = 0;
- } else if(r > 255) {
- r = 255;
- }
-
- if(g < 0) {
- g = 0;
- } else if(g > 255) {
- g = 255;
- }
-
- if(b < 0) {
- b = 0;
- } else if(b > 255) {
- b = 255;
- }
-
- R = static_cast(r);
- G = static_cast(g);
- B = static_cast(b);
-}
+using namespace cv;
Camera::Camera()
- : refcount{0}, camera{new QCamera}
+ : refcount{0}
{
- camera->setCaptureMode(QCamera::CaptureVideo);
- camera->setViewfinder(this);
-
-#if 0 // Crashes on Windows
- QMediaService *m = camera->service();
- QVideoEncoderSettingsControl *enc = m->requestControl();
- QVideoEncoderSettings sets = enc->videoSettings();
- sets.setResolution(640, 480);
- enc->setVideoSettings(sets);
-#endif
-
- connect(camera, SIGNAL(error(QCamera::Error)), this, SLOT(onCameraError(QCamera::Error)));
-
- supportedFormats << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12 << QVideoFrame::Format_RGB32;
}
void Camera::suscribe()
@@ -75,7 +29,7 @@ void Camera::suscribe()
if (refcount <= 0)
{
refcount = 1;
- camera->start();
+ cam.open(0);
}
else
refcount++;
@@ -87,226 +41,76 @@ void Camera::unsuscribe()
if (refcount <= 0)
{
- camera->stop();
+ cam.release();
refcount = 0;
}
}
-QVideoFrame Camera::getLastFrame()
+Mat Camera::getLastFrame()
{
- return lastFrame;
+ Mat frame;
+ cam >> frame;
+ return frame;
}
-bool Camera::start(const QVideoSurfaceFormat &format)
-{
- if(supportedFormats.contains(format.pixelFormat()))
- {
- frameFormat = format.pixelFormat();
- QAbstractVideoSurface::start(format);
- return true;
- }
- else
- {
- QMessageBox::warning(0, "Camera error", "The camera only supports rare video formats, can't use it");
- return false;
- }
-}
-
-bool Camera::present(const QVideoFrame &frame)
-{
- QVideoFrame frameMap(frame); // Basically a const_cast because shallow copies
- if (!frameMap.map(QAbstractVideoBuffer::ReadOnly))
- {
- qWarning() << "Camera::present: Unable to map frame";
- return false;
- }
- int w = frameMap.width(), h = frameMap.height();
- int bpl = frameMap.bytesPerLine(), size = frameMap.mappedBytes();
- QVideoFrame frameCopy(size, QSize(w, h), bpl, frameMap.pixelFormat());
- frameCopy.map(QAbstractVideoBuffer::WriteOnly);
- memcpy(frameCopy.bits(), frameMap.bits(), size);
- frameCopy.unmap();
- lastFrame = frameCopy;
- frameMap.unmap();
- return true;
-}
-
-QList Camera::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
-{
- if (handleType == QAbstractVideoBuffer::NoHandle)
- return supportedFormats;
- else
- return QList();
-}
-
-void Camera::onCameraError(QCamera::Error value)
-{
- QMessageBox::warning(0,"Camera error",QString("Error %1 : %2")
- .arg(value).arg(camera->errorString()));
-}
-
-bool Camera::isFormatSupported(const QVideoSurfaceFormat& format) const
-{
- if (format.pixelFormat() == 0)
- {
- //QMessageBox::warning(0, "Camera eror","The camera's video format is not supported !");
- return QAbstractVideoSurface::isFormatSupported(format);
- }
- else if(supportedFormats.contains(format.pixelFormat()))
- {
- return true;
- }
- else
- {
- QMessageBox::warning(0, tr("Camera eror"),
- tr("Camera format %1 not supported, can't use the camera")
- .arg(format.pixelFormat()));
- return false;
- }
-}
-
-
QImage Camera::getLastImage()
{
- if (!lastFrame.map(QAbstractVideoBuffer::ReadOnly))
+ Mat3b src = getLastFrame();
+ QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
+ for (int y = 0; y < src.rows; ++y)
{
- qWarning() << "Camera::getLastImage: Error maping last frame";
- return QImage();
+ const cv::Vec3b *srcrow = src[y];
+ QRgb *destrow = (QRgb*)dest.scanLine(y);
+ for (int x = 0; x < src.cols; ++x)
+ destrow[x] = qRgba(srcrow[x][2], srcrow[x][1], srcrow[x][0], 255);
}
- int w = lastFrame.width(), h = lastFrame.height();
- int bpl = lastFrame.bytesPerLine(), cxbpl = bpl/2;
- QImage img(w, h, QImage::Format_RGB32);
-
- if (frameFormat == QVideoFrame::Format_YUV420P)
- {
- uint8_t* yData = lastFrame.bits();
- uint8_t* uData = yData + (bpl * h);
- uint8_t* vData = uData + (bpl * h / 4);
- for (int i = 0; i< h; i++)
- {
- uint32_t* scanline = (uint32_t*)img.scanLine(i);
- for (int j=0; j < bpl; j++)
- {
- uint8_t Y = yData[i*bpl + j];
- uint8_t U = uData[i/2*cxbpl + j/2];
- uint8_t V = vData[i/2*cxbpl + j/2];
-
- uint8_t R, G, B;
- fromYCbCrToRGB(Y, U, V, R, G, B);
-
- scanline[j] = (0xFF<<24) + (R<<16) + (G<<8) + B;
- }
- }
- }
- else if (frameFormat == QVideoFrame::Format_YV12)
- {
- uint8_t* yData = lastFrame.bits();
- uint8_t* vData = yData + (bpl * h);
- uint8_t* uData = vData + (bpl * h / 4);
- for (int i = 0; i< h; i++)
- {
- uint32_t* scanline = (uint32_t*)img.scanLine(i);
- for (int j=0; j < bpl; j++)
- {
- uint8_t Y = yData[i*bpl + j];
- uint8_t U = uData[i/2*cxbpl + j/2];
- uint8_t V = vData[i/2*cxbpl + j/2];
-
- uint8_t R, G, B;
- fromYCbCrToRGB(Y, U, V, R, G, B);
-
- scanline[j] = (0xFF<<24) + (R<<16) + (G<<8) + B;
- }
- }
- }
- else if (frameFormat == QVideoFrame::Format_RGB32)
- {
- memcpy(img.bits(), lastFrame.bits(), bpl*h);
- }
-
- lastFrame.unmap();
- return img;
+ return dest;
}
vpx_image Camera::getLastVPXImage()
{
+ Mat3b frame = getLastFrame();
vpx_image img;
- img.w = img.h = 0;
- if (!lastFrame.isValid())
- return img;
- if (!lastFrame.map(QAbstractVideoBuffer::ReadOnly))
- {
- qWarning() << "Camera::getLastVPXImage: Error maping last frame";
- return img;
- }
- int w = lastFrame.width(), h = lastFrame.height();
- int bpl = lastFrame.bytesPerLine();
+ int w = frame.size().width, h = frame.size().height;
vpx_img_alloc(&img, VPX_IMG_FMT_I420, w, h, 1); // I420 == YUV420P, same as YV12 with U and V switched
- if (frameFormat == QVideoFrame::Format_YUV420P)
+ size_t i=0, j=0;
+ for( int line = 0; line < h; ++line )
{
- uint8_t* yData = lastFrame.bits();
- uint8_t* uData = yData + (bpl * h);
- uint8_t* vData = uData + (bpl * h / 4);
- img.planes[VPX_PLANE_Y] = yData;
- img.planes[VPX_PLANE_U] = uData;
- img.planes[VPX_PLANE_V] = vData;
- }
- else if (frameFormat == QVideoFrame::Format_YV12)
- {
- uint8_t* yData = lastFrame.bits();
- uint8_t* uData = yData + (bpl * h);
- uint8_t* vData = uData + (bpl * h / 4);
- img.planes[VPX_PLANE_Y] = yData;
- img.planes[VPX_PLANE_U] = vData;
- img.planes[VPX_PLANE_V] = uData;
- }
- else if (frameFormat == QVideoFrame::Format_RGB32 || frameFormat == QVideoFrame::Format_ARGB32)
- {
- qWarning() << "Camera::getLastVPXImage: Using experimental RGB32 conversion code";
- uint8_t* rgb = lastFrame.bits();
- size_t i=0, j=0;
-
- for( size_t line = 0; line < h; ++line )
+ const cv::Vec3b *srcrow = frame[line];
+ if( !(line % 2) )
{
- if( !(line % 2) )
+ for( int x = 0; x < w; x += 2 )
{
- for( size_t x = 0; x < w; x += 2 )
- {
- uint8_t r = rgb[4 * i + 1];
- uint8_t g = rgb[4 * i + 2];
- uint8_t b = rgb[4 * i + 3];
+ uint8_t r = srcrow[x][2];
+ uint8_t g = srcrow[x][1];
+ uint8_t b = srcrow[x][0];
- img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
- img.planes[VPX_PLANE_U][j] = ((-38*r + -74*g + 112*b) >> 8) + 128;
- img.planes[VPX_PLANE_V][j] = ((112*r + -94*g + -18*b) >> 8) + 128;
- i++;
- j++;
+ img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
+ img.planes[VPX_PLANE_V][j] = ((-38*r + -74*g + 112*b) >> 8) + 128;
+ img.planes[VPX_PLANE_U][j] = ((112*r + -94*g + -18*b) >> 8) + 128;
+ i++;
+ j++;
- r = rgb[4 * i + 1];
- g = rgb[4 * i + 2];
- b = rgb[4 * i + 3];
-
- img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
- i++;
- }
+ r = srcrow[x+1][2];
+ g = srcrow[x+1][1];
+ b = srcrow[x+1][0];
+ img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
+ i++;
}
- else
+ }
+ else
+ {
+ for( int x = 0; x < w; x += 1 )
{
- for( size_t x = 0; x < w; x += 1 )
- {
- uint8_t r = rgb[4 * i + 1];
- uint8_t g = rgb[4 * i + 2];
- uint8_t b = rgb[4 * i + 3];
+ uint8_t r = srcrow[x][2];
+ uint8_t g = srcrow[x][1];
+ uint8_t b = srcrow[x][0];
- img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
- i++;
- }
+ img.planes[VPX_PLANE_Y][i] = ((66*r + 129*g + 25*b) >> 8) + 16;
+ i++;
}
}
}
-
- lastFrame.unmap();
return img;
-
}
diff --git a/widget/camera.h b/widget/camera.h
index dd085b61b..e717c5c1a 100644
--- a/widget/camera.h
+++ b/widget/camera.h
@@ -17,47 +17,29 @@
#ifndef CAMERA_H
#define CAMERA_H
-#include
-#include
-#include
+#include
#include "vpx/vpx_image.h"
+#include "opencv2/opencv.hpp"
/**
* This class is a wrapper to share a camera's captured video frames
- * In Qt cameras normally only send their frames to a single output at a time
- * So you can't, for example, send the frames over the network
- * and output them to a widget on the screen at the same time
- *
- * Instead this class allows objects to surscribe and unsuscribe, starting
- * the camera only when needed, and giving access to the last frame
+ * It allows objects to suscribe and unsuscribe to the stream, starting
+ * the camera only when needed, and giving access to the last frames
**/
-class Camera : private QAbstractVideoSurface
+class Camera
{
- Q_OBJECT
public:
Camera();
void suscribe(); ///< Call this once before trying to get frames
void unsuscribe(); ///< Call this once when you don't need frames anymore
- QVideoFrame getLastFrame(); ///< Get the last captured frame
+ cv::Mat getLastFrame(); ///< Get the last captured frame
QImage getLastImage(); ///< Convert the last frame to a QImage (can be expensive !)
vpx_image getLastVPXImage(); ///< Convert the last frame to a vpx_image (can be expensive !)
- bool isFormatSupported(const QVideoSurfaceFormat & format) const;
-
-private slots:
- void onCameraError(QCamera::Error value);
-
-private:
- bool start(const QVideoSurfaceFormat &format);
- bool present(const QVideoFrame &frame);
- QList supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
private:
int refcount; ///< Number of users suscribed to the camera
- QCamera *camera;
- QVideoFrame lastFrame;
- int frameFormat;
- QList supportedFormats;
+ cv::VideoCapture cam; ///< OpenCV camera capture opbject
};
#endif // CAMERA_H
diff --git a/widget/croppinglabel.cpp b/widget/croppinglabel.cpp
new file mode 100644
index 000000000..47b324d1e
--- /dev/null
+++ b/widget/croppinglabel.cpp
@@ -0,0 +1,142 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "croppinglabel.h"
+#include
+
+CroppingLabel::CroppingLabel(QWidget* parent)
+ : QLabel(parent)
+ , blockPaintEvents(false)
+ , editable(false)
+ , elideMode(Qt::ElideRight)
+{
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ textEdit = new QLineEdit(this);
+ textEdit->hide();
+
+ installEventFilter(this);
+ textEdit->installEventFilter(this);
+}
+
+void CroppingLabel::setEditable(bool editable)
+{
+ this->editable = editable;
+
+ if (editable)
+ setCursor(Qt::PointingHandCursor);
+ else
+ unsetCursor();
+}
+
+void CroppingLabel::setEdlideMode(Qt::TextElideMode elide)
+{
+ elideMode = elide;
+}
+
+void CroppingLabel::setText(const QString& text)
+{
+ origText = text.trimmed();
+ setElidedText();
+}
+
+void CroppingLabel::resizeEvent(QResizeEvent* ev)
+{
+ setElidedText();
+ textEdit->resize(ev->size());
+
+ QLabel::resizeEvent(ev);
+}
+
+QSize CroppingLabel::sizeHint() const
+{
+ return QSize(0, QLabel::sizeHint().height());
+}
+
+QSize CroppingLabel::minimumSizeHint() const
+{
+ return QSize(fontMetrics().width("..."), QLabel::minimumSizeHint().height());
+}
+
+void CroppingLabel::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (editable)
+ showTextEdit();
+
+ emit clicked();
+
+ QLabel::mouseReleaseEvent(e);
+}
+
+bool CroppingLabel::eventFilter(QObject *obj, QEvent *e)
+{
+ // catch paint events if needed
+ if (obj == this)
+ {
+ if (e->type() == QEvent::Paint && blockPaintEvents)
+ return true;
+ }
+
+ // events fired by the QLineEdit
+ if (obj == textEdit)
+ {
+ if (e->type() == QEvent::KeyPress)
+ {
+ QKeyEvent* keyEvent = static_cast(e);
+ if (keyEvent->key() == Qt::Key_Return)
+ hideTextEdit(true);
+
+ if (keyEvent->key() == Qt::Key_Escape)
+ hideTextEdit(false);
+ }
+
+ if (e->type() == QEvent::FocusOut)
+ hideTextEdit(true);
+ }
+
+ return false;
+}
+
+void CroppingLabel::setElidedText()
+{
+ QString elidedText = fontMetrics().elidedText(origText, elideMode, width());
+ if (elidedText != origText)
+ setToolTip(origText);
+ else
+ setToolTip(QString());
+
+ QLabel::setText(elidedText);
+}
+
+void CroppingLabel::hideTextEdit(bool acceptText)
+{
+ if (acceptText)
+ {
+ emit textChanged(textEdit->text(), origText);
+ setText(textEdit->text());
+ }
+
+ textEdit->hide();
+ blockPaintEvents = false;
+}
+
+void CroppingLabel::showTextEdit()
+{
+ blockPaintEvents = true;
+ textEdit->show();
+ textEdit->setFocus();
+ textEdit->setText(origText);
+}
diff --git a/widget/croppinglabel.h b/widget/croppinglabel.h
new file mode 100644
index 000000000..aeca082b1
--- /dev/null
+++ b/widget/croppinglabel.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#ifndef CROPPINGLABEL_H
+#define CROPPINGLABEL_H
+
+#include
+#include
+
+class CroppingLabel : public QLabel
+{
+ Q_OBJECT
+public:
+ explicit CroppingLabel(QWidget *parent = 0);
+
+ void setEditable(bool editable);
+ void setEdlideMode(Qt::TextElideMode elide);
+
+ virtual void setText(const QString& text);
+ virtual void resizeEvent(QResizeEvent *ev);
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual bool eventFilter(QObject *obj, QEvent *e);
+
+signals:
+ void textChanged(QString newText, QString oldText);
+ void clicked();
+
+protected:
+ void setElidedText();
+ void hideTextEdit(bool acceptText);
+ void showTextEdit();
+
+private:
+ QString origText;
+ QLineEdit* textEdit;
+ bool blockPaintEvents;
+ bool editable;
+ Qt::TextElideMode elideMode;
+};
+
+#endif // CROPPINGLABEL_H
diff --git a/widget/emoticonswidget.cpp b/widget/emoticonswidget.cpp
new file mode 100644
index 000000000..bab7abe8d
--- /dev/null
+++ b/widget/emoticonswidget.cpp
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "emoticonswidget.h"
+#include "smileypack.h"
+#include "style.h"
+
+#include
+#include
+#include
+#include
+#include
+
+EmoticonsWidget::EmoticonsWidget(QWidget *parent) :
+ QMenu(parent)
+{
+ setStyleSheet(Style::get(":/ui/emoticonWidget/emoticonWidget.css"));
+ setLayout(&layout);
+ layout.addWidget(&stack);
+
+ QWidget* pageButtonsContainer = new QWidget;
+ QHBoxLayout* buttonLayout = new QHBoxLayout;
+ pageButtonsContainer->setLayout(buttonLayout);
+
+ layout.addWidget(pageButtonsContainer);
+
+ const int maxCols = 5;
+ const int maxRows = 3;
+ const int itemsPerPage = maxRows * maxCols;
+
+ const QList& emoticons = SmileyPack::getInstance().getEmoticons();
+ int itemCount = emoticons.size();
+ int pageCount = (itemCount / itemsPerPage) + 1;
+ int currPage = 0;
+ int currItem = 0;
+ int row = 0;
+ int col = 0;
+
+ // create pages
+ buttonLayout->addStretch();
+ for (int i = 0; i < pageCount; i++)
+ {
+ QGridLayout* pageLayout = new QGridLayout;
+ pageLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), maxRows, 0);
+ pageLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, maxCols);
+
+ QWidget* page = new QWidget;
+ page->setLayout(pageLayout);
+ stack.addWidget(page);
+
+ // page buttons are only needed if there is more than 1 page
+ if (pageCount > 1)
+ {
+ QRadioButton* pageButton = new QRadioButton;
+ pageButton->setProperty("pageIndex", i);
+ pageButton->setChecked(i == 0);
+ buttonLayout->addWidget(pageButton);
+
+ connect(pageButton, &QRadioButton::clicked, this, &EmoticonsWidget::onPageButtonClicked);
+ }
+ }
+ buttonLayout->addStretch();
+
+ for (const QStringList& set : emoticons)
+ {
+ QPushButton* button = new QPushButton;
+ button->setIcon(SmileyPack::getInstance().getAsIcon(set[0]));
+ button->setToolTip(set.join(" "));
+ button->setProperty("sequence", set[0]);
+ button->setFlat(true);
+
+ connect(button, &QPushButton::clicked, this, &EmoticonsWidget::onSmileyClicked);
+
+ qobject_cast(stack.widget(currPage)->layout())->addWidget(button, row, col);
+
+ col++;
+ currItem++;
+
+ // next row
+ if (col >= maxCols)
+ {
+ col = 0;
+ row++;
+ }
+
+ // next page
+ if (currItem >= itemsPerPage)
+ {
+ row = 0;
+ currItem = 0;
+ currPage++;
+ }
+ }
+
+ // calculates sizeHint
+ layout.activate();
+}
+
+void EmoticonsWidget::onSmileyClicked()
+{
+ // hide the QMenu
+ QMenu::hide();
+
+ // emit insert emoticon
+ QWidget* sender = qobject_cast(QObject::sender());
+ if (sender)
+ emit insertEmoticon(' ' + sender->property("sequence").toString() + ' ');
+}
+
+void EmoticonsWidget::onPageButtonClicked()
+{
+ QWidget* sender = qobject_cast(QObject::sender());
+ if (sender)
+ {
+ int page = sender->property("pageIndex").toInt();
+ stack.setCurrentIndex(page);
+ }
+}
+
+QSize EmoticonsWidget::sizeHint() const
+{
+ return layout.sizeHint();
+}
diff --git a/audiobuffer.h b/widget/emoticonswidget.h
similarity index 59%
rename from audiobuffer.h
rename to widget/emoticonswidget.h
index e94b70447..559fb7443 100644
--- a/audiobuffer.h
+++ b/widget/emoticonswidget.h
@@ -14,29 +14,32 @@
See the COPYING file for more details.
*/
-#ifndef AUDIOBUFFER_H
-#define AUDIOBUFFER_H
+#ifndef EMOTICONSWIDGET_H
+#define EMOTICONSWIDGET_H
-#include
-#include
-#include
+#include
+#include
+#include
-class AudioBuffer : public QIODevice
+class EmoticonsWidget : public QMenu
{
Q_OBJECT
public:
- explicit AudioBuffer();
- ~AudioBuffer();
+ explicit EmoticonsWidget(QWidget *parent = 0);
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
- qint64 bytesAvailable() const;
- qint64 bufferSize() const;
- void clear();
+signals:
+ void insertEmoticon(QString str);
+
+private slots:
+ void onSmileyClicked();
+ void onPageButtonClicked();
private:
- QByteArray buffer;
- mutable QMutex bufferMutex;
+ QStackedWidget stack;
+ QVBoxLayout layout;
+
+public:
+ virtual QSize sizeHint() const;
};
-#endif // AUDIOBUFFER_H
+#endif // EMOTICONSWIDGET_H
diff --git a/widget/filetransfertwidget.cpp b/widget/filetransfertwidget.cpp
index 568ce93a2..41fb4ed56 100644
--- a/widget/filetransfertwidget.cpp
+++ b/widget/filetransfertwidget.cpp
@@ -18,6 +18,7 @@
#include "widget.h"
#include "core.h"
#include "math.h"
+#include "style.h"
#include
#include
#include
@@ -36,10 +37,7 @@ FileTransfertWidget::FileTransfertWidget(ToxFile File)
QFont prettysmall;
prettysmall.setPixelSize(10);
this->setObjectName("default");
- QFile f0(":/ui/fileTransferWidget/fileTransferWidget.css");
- f0.open(QFile::ReadOnly | QFile::Text);
- QTextStream fileTransfertWidgetStylesheet(&f0);
- this->setStyleSheet(fileTransfertWidgetStylesheet.readAll());
+ this->setStyleSheet(Style::get(":/ui/fileTransferWidget/fileTransferWidget.css"));
QPalette greybg;
greybg.setColor(QPalette::Window, QColor(209,209,209));
greybg.setColor(QPalette::Base, QColor(150,150,150));
@@ -71,20 +69,9 @@ FileTransfertWidget::FileTransfertWidget(ToxFile File)
buttonWidget->setAutoFillBackground(true);
buttonWidget->setLayout(buttonLayout);
- QFile f1(":/ui/stopFileButton/style.css");
- f1.open(QFile::ReadOnly | QFile::Text);
- QTextStream stopFileButtonStylesheetStream(&f1);
- stopFileButtonStylesheet = stopFileButtonStylesheetStream.readAll();
-
- QFile f2(":/ui/pauseFileButton/style.css");
- f2.open(QFile::ReadOnly | QFile::Text);
- QTextStream pauseFileButtonStylesheetStream(&f2);
- pauseFileButtonStylesheet = pauseFileButtonStylesheetStream.readAll();
-
- QFile f3(":/ui/acceptFileButton/style.css");
- f3.open(QFile::ReadOnly | QFile::Text);
- QTextStream acceptFileButtonStylesheetStream(&f3);
- acceptFileButtonStylesheet = acceptFileButtonStylesheetStream.readAll();
+ stopFileButtonStylesheet = Style::get(":/ui/stopFileButton/style.css");
+ pauseFileButtonStylesheet = Style::get(":/ui/pauseFileButton/style.css");
+ acceptFileButtonStylesheet = Style::get(":/ui/acceptFileButton/style.css");
topright->setStyleSheet(stopFileButtonStylesheet);
if (File.direction == ToxFile::SENDING)
@@ -151,13 +138,13 @@ FileTransfertWidget::FileTransfertWidget(ToxFile File)
buttonLayout->setSpacing(0);
}
-QString FileTransfertWidget::getHumanReadableSize(int size)
+QString FileTransfertWidget::getHumanReadableSize(unsigned long long size)
{
static const char* suffix[] = {"B","kiB","MiB","GiB","TiB"};
int exp = 0;
if (size)
exp = std::min( (int) (log(size) / log(1024)), (int) (sizeof(suffix) / sizeof(suffix[0]) - 1));
- return QString().setNum(size / pow(1024, exp),'g',3).append(suffix[exp]);
+ return QString().setNum(size / pow(1024, exp),'f',2).append(suffix[exp]);
}
void FileTransfertWidget::onFileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection Direction)
@@ -174,7 +161,7 @@ void FileTransfertWidget::onFileTransferInfo(int FriendId, int FileNum, int64_t
qWarning() << "FileTransfertWidget::onFileTransferInfo: Negative transfer speed !";
diff = 0;
}
- int rawspeed = diff / timediff;
+ long rawspeed = diff / timediff;
speed->setText(getHumanReadableSize(rawspeed)+"/s");
size->setText(getHumanReadableSize(Filesize));
if (!rawspeed)
@@ -184,10 +171,15 @@ void FileTransfertWidget::onFileTransferInfo(int FriendId, int FileNum, int64_t
etaTime = etaTime.addSecs(etaSecs);
eta->setText(etaTime.toString("mm:ss"));
if (!Filesize)
+ {
progress->setValue(0);
+ qDebug() << QString("FT: received %1 bytes of an empty file, stop sending sequential devices, zetok!").arg(BytesSent);
+ }
else
+ {
progress->setValue(BytesSent*100/Filesize);
- qDebug() << QString("FT: received %1/%2 bytes, progress is %3%").arg(BytesSent).arg(Filesize).arg(BytesSent*100/Filesize);
+ qDebug() << QString("FT: received %1/%2 bytes, progress is %3%").arg(BytesSent).arg(Filesize).arg(BytesSent*100/Filesize);
+ }
lastUpdate = newtime;
lastBytesSent = BytesSent;
}
@@ -286,7 +278,7 @@ void FileTransfertWidget::acceptRecvRequest()
QString path;
while (true)
{
- path = QFileDialog::getSaveFileName(0,tr("Save a file","Title of the file saving dialog"),QDir::currentPath()+'/'+filename->text());
+ path = QFileDialog::getSaveFileName(this, tr("Save a file","Title of the file saving dialog"), QDir::current().filePath(filename->text()));
if (path.isEmpty())
return;
else
@@ -297,7 +289,7 @@ void FileTransfertWidget::acceptRecvRequest()
if (isWritable(path))
break;
else
- QMessageBox::warning(0, tr("Location not writable","Title of permissions popup"), tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup"));
+ QMessageBox::warning(this, tr("Location not writable","Title of permissions popup"), tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup"));
}
}
diff --git a/widget/filetransfertwidget.h b/widget/filetransfertwidget.h
index c5933eeb5..699c9d548 100644
--- a/widget/filetransfertwidget.h
+++ b/widget/filetransfertwidget.h
@@ -49,7 +49,7 @@ private slots:
void pauseResumeSend();
private:
- QString getHumanReadableSize(int size);
+ QString getHumanReadableSize(unsigned long long size);
private:
QLabel *pic, *filename, *size, *speed, *eta;
diff --git a/widget/form/addfriendform.cpp b/widget/form/addfriendform.cpp
index 76072b230..9d09e0682 100644
--- a/widget/form/addfriendform.cpp
+++ b/widget/form/addfriendform.cpp
@@ -35,6 +35,7 @@ AddFriendForm::AddFriendForm() : dns(this)
toxIdLabel.setText(tr("Tox ID","Tox ID of the person you're sending a friend request to"));
messageLabel.setText(tr("Message","The message you send in friend requests"));
sendButton.setText(tr("Send friend request"));
+ message.setPlaceholderText(tr("Tox me maybe?","Default message in friend requests if the field is left blank. Write something appropriate!"));
main->setLayout(&layout);
layout.addWidget(&toxIdLabel);
@@ -56,7 +57,7 @@ AddFriendForm::~AddFriendForm()
main->deleteLater();
}
-void AddFriendForm::show(Ui::Widget &ui)
+void AddFriendForm::show(Ui::MainWindow &ui)
{
ui.mainContent->layout()->addWidget(main);
ui.mainHead->layout()->addWidget(head);
@@ -81,7 +82,7 @@ void AddFriendForm::showWarning(const QString &message) const
QString AddFriendForm::getMessage() const
{
const QString msg = message.toPlainText();
- return !msg.isEmpty() ? msg : tr("Tox me maybe?","Default message in friend requests if the field is left blank. Write something appropriate!");
+ return !msg.isEmpty() ? msg : message.placeholderText();
}
void AddFriendForm::onSendTriggered()
diff --git a/widget/form/addfriendform.h b/widget/form/addfriendform.h
index 7f2263827..0edcf2214 100644
--- a/widget/form/addfriendform.h
+++ b/widget/form/addfriendform.h
@@ -17,7 +17,7 @@
#ifndef ADDFRIENDFORM_H
#define ADDFRIENDFORM_H
-#include "ui_widget.h"
+#include "ui_mainwindow.h"
#include
#include
@@ -33,7 +33,7 @@ public:
AddFriendForm();
~AddFriendForm();
- void show(Ui::Widget& ui);
+ void show(Ui::MainWindow &ui);
bool isToxId(const QString& value) const;
void showWarning(const QString& message) const;
QString getMessage() const;
diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp
index 13d4b5271..50f09f5a2 100644
--- a/widget/form/chatform.cpp
+++ b/widget/form/chatform.cpp
@@ -16,14 +16,20 @@
#include "chatform.h"
#include "friend.h"
+#include "smileypack.h"
#include "widget/friendwidget.h"
#include "widget/widget.h"
#include "widget/filetransfertwidget.h"
+#include "widget/emoticonswidget.h"
+#include "style.h"
#include
#include
#include
#include
#include
+#include
+#include
+#include
ChatForm::ChatForm(Friend* chatFriend)
: f(chatFriend), curRow{0}, lockSliderToBottom{true}
@@ -31,12 +37,16 @@ ChatForm::ChatForm(Friend* chatFriend)
main = new QWidget(), head = new QWidget(), chatAreaWidget = new QWidget();
name = new QLabel(), avatar = new QLabel(), statusMessage = new QLabel();
headLayout = new QHBoxLayout(), mainFootLayout = new QHBoxLayout();
- headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout(), footButtonsSmall = new QVBoxLayout();
+ headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout(),
+ footButtonsSmall = new QVBoxLayout(), volMicLayout = new QVBoxLayout();
mainChatLayout = new QGridLayout();
msgEdit = new ChatTextEdit();
- sendButton = new QPushButton(), fileButton = new QPushButton(), emoteButton = new QPushButton(), callButton = new QPushButton(), videoButton = new QPushButton();
+ sendButton = new QPushButton(), fileButton = new QPushButton(), emoteButton = new QPushButton(),
+ callButton = new QPushButton(), videoButton = new QPushButton(),
+ volButton = new QPushButton(), micButton = new QPushButton();
chatArea = new QScrollArea();
netcam = new NetCamView();
+ audioInputFlag = false;
QFont bold;
bold.setBold(true);
@@ -49,16 +59,8 @@ ChatForm::ChatForm(Friend* chatFriend)
avatar->setPixmap(QPixmap(":/img/contact_dark.png"));
chatAreaWidget->setLayout(mainChatLayout);
- QString chatAreaStylesheet = "";
- try
- {
- QFile f(":/ui/chatArea/chatArea.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream chatAreaStylesheetStream(&f);
- chatAreaStylesheet = chatAreaStylesheetStream.readAll();
- }
- catch (int e) {}
- chatArea->setStyleSheet(chatAreaStylesheet);
+ chatAreaWidget->setStyleSheet(Style::get(":/ui/chatArea/chatArea.css"));
+
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
chatArea->setWidgetResizable(true);
chatArea->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -69,76 +71,43 @@ ChatForm::ChatForm(Friend* chatFriend)
footButtonsSmall->setSpacing(2);
- QString msgEditStylesheet = "";
- try
- {
- QFile f(":/ui/msgEdit/msgEdit.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream msgEditStylesheetStream(&f);
- msgEditStylesheet = msgEditStylesheetStream.readAll();
- }
- catch (int e) {}
- msgEdit->setStyleSheet(msgEditStylesheet);
+ msgEdit->setStyleSheet(Style::get(":/ui/msgEdit/msgEdit.css"));
msgEdit->setFixedHeight(50);
msgEdit->setFrameStyle(QFrame::NoFrame);
- QString sendButtonStylesheet = "";
- try
- {
- QFile f(":/ui/sendButton/sendButton.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream sendButtonStylesheetStream(&f);
- sendButtonStylesheet = sendButtonStylesheetStream.readAll();
- }
- catch (int e) {}
- sendButton->setStyleSheet(sendButtonStylesheet);
+ sendButton->setStyleSheet(Style::get(":/ui/sendButton/sendButton.css"));
+ fileButton->setStyleSheet(Style::get(":/ui/fileButton/fileButton.css"));
+ emoteButton->setStyleSheet(Style::get(":/ui/emoteButton/emoteButton.css"));
- QString fileButtonStylesheet = "";
- try
- {
- QFile f(":/ui/fileButton/fileButton.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream fileButtonStylesheetStream(&f);
- fileButtonStylesheet = fileButtonStylesheetStream.readAll();
- }
- catch (int e) {}
- fileButton->setStyleSheet(fileButtonStylesheet);
-
-
- QString emoteButtonStylesheet = "";
- try
- {
- QFile f(":/ui/emoteButton/emoteButton.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream emoteButtonStylesheetStream(&f);
- emoteButtonStylesheet = emoteButtonStylesheetStream.readAll();
- }
- catch (int e) {}
- emoteButton->setStyleSheet(emoteButtonStylesheet);
-
- QString callButtonStylesheet = "";
- try
- {
- QFile f(":/ui/callButton/callButton.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream callButtonStylesheetStream(&f);
- callButtonStylesheet = callButtonStylesheetStream.readAll();
- }
- catch (int e) {}
callButton->setObjectName("green");
- callButton->setStyleSheet(callButtonStylesheet);
+ callButton->setStyleSheet(Style::get(":/ui/callButton/callButton.css"));
- QString videoButtonStylesheet = "";
+ videoButton->setObjectName("green");
+ videoButton->setStyleSheet(Style::get(":/ui/videoButton/videoButton.css"));
+
+ QString volButtonStylesheet = "";
try
{
- QFile f(":/ui/videoButton/videoButton.css");
+ QFile f(":/ui/volButton/volButton.css");
f.open(QFile::ReadOnly | QFile::Text);
- QTextStream videoButtonStylesheetStream(&f);
- videoButtonStylesheet = videoButtonStylesheetStream.readAll();
+ QTextStream volButtonStylesheetStream(&f);
+ volButtonStylesheet = volButtonStylesheetStream.readAll();
}
catch (int e) {}
- videoButton->setObjectName("green");
- videoButton->setStyleSheet(videoButtonStylesheet);
+ volButton->setObjectName("green");
+ volButton->setStyleSheet(volButtonStylesheet);
+
+ QString micButtonStylesheet = "";
+ try
+ {
+ QFile f(":/ui/micButton/micButton.css");
+ f.open(QFile::ReadOnly | QFile::Text);
+ QTextStream micButtonStylesheetStream(&f);
+ micButtonStylesheet = micButtonStylesheetStream.readAll();
+ }
+ catch (int e) {}
+ micButton->setObjectName("green");
+ micButton->setStyleSheet(micButtonStylesheet);
main->setLayout(mainLayout);
mainLayout->addWidget(chatArea);
@@ -158,9 +127,13 @@ ChatForm::ChatForm(Friend* chatFriend)
headLayout->addWidget(avatar);
headLayout->addLayout(headTextLayout);
headLayout->addStretch();
+ headLayout->addLayout(volMicLayout);
headLayout->addWidget(callButton);
headLayout->addWidget(videoButton);
+ volMicLayout->addWidget(micButton);
+ volMicLayout->addWidget(volButton);
+
headTextLayout->addStretch();
headTextLayout->addWidget(name);
headTextLayout->addWidget(statusMessage);
@@ -173,20 +146,22 @@ ChatForm::ChatForm(Friend* chatFriend)
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
fileButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
emoteButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
-// callButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
-// videoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
-// msgEdit->setAttribute(Qt::WA_LayoutUsesWidgetRect);
-// chatArea->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ // callButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ // videoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ // msgEdit->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ // chatArea->setAttribute(Qt::WA_LayoutUsesWidgetRect);
connect(Widget::getInstance()->getCore(), &Core::fileSendStarted, this, &ChatForm::startFileSend);
connect(Widget::getInstance()->getCore(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay);
- connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
- connect(fileButton, SIGNAL(clicked()), this, SLOT(onAttachClicked()));
- connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
- connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
- connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
- connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
- connect(chatArea, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onChatContextMenuRequested(QPoint)));
+ connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
+ connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
+ connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered);
+ connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered);
+ connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
+ connect(chatArea->verticalScrollBar(), &QScrollBar::rangeChanged, this, &ChatForm::onSliderRangeChanged);
+ connect(chatArea, &QScrollArea::customContextMenuRequested, this, &ChatForm::onChatContextMenuRequested);
+ connect(emoteButton, &QPushButton::clicked, this, &ChatForm::onEmoteButtonClicked);
+ connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
}
ChatForm::~ChatForm()
@@ -196,7 +171,7 @@ ChatForm::~ChatForm()
delete netcam;
}
-void ChatForm::show(Ui::Widget &ui)
+void ChatForm::show(Ui::MainWindow &ui)
{
ui.mainContent->layout()->addWidget(main);
ui.mainHead->layout()->addWidget(head);
@@ -243,8 +218,6 @@ void ChatForm::addMessage(QString author, QString message, QString date)
void ChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date)
{
- QPalette greentext;
- greentext.setColor(QPalette::WindowText, QColor(61,204,61));
QScrollBar* scroll = chatArea->verticalScrollBar();
lockSliderToBottom = scroll && scroll->value() == scroll->maximum();
author->setAlignment(Qt::AlignTop | Qt::AlignRight);
@@ -272,8 +245,24 @@ void ChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date)
}
else if (curRow)// onSaveLogClicked expects 0 or 3 QLabel per line
author->setText("");
- if (message->text()[0] == '>')
- message->setPalette(greentext);
+
+ QColor greentext(61,204,61);
+ QString fontTemplate = "%2";
+
+ QString finalMessage;
+ QStringList messageLines = message->text().split("\n");
+ for (QString& s : messageLines)
+ {
+ if (QRegExp("^[ ]*>.*").exactMatch(s))
+ finalMessage += fontTemplate.arg(greentext.name(), s.replace(" ", " "));
+ else
+ finalMessage += s.replace(" ", " ");
+ finalMessage += " ";
+ }
+ message->setText(finalMessage.left(finalMessage.length()-4));
+ message->setText(SmileyPack::getInstance().smileyfied(message->text()));
+ message->setTextFormat(Qt::RichText);
+
mainChatLayout->addWidget(author, curRow, 0);
mainChatLayout->addWidget(message, curRow, 1);
mainChatLayout->addWidget(date, curRow, 3);
@@ -297,6 +286,12 @@ void ChatForm::onAttachClicked()
QFile file(path);
if (!file.exists() || !file.open(QIODevice::ReadOnly))
return;
+ if (file.isSequential())
+ {
+ QMessageBox::critical(0, "Bad Idea", "You're trying to send a special (sequential) file, that's not going to work!");
+ return;
+ file.close();
+ }
long long filesize = file.size();
file.close();
QFileInfo fi(path);
@@ -308,13 +303,14 @@ void ChatForm::onSliderRangeChanged()
{
QScrollBar* scroll = chatArea->verticalScrollBar();
if (lockSliderToBottom)
- scroll->setValue(scroll->maximum());
+ scroll->setValue(scroll->maximum());
}
void ChatForm::startFileSend(ToxFile file)
{
if (file.friendId != f->friendId)
return;
+
QLabel *author = new QLabel(Widget::getInstance()->getUsername());
QLabel *date = new QLabel(QTime::currentTime().toString("hh:mm"));
QScrollBar* scroll = chatArea->verticalScrollBar();
@@ -351,6 +347,7 @@ void ChatForm::onFileRecvRequest(ToxFile file)
{
if (file.friendId != f->friendId)
return;
+
QLabel *author = new QLabel(f->getName());
QLabel *date = new QLabel(QTime::currentTime().toString("hh:mm"));
QScrollBar* scroll = chatArea->verticalScrollBar();
@@ -378,12 +375,21 @@ void ChatForm::onFileRecvRequest(ToxFile file)
connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransfertWidget::onFileTransferInfo);
connect(Widget::getInstance()->getCore(), &Core::fileTransferCancelled, fileTrans, &FileTransfertWidget::onFileTransferCancelled);
connect(Widget::getInstance()->getCore(), &Core::fileTransferFinished, fileTrans, &FileTransfertWidget::onFileTransferFinished);
+
+ Widget* w = Widget::getInstance();
+ if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow())
+ {
+ w->newMessageAlert();
+ f->hasNewEvents=true;
+ f->widget->updateStatusLight();
+ }
}
void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
{
if (FriendId != f->friendId)
return;
+
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@@ -405,11 +411,11 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
}
Widget* w = Widget::getInstance();
- if (!w->isFriendWidgetCurActiveWidget(f))
+ if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow())
{
w->newMessageAlert();
- f->hasNewMessages=true;
- w->updateFriendStatusLights(f->friendId);
+ f->hasNewEvents=true;
+ f->widget->updateStatusLight();
}
}
@@ -417,6 +423,8 @@ void ChatForm::onAvStart(int FriendId, int CallId, bool video)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = true;
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@@ -443,6 +451,10 @@ void ChatForm::onAvCancel(int FriendId, int)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -458,6 +470,10 @@ void ChatForm::onAvEnd(int FriendId, int)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -473,6 +489,7 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
{
if (FriendId != f->friendId)
return;
+
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@@ -498,6 +515,7 @@ void ChatForm::onAvStarting(int FriendId, int, bool video)
{
if (FriendId != f->friendId)
return;
+
callButton->disconnect();
videoButton->disconnect();
if (video)
@@ -523,6 +541,10 @@ void ChatForm::onAvEnding(int FriendId, int)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -540,6 +562,10 @@ void ChatForm::onAvRequestTimeout(int FriendId, int)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -557,6 +583,10 @@ void ChatForm::onAvPeerTimeout(int FriendId, int)
{
if (FriendId != f->friendId)
return;
+
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -570,25 +600,43 @@ void ChatForm::onAvPeerTimeout(int FriendId, int)
netcam->hide();
}
+void ChatForm::onAvMediaChange(int, int, bool video)
+{
+ if (video)
+ {
+ netcam->show();
+ }
+ else
+ {
+ netcam->hide();
+ }
+}
+
void ChatForm::onAnswerCallTriggered()
{
+ audioInputFlag = true;
emit answerCall(callId);
}
void ChatForm::onHangupCallTriggered()
{
+ audioInputFlag = false;
emit hangupCall(callId);
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
}
void ChatForm::onCallTriggered()
{
- callButton->disconnect();
- videoButton->disconnect();
- emit startCall(f->friendId);
+ audioInputFlag = true;
+ callButton->disconnect();
+ videoButton->disconnect();
+ emit startCall(f->friendId);
}
void ChatForm::onVideoCallTriggered()
{
+ audioInputFlag = true;
callButton->disconnect();
videoButton->disconnect();
emit startVideoCall(f->friendId, true);
@@ -596,6 +644,9 @@ void ChatForm::onVideoCallTriggered()
void ChatForm::onCancelCallTriggered()
{
+ audioInputFlag = false;
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
callButton->disconnect();
videoButton->disconnect();
callButton->setObjectName("green");
@@ -650,3 +701,48 @@ void ChatForm::onSaveLogClicked()
file.write(log.toUtf8());
file.close();
}
+
+void ChatForm::onEmoteButtonClicked()
+{
+ // don't show the smiley selection widget if there are no smileys available
+ if (SmileyPack::getInstance().getEmoticons().empty())
+ return;
+
+ EmoticonsWidget widget;
+ connect(&widget, &EmoticonsWidget::insertEmoticon, this, &ChatForm::onEmoteInsertRequested);
+
+ QWidget* sender = qobject_cast(QObject::sender());
+ if (sender)
+ {
+ QPoint pos = -QPoint(widget.sizeHint().width() / 2, widget.sizeHint().height()) - QPoint(0, 10);
+ widget.exec(sender->mapToGlobal(pos));
+ }
+}
+
+void ChatForm::onEmoteInsertRequested(QString str)
+{
+ // insert the emoticon
+ QWidget* sender = qobject_cast(QObject::sender());
+ if (sender)
+ msgEdit->insertPlainText(str);
+
+ msgEdit->setFocus(); // refocus so that we can continue typing
+}
+
+void ChatForm::onMicMuteToggle()
+{
+ if (audioInputFlag == true)
+ {
+ emit micMuteToggle(callId);
+ if (micButton->objectName() == "red")
+ {
+ micButton->setObjectName("green");
+ micButton->style()->polish(micButton);
+ }
+ else
+ {
+ micButton->setObjectName("red");
+ micButton->style()->polish(micButton);
+ }
+ }
+}
diff --git a/widget/form/chatform.h b/widget/form/chatform.h
index d6d44143b..dd746d6c1 100644
--- a/widget/form/chatform.h
+++ b/widget/form/chatform.h
@@ -28,7 +28,7 @@
#include
#include "widget/tool/chattextedit.h"
-#include "ui_widget.h"
+#include "ui_mainwindow.h"
#include "core.h"
#include "widget/netcamview.h"
@@ -43,7 +43,7 @@ class ChatForm : public QObject
public:
ChatForm(Friend* chatFriend);
~ChatForm();
- void show(Ui::Widget& ui);
+ void show(Ui::MainWindow &ui);
void setName(QString newName);
void setStatusMessage(QString newMessage);
void addFriendMessage(QString message);
@@ -58,6 +58,7 @@ signals:
void answerCall(int callId);
void hangupCall(int callId);
void cancelCall(int callId, int friendId);
+ void micMuteToggle(int callId);
public slots:
void startFileSend(ToxFile file);
@@ -71,6 +72,8 @@ public slots:
void onAvEnding(int FriendId, int CallId);
void onAvRequestTimeout(int FriendId, int CallId);
void onAvPeerTimeout(int FriendId, int CallId);
+ void onAvMediaChange(int FriendId, int CallId, bool video);
+ void onMicMuteToggle();
private slots:
void onSendTriggered();
@@ -83,21 +86,23 @@ private slots:
void onCancelCallTriggered();
void onChatContextMenuRequested(QPoint pos);
void onSaveLogClicked();
+ void onEmoteButtonClicked();
+ void onEmoteInsertRequested(QString str);
private:
Friend* f;
QHBoxLayout *headLayout, *mainFootLayout;
- QVBoxLayout *headTextLayout, *mainLayout, *footButtonsSmall;
+ QVBoxLayout *headTextLayout, *mainLayout, *footButtonsSmall, *volMicLayout;
QGridLayout *mainChatLayout;
QLabel *avatar, *name, *statusMessage;
ChatTextEdit *msgEdit;
- QPushButton *sendButton, *fileButton, *emoteButton, *callButton, *videoButton;
+ QPushButton *sendButton, *fileButton, *emoteButton, *callButton, *videoButton, *volButton, *micButton;
QScrollArea *chatArea;
QWidget *main, *head, *chatAreaWidget;
QString previousName;
NetCamView* netcam;
int curRow;
- bool lockSliderToBottom;
+ bool lockSliderToBottom, audioInputFlag;
int callId;
};
diff --git a/widget/form/filesform.cpp b/widget/form/filesform.cpp
index 14ffe5fe0..6d69c1f5a 100644
--- a/widget/form/filesform.cpp
+++ b/widget/form/filesform.cpp
@@ -50,7 +50,7 @@ FilesForm::~FilesForm()
// I'm not too bummed about removing it
}
-void FilesForm::show(Ui::Widget& ui)
+void FilesForm::show(Ui::MainWindow& ui)
{
ui.mainContent->layout()->addWidget(&main);
ui.mainHead->layout()->addWidget(head);
diff --git a/widget/form/filesform.h b/widget/form/filesform.h
index f8fb51105..0f1a2b1d8 100644
--- a/widget/form/filesform.h
+++ b/widget/form/filesform.h
@@ -17,7 +17,7 @@
#ifndef FILESFORM_H
#define FILESFORM_H
-#include "ui_widget.h"
+#include "ui_mainwindow.h"
#include
#include
@@ -37,7 +37,7 @@ public:
FilesForm();
~FilesForm();
- void show(Ui::Widget& ui);
+ void show(Ui::MainWindow &ui);
public slots:
void onFileDownloadComplete(const QString& path);
diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp
index f3f12afcf..e5e630ae1 100644
--- a/widget/form/groupchatform.cpp
+++ b/widget/form/groupchatform.cpp
@@ -20,6 +20,7 @@
#include "widget/widget.h"
#include "friend.h"
#include "friendlist.h"
+#include "style.h"
#include
#include
#include
@@ -55,16 +56,8 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
namesList->setFont(small);
chatAreaWidget->setLayout(mainChatLayout);
- QString chatAreaStylesheet = "";
- try
- {
- QFile f(":/ui/chatArea/chatArea.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream chatAreaStylesheetStream(&f);
- chatAreaStylesheet = chatAreaStylesheetStream.readAll();
- }
- catch (int e) {}
- chatArea->setStyleSheet(chatAreaStylesheet);
+
+ chatArea->setStyleSheet(Style::get(":/ui/chatArea/chatArea.css"));
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
chatArea->setWidgetResizable(true);
chatArea->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -73,35 +66,15 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
mainChatLayout->setColumnStretch(1,1);
mainChatLayout->setSpacing(10);
-
- QString msgEditStylesheet = "";
- try
- {
- QFile f(":/ui/msgEdit/msgEdit.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream msgEditStylesheetStream(&f);
- msgEditStylesheet = msgEditStylesheetStream.readAll();
- }
- catch (int e) {}
msgEdit->setObjectName("group");
- msgEdit->setStyleSheet(msgEditStylesheet);
+ msgEdit->setStyleSheet(Style::get(":/ui/msgEdit/msgEdit.css"));
msgEdit->setFixedHeight(50);
msgEdit->setFrameStyle(QFrame::NoFrame);
mainChatLayout->setColumnStretch(1,1);
mainChatLayout->setHorizontalSpacing(10);
- QString sendButtonStylesheet = "";
- try
- {
- QFile f(":/ui/sendButton/sendButton.css");
- f.open(QFile::ReadOnly | QFile::Text);
- QTextStream sendButtonStylesheetStream(&f);
- sendButtonStylesheet = sendButtonStylesheetStream.readAll();
- }
- catch (int e) {}
- sendButton->setStyleSheet(sendButtonStylesheet);
-
+ sendButton->setStyleSheet(Style::get(":/ui/sendButton/sendButton.css"));
sendButton->setFixedSize(50, 50);
main->setLayout(mainLayout);
@@ -142,7 +115,7 @@ GroupChatForm::~GroupChatForm()
delete main;
}
-void GroupChatForm::show(Ui::Widget &ui)
+void GroupChatForm::show(Ui::MainWindow &ui)
{
ui.mainContent->layout()->addWidget(main);
ui.mainHead->layout()->addWidget(head);
diff --git a/widget/form/groupchatform.h b/widget/form/groupchatform.h
index b4ac9a5ce..af008476a 100644
--- a/widget/form/groupchatform.h
+++ b/widget/form/groupchatform.h
@@ -27,7 +27,7 @@
#include
#include "widget/tool/chattextedit.h"
-#include "ui_widget.h"
+#include "ui_mainwindow.h"
// Spacing in px inserted when the author of the last message changes
#define AUTHOR_CHANGE_SPACING 5
@@ -40,7 +40,7 @@ class GroupChatForm : public QObject
public:
GroupChatForm(Group* chatGroup);
~GroupChatForm();
- void show(Ui::Widget& ui);
+ void show(Ui::MainWindow &ui);
void setName(QString newName);
void addGroupMessage(QString message, int peerId);
void addMessage(QString author, QString message, QString date=QTime::currentTime().toString("hh:mm"));
diff --git a/widget/form/settingsform.cpp b/widget/form/settingsform.cpp
index 573d80101..bb8c12093 100644
--- a/widget/form/settingsform.cpp
+++ b/widget/form/settingsform.cpp
@@ -17,9 +17,12 @@
#include "settingsform.h"
#include "widget/widget.h"
#include "settings.h"
+#include "smileypack.h"
#include
#include
#include
+#include
+#include
SettingsForm::SettingsForm()
: QObject()
@@ -55,6 +58,12 @@ SettingsForm::SettingsForm()
useTranslations.setChecked(Settings::getInstance().getUseTranslations());
makeToxPortable.setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application"));
makeToxPortable.setChecked(Settings::getInstance().getMakeToxPortable());
+ makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox"));
+
+ smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label"));
+ for (auto entry : SmileyPack::listSmileyPacks())
+ smileyPackBrowser.addItem(entry.first, entry.second);
+ smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack()));
main->setLayout(&layout);
layout.addWidget(&idLabel);
@@ -73,7 +82,9 @@ SettingsForm::SettingsForm()
layout.addWidget(&enableIPv6);
layout.addWidget(&useTranslations);
layout.addWidget(&makeToxPortable);
- //layout.addStretch();
+ layout.addWidget(&smileyPackLabel);
+ layout.addWidget(&smileyPackBrowser);
+ layout.addStretch();
head->setLayout(&headLayout);
headLayout.addWidget(&headLabel);
@@ -87,6 +98,7 @@ SettingsForm::SettingsForm()
connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated()));
connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated()));
connect(&idLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked()));
+ connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int)));
}
SettingsForm::~SettingsForm()
@@ -116,7 +128,7 @@ void SettingsForm::setFriendAddress(const QString& friendAddress)
id.setText(friendAddress);
}
-void SettingsForm::show(Ui::Widget &ui)
+void SettingsForm::show(Ui::MainWindow &ui)
{
profiles.clear();
for (QString profile : searchProfiles())
@@ -198,3 +210,9 @@ void SettingsForm::onMakeToxPortableUpdated()
{
Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked());
}
+
+void SettingsForm::onSmileyBrowserIndexChanged(int index)
+{
+ QString filename = smileyPackBrowser.itemData(index).toString();
+ Settings::getInstance().setSmileyPack(filename);
+}
diff --git a/widget/form/settingsform.h b/widget/form/settingsform.h
index a14ed9142..8e012c5ee 100644
--- a/widget/form/settingsform.h
+++ b/widget/form/settingsform.h
@@ -31,9 +31,9 @@
#include
#include
#include
-#include "widget/tool/clickablelabel.h"
-#include "ui_widget.h"
+#include "ui_mainwindow.h"
#include "widget/selfcamview.h"
+#include "widget/croppinglabel.h"
#include "core.h"
class SettingsForm : public QObject
@@ -43,7 +43,7 @@ public:
SettingsForm();
~SettingsForm();
- void show(Ui::Widget& ui);
+ void show(Ui::MainWindow &ui);
static QList searchProfiles();
public slots:
@@ -58,12 +58,13 @@ private slots:
void onEnableIPv6Updated();
void onUseTranslationUpdated();
void onMakeToxPortableUpdated();
+ void onSmileyBrowserIndexChanged(int index);
void copyIdClicked();
private:
- QLabel headLabel;/*, nameLabel, statusTextLabel;*/
+ QLabel headLabel, smileyPackLabel;
QTextEdit id;
- ClickableLabel idLabel;
+ CroppingLabel idLabel;
QLabel profilesLabel;
QComboBox profiles;
QPushButton loadConf, exportConf, delConf, importConf, videoTest;
@@ -71,10 +72,8 @@ private:
QCheckBox enableIPv6, useTranslations, makeToxPortable;
QVBoxLayout layout, headLayout;
QWidget *main, *head, *hboxcont1, *hboxcont2;
+ QComboBox smileyPackBrowser;
QString getSelectedSavePath();
-
-public:
- //QLineEdit name, statusText;
};
#endif // SETTINGSFORM_H
diff --git a/widget/friendlistwidget.cpp b/widget/friendlistwidget.cpp
new file mode 100644
index 000000000..aced0f297
--- /dev/null
+++ b/widget/friendlistwidget.cpp
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+#include "friendlistwidget.h"
+#include
+
+FriendListWidget::FriendListWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ mainLayout = new QGridLayout();
+ setLayout(mainLayout);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ layout()->setSpacing(0);
+ layout()->setMargin(0);
+
+ groupLayout = new QVBoxLayout();
+ groupLayout->setSpacing(0);
+ groupLayout->setMargin(0);
+
+ for (Status s : {Status::Online, Status::Away, Status::Busy, Status::Offline})
+ {
+ QLayout *l = new QVBoxLayout();
+ l->setSpacing(0);
+ l->setMargin(0);
+
+ layouts[static_cast(s)] = l;
+ }
+
+ mainLayout->addLayout(layouts[static_cast(Status::Online)], 0, 0);
+ mainLayout->addLayout(groupLayout, 1, 0);
+ mainLayout->addLayout(layouts[static_cast(Status::Away)], 2, 0);
+ mainLayout->addLayout(layouts[static_cast(Status::Busy)], 3, 0);
+ mainLayout->addLayout(layouts[static_cast(Status::Offline)], 4, 0);
+}
+
+QLayout* FriendListWidget::getGroupLayout()
+{
+ return groupLayout;
+}
+
+QLayout* FriendListWidget::getFriendLayout(Status s)
+{
+ auto res = layouts.find(static_cast(s));
+ if (res != layouts.end())
+ return res.value();
+
+ qDebug() << "Friend Status: " << static_cast(s) << " not found!";
+ return layouts[static_cast(Status::Online)];
+}
+
+void FriendListWidget::moveWidget(QWidget *w, Status s)
+{
+ mainLayout->removeWidget(w);
+ getFriendLayout(s)->addWidget(w);
+}
diff --git a/widget/videosurface.h b/widget/friendlistwidget.h
similarity index 51%
rename from widget/videosurface.h
rename to widget/friendlistwidget.h
index c93ed2c8f..02baa3f94 100644
--- a/widget/videosurface.h
+++ b/widget/friendlistwidget.h
@@ -14,29 +14,31 @@
See the COPYING file for more details.
*/
-#ifndef VIDEOSURFACE_H
-#define VIDEOSURFACE_H
+#ifndef FRIENDLISTWIDGET_H
+#define FRIENDLISTWIDGET_H
-#include
-#include
-#include "vpx/vpx_image.h"
+#include
+#include
+#include "core.h"
-class VideoSurface : public QAbstractVideoSurface
+class FriendListWidget : public QWidget
{
Q_OBJECT
public:
- VideoSurface();
- bool start(const QVideoSurfaceFormat &format);
- bool present(const QVideoFrame &frame);
- QList supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
+ explicit FriendListWidget(QWidget *parent = 0);
+
+ QLayout* getGroupLayout();
+ QLayout* getFriendLayout(Status s);
+ void moveWidget(QWidget *w, Status s);
signals:
- // Slots MUST be called with a direct or blocking connection, or img may die before they return !
- void videoFrameReady(vpx_image img);
+
+public slots:
private:
- QVideoSurfaceFormat mVideoFormat;
- vpx_image_t input;
+ QHash layouts;
+ QLayout *groupLayout;
+ QGridLayout *mainLayout;
};
-#endif // VIDEOSURFACE_H
+#endif // FRIENDLISTWIDGET_H
diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp
index 845bf816c..97c7b9c77 100644
--- a/widget/friendwidget.cpp
+++ b/widget/friendwidget.cpp
@@ -19,22 +19,24 @@
#include "grouplist.h"
#include "groupwidget.h"
#include "widget.h"
+#include "friendlist.h"
+#include "friend.h"
#include
#include
FriendWidget::FriendWidget(int FriendId, QString id)
: friendId(FriendId)
{
- this->setMouseTracking(true);
- this->setAutoFillBackground(true);
- this->setFixedWidth(225);
- this->setFixedHeight(55);
- this->setLayout(&layout);
+ setMouseTracking(true);
+ setAutoFillBackground(true);
+ setFixedHeight(55);
+ setLayout(&layout);
layout.setSpacing(0);
layout.setMargin(0);
layout.setStretchFactor(this, 100);
textLayout.setSpacing(0);
textLayout.setMargin(0);
+ setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft
avatar.setPixmap(QPixmap(":img/contact.png"));
name.setText(id);
@@ -62,22 +64,16 @@ FriendWidget::FriendWidget(int FriendId, QString id)
layout.addWidget(&avatar);
layout.addSpacing(5);
layout.addLayout(&textLayout);
- layout.addStretch();
layout.addSpacing(5);
layout.addWidget(&statusPic);
layout.addSpacing(5);
isActiveWidget = 0;
-}
-void FriendWidget::setNewFixedWidth(int newWidth)
-{
- this->setFixedWidth(newWidth);
-}
-
-void FriendWidget::mouseReleaseEvent (QMouseEvent*)
-{
- emit friendWidgetClicked(this);
+ layout.invalidate();
+ layout.update();
+ layout.activate();
+ updateGeometry();
}
void FriendWidget::contextMenuEvent(QContextMenuEvent * event)
@@ -121,47 +117,6 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event)
}
}
-void FriendWidget::mousePressEvent(QMouseEvent *event)
-{
- if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton)
- {
- if (isActiveWidget)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(250,250,250,255));
- this->setPalette(pal);
- }
- else
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(85,85,85,255));
- this->setPalette(pal);
- }
- }
-}
-
-void FriendWidget::enterEvent(QEvent*)
-{
- if (isActiveWidget != 1)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(75,75,75,255));
- lastColor = this->palette().background().color();
- this->setPalette(pal);
- }
-}
-
-void FriendWidget::leaveEvent(QEvent*)
-{
- if (isActiveWidget != 1)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, lastColor);
- this->setPalette(pal);
- }
-}
-
-
void FriendWidget::setAsActiveChatroom()
{
isActiveWidget = 1;
@@ -199,3 +154,38 @@ void FriendWidget::setAsInactiveChatroom()
this->setPalette(pal3);
avatar.setPixmap(QPixmap(":img/contact.png"));
}
+
+void FriendWidget::updateStatusLight()
+{
+ Friend* f = FriendList::findFriend(friendId);
+ Status status = f->friendStatus;
+
+ if (status == Status::Online && f->hasNewEvents == 0)
+ statusPic.setPixmap(QPixmap(":img/status/dot_online.png"));
+ else if (status == Status::Online && f->hasNewEvents == 1)
+ statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
+ else if (status == Status::Away && f->hasNewEvents == 0)
+ statusPic.setPixmap(QPixmap(":img/status/dot_idle.png"));
+ else if (status == Status::Away && f->hasNewEvents == 1)
+ statusPic.setPixmap(QPixmap(":img/status/dot_idle_notification.png"));
+ else if (status == Status::Busy && f->hasNewEvents == 0)
+ statusPic.setPixmap(QPixmap(":img/status/dot_busy.png"));
+ else if (status == Status::Busy && f->hasNewEvents == 1)
+ statusPic.setPixmap(QPixmap(":img/status/dot_busy_notification.png"));
+ else if (status == Status::Offline && f->hasNewEvents == 0)
+ statusPic.setPixmap(QPixmap(":img/status/dot_away.png"));
+ else if (status == Status::Offline && f->hasNewEvents == 1)
+ statusPic.setPixmap(QPixmap(":img/status/dot_away_notification.png"));
+}
+
+void FriendWidget::setChatForm(Ui::MainWindow &ui)
+{
+ Friend* f = FriendList::findFriend(friendId);
+ f->chatForm->show(ui);
+}
+
+void FriendWidget::resetEventFlags()
+{
+ Friend* f = FriendList::findFriend(friendId);
+ f->hasNewEvents = 0;
+}
diff --git a/widget/friendwidget.h b/widget/friendwidget.h
index 091f78c69..257d48a24 100644
--- a/widget/friendwidget.h
+++ b/widget/friendwidget.h
@@ -22,19 +22,20 @@
#include
#include
-struct FriendWidget : public QWidget
+#include "genericchatroomwidget.h"
+#include "croppinglabel.h"
+
+struct FriendWidget : public GenericChatroomWidget
{
Q_OBJECT
public:
FriendWidget(int FriendId, QString id);
- void mouseReleaseEvent (QMouseEvent* event);
- void mousePressEvent(QMouseEvent *event);
void contextMenuEvent(QContextMenuEvent * event);
- void enterEvent(QEvent* event);
- void leaveEvent(QEvent* event);
void setAsActiveChatroom();
void setAsInactiveChatroom();
- void setNewFixedWidth(int newWidth);
+ void updateStatusLight();
+ void setChatForm(Ui::MainWindow &);
+ void resetEventFlags();
signals:
void friendWidgetClicked(FriendWidget* widget);
@@ -43,13 +44,8 @@ signals:
public:
int friendId;
- QLabel avatar, name, statusMessage, statusPic;
- QHBoxLayout layout;
- QVBoxLayout textLayout;
-
-private:
- QColor lastColor;
- int isActiveWidget;
+ QLabel avatar, statusPic;
+ CroppingLabel name, statusMessage;
};
#endif // FRIENDWIDGET_H
diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp
new file mode 100644
index 000000000..234da1222
--- /dev/null
+++ b/widget/genericchatroomwidget.cpp
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#include "genericchatroomwidget.h"
+#include
+
+GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) :
+ QWidget(parent)
+{
+}
+
+int GenericChatroomWidget::isActive()
+{
+ return isActiveWidget;
+}
+
+void GenericChatroomWidget::mousePressEvent(QMouseEvent *event)
+{
+ if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton)
+ {
+ if (isActive())
+ {
+ QPalette pal;
+ pal.setColor(QPalette::Background, QColor(250,250,250,255));
+ this->setPalette(pal);
+ }
+ else
+ {
+ QPalette pal;
+ pal.setColor(QPalette::Background, QColor(85,85,85,255));
+ this->setPalette(pal);
+ }
+ }
+}
+
+void GenericChatroomWidget::leaveEvent(QEvent *)
+{
+ if (isActive() != 1)
+ {
+ QPalette pal;
+ pal.setColor(QPalette::Background, lastColor);
+ this->setPalette(pal);
+ }
+}
+
+void GenericChatroomWidget::enterEvent(QEvent *)
+{
+ if (isActive() != 1)
+ {
+ QPalette pal;
+ pal.setColor(QPalette::Background, QColor(75,75,75,255));
+ lastColor = this->palette().background().color();
+ this->setPalette(pal);
+ }
+}
+
+void GenericChatroomWidget::mouseReleaseEvent(QMouseEvent*)
+{
+ emit chatroomWidgetClicked(this);
+}
diff --git a/widget/genericchatroomwidget.h b/widget/genericchatroomwidget.h
new file mode 100644
index 000000000..14e46c16e
--- /dev/null
+++ b/widget/genericchatroomwidget.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2014 by Project Tox
+
+ This file is part of qTox, a Qt-based graphical interface for Tox.
+
+ This program 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.
+ This program 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 COPYING file for more details.
+*/
+
+#ifndef GENERICCHATROOMWIDGET_H
+#define GENERICCHATROOMWIDGET_H
+
+#include
+#include
+#include
+
+namespace Ui {
+ class MainWindow;
+}
+
+class GenericChatroomWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ GenericChatroomWidget(QWidget *parent = 0);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent (QMouseEvent* event);
+ void leaveEvent(QEvent *);
+ void enterEvent(QEvent *);
+
+ virtual void setAsActiveChatroom(){;}
+ virtual void setAsInactiveChatroom(){;}
+ virtual void updateStatusLight(){;}
+ virtual void setChatForm(Ui::MainWindow &){;}
+ virtual void resetEventFlags(){;}
+
+ int isActive();
+
+signals:
+ void chatroomWidgetClicked(GenericChatroomWidget* widget);
+
+public slots:
+
+protected:
+ int isActiveWidget;
+ QColor lastColor;
+ QHBoxLayout layout;
+ QVBoxLayout textLayout;
+};
+
+#endif // GENERICCHATROOMWIDGET_H
diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp
index 6eb995031..b8c1cbcc0 100644
--- a/widget/groupwidget.cpp
+++ b/widget/groupwidget.cpp
@@ -17,22 +17,26 @@
#include "groupwidget.h"
#include "grouplist.h"
#include "group.h"
+#include "settings.h"
+#include "widget/form/groupchatform.h"
#include
#include
#include
+#include "ui_mainwindow.h"
+
GroupWidget::GroupWidget(int GroupId, QString Name)
: groupId{GroupId}
{
- this->setMouseTracking(true);
- this->setAutoFillBackground(true);
- this->setLayout(&layout);
- this->setFixedWidth(225);
- this->setFixedHeight(55);
+ setMouseTracking(true);
+ setAutoFillBackground(true);
+ setLayout(&layout);
+ setFixedHeight(55);
layout.setSpacing(0);
layout.setMargin(0);
textLayout.setSpacing(0);
textLayout.setMargin(0);
+ setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft
avatar.setPixmap(QPixmap(":img/group.png"));
statusPic.setPixmap(QPixmap(":img/status/dot_online.png"));
@@ -72,16 +76,6 @@ GroupWidget::GroupWidget(int GroupId, QString Name)
isActiveWidget = 0;
}
-void GroupWidget::setNewFixedWidth(int newWidth)
-{
- this->setFixedWidth(newWidth);
-}
-
-void GroupWidget::mouseReleaseEvent (QMouseEvent*)
-{
- emit groupWidgetClicked(this);
-}
-
void GroupWidget::contextMenuEvent(QContextMenuEvent * event)
{
QPoint pos = event->globalPos();
@@ -99,46 +93,6 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent * event)
}
}
-void GroupWidget::mousePressEvent(QMouseEvent *event)
-{
- if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton)
- {
- if (isActiveWidget)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(250,250,250,255));
- this->setPalette(pal);
- }
- else
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(85,85,85,255));
- this->setPalette(pal);
- }
- }
-}
-
-void GroupWidget::enterEvent(QEvent*)
-{
- if (isActiveWidget != 1)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, QColor(75,75,75,255));
- lastColor = this->palette().background().color();
- this->setPalette(pal);
- }
-}
-
-void GroupWidget::leaveEvent(QEvent*)
-{
- if (isActiveWidget != 1)
- {
- QPalette pal;
- pal.setColor(QPalette::Background, lastColor);
- this->setPalette(pal);
- }
-}
-
void GroupWidget::onUserListChanged()
{
Group* g = GroupList::findGroup(groupId);
@@ -185,3 +139,40 @@ void GroupWidget::setAsInactiveChatroom()
this->setPalette(pal3);
avatar.setPixmap(QPixmap(":img/group.png"));
}
+
+void GroupWidget::updateStatusLight()
+{
+ Group *g = GroupList::findGroup(groupId);
+
+ if (Settings::getInstance().getUseNativeDecoration())
+ {
+ if (g->hasNewMessages == 0)
+ {
+ statusPic.setPixmap(QPixmap(":img/status/dot_online.png"));
+ } else {
+ if (g->userWasMentioned == 0) statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
+ else statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
+ }
+ } else {
+ if (g->hasNewMessages == 0)
+ {
+ statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png"));
+ } else {
+ if (g->userWasMentioned == 0) statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png"));
+ else statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png"));
+ }
+ }
+}
+
+void GroupWidget::setChatForm(Ui::MainWindow &ui)
+{
+ Group* g = GroupList::findGroup(groupId);
+ g->chatForm->show(ui);
+}
+
+void GroupWidget::resetEventFlags()
+{
+ Group* g = GroupList::findGroup(groupId);
+ g->hasNewMessages = 0;
+ g->userWasMentioned = 0;
+}
diff --git a/widget/groupwidget.h b/widget/groupwidget.h
index fe66a2371..c32db80a6 100644
--- a/widget/groupwidget.h
+++ b/widget/groupwidget.h
@@ -19,21 +19,20 @@
#include
#include
-#include
-#include
+#include "genericchatroomwidget.h"
-class GroupWidget : public QWidget
+class GroupWidget : public GenericChatroomWidget
{
Q_OBJECT
public:
GroupWidget(int GroupId, QString Name);
void onUserListChanged();
- void mouseReleaseEvent (QMouseEvent* event);
- void mousePressEvent(QMouseEvent *event);
void contextMenuEvent(QContextMenuEvent * event);
- void enterEvent(QEvent* event);
- void leaveEvent(QEvent* event);
-
+ void setAsInactiveChatroom();
+ void setAsActiveChatroom();
+ void updateStatusLight();
+ void setChatForm(Ui::MainWindow &);
+ void resetEventFlags();
signals:
void groupWidgetClicked(GroupWidget* widget);
@@ -42,15 +41,6 @@ signals:
public:
int groupId;
QLabel avatar, name, nusers, statusPic;
- QHBoxLayout layout;
- QVBoxLayout textLayout;
- void setAsInactiveChatroom();
- void setAsActiveChatroom();
- void setNewFixedWidth(int newWidth);
-
-private:
- QColor lastColor;
- int isActiveWidget;
};
#endif // GROUPWIDGET_H
diff --git a/widget/netcamview.cpp b/widget/netcamview.cpp
index dd7454972..cd9e78fda 100644
--- a/widget/netcamview.cpp
+++ b/widget/netcamview.cpp
@@ -89,8 +89,8 @@ QImage NetCamView::convert(vpx_image& frame)
QImage img(w, h, QImage::Format_RGB32);
uint8_t* yData = frame.planes[VPX_PLANE_Y];
- uint8_t* uData = frame.planes[VPX_PLANE_U];
- uint8_t* vData = frame.planes[VPX_PLANE_V];
+ uint8_t* uData = frame.planes[VPX_PLANE_V];
+ uint8_t* vData = frame.planes[VPX_PLANE_U];
for (int i = 0; i< h; i++)
{
uint32_t* scanline = (uint32_t*)img.scanLine(i);
diff --git a/widget/selfcamview.cpp b/widget/selfcamview.cpp
index d38b773dd..2d46e99bb 100644
--- a/widget/selfcamview.cpp
+++ b/widget/selfcamview.cpp
@@ -15,15 +15,13 @@
*/
#include "selfcamview.h"
-#include
-#include
#include
#include
-#include
-#include "videosurface.h"
#include "widget.h"
+using namespace cv;
+
SelfCamView::SelfCamView(Camera* Cam, QWidget* parent)
: QWidget(parent), displayLabel{new QLabel},
mainLayout{new QHBoxLayout()}, cam(Cam)
diff --git a/widget/tool/chattextedit.cpp b/widget/tool/chattextedit.cpp
index face13191..8f727cfbb 100644
--- a/widget/tool/chattextedit.cpp
+++ b/widget/tool/chattextedit.cpp
@@ -20,6 +20,7 @@
ChatTextEdit::ChatTextEdit(QWidget *parent) :
QTextEdit(parent)
{
+ setPlaceholderText("Type your message here...");
}
void ChatTextEdit::keyPressEvent(QKeyEvent * event)
diff --git a/widget/tool/copyableelidelabel.cpp b/widget/tool/copyableelidelabel.cpp
deleted file mode 100644
index ae05717ca..000000000
--- a/widget/tool/copyableelidelabel.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- Copyright (C) 2013 by Maxim Biro
-
- This file is part of Tox Qt GUI.
-
- This program is free 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.
- This program 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 COPYING file for more details.
-*/
-
-#include "copyableelidelabel.h"
-
-#include
-#include
-#include
-
-CopyableElideLabel::CopyableElideLabel(QWidget* parent) :
- ElideLabel(parent)
-{
- setContextMenuPolicy(Qt::CustomContextMenu);
- connect(this, &CopyableElideLabel::customContextMenuRequested, this, &CopyableElideLabel::showContextMenu);
-
- actionCopy = new QAction(CopyableElideLabel::tr("Copy"), this);
- connect(actionCopy, &QAction::triggered, [this]() {
- QApplication::clipboard()->setText(text());
- });
-}
-
-void CopyableElideLabel::showContextMenu(const QPoint& pos)
-{
- if (text().length() == 0) {
- return;
- }
-
- QPoint globalPos = mapToGlobal(pos);
-
- QMenu contextMenu;
- contextMenu.addAction(actionCopy);
-
- contextMenu.exec(globalPos);
-}
diff --git a/widget/tool/copyableelidelabel.h b/widget/tool/copyableelidelabel.h
deleted file mode 100644
index 69bc09382..000000000
--- a/widget/tool/copyableelidelabel.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright (C) 2013 by Maxim Biro
-
- This file is part of Tox Qt GUI.
-
- This program is free 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.
- This program 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 COPYING file for more details.
-*/
-
-#ifndef COPYABLEELIDELABEL_HPP
-#define COPYABLEELIDELABEL_HPP
-
-#include "elidelabel.h"
-
-class CopyableElideLabel : public ElideLabel
-{
- Q_OBJECT
-public:
- explicit CopyableElideLabel(QWidget* parent = 0);
-
-private:
- QAction* actionCopy;
-
-private slots:
- void showContextMenu(const QPoint& pos);
-
-};
-
-#endif // COPYABLEELIDELABEL_HPP
diff --git a/widget/tool/editablelabelwidget.cpp b/widget/tool/editablelabelwidget.cpp
deleted file mode 100644
index a9c87f27a..000000000
--- a/widget/tool/editablelabelwidget.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- Copyright (C) 2013 by Maxim Biro
-
- This file is part of Tox Qt GUI.
-
- This program is free 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.
- This program 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 COPYING file for more details.
-*/
-
-#include "editablelabelwidget.h"
-
-#include
-#include
-#include
-#include
-#include
-
-ClickableCopyableElideLabel::ClickableCopyableElideLabel(QWidget* parent) :
- CopyableElideLabel(parent)
-{
-}
-
-bool ClickableCopyableElideLabel::event(QEvent* event)
-{
- if (event->type() == QEvent::MouseButtonRelease) {
- QMouseEvent* mouseEvent = static_cast(event);
- if (mouseEvent->button() == Qt::LeftButton) {
- emit clicked();
- }
- } else if (event->type() == QEvent::Enter) {
- QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
- } else if (event->type() == QEvent::Leave) {
- QApplication::restoreOverrideCursor();
- }
-
- return CopyableElideLabel::event(event);
-}
-
-EditableLabelWidget::EditableLabelWidget(QWidget* parent) :
- QStackedWidget(parent), isSubmitting(false)
-{
- label = new ClickableCopyableElideLabel(this);
-
- connect(label, &ClickableCopyableElideLabel::clicked, this, &EditableLabelWidget::onLabelClicked);
-
- lineEdit = new EscLineEdit(this);
- lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
- lineEdit->setMinimumHeight(label->fontMetrics().lineSpacing() + LINE_SPACING_OFFSET);
-
- // Set dark background for >windows
- //QColor toxDarkAsMySoul(28,28,28);
- //QPalette darkPal;
- //darkPal.setColor(QPalette::Window, toxDarkAsMySoul);
- //darkPal.setColor(QPalette::Base, toxDarkAsMySoul);
- //lineEdit->setPalette(darkPal);
-
- connect(lineEdit, &EscLineEdit::editingFinished, this, &EditableLabelWidget::onLabelChangeSubmited);
- connect(lineEdit, &EscLineEdit::escPressed, this, &EditableLabelWidget::onLabelChangeCancelled);
-
- addWidget(label);
- addWidget(lineEdit);
-
- setCurrentWidget(label);
-}
-
-void EditableLabelWidget::setText(const QString& text)
-{
- label->setText(text);
- lineEdit->setText(text);
-}
-
-QString EditableLabelWidget::text()
-{
- return label->text();
-}
-
-void EditableLabelWidget::onLabelChangeSubmited()
-{
- if (isSubmitting) {
- return;
- }
- isSubmitting = true;
-
- QString oldText = label->text();
- QString newText = lineEdit->text();
- // `lineEdit->clearFocus()` triggers `onLabelChangeSubmited()`, we use `isSubmitting` as a workaround
- lineEdit->clearFocus();
- setCurrentWidget(label);
-
- if (oldText != newText) {
- label->setText(newText);
- emit textChanged(newText, oldText);
- }
-
- isSubmitting = false;
-}
-
-void EditableLabelWidget::onLabelChangeCancelled()
-{
- // order of calls matters, since clearFocus() triggers EditableLabelWidget::onLabelChangeSubmited()
- lineEdit->setText(label->text());
- lineEdit->clearFocus();
- setCurrentWidget(label);
-}
-
-void EditableLabelWidget::onLabelClicked()
-{
- setCurrentWidget(lineEdit);
- lineEdit->setFocus();
-}
diff --git a/widget/tool/editablelabelwidget.h b/widget/tool/editablelabelwidget.h
deleted file mode 100644
index 17772f8c4..000000000
--- a/widget/tool/editablelabelwidget.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- Copyright (C) 2013 by Maxim Biro
-
- This file is part of Tox Qt GUI.
-
- This program is free 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.
- This program 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 COPYING file for more details.
-*/
-
-#ifndef EDITABLELABELWIDGET_HPP
-#define EDITABLELABELWIDGET_HPP
-
-#include "copyableelidelabel.h"
-#include "esclineedit.h"
-
-#include
-#include
-
-class ClickableCopyableElideLabel : public CopyableElideLabel
-{
- Q_OBJECT
-public:
- explicit ClickableCopyableElideLabel(QWidget* parent = 0);
-
-protected:
- bool event(QEvent* event) Q_DECL_OVERRIDE;
-
-signals:
- void clicked();
-
-};
-
-class EditableLabelWidget : public QStackedWidget
-{
- Q_OBJECT
-public:
- explicit EditableLabelWidget(QWidget* parent = 0);
-
- ClickableCopyableElideLabel* label;
- EscLineEdit* lineEdit;
-
- void setText(const QString& text);
- QString text();
-
-private:
- static const int LINE_SPACING_OFFSET = 2;
- bool isSubmitting;
-
-private slots:
- void onLabelChangeSubmited();
- void onLabelChangeCancelled();
- void onLabelClicked();
-
-signals:
- void textChanged(QString newText, QString oldText);
-
-};
-
-#endif // EDITABLELABELWIDGET_HPP
diff --git a/widget/tool/elidelabel.cpp b/widget/tool/elidelabel.cpp
deleted file mode 100644
index 239400f49..000000000
--- a/widget/tool/elidelabel.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- Copyright (C) 2013 by Maxim Biro
-
- This file is part of Tox Qt GUI.
-
- This program is free 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.
- This program 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 COPYING file for more details.
-*/
-
-#include "elidelabel.h"
-
-#include
-#include