mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-03 20:03:50 +00:00
chore(game-ui): extract chat panel into dedicated UI module
- moved chat panel logic out of `game_screen` into `chat_panel` - added chat_panel.hpp and chat_panel.cpp - updated game_screen.hpp and game_screen.cpp to integrate new `ChatPanel` component - updated build config in CMakeLists.txt to include new UI module sources
This commit is contained in:
parent
c1c28d4216
commit
0f1cd5fe9a
5 changed files with 5227 additions and 5023 deletions
|
|
@ -556,6 +556,7 @@ set(WOWEE_SOURCES
|
||||||
src/ui/character_create_screen.cpp
|
src/ui/character_create_screen.cpp
|
||||||
src/ui/character_screen.cpp
|
src/ui/character_screen.cpp
|
||||||
src/ui/game_screen.cpp
|
src/ui/game_screen.cpp
|
||||||
|
src/ui/chat_panel.cpp
|
||||||
src/ui/inventory_screen.cpp
|
src/ui/inventory_screen.cpp
|
||||||
src/ui/quest_log_screen.cpp
|
src/ui/quest_log_screen.cpp
|
||||||
src/ui/spellbook_screen.cpp
|
src/ui/spellbook_screen.cpp
|
||||||
|
|
|
||||||
194
include/ui/chat_panel.hpp
Normal file
194
include/ui/chat_panel.hpp
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "game/game_handler.hpp"
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace wowee {
|
||||||
|
namespace pipeline { class AssetManager; }
|
||||||
|
namespace rendering { class Renderer; }
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class InventoryScreen;
|
||||||
|
class SpellbookScreen;
|
||||||
|
class QuestLogScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Self-contained chat UI panel extracted from GameScreen.
|
||||||
|
*
|
||||||
|
* Owns all chat state: input buffer, sent-history, tab filtering,
|
||||||
|
* slash-command parsing, chat bubbles, and chat-related settings.
|
||||||
|
*/
|
||||||
|
class ChatPanel {
|
||||||
|
public:
|
||||||
|
ChatPanel();
|
||||||
|
|
||||||
|
// ---- Main entry points (called by GameScreen) ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the chat window (tabs, history, input, etc.)
|
||||||
|
*/
|
||||||
|
void render(game::GameHandler& gameHandler,
|
||||||
|
InventoryScreen& inventoryScreen,
|
||||||
|
SpellbookScreen& spellbookScreen,
|
||||||
|
QuestLogScreen& questLogScreen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render 3D-projected chat bubbles above entities.
|
||||||
|
*/
|
||||||
|
void renderBubbles(game::GameHandler& gameHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register one-shot callbacks on GameHandler (call once per session).
|
||||||
|
* Sets up the chat-bubble callback.
|
||||||
|
*/
|
||||||
|
void setupCallbacks(game::GameHandler& gameHandler);
|
||||||
|
|
||||||
|
// ---- Input helpers (called by GameScreen keybind handling) ----
|
||||||
|
|
||||||
|
bool isChatInputActive() const { return chatInputActive_; }
|
||||||
|
|
||||||
|
/** Insert a spell / item link into the chat input buffer (shift-click). */
|
||||||
|
void insertChatLink(const std::string& link);
|
||||||
|
|
||||||
|
/** Activate the input field with a leading '/' (slash key). */
|
||||||
|
void activateSlashInput();
|
||||||
|
|
||||||
|
/** Activate (focus) the input field (Enter key). */
|
||||||
|
void activateInput();
|
||||||
|
|
||||||
|
/** Request that the chat input be focused next frame. */
|
||||||
|
void requestRefocus() { refocusChatInput_ = true; }
|
||||||
|
|
||||||
|
/** Set up a whisper to the given player name and focus input. */
|
||||||
|
void setWhisperTarget(const std::string& name);
|
||||||
|
|
||||||
|
/** Execute a macro body (one line per 'click'). */
|
||||||
|
void executeMacroText(game::GameHandler& gameHandler,
|
||||||
|
InventoryScreen& inventoryScreen,
|
||||||
|
SpellbookScreen& spellbookScreen,
|
||||||
|
QuestLogScreen& questLogScreen,
|
||||||
|
const std::string& macroText);
|
||||||
|
|
||||||
|
// ---- Slash-command side-effects ----
|
||||||
|
// GameScreen reads these each frame, then clears them.
|
||||||
|
|
||||||
|
struct SlashCommands {
|
||||||
|
bool showInspect = false;
|
||||||
|
bool toggleThreat = false;
|
||||||
|
bool showBgScore = false;
|
||||||
|
bool showGmTicket = false;
|
||||||
|
bool showWho = false;
|
||||||
|
bool toggleCombatLog = false;
|
||||||
|
bool takeScreenshot = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Return accumulated slash-command flags and reset them. */
|
||||||
|
SlashCommands consumeSlashCommands();
|
||||||
|
|
||||||
|
// ---- Chat settings (read/written by GameScreen save/load & settings tab) ----
|
||||||
|
|
||||||
|
bool chatShowTimestamps = false;
|
||||||
|
int chatFontSize = 1; // 0=small, 1=medium, 2=large
|
||||||
|
bool chatAutoJoinGeneral = true;
|
||||||
|
bool chatAutoJoinTrade = true;
|
||||||
|
bool chatAutoJoinLocalDefense = true;
|
||||||
|
bool chatAutoJoinLFG = true;
|
||||||
|
bool chatAutoJoinLocal = true;
|
||||||
|
int activeChatTab = 0;
|
||||||
|
|
||||||
|
/** Spell icon lookup callback — set by GameScreen each frame before render(). */
|
||||||
|
std::function<VkDescriptorSet(uint32_t, pipeline::AssetManager*)> getSpellIcon;
|
||||||
|
|
||||||
|
/** Render the "Chat" tab inside the Settings window. */
|
||||||
|
void renderSettingsTab(std::function<void()> saveSettingsFn);
|
||||||
|
|
||||||
|
/** Reset all chat settings to defaults. */
|
||||||
|
void restoreDefaults();
|
||||||
|
|
||||||
|
/** Replace $g/$G and $n/$N gender/name placeholders in quest/chat text. */
|
||||||
|
std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ---- Chat input state ----
|
||||||
|
char chatInputBuffer_[512] = "";
|
||||||
|
char whisperTargetBuffer_[256] = "";
|
||||||
|
bool chatInputActive_ = false;
|
||||||
|
int selectedChatType_ = 0; // 0=SAY .. 10=CHANNEL
|
||||||
|
int lastChatType_ = 0;
|
||||||
|
int selectedChannelIdx_ = 0;
|
||||||
|
bool chatInputMoveCursorToEnd_ = false;
|
||||||
|
bool refocusChatInput_ = false;
|
||||||
|
|
||||||
|
// Sent-message history (Up/Down arrow recall)
|
||||||
|
std::vector<std::string> chatSentHistory_;
|
||||||
|
int chatHistoryIdx_ = -1;
|
||||||
|
|
||||||
|
// Macro stop flag
|
||||||
|
bool macroStopped_ = false;
|
||||||
|
|
||||||
|
// Tab-completion state
|
||||||
|
std::string chatTabPrefix_;
|
||||||
|
std::vector<std::string> chatTabMatches_;
|
||||||
|
int chatTabMatchIdx_ = -1;
|
||||||
|
|
||||||
|
// Mention notification
|
||||||
|
size_t chatMentionSeenCount_ = 0;
|
||||||
|
|
||||||
|
// ---- Chat tabs ----
|
||||||
|
struct ChatTab {
|
||||||
|
std::string name;
|
||||||
|
uint64_t typeMask;
|
||||||
|
};
|
||||||
|
std::vector<ChatTab> chatTabs_;
|
||||||
|
std::vector<int> chatTabUnread_;
|
||||||
|
size_t chatTabSeenCount_ = 0;
|
||||||
|
|
||||||
|
void initChatTabs();
|
||||||
|
bool shouldShowMessage(const game::MessageChatData& msg, int tabIndex) const;
|
||||||
|
|
||||||
|
// ---- Chat window visual state ----
|
||||||
|
bool chatScrolledUp_ = false;
|
||||||
|
bool chatForceScrollToBottom_ = false;
|
||||||
|
bool chatWindowLocked_ = true;
|
||||||
|
ImVec2 chatWindowPos_ = ImVec2(0.0f, 0.0f);
|
||||||
|
bool chatWindowPosInit_ = false;
|
||||||
|
|
||||||
|
// ---- Chat bubbles ----
|
||||||
|
struct ChatBubble {
|
||||||
|
uint64_t senderGuid = 0;
|
||||||
|
std::string message;
|
||||||
|
float timeRemaining = 0.0f;
|
||||||
|
float totalDuration = 0.0f;
|
||||||
|
bool isYell = false;
|
||||||
|
};
|
||||||
|
std::vector<ChatBubble> chatBubbles_;
|
||||||
|
bool chatBubbleCallbackSet_ = false;
|
||||||
|
|
||||||
|
// ---- Whisper toast state (populated in render, rendered by GameScreen/ToastManager) ----
|
||||||
|
// Whisper scanning lives here because it's tightly coupled to chat history iteration.
|
||||||
|
size_t whisperSeenCount_ = 0;
|
||||||
|
|
||||||
|
// ---- Helpers ----
|
||||||
|
void sendChatMessage(game::GameHandler& gameHandler,
|
||||||
|
InventoryScreen& inventoryScreen,
|
||||||
|
SpellbookScreen& spellbookScreen,
|
||||||
|
QuestLogScreen& questLogScreen);
|
||||||
|
const char* getChatTypeName(game::ChatType type) const;
|
||||||
|
ImVec4 getChatTypeColor(game::ChatType type) const;
|
||||||
|
|
||||||
|
// Cached game handler for input callback (set each frame in render)
|
||||||
|
game::GameHandler* cachedGameHandler_ = nullptr;
|
||||||
|
|
||||||
|
// Join channel input buffer
|
||||||
|
char joinChannelBuffer_[128] = "";
|
||||||
|
|
||||||
|
// Slash command flags (accumulated, consumed by GameScreen)
|
||||||
|
SlashCommands slashCmds_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace wowee
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "ui/spellbook_screen.hpp"
|
#include "ui/spellbook_screen.hpp"
|
||||||
#include "ui/talent_screen.hpp"
|
#include "ui/talent_screen.hpp"
|
||||||
#include "ui/keybinding_manager.hpp"
|
#include "ui/keybinding_manager.hpp"
|
||||||
|
#include "ui/chat_panel.hpp"
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -37,56 +38,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* Check if chat input is active
|
* Check if chat input is active
|
||||||
*/
|
*/
|
||||||
bool isChatInputActive() const { return chatInputActive; }
|
bool isChatInputActive() const { return chatPanel_.isChatInputActive(); }
|
||||||
|
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void applyAudioVolumes(rendering::Renderer* renderer);
|
void applyAudioVolumes(rendering::Renderer* renderer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Chat state
|
// Chat panel (extracted from GameScreen — owns all chat state and rendering)
|
||||||
char chatInputBuffer[512] = "";
|
ChatPanel chatPanel_;
|
||||||
char whisperTargetBuffer[256] = "";
|
|
||||||
bool chatInputActive = false;
|
|
||||||
int selectedChatType = 0; // 0=SAY, 1=YELL, 2=PARTY, 3=GUILD, 4=WHISPER, ..., 10=CHANNEL
|
|
||||||
int lastChatType = 0; // Track chat type changes
|
|
||||||
int selectedChannelIdx = 0; // Index into joinedChannels_ when selectedChatType==10
|
|
||||||
bool chatInputMoveCursorToEnd = false;
|
|
||||||
|
|
||||||
// Chat sent-message history (Up/Down arrow recall)
|
|
||||||
std::vector<std::string> chatSentHistory_;
|
|
||||||
int chatHistoryIdx_ = -1; // -1 = not browsing history
|
|
||||||
|
|
||||||
// Set to true by /stopmacro; checked in executeMacroText to halt remaining commands.
|
|
||||||
bool macroStopped_ = false;
|
|
||||||
|
|
||||||
// Action bar error-flash: spellId → wall-clock time (seconds) when the flash ends.
|
// Action bar error-flash: spellId → wall-clock time (seconds) when the flash ends.
|
||||||
// Populated by the SpellCastFailedCallback; queried during action bar button rendering.
|
// Populated by the SpellCastFailedCallback; queried during action bar button rendering.
|
||||||
std::unordered_map<uint32_t, float> actionFlashEndTimes_;
|
std::unordered_map<uint32_t, float> actionFlashEndTimes_;
|
||||||
|
|
||||||
// Cached game handler for input callbacks (set each frame in render)
|
|
||||||
game::GameHandler* cachedGameHandler_ = nullptr;
|
|
||||||
|
|
||||||
// Tab-completion state for slash commands and player names
|
|
||||||
std::string chatTabPrefix_; // prefix captured on first Tab press
|
|
||||||
std::vector<std::string> chatTabMatches_; // matching command list
|
|
||||||
int chatTabMatchIdx_ = -1; // active match index (-1 = inactive)
|
|
||||||
|
|
||||||
// Mention notification: plays a sound when the player's name appears in chat
|
|
||||||
size_t chatMentionSeenCount_ = 0; // how many messages have been scanned for mentions
|
|
||||||
|
|
||||||
// Chat tabs
|
|
||||||
int activeChatTab_ = 0;
|
|
||||||
struct ChatTab {
|
|
||||||
std::string name;
|
|
||||||
uint64_t typeMask; // bitmask of ChatType values to show (64-bit: types go up to 84)
|
|
||||||
};
|
|
||||||
std::vector<ChatTab> chatTabs_;
|
|
||||||
std::vector<int> chatTabUnread_; // unread message count per tab (0 = none)
|
|
||||||
size_t chatTabSeenCount_ = 0; // how many history messages have been processed
|
|
||||||
void initChatTabs();
|
|
||||||
bool shouldShowMessage(const game::MessageChatData& msg, int tabIndex) const;
|
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
bool showEntityWindow = false;
|
bool showEntityWindow = false;
|
||||||
bool showChatWindow = true;
|
bool showChatWindow = true;
|
||||||
|
|
@ -165,13 +130,7 @@ private:
|
||||||
char petitionNameBuffer_[64] = {0};
|
char petitionNameBuffer_[64] = {0};
|
||||||
char addRankNameBuffer_[64] = {0};
|
char addRankNameBuffer_[64] = {0};
|
||||||
bool showAddRankModal_ = false;
|
bool showAddRankModal_ = false;
|
||||||
bool refocusChatInput = false;
|
|
||||||
bool vendorBagsOpened_ = false; // Track if bags were auto-opened for current vendor session
|
bool vendorBagsOpened_ = false; // Track if bags were auto-opened for current vendor session
|
||||||
bool chatScrolledUp_ = false; // true when user has scrolled above the latest messages
|
|
||||||
bool chatForceScrollToBottom_ = false; // set to true to jump to bottom next frame
|
|
||||||
bool chatWindowLocked = true;
|
|
||||||
ImVec2 chatWindowPos_ = ImVec2(0.0f, 0.0f);
|
|
||||||
bool chatWindowPosInit_ = false;
|
|
||||||
ImVec2 questTrackerPos_ = ImVec2(-1.0f, -1.0f); // <0 = use default
|
ImVec2 questTrackerPos_ = ImVec2(-1.0f, -1.0f); // <0 = use default
|
||||||
ImVec2 questTrackerSize_ = ImVec2(220.0f, 200.0f); // saved size
|
ImVec2 questTrackerSize_ = ImVec2(220.0f, 200.0f); // saved size
|
||||||
float questTrackerRightOffset_ = -1.0f; // pixels from right edge; <0 = use default
|
float questTrackerRightOffset_ = -1.0f; // pixels from right edge; <0 = use default
|
||||||
|
|
@ -286,27 +245,6 @@ private:
|
||||||
*/
|
*/
|
||||||
void renderEntityList(game::GameHandler& gameHandler);
|
void renderEntityList(game::GameHandler& gameHandler);
|
||||||
|
|
||||||
/**
|
|
||||||
* Render chat window
|
|
||||||
*/
|
|
||||||
void renderChatWindow(game::GameHandler& gameHandler);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send chat message
|
|
||||||
*/
|
|
||||||
void sendChatMessage(game::GameHandler& gameHandler);
|
|
||||||
void executeMacroText(game::GameHandler& gameHandler, const std::string& macroText);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get chat type name
|
|
||||||
*/
|
|
||||||
const char* getChatTypeName(game::ChatType type) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get chat type color
|
|
||||||
*/
|
|
||||||
ImVec4 getChatTypeColor(game::ChatType type) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render player unit frame (top-left)
|
* Render player unit frame (top-left)
|
||||||
*/
|
*/
|
||||||
|
|
@ -385,7 +323,6 @@ private:
|
||||||
void renderEscapeMenu();
|
void renderEscapeMenu();
|
||||||
void renderSettingsWindow();
|
void renderSettingsWindow();
|
||||||
void renderSettingsAudioTab();
|
void renderSettingsAudioTab();
|
||||||
void renderSettingsChatTab();
|
|
||||||
void renderSettingsAboutTab();
|
void renderSettingsAboutTab();
|
||||||
void renderSettingsInterfaceTab();
|
void renderSettingsInterfaceTab();
|
||||||
void renderSettingsGameplayTab();
|
void renderSettingsGameplayTab();
|
||||||
|
|
@ -402,7 +339,6 @@ private:
|
||||||
void renderBfMgrInvitePopup(game::GameHandler& gameHandler);
|
void renderBfMgrInvitePopup(game::GameHandler& gameHandler);
|
||||||
void renderLfgProposalPopup(game::GameHandler& gameHandler);
|
void renderLfgProposalPopup(game::GameHandler& gameHandler);
|
||||||
void renderLfgRoleCheckPopup(game::GameHandler& gameHandler);
|
void renderLfgRoleCheckPopup(game::GameHandler& gameHandler);
|
||||||
void renderChatBubbles(game::GameHandler& gameHandler);
|
|
||||||
void renderMailWindow(game::GameHandler& gameHandler);
|
void renderMailWindow(game::GameHandler& gameHandler);
|
||||||
void renderMailComposeWindow(game::GameHandler& gameHandler);
|
void renderMailComposeWindow(game::GameHandler& gameHandler);
|
||||||
void renderBankWindow(game::GameHandler& gameHandler);
|
void renderBankWindow(game::GameHandler& gameHandler);
|
||||||
|
|
@ -527,33 +463,8 @@ private:
|
||||||
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
||||||
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK)
|
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK)
|
||||||
|
|
||||||
// Chat settings
|
|
||||||
bool chatShowTimestamps_ = false;
|
|
||||||
int chatFontSize_ = 1; // 0=small, 1=medium, 2=large
|
|
||||||
bool chatAutoJoinGeneral_ = true;
|
|
||||||
bool chatAutoJoinTrade_ = true;
|
|
||||||
bool chatAutoJoinLocalDefense_ = true;
|
|
||||||
bool chatAutoJoinLFG_ = true;
|
|
||||||
bool chatAutoJoinLocal_ = true;
|
|
||||||
|
|
||||||
// Join channel input buffer
|
|
||||||
char joinChannelBuffer_[128] = "";
|
|
||||||
|
|
||||||
static std::string getSettingsPath();
|
static std::string getSettingsPath();
|
||||||
|
|
||||||
// Gender placeholder replacement
|
|
||||||
std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler);
|
|
||||||
|
|
||||||
// Chat bubbles
|
|
||||||
struct ChatBubble {
|
|
||||||
uint64_t senderGuid = 0;
|
|
||||||
std::string message;
|
|
||||||
float timeRemaining = 0.0f;
|
|
||||||
float totalDuration = 0.0f;
|
|
||||||
bool isYell = false;
|
|
||||||
};
|
|
||||||
std::vector<ChatBubble> chatBubbles_;
|
|
||||||
bool chatBubbleCallbackSet_ = false;
|
|
||||||
bool levelUpCallbackSet_ = false;
|
bool levelUpCallbackSet_ = false;
|
||||||
bool achievementCallbackSet_ = false;
|
bool achievementCallbackSet_ = false;
|
||||||
|
|
||||||
|
|
|
||||||
4898
src/ui/chat_panel.cpp
Normal file
4898
src/ui/chat_panel.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue