diff --git a/INSTALL.md b/INSTALL.md
index a0d4680de..831d3c3fa 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -15,7 +15,7 @@
| OpenCV | >= 2.4.9 | core, highgui, imgproc |
| OpenAL Soft | >= 1.16.0 | |
| filter_audio | most recent | |
-
+| qrencode | >= 3.0.3 | |
##Linux
@@ -59,22 +59,22 @@ git clone https://github.com/tux3/qTox.git qTox
The following steps assumes that you cloned the repository at "/home/user/qTox". If you decided to choose another location, replace corresponding parts.
-###GCC, Qt, OpenCV and OpanAL Soft
+###GCC, Qt, OpenCV, OpanAL Soft and QRCode
Arch Linux:
```bash
-sudo pacman -S --needed base-devel qt5 opencv openal libxss
+sudo pacman -S --needed base-devel qt5 opencv openal libxss qrencode
```
Debian / Ubuntu:
```bash
-sudo apt-get install build-essential qt5-qmake qt5-default qttools5-dev-tools libqt5opengl5-dev libqt5svg5-dev libopenal-dev libopencv-dev libxss-dev
+sudo apt-get install build-essential qt5-qmake qt5-default qttools5-dev-tools libqt5opengl5-dev libqt5svg5-dev libopenal-dev libopencv-dev libxss-dev qrencode
```
Fedora:
```bash
yum groupinstall "Development Tools"
-yum install qt-devel qt-doc qt-creator qt5-qtsvg opencv-devel openal-soft-devel libXScrnSaver-devel
+yum install qt-devel qt-doc qt-creator qt5-qtsvg opencv-devel openal-soft-devel libXScrnSaver-devel qrencode
```
Slackware:
@@ -87,6 +87,8 @@ http://slackbuilds.org/repository/14.1/libraries/qt5/
http://slackbuilds.org/repository/14.1/libraries/opencv/
+http://slackbuilds.org/slackbuilds/14.1/graphics/qrencode/
+
###Tox Core
diff --git a/qtox.pro b/qtox.pro
index d1fe9def5..aec2d9b50 100644
--- a/qtox.pro
+++ b/qtox.pro
@@ -134,7 +134,7 @@ win32 {
LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread
LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 -lopus
LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -lws2_32 -liphlpapi -lz
-
+ LIBS += -lqrencode
contains(DEFINES, QTOX_FILTER_AUDIO) {
contains(STATICPKG, YES) {
LIBS += -Wl,-Bstatic -lfilteraudio
@@ -149,6 +149,7 @@ win32 {
QMAKE_INFO_PLIST = osx/info.plist
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -lopus -framework OpenAL -lopencv_core -lopencv_highgui -mmacosx-version-min=10.7
+ LIBS += -lqrencode
contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation }
contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio }
} else {
@@ -165,8 +166,10 @@ win32 {
LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic
LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
+ LIBS += -lqrencode
} else {
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
+ LIBS += -lqrencode
}
contains(DEFINES, QTOX_PLATFORM_EXT) {
@@ -424,7 +427,8 @@ SOURCES += \
src/video/netvideosource.cpp \
src/video/videoframe.cpp \
src/widget/gui.cpp \
- src/toxme.cpp
+ src/toxme.cpp \
+ src/misc/qrwidget.cpp
HEADERS += \
src/audio.h \
@@ -445,4 +449,5 @@ HEADERS += \
src/video/videoframe.h \
src/video/videosource.h \
src/widget/gui.h \
- src/toxme.h
+ src/toxme.h \
+ src/misc/qrwidget.h
diff --git a/simple_make.sh b/simple_make.sh
index 8557f6d81..c845dc26f 100755
--- a/simple_make.sh
+++ b/simple_make.sh
@@ -2,12 +2,12 @@
if which apt-get; then
sudo apt-get install build-essential qt5-qmake qt5-default libopenal-dev libopencv-dev \
- libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev qttools5-dev-tools qtchooser libxss-dev libqt5svg5*
+ libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev qttools5-dev-tools qtchooser libxss-dev libqt5svg5* qrencode
elif which pacman; then
- sudo pacman -S --needed base-devel qt5 opencv openal opus libvpx libxss qt5-svg
+ sudo pacman -S --needed base-devel qt5 opencv openal opus libvpx libxss qt5-svg qrencode
elif which yum; then
sudo yum groupinstall "Development Tools"
- sudo yum install qt-devel qt-doc qt-creator opencv-devel openal-soft-devel libtool autoconf automake check check-devel libXScrnSaver-devel qt5-qtsvg
+ sudo yum install qt-devel qt-doc qt-creator opencv-devel openal-soft-devel libtool autoconf automake check check-devel libXScrnSaver-devel qt5-qtsvg qrencode
else
echo "Unknown package manager, attempting to compile anyways"
fi
diff --git a/src/misc/qrwidget.cpp b/src/misc/qrwidget.cpp
new file mode 100644
index 000000000..0ee1d0c0d
--- /dev/null
+++ b/src/misc/qrwidget.cpp
@@ -0,0 +1,103 @@
+#include "qrwidget.h"
+#include
+#include
+#include
+#include
+#include "qrencode.h"
+
+QRWidget::QRWidget(QWidget *parent) : QWidget(parent), data("0")
+//Note: The encoding fails with empty string so I just default to something else.
+//Use the setQRData() call to change this.
+{
+ //size of the qimage might be problematic in the future, but it works for me
+ size.setWidth(480);
+ size.setHeight(480);
+ image = new QImage(size, QImage::Format_RGB32);
+}
+
+void QRWidget::setQRData(QString data)
+{
+ this->data = "tox:" + data;
+ paintImage();
+}
+
+QImage* QRWidget::getImage()
+{
+ return image;
+}
+
+/**
+ * @brief QRWidget::saveImage
+ * @param path Full path to the file with extension.
+ * @return indicate if saving was successful.
+ */
+bool QRWidget::saveImage(QString path)
+{
+ return image->save(path, 0, 75); //0 - image format same as file extension, 75-quality, png file is ~6.3kb
+}
+
+QString QRWidget::getImageAsText()
+{
+ paintImage();
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::WriteOnly);
+ image->save(&buffer, "PNG"); // writes the image in PNG format inside the buffer
+
+ QString iconBase64 = QString::fromLatin1(ba.toBase64().data());
+ QString base64Image = "";
+
+ return QString(base64Image);
+}
+
+//http://stackoverflow.com/questions/21400254/how-to-draw-a-qr-code-with-qt-in-native-c-c
+void QRWidget::paintImage()
+{
+ QPainter painter(image);
+ //NOTE: I have hardcoded some parameters here that would make more sense as variables.
+ // ECLEVEL_M is much faster recognizable by barcodescanner any any other type
+ QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_M, QR_MODE_8, 0);
+
+ if(0 != qr)
+ {
+ QColor fg("black");
+ QColor bg("white");
+ painter.setBrush(bg);
+ painter.setPen(Qt::NoPen);
+ painter.drawRect(0, 0, size.width(), size.height());
+ painter.setBrush(fg);
+ const int s = qr->width > 0 ? qr->width : 1;
+ const double w = width();
+ const double h = height();
+ const double aspect = w / h;
+ const double scale = ((aspect > 1.0) ? h : w) / s;
+
+ for(int y = 0; y < s; y++)
+ {
+ const int yy = y * s;
+ for(int x = 0; x < s; x++)
+ {
+ const int xx = yy + x;
+ const unsigned char b = qr->data[xx];
+ if(b & 0x01)
+ {
+ const double rx1 = x * scale,
+ ry1 = y * scale;
+ QRectF r(rx1, ry1, scale, scale);
+ painter.drawRects(&r, 1);
+ }
+ }
+ }
+ QRcode_free(qr);
+ painter.save();
+ }
+ else
+ {
+ QColor error("red");
+ painter.setBrush(error);
+ painter.drawRect(0, 0, width(), height());
+ qDebug() << "QR FAIL: " << strerror(errno);
+ }
+
+ qr = 0;
+}
diff --git a/src/misc/qrwidget.h b/src/misc/qrwidget.h
new file mode 100644
index 000000000..75674da6c
--- /dev/null
+++ b/src/misc/qrwidget.h
@@ -0,0 +1,26 @@
+#ifndef QRWIDGET_H
+#define QRWIDGET_H
+
+// https://stackoverflow.com/questions/21400254/how-to-draw-a-qr-code-with-qt-in-native-c-c
+
+#include
+
+class QRWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit QRWidget(QWidget *parent = 0);
+ void setQRData(QString data);
+ QString getImageAsText();
+ QImage* getImage();
+ bool saveImage(QString path);
+
+private:
+ QString data;
+ void paintImage();
+ QImage *image;
+ QSize size;
+};
+
+#endif // QRWIDGET_H
diff --git a/src/widget/form/profileform.cpp b/src/widget/form/profileform.cpp
index 41d3cccd8..4cb407eb5 100644
--- a/src/widget/form/profileform.cpp
+++ b/src/widget/form/profileform.cpp
@@ -36,7 +36,6 @@
#include
#include
-
void ProfileForm::refreshProfiles()
{
bodyUI->profiles->clear();
@@ -76,9 +75,11 @@ ProfileForm::ProfileForm(QWidget *parent) :
toxId->setReadOnly(true);
toxId->setFrame(false);
toxId->setFont(Style::getFont(Style::Small));
+
+ QVBoxLayout *toxIdGroup = qobject_cast(bodyUI->toxGroup->layout());
+ toxIdGroup->replaceWidget(bodyUI->toxId, toxId);
+ bodyUI->toxId->hide();
- bodyUI->toxGroup->layout()->addWidget(toxId);
-
profilePicture = new MaskablePixmapWidget(this, QSize(64, 64), ":/img/avatar_mask.png");
profilePicture->setPixmap(QPixmap(":/img/contact_dark.png"));
profilePicture->setClickable(true);
@@ -169,6 +170,11 @@ void ProfileForm::setToxId(const QString& id)
{
toxId->setText(id);
toxId->setCursorPosition(0);
+
+ qr = new QRWidget();
+ qr->setQRData(id);
+ bodyUI->qrCode->setPixmap(QPixmap::fromImage(qr->getImage()->scaledToWidth(150)));
+ bodyUI->qrCode->setToolTip(qr->getImageAsText());
}
void ProfileForm::onAvatarClicked()
@@ -369,3 +375,32 @@ void ProfileForm::showEvent(QShowEvent *event)
refreshProfiles();
QWidget::showEvent(event);
}
+
+void ProfileForm::on_copyQr_clicked()
+{
+ QApplication::clipboard()->setImage(*qr->getImage());
+}
+
+void ProfileForm::on_saveQr_clicked()
+{
+ QString current = bodyUI->profiles->currentText() + ".png";
+ QString path = QFileDialog::getSaveFileName(0, tr("Save", "save qr image"),
+ QDir::home().filePath(current),
+ tr("Save QrCode (*.png)", "save dialog filter"));
+ if (!path.isEmpty())
+ {
+ bool success;
+ if (QFile::exists(path))
+ {
+ success = QFile::remove(path);
+ if (!success)
+ {
+ QMessageBox::warning(this, tr("Failed to remove file"), tr("The file you chose to overwrite could not be removed first."));
+ return;
+ }
+ }
+ success = qr->saveImage(path);
+ if (!success)
+ QMessageBox::warning(this, tr("Failed to copy file"), tr("The file you chose could not be written to."));
+ }
+}
diff --git a/src/widget/form/profileform.h b/src/widget/form/profileform.h
index 830e486db..82cd829ef 100644
--- a/src/widget/form/profileform.h
+++ b/src/widget/form/profileform.h
@@ -22,6 +22,7 @@
#include
#include
#include "src/core.h"
+#include "src/misc/qrwidget.h"
class CroppingLabel;
class Core;
@@ -36,7 +37,7 @@ class ClickableTE : public QLineEdit
{
Q_OBJECT
public:
-
+
signals:
void clicked();
protected:
@@ -73,7 +74,10 @@ private slots:
void onNewClicked();
void disableSwitching();
void enableSwitching();
-
+ void on_copyQr_clicked();
+
+ void on_saveQr_clicked();
+
protected:
virtual void showEvent(QShowEvent *);
@@ -85,6 +89,7 @@ private:
Core* core;
QTimer timer;
bool hasCheck = false;
+ QRWidget *qr;
ClickableTE* toxId;
};
diff --git a/src/widget/form/profileform.ui b/src/widget/form/profileform.ui
index 58633511a..0b02d718a 100644
--- a/src/widget/form/profileform.ui
+++ b/src/widget/form/profileform.ui
@@ -6,8 +6,8 @@
0
0
- 439
- 472
+ 442
+ 659
@@ -39,8 +39,8 @@
0
0
- 419
- 452
+ 422
+ 639
@@ -97,6 +97,52 @@ Share it with your friends to communicate.
+ -
+
+
+ -
+
+
+
-
+
+
+ QRCODE
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
-
+
+
+ Share this code, so friends can add you
+
+
+
+ -
+
+
+ Save image
+
+
+
+ -
+
+
+ Copy image
+
+
+
+
+
+
+
+
+
@@ -212,7 +258,7 @@ Profile does not contain your history.
CroppingLabel
QLabel
- src/widget/croppinglabel.h
+ src/widget/croppinglabel.h