diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 326a95d4a..6249d5681 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #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(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); +} diff --git a/retroshare-gui/src/gui/chat/ChatWidget.h b/retroshare-gui/src/gui/chat/ChatWidget.h index b1b0a23db..535636ddd 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.h +++ b/retroshare-gui/src/gui/chat/ChatWidget.h @@ -194,6 +194,7 @@ private slots: void quote(); void dropPlacemark(); void saveImage(); + void saveSticker(); private: bool findText(const QString& qsStringToFind); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.ui b/retroshare-gui/src/gui/chat/ChatWidget.ui index 144eeae6f..d8a4125e0 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.ui +++ b/retroshare-gui/src/gui/chat/ChatWidget.ui @@ -389,7 +389,7 @@ border-image: url(:/images/closepressed.png) - :/icons/png/new.png:/icons/png/new.png + :/icons/png/addstickers.png:/icons/png/addstickers.png @@ -981,6 +981,15 @@ border-image: url(:/images/closepressed.png) Save image + + + + :/icons/png/addstickers.png:/icons/png/addstickers.png + + + Import sticker + + true diff --git a/retroshare-gui/src/gui/common/Emoticons.cpp b/retroshare-gui/src/gui/common/Emoticons.cpp index 37e40e72f..347d88b6e 100644 --- a/retroshare-gui/src/gui/common/Emoticons.cpp +++ b/retroshare-gui/src/gui/common/Emoticons.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -41,17 +42,21 @@ static QHash, QHash > > Smileys; static QVector grpOrdered; -static QVector StickerGroups; static QStringList filters; +static QStringList stickerFolders; static QHash tooltipcache; +static QHash 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& stickerTabs) +{ + for(int i = 0; i < stickerFolders.count(); ++i) + refreshStickerTabs(stickerTabs, stickerFolders[i]); +} + +void Emoticons::refreshStickerTabs(QVector& 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 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 grp(StickerGroups); + QVectorIterator 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 children = container->findChildren(); for(int i = 0; i < children.length(); ++i) { if(!children[i]->toolTip().contains('<')) { @@ -464,4 +492,5 @@ void Emoticons::loadToolTips(QWidget *container) } } + QApplication::restoreOverrideCursor(); } diff --git a/retroshare-gui/src/gui/common/Emoticons.h b/retroshare-gui/src/gui/common/Emoticons.h index f4b42c0ff..0d9a6bedd 100644 --- a/retroshare-gui/src/gui/common/Emoticons.h +++ b/retroshare-gui/src/gui/common/Emoticons.h @@ -21,6 +21,8 @@ #ifndef _EMOTICONS_H #define _EMOTICONS_H +#include + 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& stickerTabs, QString foldername); + static void refreshStickerTabs(QVector& stickerTabs); }; #endif diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 04a6702b1..81eeecb08 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -290,6 +290,8 @@ icons/png/bandwidth.png icons/png/options2.png icons/png/exit2.png + icons/svg/addstickers.svg + icons/png/addstickers.png icons/textedit/bold.png icons/textedit/bullet-list.png icons/textedit/italic.png diff --git a/retroshare-gui/src/gui/icons/png/addstickers.png b/retroshare-gui/src/gui/icons/png/addstickers.png new file mode 100644 index 000000000..91c4ee4c3 Binary files /dev/null and b/retroshare-gui/src/gui/icons/png/addstickers.png differ diff --git a/retroshare-gui/src/gui/icons/svg/addstickers.svg b/retroshare-gui/src/gui/icons/svg/addstickers.svg new file mode 100644 index 000000000..01d317bb6 --- /dev/null +++ b/retroshare-gui/src/gui/icons/svg/addstickers.svg @@ -0,0 +1,61 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/retroshare-gui/src/util/imageutil.cpp b/retroshare-gui/src/util/imageutil.cpp index 648fe392c..c507bfa05 100644 --- a/retroshare-gui/src/util/imageutil.cpp +++ b/retroshare-gui/src/util/imageutil.cpp @@ -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 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 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 diff --git a/retroshare-gui/src/util/imageutil.h b/retroshare-gui/src/util/imageutil.h index dfea67282..a6ff19b88 100644 --- a/retroshare-gui/src/util/imageutil.h +++ b/retroshare-gui/src/util/imageutil.h @@ -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: