/* Copyright 2021 flyinghead This file is part of Flycast. Flycast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Flycast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ #pragma once #include "types.h" #include "gui.h" #include "imgui/imgui.h" #include "network/ggpo.h" #include class Chat { std::vector> lines; bool visible = false; bool newMessage = false; bool focus = false; std::string localPlayerName; std::string remotePlayerName; const ImVec4 WHITE { 1, 1, 1, 1 }; const ImVec4 YELLOW { 1, 1, 0, 1 }; bool manual_open = false; bool enable_timeout = false; std::chrono::steady_clock::time_point launch_time; std::string playerName(bool remote) { if (remote) return !remotePlayerName.empty() ? remotePlayerName : config::ActAsServer ? "P2" : "P1"; else return !localPlayerName.empty() ? localPlayerName : config::ActAsServer ? "P1" : "P2"; } public: void toggle_timeout() { if (config::GGPOChatTimeoutToggle && !manual_open) { enable_timeout = true; launch_time = std::chrono::steady_clock::now(); } } void reset() { visible = false; lines.clear(); } void display() { auto timeout = std::chrono::seconds(config::GGPOChatTimeout.get()); if (enable_timeout && std::chrono::steady_clock::now() - launch_time > timeout) { visible = false; enable_timeout = false; manual_open = false; } if (!visible) return; ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); ImGui::SetNextWindowPos(ImVec2(settings.display.width / 2, settings.display.height) - ScaledVec2(200.f, 220.f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ScaledVec2(400, 220), ImGuiCond_FirstUseEver); ImGui::SetNextWindowBgAlpha(0.7f); ImGui::SetNextWindowFocus(); if (ImGui::Begin("Chat", &visible, ImGuiWindowFlags_NoScrollbar)) { ImGui::BeginChild(ImGui::GetID("log"), ImVec2(0, -ImGui::GetStyle().ItemSpacing.x - ImGui::GetFontSize() - ImGui::GetStyle().FramePadding.x * 2), true, ImGuiWindowFlags_DragScrolling); ImGui::PushTextWrapPos(ImGui::GetContentRegionAvail().x); for (const auto& p : lines) ImGui::TextColored(p.first, "%s", p.second.c_str()); ImGui::PopTextWrapPos(); if (newMessage) { newMessage = false; ImGui::SetScrollHereY(1.f); } ImGui::EndChild(); static char buf[512]; ImGui::SetNextItemWidth(-0.001f); if (ImGui::InputText("##input", buf, sizeof(buf), ImGuiInputTextFlags_EnterReturnsTrue)) { if (buf[0] != '\0') { ggpo::sendChatMessage(config::ActAsServer ? 0 : 1, buf); std::string line = "<" + playerName(false) + "> " + std::string(buf); lines.push_back(std::make_pair(WHITE, line)); buf[0] = '\0'; newMessage = true; enable_timeout = false; } ImGui::SetKeyboardFocusHere(-1); } else if (focus) { ImGui::SetKeyboardFocusHere(-1); focus = false; } ImGui::SetItemDefaultFocus(); } ImGui::End(); ImGui::PopStyleVar(2); } void receive(int playerNum, const std::string& msg) { if (config::GGPOChat && !visible) { visible = true; toggle_timeout(); } std::string line = "<" + playerName(true) + "> " + msg; lines.push_back(std::make_pair(YELLOW, line)); newMessage = true; } void toggle(bool manual = false) { visible = !visible; focus = visible; if (manual) manual_open = manual; } void setLocalPlayerName(const std::string& name) { localPlayerName = name; } void setRemotePlayerName(const std::string& name) { remotePlayerName = name; } };