From 4c392178dac1de9a299beb78989c4e0f3fecade9 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 20 May 2018 11:15:15 +0200 Subject: Add image preview and url/image open in browser --- src/ImagePreview.cpp | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/ImagePreview.cpp (limited to 'src/ImagePreview.cpp') 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 +#include + +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; + } +} -- cgit v1.2.3