#include "../include/ImagePreview.hpp" #include "../include/Settings.hpp" #include "../include/Gif.hpp" #include #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) { ImagePreview *instance = getInstance(); if(texture == instance->texture) return; instance->texture = texture; instance->contentType = texture ? ContentType::TEXTURE : ContentType::NONE; imagePreviewUrl = url; if(texture) instance->sprite.setTexture(*texture, true); else instance->sprite = sf::Sprite(); } void ImagePreview::preview(Gif *gif, const std::string &url) { ImagePreview *instance = getInstance(); if(gif == instance->gif) return; instance->gif = gif; instance->contentType = gif ? ContentType::GIF : ContentType::NONE; imagePreviewUrl = url; instance->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) { ImagePreview *instance = getInstance(); if(instance->contentType == ContentType::NONE) return; if(event.mouseButton.button == sf::Mouse::Button::Left) { const auto &imagePos = instance->position; const auto &imageSize = instance->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 cmd = "xdg-open "; cmd += escapeCommandArg(imagePreviewUrl); 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) { ImagePreview *instance = getInstance(); if(instance->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 = instance->calculateImageSize(windowSize); instance->size = imageSize; window.draw(background); switch(instance->contentType) { case ContentType::TEXTURE: { auto textureSize = instance->sprite.getTexture()->getSize(); instance->position = sf::Vector2f(windowSize.x / 2 - imageSize.x / 2, windowSize.y / 2 - imageSize.y / 2); instance->sprite.setPosition(instance->position); instance->sprite.setScale((double)imageSize.x / (double)textureSize.x, (double)imageSize.y / (double)textureSize.y); window.draw(instance->sprite); break; } case ContentType::GIF: { auto *gif = static_cast(instance->gif); gif->update(); auto textureSize = gif->getSize(); instance->position = sf::Vector2f(windowSize.x / 2 - imageSize.x / 2, windowSize.y / 2 - imageSize.y / 2); sf::Sprite sprite(gif->texture); sprite.setPosition(instance->position); sprite.setScale(sf::Vector2f((double)imageSize.x / (double)textureSize.x, (double)imageSize.y / (double)textureSize.y)); window.draw(sprite); break; } } instance->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: auto size = gif->getSize(); textureSize.x = size.x; textureSize.y = size.y; 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; } }