WoW Model Viewer
Your premiere tool for viewing, equipping and animating World of Warcraft models.
Loading...
Searching...
No Matches
AppDialogs.cpp
Go to the documentation of this file.
1#include "AppDialogs.h"
2
3#ifdef _WIN32
4#include <windows.h>
5#endif
6
7#include <glad/gl.h>
8
9#include "imgui.h"
10#include "imgui_stdlib.h"
11
12#include "AppState.h"
13#include "GameLoader.h"
14#include "URLImportHandler.h"
15
16// Engine headers for version / locale queries
17#include "Game.h"
18#include "WoWFolder.h"
19#include "GlobalSettings.h"
20
21#include <string>
22
23// ---- URL Import dialog ----------------------------------------------------
24
26{
27 if (app.ui.showImportDialog)
28 ImGui::OpenPopup("Import from URL##ImportModal");
29
30 if (ImGui::BeginPopupModal("Import from URL##ImportModal", &app.ui.showImportDialog,
31 ImGuiWindowFlags_AlwaysAutoResize))
32 {
33 ImGui::Text("Paste an Armory, Battle.net, or Wowhead URL:");
34 ImGui::Spacing();
35
37 {
38 ImGui::SetKeyboardFocusHere();
39 app.ui.importPopupJustOpened = false;
40 }
41
42 ImGui::SetNextItemWidth(500);
43 ImGui::InputText("##importUrl", &app.exporting.importUrlBuf);
44
45 ImGui::Spacing();
46 if (ImGui::Button("Import", ImVec2(120, 0)))
48 ImGui::SameLine();
49 if (ImGui::Button("Cancel", ImVec2(120, 0)))
50 {
51 app.ui.showImportDialog = false;
52 ImGui::CloseCurrentPopup();
53 }
54
55 if (!app.exporting.importStatus.empty())
56 {
57 ImGui::Spacing();
58 bool isError = app.exporting.importStatus.find("failed") != std::string::npos ||
59 app.exporting.importStatus.find("No ") != std::string::npos ||
60 app.exporting.importStatus.find("not") != std::string::npos ||
61 app.exporting.importStatus.find("Please") != std::string::npos;
62 if (isError)
63 ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", app.exporting.importStatus.c_str());
64 else
65 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%s", app.exporting.importStatus.c_str());
66 }
67
68 ImGui::EndPopup();
69 }
70}
71
72// ---- Config selection modal -----------------------------------------------
73
75{
77 ImGui::OpenPopup("Select WoW Config");
78
79 if (ImGui::BeginPopupModal("Select WoW Config", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
80 {
81 ImGui::Text("Multiple configurations found. Please select one:");
82 ImGui::Separator();
83
84 for (int i = 0; i < static_cast<int>(app.loading.pendingConfigs.size()); ++i)
85 {
86 std::string label = app.loading.pendingConfigs[i].locale + " - " + app.loading.pendingConfigs[i].product;
87 if (!app.loading.pendingConfigs[i].version.empty())
88 label += " (" + app.loading.pendingConfigs[i].version + ")";
89 ImGui::RadioButton(label.c_str(), &app.loading.selectedConfig, i);
90 }
91
92 ImGui::Separator();
93 if (ImGui::Button("OK", ImVec2(120, 0)))
94 {
95 app.loading.showConfigPopup = false;
96 ImGui::CloseCurrentPopup();
98 }
99 ImGui::SameLine();
100 if (ImGui::Button("Cancel", ImVec2(120, 0)))
101 {
102 app.loading.showConfigPopup = false;
103 GameLoader::setLoadStatus("Load cancelled.", app);
104 ImGui::CloseCurrentPopup();
105 }
106 ImGui::EndPopup();
107 }
108}
109
110// ---- About dialog ---------------------------------------------------------
111
113{
114 if (app.ui.showAboutDialog)
115 ImGui::OpenPopup("About WoW Model Viewer");
116
117 if (ImGui::BeginPopupModal("About WoW Model Viewer", &app.ui.showAboutDialog,
118 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
119 {
120 // Convert wstring title to narrow UTF-8 string for ImGui
121 std::wstring wTitle = GLOBALSETTINGS.appTitle();
122 std::string title;
123 if (!wTitle.empty())
124 {
125#ifdef _WIN32
126 int n = WideCharToMultiByte(CP_UTF8, 0, wTitle.c_str(),
127 static_cast<int>(wTitle.size()), nullptr, 0, nullptr, nullptr);
128 title.resize(n);
129 WideCharToMultiByte(CP_UTF8, 0, wTitle.c_str(),
130 static_cast<int>(wTitle.size()), title.data(), n, nullptr, nullptr);
131#else
132 title.assign(wTitle.begin(), wTitle.end());
133#endif
134 }
135 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s", title.c_str());
136
137 ImGui::Separator();
138 ImGui::Text("A 3D model viewer for World of Warcraft game assets.");
139 ImGui::Spacing();
140 ImGui::Text("Built with GLFW, OpenGL, and Dear ImGui.");
141 ImGui::Text("Uses CASCLib for game data access.");
142 ImGui::Spacing();
143 ImGui::Separator();
144 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "https://wowmodelviewer.net");
145 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "https://github.com/wowmodelviewer/wowmodelviewer");
146 ImGui::Spacing();
147 ImGui::Text("GL_RENDERER: %s", glGetString(GL_RENDERER));
148 ImGui::Text("GL_VERSION: %s", glGetString(GL_VERSION));
149 ImGui::Spacing();
150
151 if (ImGui::Button("Close", ImVec2(120, 0)))
152 {
153 app.ui.showAboutDialog = false;
154 ImGui::CloseCurrentPopup();
155 }
156 ImGui::EndPopup();
157 }
158}
159
160// ---- Language / Locale dialog ---------------------------------------------
161
163{
164 if (app.ui.showLanguageDialog)
165 ImGui::OpenPopup("Language / Locale");
166
167 if (ImGui::BeginPopupModal("Language / Locale", &app.ui.showLanguageDialog,
168 ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
169 {
170 if (!app.loading.isWoWLoaded)
171 {
172 ImGui::TextWrapped("Game data is not loaded. Load WoW first, then change the locale here.");
173 ImGui::Spacing();
174 if (ImGui::Button("OK", ImVec2(120, 0)))
175 {
176 app.ui.showLanguageDialog = false;
177 ImGui::CloseCurrentPopup();
178 }
179 }
180 else
181 {
182 ImGui::Text("Current locale: %s", GAMEDIRECTORY.locale().c_str());
183 ImGui::Separator();
184 ImGui::Text("Select a different locale to reload game data:");
185 ImGui::Spacing();
186
187 auto configs = GAMEDIRECTORY.configsFound();
188 for (int i = 0; i < static_cast<int>(configs.size()); ++i)
189 {
190 std::string label = configs[i].locale + " - " + configs[i].product;
191 bool isCurrent = (configs[i].locale == GAMEDIRECTORY.locale());
192 if (isCurrent)
193 ImGui::BeginDisabled();
194
195 if (ImGui::Button(label.c_str(), ImVec2(-1, 0)))
196 {
197 app.ui.showLanguageDialog = false;
198 ImGui::CloseCurrentPopup();
199 app.loading.isWoWLoaded = false;
200 app.loading.initDB = false;
201 app.loading.loadInProgress = true;
202 app.loading.loadProgress = 0.0f;
203 GameLoader::setLoadStatus("Reloading with locale: " + configs[i].locale + "...", app);
204 GameLoader::launchLoadThread(configs[i], app);
205 }
206
207 if (isCurrent)
208 ImGui::EndDisabled();
209 }
210
211 ImGui::Spacing();
212 if (ImGui::Button("Cancel", ImVec2(120, 0)))
213 {
214 app.ui.showLanguageDialog = false;
215 ImGui::CloseCurrentPopup();
216 }
217 }
218 ImGui::EndPopup();
219 }
220}
#define GAMEDIRECTORY
Definition Game.h:9
#define GLOBALSETTINGS
void drawConfigPopup(AppState &app)
Draw the game config selection popup (locale / product picker).
void drawAboutDialog(AppState &app)
Draw the About dialog with version and credits.
void drawLanguageDialog(AppState &app)
Draw the Language / Locale selection dialog.
void drawImportDialog(AppState &app)
Draw the URL import dialog (Armory / Wowhead).
void setLoadStatus(const std::string &s, AppState &app)
Thread-safe load-status setters / getters (lock app.loadStatusMutex).
void launchLoadThread(const core::GameConfig &config, AppState &app)
Spawn the background loading thread for the given config.
void doImport(AppState &app)
Top-level aggregate of all mutable application state.
Definition AppState.h:261
LoadingState loading
Definition AppState.h:263
ExportState exporting
Definition AppState.h:268
UIState ui
Definition AppState.h:264
std::string importUrlBuf
Definition AppState.h:250
std::string importStatus
Definition AppState.h:251
std::atomic< float > loadProgress
Definition AppState.h:94
bool showConfigPopup
Definition AppState.h:101
bool isWoWLoaded
Definition AppState.h:91
std::atomic< bool > initDB
Definition AppState.h:92
bool loadInProgress
Definition AppState.h:95
int selectedConfig
Definition AppState.h:103
std::vector< core::GameConfig > pendingConfigs
Definition AppState.h:102
bool showAboutDialog
Definition AppState.h:112
bool showLanguageDialog
Definition AppState.h:113
bool importPopupJustOpened
Definition AppState.h:132
bool showImportDialog
Definition AppState.h:128