about summary refs log tree commit diff stats
path: root/src/tracker_frame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tracker_frame.cpp')
-rw-r--r--src/tracker_frame.cpp242
1 files changed, 112 insertions, 130 deletions
diff --git a/src/tracker_frame.cpp b/src/tracker_frame.cpp index 587d87b..e8d7ef6 100644 --- a/src/tracker_frame.cpp +++ b/src/tracker_frame.cpp
@@ -5,9 +5,11 @@
5#include <wx/choicebk.h> 5#include <wx/choicebk.h>
6#include <wx/filedlg.h> 6#include <wx/filedlg.h>
7#include <wx/notebook.h> 7#include <wx/notebook.h>
8#include <wx/splitter.h>
8#include <wx/stdpaths.h> 9#include <wx/stdpaths.h>
9#include <wx/webrequest.h> 10#include <wx/webrequest.h>
10 11
12#include <algorithm>
11#include <nlohmann/json.hpp> 13#include <nlohmann/json.hpp>
12#include <sstream> 14#include <sstream>
13 15
@@ -16,6 +18,11 @@
16#include "connection_dialog.h" 18#include "connection_dialog.h"
17#include "ipc_dialog.h" 19#include "ipc_dialog.h"
18#include "ipc_state.h" 20#include "ipc_state.h"
21#include "items_pane.h"
22#include "log_dialog.h"
23#include "logger.h"
24#include "options_pane.h"
25#include "paintings_pane.h"
19#include "settings_dialog.h" 26#include "settings_dialog.h"
20#include "subway_map.h" 27#include "subway_map.h"
21#include "tracker_config.h" 28#include "tracker_config.h"
@@ -44,14 +51,13 @@ enum TrackerFrameIds {
44 ID_SETTINGS = 3, 51 ID_SETTINGS = 3,
45 ID_ZOOM_IN = 4, 52 ID_ZOOM_IN = 4,
46 ID_ZOOM_OUT = 5, 53 ID_ZOOM_OUT = 5,
47 ID_OPEN_SAVE_FILE = 6,
48 ID_IPC_CONNECT = 7, 54 ID_IPC_CONNECT = 7,
55 ID_LOG_DIALOG = 8,
49}; 56};
50 57
51wxDEFINE_EVENT(STATE_RESET, wxCommandEvent); 58wxDEFINE_EVENT(STATE_RESET, wxCommandEvent);
52wxDEFINE_EVENT(STATE_CHANGED, wxCommandEvent); 59wxDEFINE_EVENT(STATE_CHANGED, StateChangedEvent);
53wxDEFINE_EVENT(STATUS_CHANGED, wxCommandEvent); 60wxDEFINE_EVENT(STATUS_CHANGED, wxCommandEvent);
54wxDEFINE_EVENT(REDRAW_POSITION, wxCommandEvent);
55wxDEFINE_EVENT(CONNECT_TO_AP, ApConnectEvent); 61wxDEFINE_EVENT(CONNECT_TO_AP, ApConnectEvent);
56 62
57TrackerFrame::TrackerFrame() 63TrackerFrame::TrackerFrame()
@@ -62,16 +68,22 @@ TrackerFrame::TrackerFrame()
62 AP_SetTrackerFrame(this); 68 AP_SetTrackerFrame(this);
63 IPC_SetTrackerFrame(this); 69 IPC_SetTrackerFrame(this);
64 70
71 SetTheIconCache(&icons_);
72
73 updater_ = std::make_unique<Updater>(this);
74 updater_->Cleanup();
75
65 wxMenu *menuFile = new wxMenu(); 76 wxMenu *menuFile = new wxMenu();
66 menuFile->Append(ID_AP_CONNECT, "&Connect to Archipelago"); 77 menuFile->Append(ID_AP_CONNECT, "&Connect to Archipelago");
67 menuFile->Append(ID_IPC_CONNECT, "&Connect to Lingo"); 78 menuFile->Append(ID_IPC_CONNECT, "&Connect to Lingo");
68 menuFile->Append(ID_OPEN_SAVE_FILE, "&Open Save Data\tCtrl-O");
69 menuFile->Append(ID_SETTINGS, "&Settings"); 79 menuFile->Append(ID_SETTINGS, "&Settings");
70 menuFile->Append(wxID_EXIT); 80 menuFile->Append(wxID_EXIT);
71 81
72 wxMenu *menuView = new wxMenu(); 82 wxMenu *menuView = new wxMenu();
73 zoom_in_menu_item_ = menuView->Append(ID_ZOOM_IN, "Zoom In\tCtrl-+"); 83 zoom_in_menu_item_ = menuView->Append(ID_ZOOM_IN, "Zoom In\tCtrl-+");
74 zoom_out_menu_item_ = menuView->Append(ID_ZOOM_OUT, "Zoom Out\tCtrl--"); 84 zoom_out_menu_item_ = menuView->Append(ID_ZOOM_OUT, "Zoom Out\tCtrl--");
85 menuView->AppendSeparator();
86 menuView->Append(ID_LOG_DIALOG, "Show Log Window\tCtrl-L");
75 87
76 zoom_in_menu_item_->Enable(false); 88 zoom_in_menu_item_->Enable(false);
77 zoom_out_menu_item_->Enable(false); 89 zoom_out_menu_item_->Enable(false);
@@ -98,30 +110,43 @@ TrackerFrame::TrackerFrame()
98 ID_CHECK_FOR_UPDATES); 110 ID_CHECK_FOR_UPDATES);
99 Bind(wxEVT_MENU, &TrackerFrame::OnZoomIn, this, ID_ZOOM_IN); 111 Bind(wxEVT_MENU, &TrackerFrame::OnZoomIn, this, ID_ZOOM_IN);
100 Bind(wxEVT_MENU, &TrackerFrame::OnZoomOut, this, ID_ZOOM_OUT); 112 Bind(wxEVT_MENU, &TrackerFrame::OnZoomOut, this, ID_ZOOM_OUT);
113 Bind(wxEVT_MENU, &TrackerFrame::OnOpenLogWindow, this, ID_LOG_DIALOG);
101 Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &TrackerFrame::OnChangePage, this); 114 Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &TrackerFrame::OnChangePage, this);
102 Bind(wxEVT_MENU, &TrackerFrame::OnOpenFile, this, ID_OPEN_SAVE_FILE); 115 Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, &TrackerFrame::OnSashPositionChanged,
116 this);
103 Bind(STATE_RESET, &TrackerFrame::OnStateReset, this); 117 Bind(STATE_RESET, &TrackerFrame::OnStateReset, this);
104 Bind(STATE_CHANGED, &TrackerFrame::OnStateChanged, this); 118 Bind(STATE_CHANGED, &TrackerFrame::OnStateChanged, this);
105 Bind(STATUS_CHANGED, &TrackerFrame::OnStatusChanged, this); 119 Bind(STATUS_CHANGED, &TrackerFrame::OnStatusChanged, this);
106 Bind(REDRAW_POSITION, &TrackerFrame::OnRedrawPosition, this);
107 Bind(CONNECT_TO_AP, &TrackerFrame::OnConnectToAp, this); 120 Bind(CONNECT_TO_AP, &TrackerFrame::OnConnectToAp, this);
108 121
109 wxChoicebook *choicebook = new wxChoicebook(this, wxID_ANY); 122 wxSize logicalSize = FromDIP(wxSize(1280, 728));
123
124 splitter_window_ = new wxSplitterWindow(this, wxID_ANY);
125 splitter_window_->SetMinimumPaneSize(logicalSize.x / 5);
126
127 wxChoicebook *choicebook = new wxChoicebook(splitter_window_, wxID_ANY);
128
110 achievements_pane_ = new AchievementsPane(choicebook); 129 achievements_pane_ = new AchievementsPane(choicebook);
111 choicebook->AddPage(achievements_pane_, "Achievements"); 130 choicebook->AddPage(achievements_pane_, "Achievements");
112 131
113 notebook_ = new wxNotebook(this, wxID_ANY); 132 items_pane_ = new ItemsPane(choicebook);
133 choicebook->AddPage(items_pane_, "Items");
134
135 options_pane_ = new OptionsPane(choicebook);
136 choicebook->AddPage(options_pane_, "Options");
137
138 paintings_pane_ = new PaintingsPane(choicebook);
139 choicebook->AddPage(paintings_pane_, "Paintings");
140
141 notebook_ = new wxNotebook(splitter_window_, wxID_ANY);
114 tracker_panel_ = new TrackerPanel(notebook_); 142 tracker_panel_ = new TrackerPanel(notebook_);
115 subway_map_ = new SubwayMap(notebook_); 143 subway_map_ = new SubwayMap(notebook_);
116 notebook_->AddPage(tracker_panel_, "Map"); 144 notebook_->AddPage(tracker_panel_, "Map");
117 notebook_->AddPage(subway_map_, "Subway"); 145 notebook_->AddPage(subway_map_, "Subway");
118 146
119 wxBoxSizer *top_sizer = new wxBoxSizer(wxHORIZONTAL); 147 splitter_window_->SplitVertically(choicebook, notebook_, logicalSize.x / 4);
120 top_sizer->Add(choicebook, wxSizerFlags().Expand().Proportion(1));
121 top_sizer->Add(notebook_, wxSizerFlags().Expand().Proportion(3));
122 148
123 SetSizerAndFit(top_sizer); 149 SetSize(logicalSize);
124 SetSize(1280, 728);
125 150
126 if (!GetTrackerConfig().asked_to_check_for_updates) { 151 if (!GetTrackerConfig().asked_to_check_for_updates) {
127 GetTrackerConfig().asked_to_check_for_updates = true; 152 GetTrackerConfig().asked_to_check_for_updates = true;
@@ -138,7 +163,7 @@ TrackerFrame::TrackerFrame()
138 } 163 }
139 164
140 if (GetTrackerConfig().should_check_for_updates) { 165 if (GetTrackerConfig().should_check_for_updates) {
141 CheckForUpdates(/*manual=*/false); 166 updater_->CheckForUpdates(/*invisible=*/true);
142 } 167 }
143 168
144 SetStatusText(GetStatusMessage()); 169 SetStatusText(GetStatusMessage());
@@ -158,15 +183,8 @@ void TrackerFrame::ResetIndicators() {
158 QueueEvent(new wxCommandEvent(STATE_RESET)); 183 QueueEvent(new wxCommandEvent(STATE_RESET));
159} 184}
160 185
161void TrackerFrame::UpdateIndicators(UpdateIndicatorsMode mode) { 186void TrackerFrame::UpdateIndicators(StateUpdate state) {
162 auto evt = new wxCommandEvent(STATE_CHANGED); 187 QueueEvent(new StateChangedEvent(STATE_CHANGED, GetId(), std::move(state)));
163 evt->SetInt(static_cast<int>(mode));
164
165 QueueEvent(evt);
166}
167
168void TrackerFrame::RedrawPosition() {
169 QueueEvent(new wxCommandEvent(REDRAW_POSITION));
170} 188}
171 189
172void TrackerFrame::OnAbout(wxCommandEvent &event) { 190void TrackerFrame::OnAbout(wxCommandEvent &event) {
@@ -231,15 +249,18 @@ void TrackerFrame::OnSettings(wxCommandEvent &event) {
231 GetTrackerConfig().should_check_for_updates = 249 GetTrackerConfig().should_check_for_updates =
232 dlg.GetShouldCheckForUpdates(); 250 dlg.GetShouldCheckForUpdates();
233 GetTrackerConfig().hybrid_areas = dlg.GetHybridAreas(); 251 GetTrackerConfig().hybrid_areas = dlg.GetHybridAreas();
234 GetTrackerConfig().show_hunt_panels = dlg.GetShowHuntPanels(); 252 GetTrackerConfig().visible_panels = dlg.GetVisiblePanels();
253 GetTrackerConfig().track_position = dlg.GetTrackPosition();
235 GetTrackerConfig().Save(); 254 GetTrackerConfig().Save();
236 255
237 UpdateIndicators(); 256 UpdateIndicators(StateUpdate{.cleared_locations = true,
257 .player_position = true,
258 .changed_settings = true});
238 } 259 }
239} 260}
240 261
241void TrackerFrame::OnCheckForUpdates(wxCommandEvent &event) { 262void TrackerFrame::OnCheckForUpdates(wxCommandEvent &event) {
242 CheckForUpdates(/*manual=*/true); 263 updater_->CheckForUpdates(/*invisible=*/false);
243} 264}
244 265
245void TrackerFrame::OnZoomIn(wxCommandEvent &event) { 266void TrackerFrame::OnZoomIn(wxCommandEvent &event) {
@@ -254,132 +275,93 @@ void TrackerFrame::OnZoomOut(wxCommandEvent &event) {
254 } 275 }
255} 276}
256 277
257void TrackerFrame::OnChangePage(wxBookCtrlEvent &event) { 278void TrackerFrame::OnOpenLogWindow(wxCommandEvent &event) {
258 zoom_in_menu_item_->Enable(event.GetSelection() == 1); 279 if (log_dialog_ == nullptr) {
259 zoom_out_menu_item_->Enable(event.GetSelection() == 1); 280 log_dialog_ = new LogDialog(this);
260} 281 log_dialog_->Show();
282 TrackerSetLogDialog(log_dialog_);
261 283
262void TrackerFrame::OnOpenFile(wxCommandEvent &event) { 284 log_dialog_->Bind(wxEVT_CLOSE_WINDOW, &TrackerFrame::OnCloseLogWindow,
263 wxFileDialog open_file_dialog( 285 this);
264 this, "Open Lingo Save File", 286 } else {
265 fmt::format("{}\\Godot\\app_userdata\\Lingo\\level1_stable", 287 log_dialog_->SetFocus();
266 wxStandardPaths::Get().GetUserConfigDir().ToStdString()),
267 AP_GetSaveName(), "Lingo save file (*.save)|*.save",
268 wxFD_OPEN | wxFD_FILE_MUST_EXIST);
269 if (open_file_dialog.ShowModal() == wxID_CANCEL) {
270 return;
271 } 288 }
289}
272 290
273 std::string savedata_path = open_file_dialog.GetPath().ToStdString(); 291void TrackerFrame::OnCloseLogWindow(wxCloseEvent& event) {
292 TrackerSetLogDialog(nullptr);
293 log_dialog_ = nullptr;
274 294
275 if (panels_panel_ == nullptr) { 295 event.Skip();
276 panels_panel_ = new TrackerPanel(notebook_); 296}
277 notebook_->AddPage(panels_panel_, "Panels");
278 }
279 297
280 notebook_->SetSelection(notebook_->FindPage(panels_panel_)); 298void TrackerFrame::OnChangePage(wxBookCtrlEvent &event) {
281 panels_panel_->SetSavedataPath(savedata_path); 299 zoom_in_menu_item_->Enable(event.GetSelection() == 1);
300 zoom_out_menu_item_->Enable(event.GetSelection() == 1);
301}
302
303void TrackerFrame::OnSashPositionChanged(wxSplitterEvent& event) {
304 notebook_->Refresh();
282} 305}
283 306
284void TrackerFrame::OnStateReset(wxCommandEvent &event) { 307void TrackerFrame::OnStateReset(wxCommandEvent &event) {
285 tracker_panel_->UpdateIndicators(); 308 tracker_panel_->UpdateIndicators(/*reset=*/true);
286 achievements_pane_->UpdateIndicators(); 309 achievements_pane_->UpdateIndicators();
310 items_pane_->ResetIndicators();
311 options_pane_->OnConnect();
312 paintings_pane_->ResetIndicators();
287 subway_map_->OnConnect(); 313 subway_map_->OnConnect();
288 if (panels_panel_ != nullptr) {
289 notebook_->DeletePage(notebook_->FindPage(panels_panel_));
290 panels_panel_ = nullptr;
291 }
292 Refresh(); 314 Refresh();
293} 315}
294 316
295void TrackerFrame::OnStateChanged(wxCommandEvent &event) { 317void TrackerFrame::OnStateChanged(StateChangedEvent &event) {
296 UpdateIndicatorsMode mode = static_cast<UpdateIndicatorsMode>(event.GetInt()); 318 const StateUpdate &state = event.GetState();
297 319
298 if (mode == kUPDATE_ALL_INDICATORS) { 320 bool hunt_panels = false;
299 tracker_panel_->UpdateIndicators(); 321 if (GetTrackerConfig().visible_panels == TrackerConfig::kHUNT_PANELS) {
300 achievements_pane_->UpdateIndicators(); 322 hunt_panels = std::any_of(
323 state.panels.begin(), state.panels.end(), [](int solve_index) {
324 return GD_GetPanel(GD_GetPanelBySolveIndex(solve_index)).hunt;
325 });
326 } else if (GetTrackerConfig().visible_panels == TrackerConfig::kALL_PANELS) {
327 hunt_panels = true;
328 }
329
330 if (!state.items.empty() || !state.paintings.empty() ||
331 state.cleared_locations || hunt_panels) {
332 // TODO: The only real reason to reset tracker_panel during an active
333 // connection is if the hunt panels setting changes. If we remove hunt
334 // panels later, we can get rid of this.
335 tracker_panel_->UpdateIndicators(/*reset=*/state.changed_settings);
301 subway_map_->UpdateIndicators(); 336 subway_map_->UpdateIndicators();
302 if (panels_panel_ != nullptr) {
303 panels_panel_->UpdateIndicators();
304 }
305 Refresh(); 337 Refresh();
306 } else if (mode == kUPDATE_ONLY_PANELS) { 338 } else if (state.player_position && GetTrackerConfig().track_position) {
307 if (panels_panel_ == nullptr) { 339 if (notebook_->GetSelection() == 0) {
308 panels_panel_ = new TrackerPanel(notebook_); 340 tracker_panel_->Refresh();
309 panels_panel_->SetPanelsMode();
310 notebook_->AddPage(panels_panel_, "Panels");
311 }
312 panels_panel_->UpdateIndicators();
313 if (notebook_->GetSelection() == 2) {
314 Refresh();
315 } 341 }
316 } 342 }
317}
318 343
319void TrackerFrame::OnStatusChanged(wxCommandEvent &event) { 344 if (std::any_of(state.panels.begin(), state.panels.end(),
320 SetStatusText(GetStatusMessage()); 345 [](int solve_index) {
321} 346 return GD_GetPanel(GD_GetPanelBySolveIndex(solve_index))
322 347 .achievement;
323void TrackerFrame::OnRedrawPosition(wxCommandEvent &event) { 348 })) {
324 if (notebook_->GetSelection() == 0) { 349 achievements_pane_->UpdateIndicators();
325 tracker_panel_->Refresh();
326 } else if (notebook_->GetSelection() == 2) {
327 panels_panel_->Refresh();
328 } 350 }
329}
330
331void TrackerFrame::OnConnectToAp(ApConnectEvent &event) {
332 AP_Connect(event.GetServer(), event.GetUser(), event.GetPass());
333}
334
335void TrackerFrame::CheckForUpdates(bool manual) {
336 wxWebRequest request = wxWebSession::GetDefault().CreateRequest(
337 this, "https://code.fourisland.com/lingo-ap-tracker/plain/VERSION");
338 351
339 if (!request.IsOk()) { 352 if (!state.items.empty()) {
340 if (manual) { 353 items_pane_->UpdateIndicators(state.items);
341 wxMessageBox("Could not check for updates.", "Error", 354 }
342 wxOK | wxICON_ERROR);
343 } else {
344 SetStatusText("Could not check for updates.");
345 }
346 355
347 return; 356 if (!state.paintings.empty()) {
357 paintings_pane_->UpdateIndicators(state.paintings);
348 } 358 }
359}
349 360
350 Bind(wxEVT_WEBREQUEST_STATE, [this, manual](wxWebRequestEvent &evt) { 361void TrackerFrame::OnStatusChanged(wxCommandEvent &event) {
351 if (evt.GetState() == wxWebRequest::State_Completed) { 362 SetStatusText(wxString::FromUTF8(GetStatusMessage()));
352 std::string response = evt.GetResponse().AsString().ToStdString(); 363}
353
354 Version latest_version(response);
355 if (kTrackerVersion < latest_version) {
356 std::ostringstream message_text;
357 message_text << "There is a newer version of Lingo AP Tracker "
358 "available. You have "
359 << kTrackerVersion.ToString()
360 << ", and the latest version is "
361 << latest_version.ToString()
362 << ". Would you like to update?";
363
364 if (wxMessageBox(message_text.str(), "Update available", wxYES_NO) ==
365 wxYES) {
366 wxLaunchDefaultBrowser(
367 "https://code.fourisland.com/lingo-ap-tracker/about/"
368 "CHANGELOG.md");
369 }
370 } else if (manual) {
371 wxMessageBox("Lingo AP Tracker is up to date!", "Lingo AP Tracker",
372 wxOK);
373 }
374 } else if (evt.GetState() == wxWebRequest::State_Failed) {
375 if (manual) {
376 wxMessageBox("Could not check for updates.", "Error",
377 wxOK | wxICON_ERROR);
378 } else {
379 SetStatusText("Could not check for updates.");
380 }
381 }
382 });
383 364
384 request.Start(); 365void TrackerFrame::OnConnectToAp(ApConnectEvent &event) {
366 AP_Connect(event.GetServer(), event.GetUser(), event.GetPass());
385} 367}