Merge pull request #1669 from hunbernd/feature/stickers-upgrade

Sticker improvements
This commit is contained in:
csoler 2019-12-26 17:30:14 +01:00 committed by GitHub
commit 358aa1e0ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 152 additions and 29 deletions

View File

@ -32,6 +32,7 @@
#include <QTextStream>
#include <QTimer>
#include <QToolTip>
#include <QInputDialog>
#include "ChatWidget.h"
#include "ui_ChatWidget.h"
@ -163,6 +164,7 @@ ChatWidget::ChatWidget(QWidget *parent)
connect(ui->actionQuote, SIGNAL(triggered()), this, SLOT(quote()));
connect(ui->actionDropPlacemark, SIGNAL(triggered()), this, SLOT(dropPlacemark()));
connect(ui->actionSave_image, SIGNAL(triggered()), this, SLOT(saveImage()));
connect(ui->actionImport_sticker, SIGNAL(triggered()), this, SLOT(saveSticker()));
connect(ui->actionShow_Hidden_Images, SIGNAL(triggered()), ui->textBrowser, SLOT(showImages()));
ui->actionShow_Hidden_Images->setIcon(ui->textBrowser->getBlockedImage());
@ -438,6 +440,7 @@ void ChatWidget::blockSending(QString msg)
#ifndef RS_ASYNC_CHAT
// sendingBlocked = true;
// ui->sendButton->setEnabled(false);
// ui->stickerButton->setEnabled(false);
#endif
ui->sendButton->setToolTip(msg);
}
@ -445,6 +448,7 @@ void ChatWidget::blockSending(QString msg)
void ChatWidget::unblockSending()
{
sendingBlocked = false;
ui->stickerButton->setEnabled(true);
updateLenOfChatTextEdit();
}
@ -1128,7 +1132,9 @@ void ChatWidget::contextMenuTextBrowser(QPoint point)
contextMnu->addAction(ui->actionShow_Hidden_Images);
ui->actionSave_image->setData(point);
ui->actionImport_sticker->setData(point);
contextMnu->addAction(ui->actionSave_image);
contextMnu->addAction(ui->actionImport_sticker);
}
QString anchor = ui->textBrowser->anchorForPosition(point);
@ -1556,6 +1562,7 @@ void ChatWidget::stickerWidget()
void ChatWidget::sendSticker()
{
if(sendingBlocked) return;
QString sticker = qobject_cast<QPushButton*>(sender())->statusTip();
QString encodedImage;
if (RsHtml::makeEmbeddedImage(sticker, encodedImage, 640*480, maxMessageSize() - 200)) { //-200 for the html stuff
@ -1910,3 +1917,13 @@ void ChatWidget::saveImage()
QTextCursor cursor = ui->textBrowser->cursorForPosition(point);
ImageUtil::extractImage(window(), cursor);
}
void ChatWidget::saveSticker()
{
QPoint point = ui->actionImport_sticker->data().toPoint();
QTextCursor cursor = ui->textBrowser->cursorForPosition(point);
QString filename = QInputDialog::getText(window(), "Import sticker", "Sticker name");
if(filename.isEmpty()) return;
filename = Emoticons::importedStickerPath() + "/" + filename + ".png";
ImageUtil::extractImage(window(), cursor, filename);
}

View File

@ -194,6 +194,7 @@ private slots:
void quote();
void dropPlacemark();
void saveImage();
void saveSticker();
private:
bool findText(const QString& qsStringToFind);

View File

@ -389,7 +389,7 @@ border-image: url(:/images/closepressed.png)
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/new.png</normaloff>:/icons/png/new.png</iconset>
<normaloff>:/icons/png/addstickers.png</normaloff>:/icons/png/addstickers.png</iconset>
</property>
<property name="iconSize">
<size>
@ -981,6 +981,15 @@ border-image: url(:/images/closepressed.png)
<string>Save image</string>
</property>
</action>
<action name="actionImport_sticker">
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/icons/png/addstickers.png</normaloff>:/icons/png/addstickers.png</iconset>
</property>
<property name="text">
<string>Import sticker</string>
</property>
</action>
<action name="actionSendAsPlainText">
<property name="checkable">
<bool>true</bool>

View File

@ -29,6 +29,7 @@
#include <QTabWidget>
#include <QWidget>
#include <QMessageBox>
#include <QDir>
#include <iostream>
#include <math.h>
@ -41,17 +42,21 @@
static QHash<QString, QPair<QVector<QString>, QHash<QString, QString> > > Smileys;
static QVector<QString> grpOrdered;
static QVector<QString > StickerGroups;
static QStringList filters;
static QStringList stickerFolders;
static QHash<QString, QString> tooltipcache;
static QHash<QString, QPixmap> iconcache;
void Emoticons::load()
{
loadSmiley();
filters << "*.png" << "*.jpg" << "*.gif";
loadSticker(QString::fromStdString(RsAccounts::ConfigDirectory()) + "/stickers"); //under .retroshare, shared between users
loadSticker(QString::fromStdString(RsAccounts::AccountDirectory()) + "/stickers"); //under account, unique for user
loadSticker(QString::fromStdString(RsAccounts::systemDataDirectory()) + "/stickers"); //exe's folder, shipped with RS
stickerFolders << (QString::fromStdString(RsAccounts::AccountDirectory()) + "/stickers"); //under account, unique for user
stickerFolders << (QString::fromStdString(RsAccounts::ConfigDirectory()) + "/stickers"); //under .retroshare, shared between users
stickerFolders << (QString::fromStdString(RsAccounts::systemDataDirectory()) + "/stickers"); //exe's folder, shipped with RS
QDir dir(QString::fromStdString(RsAccounts::AccountDirectory()));
dir.mkpath("stickers/imported");
}
void Emoticons::loadSmiley()
@ -285,7 +290,13 @@ void Emoticons::showSmileyWidget(QWidget *parent, QWidget *button, const char *s
smWidget->show() ;
}
void Emoticons::loadSticker(QString foldername)
void Emoticons::refreshStickerTabs(QVector<QString>& stickerTabs)
{
for(int i = 0; i < stickerFolders.count(); ++i)
refreshStickerTabs(stickerTabs, stickerFolders[i]);
}
void Emoticons::refreshStickerTabs(QVector<QString>& stickerTabs, QString foldername)
{
QDir dir(foldername);
if(!dir.exists()) return;
@ -293,25 +304,30 @@ void Emoticons::loadSticker(QString foldername)
//If it contains at a least one png then add it as a group
QStringList files = dir.entryList(filters, QDir::Files);
if(files.count() > 0)
StickerGroups.append(foldername);
stickerTabs.append(foldername);
//Check subfolders
QFileInfoList subfolders = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot);
for(int i = 0; i<subfolders.length(); i++)
loadSticker(subfolders[i].filePath());
refreshStickerTabs(stickerTabs, subfolders[i].filePath());
}
void Emoticons::showStickerWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above)
{
QVector<QString> stickerTabs;
refreshStickerTabs(stickerTabs);
if(stickerTabs.count() == 0) {
QString message = "No stickers installed.\nYou can install them by putting images into one of these folders:\n" + stickerFolders.join('\n');
QMessageBox::warning(parent, "Stickers", message);
return;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QWidget *smWidget = new QWidget(parent, Qt::Popup) ;
smWidget->setAttribute(Qt::WA_DeleteOnClose) ;
smWidget->setWindowTitle("Stickers") ;
if(StickerGroups.count() == 0) {
QMessageBox::warning(parent, "Stickers", "No stickers installed");
return;
}
bool bOnlyOneGroup = (StickerGroups.count() == 1);
bool bOnlyOneGroup = (stickerTabs.count() == 1);
QTabWidget *smTab = nullptr;
if (! bOnlyOneGroup)
@ -327,7 +343,7 @@ void Emoticons::showStickerWidget(QWidget *parent, QWidget *button, const char *
int maxRowCount = 0;
int maxCountPerLine = 0;
QVectorIterator<QString> grp(StickerGroups);
QVectorIterator<QString> grp(stickerTabs);
while(grp.hasNext())
{
QDir groupDir = QDir(grp.next());
@ -383,7 +399,11 @@ void Emoticons::showStickerWidget(QWidget *parent, QWidget *button, const char *
QPushButton *button = new QPushButton("", tabGrpWidget);
button->setIconSize(QSize(buttonWidth, buttonHeight));
button->setFixedSize(QSize(buttonWidth, buttonHeight));
button->setIcon(QPixmap(fi.absoluteFilePath()));
if(!iconcache.contains(fi.absoluteFilePath()))
{
iconcache.insert(fi.absoluteFilePath(), QPixmap(fi.absoluteFilePath()).scaled(buttonWidth, buttonHeight, Qt::KeepAspectRatio));
}
button->setIcon(iconcache[fi.absoluteFilePath()]);
button->setToolTip(fi.fileName());
button->setStatusTip(fi.absoluteFilePath());
button->setStyleSheet("QPushButton:hover {border: 3px solid #0099cc; border-radius: 3px;}");
@ -444,10 +464,18 @@ void Emoticons::showStickerWidget(QWidget *parent, QWidget *button, const char *
smWidget->move(x, y);
smWidget->show();
QApplication::restoreOverrideCursor();
}
QString Emoticons::importedStickerPath()
{
QDir dir(stickerFolders[0]);
return dir.absoluteFilePath("imported");
}
void Emoticons::loadToolTips(QWidget *container)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
QList<QPushButton *> children = container->findChildren<QPushButton *>();
for(int i = 0; i < children.length(); ++i) {
if(!children[i]->toolTip().contains('<')) {
@ -464,4 +492,5 @@ void Emoticons::loadToolTips(QWidget *container)
}
}
QApplication::restoreOverrideCursor();
}

View File

@ -21,6 +21,8 @@
#ifndef _EMOTICONS_H
#define _EMOTICONS_H
#include <QVector>
class QWidget;
class QString;
@ -28,14 +30,15 @@ class Emoticons
{
public:
static void load();
static void loadSmiley();
static void loadSticker(QString foldername);
static void showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above);
static void showStickerWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above);
static QString importedStickerPath();
private:
static void loadToolTips(QWidget *container);
static void loadSmiley();
static void refreshStickerTabs(QVector<QString>& stickerTabs, QString foldername);
static void refreshStickerTabs(QVector<QString>& stickerTabs);
};
#endif

View File

@ -290,6 +290,8 @@
<file>icons/png/bandwidth.png</file>
<file>icons/png/options2.png</file>
<file>icons/png/exit2.png</file>
<file>icons/svg/addstickers.svg</file>
<file>icons/png/addstickers.png</file>
<file>icons/textedit/bold.png</file>
<file>icons/textedit/bullet-list.png</file>
<file>icons/textedit/italic.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg4155"
version="1.1"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
xml:space="preserve"
width="128"
height="128"
viewBox="0 0 128 128"
sodipodi:docname="addstickers.svg"><metadata
id="metadata4161"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4159" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1152"
inkscape:window-height="801"
id="namedview4157"
showgrid="false"
inkscape:zoom="3.6195028"
inkscape:cx="53.669069"
inkscape:cy="71.112562"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4163" /><g
id="g4163"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,128)"><path
inkscape:connector-curvature="0"
id="path4167"
style="fill:#039bd5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60304987"
d="m 102.81622,51.518623 c 0,-28.330702 -22.966895,-51.29759817 -51.297597,-51.29759817 -28.330702,0 -51.29759817,22.96689617 -51.29759817,51.29759817 0,28.330702 22.96689617,51.297597 51.29759817,51.297597 28.330702,0 51.297597,-22.966895 51.297597,-51.297597" /><g
id="g835"
transform="matrix(0.16426573,0,0,-0.1695986,9.5806414,96.195902)"><g
id="g833"><g
id="g831"><path
d="m 511.653,195.545 h 0.018 C 500.227,149.939 477.629,109.379 443.689,76.275 V 76.178 C 394.902,27.098 329.298,0.021 259.891,0.021 190.485,0.021 125.202,27.026 76.122,76.107 27.043,125.186 0,190.427 0,259.834 c 0,69.407 27.474,134.654 76.554,183.735 33.107,33.106 74.409,56.647 120.015,68.089 v -0.017 c 0,0.22 1.288,0.338 2.158,0.338 2.776,0 5.26,-1.09 7.275,-3.107 L 509,205.71 c 2.647,-2.648 3.575,-6.983 2.653,-10.165 z m -331.684,243.559 -0.021,-0.051 c -21.899,-9.701 -41.643,-23.277 -58.851,-40.485 -76.502,-76.501 -76.502,-200.981 0,-277.483 38.255,-38.256 88.49,-57.377 138.742,-57.377 50.239,0 100.495,19.13 138.741,57.377 17.209,17.209 30.783,36.953 40.485,58.852 l 0.072,0.021 c -68.393,0.168 -134.341,27.402 -183.049,76.118 -48.713,48.703 -75.946,114.652 -76.119,183.028 z m 24.612,40.963 c -1.461,-8.557 -2.461,-17.209 -2.983,-25.878 -4.137,-68.081 21.19,-134.824 69.491,-183.115 44.875,-44.884 105.674,-69.928 168.688,-69.928 4.797,0 9.615,0.145 14.433,0.439 8.665,0.523 17.315,1.522 25.873,2.984 z M 462.426,180.93 c -10.888,-28.139 -27.292,-53.294 -48.845,-74.847 -84.775,-84.774 -222.71,-84.771 -307.483,0 -84.772,84.773 -84.772,222.709 0,307.482 21.554,21.552 46.709,37.957 74.848,48.846 0.695,7.955 1.75,15.883 3.17,23.732 C 149.239,474.489 117.347,454.814 91.096,428.561 46.021,383.49 21.198,323.564 21.198,259.822 c 0,-63.742 24.823,-123.667 69.896,-168.741 45.074,-45.074 105,-69.897 168.741,-69.897 63.742,0 123.669,24.823 168.742,69.896 26.251,26.251 45.926,58.144 57.582,93.02 -7.851,-1.421 -15.779,-2.476 -23.733,-3.17 z"
data-original="#000000"
class="active-path"
data-old_color="#000000"
id="path829"
inkscape:connector-curvature="0"
style="fill:#fffcfc" /></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -37,7 +37,7 @@
ImageUtil::ImageUtil() {}
void ImageUtil::extractImage(QWidget *window, QTextCursor cursor)
void ImageUtil::extractImage(QWidget *window, QTextCursor cursor, QString file)
{
cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1);
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);
@ -52,13 +52,13 @@ void ImageUtil::extractImage(QWidget *window, QTextCursor cursor)
QImage image = QImage::fromData(ba);
if(!image.isNull())
{
QString file;
success = true;
if(misc::getSaveFileName(window, RshareSettings::LASTDIR_IMAGES, "Save Picture File", "Pictures (*.png *.xpm *.jpg)", file))
if(!file.isEmpty() || misc::getSaveFileName(window, RshareSettings::LASTDIR_IMAGES, "Save Picture File", "Pictures (*.png *.xpm *.jpg)", file))
{
if(!image.save(file, 0, 100))
if(!image.save(file + ".png", 0, 100))
QMessageBox::warning(window, QApplication::translate("ImageUtil", "Save image"), QApplication::translate("ImageUtil", "Cannot save the image, invalid filename"));
if(!image.save(file, nullptr, 100))
if(!image.save(file + ".png", nullptr, 100))
QMessageBox::warning(window, QApplication::translate("ImageUtil", "Save image"), QApplication::translate("ImageUtil", "Cannot save the image, invalid filename")
+ "\n" + file);
}
}
}
@ -73,14 +73,12 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti
//nothing to do if it fits into the limits
optimized = original;
if ((maxPixels <= 0) || (optimized.width()*optimized.height() <= maxPixels)) {
if(checkSize(html, optimized, maxBytes) <= maxBytes) {
int s = checkSize(html, optimized, maxBytes);
if((maxBytes <= 0) || (s <= maxBytes)) {
return true;
}
}
QVector<QRgb> ct;
quantization(original, ct);
//Downscale the image to fit into maxPixels
double whratio = (qreal)original.width() / (qreal)original.height();
int maxwidth;
@ -98,6 +96,9 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti
return true;
}
QVector<QRgb> ct;
quantization(original, ct);
//Use binary search to find a suitable image size + linear regression to guess the file size
double maxsize = (double)checkSize(html, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither), maxBytes);
if(maxsize <= maxBytes) return true; //success

View File

@ -30,7 +30,7 @@ class ImageUtil
public:
ImageUtil();
static void extractImage(QWidget *window, QTextCursor cursor);
static void extractImage(QWidget *window, QTextCursor cursor, QString file = "");
static bool optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels = -1, int maxBytes = -1);
private: