diff --git a/include/ui/realm_screen.hpp b/include/ui/realm_screen.hpp index 8f9a9148..ed6504c1 100644 --- a/include/ui/realm_screen.hpp +++ b/include/ui/realm_screen.hpp @@ -30,12 +30,15 @@ public: onRealmSelected = callback; } + void setOnBack(std::function cb) { onBack = std::move(cb); } + /** * Reset selection state (e.g., when switching servers) */ void reset() { selectedRealmIndex = -1; realmSelected = false; + autoSelectAttempted = false; selectedRealmName.clear(); selectedRealmAddress.clear(); statusMessage.clear(); @@ -56,6 +59,7 @@ private: // UI state int selectedRealmIndex = -1; bool realmSelected = false; + bool autoSelectAttempted = false; std::string selectedRealmName; std::string selectedRealmAddress; @@ -64,6 +68,7 @@ private: // Callbacks std::function onRealmSelected; + std::function onBack; /** * Update status message diff --git a/src/core/application.cpp b/src/core/application.cpp index afada5f5..1e395b86 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -961,6 +961,15 @@ void Application::setupUICallbacks() { } }); + // Realm screen back button - return to login + uiManager->getRealmScreen().setOnBack([this]() { + if (authHandler) { + authHandler->disconnect(); + } + uiManager->getRealmScreen().reset(); + setState(AppState::AUTHENTICATION); + }); + // Character selection callback uiManager->getCharacterScreen().setOnCharacterSelected([this](uint64_t characterGuid) { LOG_INFO("Character selected: GUID=0x", std::hex, characterGuid, std::dec); diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 17aab3aa..8ee25d82 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -7,6 +7,7 @@ #include "game/opcodes.hpp" #include "game/update_field_table.hpp" #include "rendering/renderer.hpp" +#include "audio/spell_sound_manager.hpp" #include "pipeline/dbc_layout.hpp" #include "network/world_socket.hpp" #include "network/packet.hpp" @@ -6917,14 +6918,12 @@ void GameHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { if (casting) return; // Already casting - // Hearthstone is item-bound; use the item rather than direct spell cast. - if (spellId == 8690) { - LOG_INFO("Hearthstone spell intercepted, routing to useItemById(6948)"); - useItemById(6948); - return; - } - + // Hearthstone: cast spell directly (server checks item in inventory) + // Using CMSG_CAST_SPELL is more reliable than CMSG_USE_ITEM which + // depends on slot indices matching between client and server. uint64_t target = targetGuid != 0 ? targetGuid : this->targetGuid; + // Self-targeted spells like hearthstone should not send a target + if (spellId == 8690) target = 0; auto packet = packetParsers_ ? packetParsers_->buildCastSpell(spellId, target, ++castCount) : CastSpellPacket::build(spellId, target, ++castCount); @@ -7031,6 +7030,13 @@ void GameHandler::handleSpellStart(network::Packet& packet) { currentCastSpellId = data.spellId; castTimeTotal = data.castTime / 1000.0f; castTimeRemaining = castTimeTotal; + + // Play precast (channeling) sound + if (auto* renderer = core::Application::getInstance().getRenderer()) { + if (auto* ssm = renderer->getSpellSoundManager()) { + ssm->playPrecast(audio::SpellSoundManager::MagicSchool::ARCANE, audio::SpellSoundManager::SpellPower::MEDIUM); + } + } } } @@ -7040,6 +7046,13 @@ void GameHandler::handleSpellGo(network::Packet& packet) { // Cast completed if (data.casterUnit == playerGuid) { + // Play cast-complete sound before clearing state + if (auto* renderer = core::Application::getInstance().getRenderer()) { + if (auto* ssm = renderer->getSpellSoundManager()) { + ssm->playCast(audio::SpellSoundManager::MagicSchool::ARCANE); + } + } + casting = false; currentCastSpellId = 0; castTimeRemaining = 0.0f; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index df14f183..2375adb7 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -543,14 +543,16 @@ void GameScreen::renderChatWindow(game::GameHandler& gameHandler) { float chatH = 220.0f; float chatX = 8.0f; float chatY = screenH - chatH - 80.0f; // Above action bar - if (!chatWindowPosInit_) { - chatWindowPos_ = ImVec2(chatX, chatY); - chatWindowPosInit_ = true; - } if (chatWindowLocked) { + // Always recompute position from current window size when locked + chatWindowPos_ = ImVec2(chatX, chatY); ImGui::SetNextWindowSize(ImVec2(chatW, chatH), ImGuiCond_Always); ImGui::SetNextWindowPos(chatWindowPos_, ImGuiCond_Always); } else { + if (!chatWindowPosInit_) { + chatWindowPos_ = ImVec2(chatX, chatY); + chatWindowPosInit_ = true; + } ImGui::SetNextWindowSize(ImVec2(chatW, chatH), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(chatWindowPos_, ImGuiCond_FirstUseEver); } @@ -3035,10 +3037,10 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { float barX = (screenW - barW) / 2.0f; float barY = screenH - barH; - ImGui::SetNextWindowPos(ImVec2(barX, barY), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(barX, barY), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(barW, barH), ImGuiCond_Always); - ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | + ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar; @@ -3098,10 +3100,12 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { // Try to get icon texture for this slot GLuint iconTex = 0; const game::ItemDef* barItemDef = nullptr; + uint32_t itemDisplayInfoId = 0; + std::string itemNameFromQuery; if (slot.type == game::ActionBarSlot::SPELL && slot.id != 0) { iconTex = getSpellIcon(slot.id, assetMgr); } else if (slot.type == game::ActionBarSlot::ITEM && slot.id != 0) { - // Look up item in inventory for icon and name + // Search backpack auto& inv = gameHandler.getInventory(); for (int bi = 0; bi < inv.getBackpackSize(); bi++) { const auto& bs = inv.getBackpackSlot(bi); @@ -3110,8 +3114,41 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { break; } } + // Search equipped slots + if (!barItemDef) { + for (int ei = 0; ei < game::Inventory::NUM_EQUIP_SLOTS; ei++) { + const auto& es = inv.getEquipSlot(static_cast(ei)); + if (!es.empty() && es.item.itemId == slot.id) { + barItemDef = &es.item; + break; + } + } + } + // Search extra bags + if (!barItemDef) { + for (int bag = 0; bag < game::Inventory::NUM_BAG_SLOTS && !barItemDef; bag++) { + for (int si = 0; si < inv.getBagSize(bag); si++) { + const auto& bs = inv.getBagSlot(bag, si); + if (!bs.empty() && bs.item.itemId == slot.id) { + barItemDef = &bs.item; + break; + } + } + } + } if (barItemDef && barItemDef->displayInfoId != 0) { - iconTex = inventoryScreen.getItemIcon(barItemDef->displayInfoId); + itemDisplayInfoId = barItemDef->displayInfoId; + } + // Fallback: use item info cache (from server query responses) + if (itemDisplayInfoId == 0) { + if (auto* info = gameHandler.getItemInfo(slot.id)) { + itemDisplayInfoId = info->displayInfoId; + if (itemNameFromQuery.empty() && !info->name.empty()) + itemNameFromQuery = info->name; + } + } + if (itemDisplayInfoId != 0) { + iconTex = inventoryScreen.getItemIcon(itemDisplayInfoId); } } @@ -3201,18 +3238,49 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { } // Tooltip - if (ImGui::IsItemHovered() && slot.type == game::ActionBarSlot::SPELL && slot.id != 0) { - std::string fullName = getSpellName(slot.id); + if (ImGui::IsItemHovered() && !slot.isEmpty() && slot.id != 0) { ImGui::BeginTooltip(); - ImGui::Text("%s", fullName.c_str()); - ImGui::TextDisabled("Spell ID: %u", slot.id); - ImGui::EndTooltip(); - } else if (ImGui::IsItemHovered() && slot.type == game::ActionBarSlot::ITEM && slot.id != 0) { - ImGui::BeginTooltip(); - if (barItemDef) { - ImGui::Text("%s", barItemDef->name.c_str()); - } else { - ImGui::Text("Item #%u", slot.id); + if (slot.type == game::ActionBarSlot::SPELL) { + std::string fullName = getSpellName(slot.id); + ImGui::Text("%s", fullName.c_str()); + // Hearthstone: show bind point info + if (slot.id == 8690) { + uint32_t mapId = 0; + glm::vec3 pos; + if (gameHandler.getHomeBind(mapId, pos)) { + const char* mapName = "Unknown"; + switch (mapId) { + case 0: mapName = "Eastern Kingdoms"; break; + case 1: mapName = "Kalimdor"; break; + case 530: mapName = "Outland"; break; + case 571: mapName = "Northrend"; break; + } + ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), + "Home: %s", mapName); + } + ImGui::TextDisabled("Use: Teleport home"); + } + } else if (slot.type == game::ActionBarSlot::ITEM) { + if (barItemDef && !barItemDef->name.empty()) { + ImGui::Text("%s", barItemDef->name.c_str()); + } else if (!itemNameFromQuery.empty()) { + ImGui::Text("%s", itemNameFromQuery.c_str()); + } else { + ImGui::Text("Item #%u", slot.id); + } + } + // Show cooldown time remaining + if (onCooldown) { + float cd = slot.cooldownRemaining; + if (cd >= 60.0f) { + int mins = static_cast(cd) / 60; + int secs = static_cast(cd) % 60; + ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), + "Cooldown: %d min %d sec", mins, secs); + } else { + ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), + "Cooldown: %.1f sec", cd); + } } ImGui::EndTooltip(); } @@ -3301,10 +3369,10 @@ void GameScreen::renderBagBar(game::GameHandler& gameHandler) { float barX = screenW - barW - 10.0f; float barY = screenH - barH - 10.0f; - ImGui::SetNextWindowPos(ImVec2(barX, barY), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(barX, barY), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(barW, barH), ImGuiCond_Always); - ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | + ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar; @@ -3534,8 +3602,12 @@ void GameScreen::renderCastBar(game::GameHandler& gameHandler) { ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.8f, 0.6f, 0.2f, 1.0f)); char overlay[64]; - snprintf(overlay, sizeof(overlay), "Spell %u (%.1fs)", - gameHandler.getCurrentCastSpellId(), gameHandler.getCastTimeRemaining()); + uint32_t currentSpellId = gameHandler.getCurrentCastSpellId(); + const std::string& spellName = gameHandler.getSpellName(currentSpellId); + if (!spellName.empty()) + snprintf(overlay, sizeof(overlay), "%s (%.1fs)", spellName.c_str(), gameHandler.getCastTimeRemaining()); + else + snprintf(overlay, sizeof(overlay), "Casting... (%.1fs)", gameHandler.getCastTimeRemaining()); ImGui::ProgressBar(progress, ImVec2(-1, 20), overlay); ImGui::PopStyleColor(); } diff --git a/src/ui/inventory_screen.cpp b/src/ui/inventory_screen.cpp index 7f6e2f3f..21c6cf56 100644 --- a/src/ui/inventory_screen.cpp +++ b/src/ui/inventory_screen.cpp @@ -1415,11 +1415,20 @@ void InventoryScreen::renderItemTooltip(const game::ItemDef& item) { uint32_t mapId = 0; glm::vec3 pos; if (gameHandler_->getHomeBind(mapId, pos)) { - ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), - "Home: map %u (%.1f, %.1f, %.1f)", mapId, pos.x, pos.y, pos.z); + const char* mapName = "Unknown"; + switch (mapId) { + case 0: mapName = "Eastern Kingdoms"; break; + case 1: mapName = "Kalimdor"; break; + case 530: mapName = "Outland"; break; + case 571: mapName = "Northrend"; break; + case 13: mapName = "Test"; break; + case 169: mapName = "Emerald Dream"; break; + } + ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "Home: %s", mapName); } else { ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Home: not set"); } + ImGui::TextDisabled("Use: Teleport home"); } // Slot type diff --git a/src/ui/realm_screen.cpp b/src/ui/realm_screen.cpp index e2899a88..e0afe664 100644 --- a/src/ui/realm_screen.cpp +++ b/src/ui/realm_screen.cpp @@ -20,6 +20,12 @@ void RealmScreen::render(auth::AuthHandler& authHandler) { ImGui::Begin("Realm Selection", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove); + // Header with title and back button + if (ImGui::Button("Back", ImVec2(100, 36))) { + if (onBack) onBack(); + } + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.0f); ImGui::Text("Select a Realm"); ImGui::Separator(); ImGui::Spacing(); @@ -38,140 +44,184 @@ void RealmScreen::render(auth::AuthHandler& authHandler) { if (realms.empty()) { ImGui::Text("No realms available. Requesting realm list..."); authHandler.requestRealmList(); - } else if (realms.size() == 1 && !realmSelected && !realms[0].lock) { - // Auto-select the only available realm - selectedRealmIndex = 0; - realmSelected = true; - selectedRealmName = realms[0].name; - selectedRealmAddress = realms[0].address; - setStatus("Auto-selecting realm: " + realms[0].name); - if (onRealmSelected) { - onRealmSelected(selectedRealmName, selectedRealmAddress); - } } else { - // Realm table - if (ImGui::BeginTable("RealmsTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + // Auto-select: prefer realm with characters, then single realm, then first available + if (!autoSelectAttempted && !realmSelected) { + autoSelectAttempted = true; + + // First: look for realm with characters + int bestRealm = -1; + for (size_t i = 0; i < realms.size(); ++i) { + if (!realms[i].lock && realms[i].characters > 0) { + bestRealm = static_cast(i); + break; + } + } + + // If only one realm and it's unlocked, auto-connect + if (realms.size() == 1 && !realms[0].lock) { + selectedRealmIndex = 0; + realmSelected = true; + selectedRealmName = realms[0].name; + selectedRealmAddress = realms[0].address; + setStatus("Auto-selecting realm: " + realms[0].name); + if (onRealmSelected) { + onRealmSelected(selectedRealmName, selectedRealmAddress); + } + } else if (bestRealm >= 0) { + // Pre-highlight realm with characters (don't auto-connect, let user confirm) + selectedRealmIndex = bestRealm; + } + } + + // Calculate row height for table - use more vertical space + float rowHeight = std::max(28.0f, ImGui::GetTextLineHeight() + 16.0f); + + // Reserve space for bottom panel (selected realm info + buttons) + float bottomPanelHeight = 120.0f; + float tableHeight = ImGui::GetContentRegionAvail().y - bottomPanelHeight; + if (tableHeight < 200.0f) tableHeight = 200.0f; + + // Realm table - fills available width and height + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(12.0f, 8.0f)); + if (ImGui::BeginTable("RealmsTable", 5, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | + ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable, + ImVec2(0, tableHeight))) { + + // Proportional columns + float totalW = ImGui::GetContentRegionAvail().x; ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 60.0f); - ImGui::TableSetupColumn("Population", ImGuiTableColumnFlags_WidthFixed, 80.0f); - ImGui::TableSetupColumn("Characters", ImGuiTableColumnFlags_WidthFixed, 80.0f); - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, totalW * 0.12f); + ImGui::TableSetupColumn("Population", ImGuiTableColumnFlags_WidthFixed, totalW * 0.14f); + ImGui::TableSetupColumn("Characters", ImGuiTableColumnFlags_WidthFixed, totalW * 0.12f); + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, totalW * 0.12f); ImGui::TableHeadersRow(); for (size_t i = 0; i < realms.size(); ++i) { const auto& realm = realms[i]; - ImGui::TableNextRow(); + ImGui::TableNextRow(0, rowHeight); - // Name column (selectable) + // Name column (selectable, double-click to enter) ImGui::TableSetColumnIndex(0); bool isSelected = (selectedRealmIndex == static_cast(i)); - if (ImGui::Selectable(realm.name.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns)) { + char nameLabel[256]; + snprintf(nameLabel, sizeof(nameLabel), "%s##realm%zu", realm.name.c_str(), i); + if (ImGui::Selectable(nameLabel, isSelected, + ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick, + ImVec2(0, rowHeight - 8.0f))) { selectedRealmIndex = static_cast(i); + if (ImGui::IsMouseDoubleClicked(0) && !realm.lock) { + realmSelected = true; + selectedRealmName = realm.name; + selectedRealmAddress = realm.address; + setStatus("Connecting to realm: " + realm.name); + if (onRealmSelected) { + onRealmSelected(selectedRealmName, selectedRealmAddress); + } + } } // Type column ImGui::TableSetColumnIndex(1); - if (realm.icon == 0) { - ImGui::Text("Normal"); - } else if (realm.icon == 1) { - ImGui::Text("PvP"); - } else if (realm.icon == 4) { - ImGui::Text("RP"); - } else if (realm.icon == 6) { - ImGui::Text("RP-PvP"); - } else { - ImGui::Text("Type %d", realm.icon); - } + if (realm.icon == 0) ImGui::Text("Normal"); + else if (realm.icon == 1) ImGui::Text("PvP"); + else if (realm.icon == 4) ImGui::Text("RP"); + else if (realm.icon == 6) ImGui::Text("RP-PvP"); + else ImGui::Text("Type %d", realm.icon); // Population column ImGui::TableSetColumnIndex(2); ImVec4 popColor = getPopulationColor(realm.population); ImGui::PushStyleColor(ImGuiCol_Text, popColor); - if (realm.population < 0.5f) { - ImGui::Text("Low"); - } else if (realm.population < 1.0f) { - ImGui::Text("Medium"); - } else if (realm.population < 2.0f) { - ImGui::Text("High"); - } else { - ImGui::Text("Full"); - } + if (realm.population < 0.5f) ImGui::Text("Low"); + else if (realm.population < 1.0f) ImGui::Text("Medium"); + else if (realm.population < 2.0f) ImGui::Text("High"); + else ImGui::Text("Full"); ImGui::PopStyleColor(); // Characters column ImGui::TableSetColumnIndex(3); - ImGui::Text("%d", realm.characters); + if (realm.characters > 0) { + ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), "%d", realm.characters); + } else { + ImGui::TextDisabled("0"); + } // Status column ImGui::TableSetColumnIndex(4); const char* status = getRealmStatus(realm.flags); if (realm.lock) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f)); - ImGui::Text("Locked"); - ImGui::PopStyleColor(); + ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Locked"); } else { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.3f, 1.0f, 0.3f, 1.0f)); - ImGui::Text("%s", status); - ImGui::PopStyleColor(); + ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f, 1.0f), "%s", status); } } ImGui::EndTable(); } + ImGui::PopStyleVar(); // CellPadding ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); - // Selected realm info + // Bottom panel: selected realm info + action buttons if (selectedRealmIndex >= 0 && selectedRealmIndex < static_cast(realms.size())) { const auto& realm = realms[selectedRealmIndex]; - ImGui::Text("Selected Realm:"); - ImGui::Indent(); - ImGui::Text("Name: %s", realm.name.c_str()); - ImGui::Text("Address: %s", realm.address.c_str()); - ImGui::Text("Characters: %d", realm.characters); - if (realm.hasVersionInfo()) { - ImGui::Text("Version: %d.%d.%d (build %d)", - realm.majorVersion, realm.minorVersion, realm.patchVersion, realm.build); + ImGui::Text("Selected: %s", realm.name.c_str()); + ImGui::SameLine(); + ImGui::TextDisabled("(%s)", realm.address.c_str()); + if (realm.characters > 0) { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), + " - %d character%s", realm.characters, realm.characters > 1 ? "s" : ""); + } + if (realm.hasVersionInfo()) { + ImGui::SameLine(); + ImGui::TextDisabled(" v%d.%d.%d", + realm.majorVersion, realm.minorVersion, realm.patchVersion); } - ImGui::Unindent(); ImGui::Spacing(); - // Connect button + // Enter Realm button (large) if (!realm.lock) { - if (ImGui::Button("Enter Realm", ImVec2(120, 0))) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.45f, 0.15f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.2f, 0.6f, 0.2f, 1.0f)); + if (ImGui::Button("Enter Realm", ImVec2(200, 40))) { realmSelected = true; selectedRealmName = realm.name; selectedRealmAddress = realm.address; setStatus("Connecting to realm: " + realm.name); - - // Call callback if (onRealmSelected) { onRealmSelected(selectedRealmName, selectedRealmAddress); } } + ImGui::PopStyleColor(2); } else { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); - ImGui::Button("Realm Locked", ImVec2(120, 0)); + ImGui::Button("Realm Locked", ImVec2(200, 40)); ImGui::PopStyleColor(); } + + ImGui::SameLine(0, 16.0f); + if (ImGui::Button("Refresh", ImVec2(120, 40))) { + authHandler.requestRealmList(); + setStatus("Refreshing realm list..."); + } + } else { + ImGui::TextDisabled("Click a realm to select it, or double-click to enter."); + ImGui::Spacing(); + if (ImGui::Button("Refresh", ImVec2(120, 40))) { + authHandler.requestRealmList(); + setStatus("Refreshing realm list..."); + } } } - ImGui::Spacing(); - ImGui::Separator(); - ImGui::Spacing(); - - // Refresh button - if (ImGui::Button("Refresh Realm List", ImVec2(150, 0))) { - authHandler.requestRealmList(); - setStatus("Refreshing realm list..."); - } - ImGui::End(); }