#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; } }