#include "../include/MessageBoard.hpp" #include "../include/Settings.hpp" #include "../include/ResourceCache.hpp" #include #include #include #include #include using namespace std; namespace dchat { const sf::Color BACKGROUND_COLOR(40, 40, 40); const float USERNAME_PADDING_BOTTOM = 5.0f; const float MESSAGE_PADDING_BOTTOM = 20.0f; MessageBoard::MessageBoard(const sf::Vector2u &size) : selectingText(false), leftMouseButtonPressed(false) { updateStaticContentTexture(size); } MessageBoard::~MessageBoard() { for(Message *message : messages) { delete message; } } void MessageBoard::updateStaticContentTexture(const sf::Vector2u &newSize) { useStaticContentTexture = staticContentTexture.create(newSize.x, newSize.y); dirty = true; } void MessageBoard::addMessage(Message *message) { messages.push_back(message); dirty = true; } void MessageBoard::processEvent(const sf::Event &event) { if(event.type == sf::Event::MouseButtonPressed) { if(event.mouseButton.button == sf::Mouse::Button::Left) { leftMouseButtonPressed = true; mousePos.x = event.mouseButton.x; mousePos.y = event.mouseButton.y; } } else if(event.type == sf::Event::MouseButtonReleased) { if(event.mouseButton.button == sf::Mouse::Button::Left) { leftMouseButtonPressed = false; mousePos.x = event.mouseButton.x; mousePos.y = event.mouseButton.y; } } else if(event.type == sf::Event::LostFocus) { leftMouseButtonPressed = false; } else if(event.type == sf::Event::MouseMoved) { mousePos.x = event.mouseMove.x; mousePos.y = event.mouseMove.y; } if(selectingText && !leftMouseButtonPressed) { selectingText = false; } else if(!selectingText && leftMouseButtonPressed) { selectingText = true; selectingTextStart.x = mousePos.x; selectingTextStart.y = mousePos.y; } } void MessageBoard::draw(sf::RenderWindow &window) { sf::RenderTarget *renderTarget = nullptr; if(useStaticContentTexture) { renderTarget = &staticContentTexture; if(window.getSize() != staticContentTexture.getSize()) updateStaticContentTexture(window.getSize()); } else { renderTarget = &window; dirty = true; } if(dirty) { dirty = false; auto renderTargetSize = renderTarget->getSize(); if(useStaticContentTexture) staticContentTexture.clear(BACKGROUND_COLOR); else { sf::RectangleShape background(sf::Vector2f(renderTargetSize.x, renderTargetSize.y)); background.setFillColor(BACKGROUND_COLOR); renderTarget->draw(background); } const sf::Font &usernameFont = ResourceCache::getFont("fonts/Roboto-Regular.ttf"); sf::Vector2f position; for(Message *message : messages) { sf::Text usernameText(message->user->getName(), usernameFont, MessagePartText::getFontSizeScaled() * 1.3f); usernameText.setFillColor(sf::Color(15, 192, 252)); usernameText.setPosition(position); renderTarget->draw(usernameText); position.y += usernameText.getCharacterSize() + USERNAME_PADDING_BOTTOM; for(MessagePart *messagePart : message->getParts()) { switch(messagePart->type) { case MessagePart::Type::TEXT: { MessagePartText *messagePartText = static_cast(messagePart); messagePartText->text.setFillColor(sf::Color(240, 240, 240)); messagePartText->text.setCharacterSize(MessagePartText::getFontSizeScaled()); messagePartText->text.setPosition(floor(position.x), floor(position.y + MessagePart::getSizeScaled() * 0.5f - MessagePartText::getFontSizeScaled() * 0.5f)); renderTarget->draw(messagePartText->text); position.x += messagePartText->text.getLocalBounds().width; break; } } } position.x = 0.0f; position.y += MessagePart::getSizeScaled() + MESSAGE_PADDING_BOTTOM; } if(useStaticContentTexture) staticContentTexture.display(); } if(useStaticContentTexture) window.draw(sf::Sprite(staticContentTexture.getTexture())); if(!selectingText) return; sf::Vector2f selectionRectStart(min((float)mousePos.x, selectingTextStart.x), min((float)mousePos.y, selectingTextStart.y)); sf::Vector2f selectionRectEnd(max((float)mousePos.x, selectingTextStart.x), max((float)mousePos.y, selectingTextStart.y)); sf::FloatRect selectionRect(selectionRectStart, selectionRectEnd - selectionRectStart); for(Message *message : messages) { float messagePartStartX = -999.0f; float messagePartEndX = 0.0f; float messagePartX = 0.0f; float messagePartStartY = 0.0f; for(MessagePart *messagePart : message->getParts()) { sf::Vector2f position = messagePart->getPosition(); sf::Vector2f size = messagePart->getSize(); sf::FloatRect messagePartRect(position, size); if(!selectionRect.intersects(messagePartRect)) continue; switch(messagePart->type) { case MessagePart::Type::TEXT: { MessagePartText *messagePartText = static_cast(messagePart); messagePartStartY = position.y; sf::Uint32 prevCodePoint = -1; for(int i = 0; i < messagePartText->text.getString().getSize(); ++i) { sf::Uint32 codePoint = messagePartText->text.getString()[i]; const sf::Glyph &glyph = messagePartText->text.getFont()->getGlyph(codePoint, messagePartText->text.getCharacterSize(), false); float glyphWidth = glyph.advance; if(prevCodePoint != -1) glyphWidth += messagePartText->text.getFont()->getKerning(prevCodePoint, codePoint, messagePartText->text.getCharacterSize()); if(selectionRect.left < messagePartX + glyph.advance * 0.5f) { if(messagePartStartX < 0.0f) { messagePartStartX = messagePartX; if(mousePos.y > messagePartStartY + MessagePart::getSizeScaled()) { messagePartEndX = position.x + size.x; goto nextMessagePart; } } } if(selectionRect.left + selectionRect.width > messagePartX + glyph.advance * 0.5f) { messagePartEndX = messagePartX + glyphWidth; } else break; messagePartX += glyphWidth; prevCodePoint = codePoint; } break; } } nextMessagePart: ; } if(messagePartStartX >= 0.0f) { sf::RectangleShape selectionShape(sf::Vector2f(floor(messagePartEndX - messagePartStartX), floor(MessagePart::getSizeScaled()))); selectionShape.setPosition(messagePartStartX, messagePartStartY); selectionShape.setFillColor(sf::Color(100, 100, 255, 100)); window.draw(selectionShape); } } } }