aboutsummaryrefslogtreecommitdiff
path: root/src/ImagePreview.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-05-20 11:15:15 +0200
committerdec05eba <dec05eba@protonmail.com>2018-05-20 11:15:18 +0200
commit4c392178dac1de9a299beb78989c4e0f3fecade9 (patch)
tree552b7a7dfa58e8193705934059e28461815bb951 /src/ImagePreview.cpp
parent34e1d3d9d40f9b9139b801de99292a563c3c9a96 (diff)
Add image preview and url/image open in browser
Diffstat (limited to 'src/ImagePreview.cpp')
-rw-r--r--src/ImagePreview.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/ImagePreview.cpp b/src/ImagePreview.cpp
new file mode 100644
index 0000000..0b36dbd
--- /dev/null
+++ b/src/ImagePreview.cpp
@@ -0,0 +1,168 @@
+#include "../include/ImagePreview.hpp"
+#include "../include/Settings.hpp"
+#include "../include/StringUtils.hpp"
+#include "../include/Gif.hpp"
+#include <SFML/Graphics/RectangleShape.hpp>
+#include <cassert>
+
+namespace dchat
+{
+ static const float PADDING_VERTICAL = 40.0f;
+ static const float PADDING_HORIZONTAL = 40.0f;
+
+ static ImagePreview *instance = nullptr;
+ static std::string imagePreviewUrl;
+
+ ImagePreview* ImagePreview::getInstance()
+ {
+ if(!instance)
+ instance = new ImagePreview();
+ return instance;
+ }
+
+ void ImagePreview::preview(sf::Texture *texture, const std::string &url)
+ {
+ if(texture == getInstance()->texture) return;
+ getInstance()->texture = texture;
+ getInstance()->contentType = texture ? ContentType::TEXTURE : ContentType::NONE;
+ imagePreviewUrl = url;
+ if(texture)
+ getInstance()->sprite.setTexture(*texture, true);
+ else
+ getInstance()->sprite = sf::Sprite();
+ }
+
+ void ImagePreview::preview(Gif *gif, const std::string &url)
+ {
+ if(gif == getInstance()->gif) return;
+ getInstance()->gif = gif;
+ getInstance()->contentType = gif ? ContentType::GIF : ContentType::NONE;
+ imagePreviewUrl = url;
+ getInstance()->sprite = sf::Sprite();
+ }
+
+ void* ImagePreview::getPreviewContentPtr()
+ {
+ return getInstance()->texture;
+ }
+
+ sf::Int32 ImagePreview::getTimeSinceLastSeenMs()
+ {
+ return getInstance()->lastSeenTimer.getElapsedTime().asMilliseconds();
+ }
+
+ void ImagePreview::processEvent(const sf::Event &event)
+ {
+ if(getInstance()->contentType == ContentType::NONE) return;
+
+ if(event.mouseButton.button == sf::Mouse::Button::Left)
+ {
+ sf::Vector2f imagePos;
+ switch(getInstance()->contentType)
+ {
+ case ContentType::TEXTURE:
+ imagePos = getInstance()->sprite.getPosition();
+ break;
+ case ContentType::GIF:
+ imagePos = getInstance()->gif->getPosition();
+ break;
+ }
+ getInstance()->sprite.getPosition();
+ const auto &imageSize = getInstance()->size;
+ bool mouseInside = false;
+ if(event.mouseButton.x >= imagePos.x && event.mouseButton.x <= imagePos.x + imageSize.x &&
+ event.mouseButton.y >= imagePos.y && event.mouseButton.y <= imagePos.y + imageSize.y)
+ {
+ mouseInside = true;
+ }
+
+ if(event.type == sf::Event::MouseButtonPressed && mouseInside && !imagePreviewUrl.empty())
+ {
+ // TODO: Implement for other platforms than linux
+ std::string escapedUrl = stringReplaceChar(imagePreviewUrl, "'", "");
+ escapedUrl = stringReplaceChar(escapedUrl, "\\", "");
+ std::string cmd = "xdg-open '";
+ cmd += escapedUrl;
+ cmd += "'";
+ printf("Clicked on web page preview, opening web page by running command: %s\n", cmd.c_str());
+ system(cmd.c_str());
+ }
+ else if(event.type == sf::Event::MouseButtonReleased && !mouseInside)
+ {
+ ImagePreview::preview((sf::Texture*)nullptr);
+ }
+ }
+ else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
+ {
+ ImagePreview::preview((sf::Texture*)nullptr);
+ }
+ }
+
+ void ImagePreview::draw(sf::RenderWindow &window)
+ {
+ if(getInstance()->contentType == ContentType::NONE) return;
+
+ auto windowSize = window.getSize();
+ sf::RectangleShape background(sf::Vector2f(windowSize.x, windowSize.y));
+ background.setFillColor(sf::Color(0, 0, 0, 200));
+
+ auto imageSize = getInstance()->calculateImageSize(windowSize);
+ getInstance()->size = imageSize;
+
+ window.draw(background);
+ switch(getInstance()->contentType)
+ {
+ case ContentType::TEXTURE:
+ {
+ auto textureSize = getInstance()->sprite.getTexture()->getSize();
+ getInstance()->sprite.setPosition(windowSize.x / 2 - imageSize.x / 2, windowSize.y / 2 - imageSize.y / 2);
+ getInstance()->sprite.setScale((double)imageSize.x / (double)textureSize.x, (double)imageSize.y / (double)textureSize.y);
+ window.draw(getInstance()->sprite);
+ break;
+ }
+ case ContentType::GIF:
+ {
+ auto textureSize = getInstance()->gif->getSize();
+ getInstance()->gif->setPosition(sf::Vector2f(windowSize.x / 2 - imageSize.x / 2, windowSize.y / 2 - imageSize.y / 2));
+ getInstance()->gif->setScale(sf::Vector2f((double)imageSize.x / (double)textureSize.x, (double)imageSize.y / (double)textureSize.y));
+ getInstance()->gif->draw(window);
+ break;
+ }
+ }
+ getInstance()->lastSeenTimer.restart();
+ }
+
+ sf::Vector2u ImagePreview::calculateImageSize(sf::Vector2u windowSize) const
+ {
+ assert(contentType != ContentType::NONE);
+ sf::Vector2u imageMaxSize(windowSize.x - PADDING_HORIZONTAL * Settings::getScaling() * 2.0f, windowSize.y - PADDING_VERTICAL * Settings::getScaling() * 2.0f);
+ sf::Vector2u textureSize;
+ switch(contentType)
+ {
+ case ContentType::TEXTURE:
+ textureSize = texture->getSize();
+ break;
+ case ContentType::GIF:
+ textureSize = gif->getSize();
+ break;
+ }
+ auto imageSize = textureSize;
+ double textureWidthHeightRatio = (double)imageSize.x / (double)imageSize.y;
+ double textureHeightWidthRatio = (double)imageSize.y / (double)imageSize.x;
+
+ int overflowVertical = (int)imageSize.y - (int)imageMaxSize.y;
+ if(overflowVertical > 0)
+ {
+ imageSize.y = imageMaxSize.y;
+ imageSize.x -= (overflowVertical * textureWidthHeightRatio);
+ }
+
+ int overflowHorizontal = (int)imageSize.x - (int)imageMaxSize.x;
+ if(overflowHorizontal > 0)
+ {
+ imageSize.x = imageMaxSize.x;
+ imageSize.y -= (overflowHorizontal * textureHeightWidthRatio);
+ }
+ return imageSize;
+ }
+}