#include "../include/Chatbar.hpp" #include "../include/ResourceCache.hpp" #include "../include/Settings.hpp" #include "../include/Channel.hpp" #include #include using namespace std; namespace dchat { const float FONT_SIZE = 24; const float BOX_PADDING_X = 15.0f; const float BOX_PADDING_Y = 5.0f; const int BLINK_TIME_VISIBLE_MS = 500; const int BLINK_TIME_INVISIBLE_MS = 500; Chatbar::Chatbar() : text("", ResourceCache::getFont("fonts/Roboto-Regular.ttf"), FONT_SIZE * Settings::getScaling()), caretIndex(0), focused(true) { text.setFillColor(sf::Color(240, 240, 240)); background.setFillColor(sf::Color(60, 60, 60)); } void Chatbar::addChar(sf::Uint32 codePoint) { auto str = text.getString(); str.insert(caretIndex, codePoint); text.setString(str); ++caretIndex; caretOffset = text.findCharacterPos(caretIndex) - text.getPosition(); blinkTimer.restart(); } const sf::String& Chatbar::getString() const { return text.getString(); } void Chatbar::removePreviousChar() { if(caretIndex > 0) { auto str = text.getString(); str.erase(caretIndex - 1); text.setString(str); --caretIndex; caretOffset = text.findCharacterPos(caretIndex) - text.getPosition(); } blinkTimer.restart(); } void Chatbar::removeNextChar() { if(caretIndex < text.getString().getSize()) { auto str = text.getString(); str.erase(caretIndex); text.setString(str); } blinkTimer.restart(); } void Chatbar::clear() { text.setString(""); caretIndex = 0; caretOffset.x = 0.0f; caretOffset.y = 0.0f; blinkTimer.restart(); } void Chatbar::moveCaretLeft() { caretIndex = max(0, caretIndex - 1); // TODO: Use glyph size to optimize this, no need to iterate all glyphs caretOffset = text.findCharacterPos(caretIndex) - text.getPosition(); blinkTimer.restart(); } void Chatbar::moveCaretRight() { caretIndex = min((int)text.getString().getSize(), caretIndex + 1); caretOffset = text.findCharacterPos(caretIndex) - text.getPosition(); blinkTimer.restart(); } bool Chatbar::isFocused() const { return focused; } void Chatbar::processEvent(const sf::Event &event, Channel *channel) { if(!focused) return; if(event.type == sf::Event::TextEntered) { if(event.text.unicode == 8) // backspace removePreviousChar(); else if(event.text.unicode == 13) // enter { if(!getString().isEmpty()) { if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::Key::RShift)) { addChar('\n'); } else { auto chatbarMsgUtf8 = getString().toUtf8(); string msg; msg.resize(chatbarMsgUtf8.size()); memcpy(&msg[0], chatbarMsgUtf8.data(), chatbarMsgUtf8.size()); channel->getMessageBoard().addMessage(new Message(channel->getLocalUser(), msg)); clear(); } } } else if(event.text.unicode == 127) // delete { removeNextChar(); } else { addChar(event.text.unicode); } } else if(event.type == sf::Event::KeyPressed) { if(event.key.code == sf::Keyboard::Left) moveCaretLeft(); else if(event.key.code == sf::Keyboard::Right) moveCaretRight(); } } void Chatbar::draw(sf::RenderWindow &window, const sf::Vector2f &position) { auto windowSize = window.getSize(); sf::Vector2f backgroundSize(floor(windowSize.x * 0.7f), floor(text.getCharacterSize() * 1.7f + BOX_PADDING_Y * 2.0f)); sf::Vector2f backgroundPos(floor(position.x), floor(position.y + windowSize.y - backgroundSize.y - 20.0f)); background.setSize(backgroundSize); background.setPosition(backgroundPos); text.setPosition(floor(backgroundPos.x + BOX_PADDING_X), floor(backgroundPos.y + backgroundSize.y * 0.5f - text.getCharacterSize() * 0.5f)); window.draw(background); window.draw(text); int blinkElapsedTime = blinkTimer.getElapsedTime().asMilliseconds(); if(focused && blinkElapsedTime <= BLINK_TIME_VISIBLE_MS) { sf::RectangleShape caretShape(sf::Vector2f(2.0f, backgroundSize.y - BOX_PADDING_Y * 2.0f)); caretShape.setPosition(floor(text.getPosition().x + caretOffset.x), (caretOffset.y + backgroundPos.y + BOX_PADDING_Y)); window.draw(caretShape); } if(blinkElapsedTime > BLINK_TIME_VISIBLE_MS + BLINK_TIME_INVISIBLE_MS) blinkTimer.restart(); } }