about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-02-08 15:11:23 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2025-02-08 15:11:23 -0500
commit712313d825db7ce7c9d4457f7564b27d3dd4ce64 (patch)
treea4fa488b66b19a825bebd8dfea8cdf97d2e9452b
parent9b8570921477e374f53fa9df183f1776cf345f73 (diff)
downloadlingo-ap-tracker-712313d825db7ce7c9d4457f7564b27d3dd4ce64.tar.gz
lingo-ap-tracker-712313d825db7ce7c9d4457f7564b27d3dd4ce64.tar.bz2
lingo-ap-tracker-712313d825db7ce7c9d4457f7564b27d3dd4ce64.zip
Added a scrollbar to subway reports
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/report_popup.cpp98
-rw-r--r--src/report_popup.h30
-rw-r--r--src/subway_map.cpp127
-rw-r--r--src/subway_map.h7
5 files changed, 186 insertions, 77 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f46c158..e976cdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -51,6 +51,7 @@ add_executable(lingo_ap_tracker
51 "src/godot_variant.cpp" 51 "src/godot_variant.cpp"
52 "src/ipc_state.cpp" 52 "src/ipc_state.cpp"
53 "src/ipc_dialog.cpp" 53 "src/ipc_dialog.cpp"
54 "src/report_popup.cpp"
54 "vendor/whereami/whereami.c" 55 "vendor/whereami/whereami.c"
55) 56)
56set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20) 57set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20)
diff --git a/src/report_popup.cpp b/src/report_popup.cpp new file mode 100644 index 0000000..d772b32 --- /dev/null +++ b/src/report_popup.cpp
@@ -0,0 +1,98 @@
1#include "report_popup.h"
2
3#include <wx/dcbuffer.h>
4
5#include <map>
6#include <string>
7
8#include "global.h"
9#include "tracker_state.h"
10
11ReportPopup::ReportPopup(wxWindow* parent)
12 : wxScrolledCanvas(parent, wxID_ANY) {
13 SetBackgroundStyle(wxBG_STYLE_PAINT);
14
15 unchecked_eye_ =
16 wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(),
17 wxBITMAP_TYPE_PNG)
18 .Scale(32, 32));
19 checked_eye_ = wxBitmap(
20 wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG)
21 .Scale(32, 32));
22
23 SetScrollRate(5, 5);
24
25 SetBackgroundColour(*wxBLACK);
26 Hide();
27
28 Bind(wxEVT_PAINT, &ReportPopup::OnPaint, this);
29}
30
31void ReportPopup::SetDoorId(int door_id) {
32 door_id_ = door_id;
33
34 UpdateIndicators();
35}
36
37void ReportPopup::Reset() {
38 door_id_ = -1;
39}
40
41void ReportPopup::UpdateIndicators() {
42 wxMemoryDC mem_dc;
43
44 const std::map<std::string, bool>& report = GetDoorRequirements(door_id_);
45
46 int acc_height = 10;
47 int col_width = 0;
48
49 for (const auto& [text, obtained] : report) {
50 wxSize item_extent = mem_dc.GetTextExtent(text);
51 int item_height = std::max(32, item_extent.GetHeight()) + 10;
52 acc_height += item_height;
53
54 if (item_extent.GetWidth() > col_width) {
55 col_width = item_extent.GetWidth();
56 }
57 }
58
59 int item_width = col_width + 10 + 32;
60 int full_width = item_width + 20;
61
62 Fit();
63 SetVirtualSize(full_width, acc_height);
64
65 rendered_ = wxBitmap(full_width, acc_height);
66 mem_dc.SelectObject(rendered_);
67 mem_dc.SetPen(*wxTRANSPARENT_PEN);
68 mem_dc.SetBrush(*wxBLACK_BRUSH);
69 mem_dc.DrawRectangle({0, 0}, {full_width, acc_height});
70
71 mem_dc.SetFont(GetFont());
72
73 int cur_height = 10;
74
75 for (const auto& [text, obtained] : report) {
76 wxBitmap* eye_ptr = obtained ? &checked_eye_ : &unchecked_eye_;
77
78 mem_dc.DrawBitmap(*eye_ptr, wxPoint{10, cur_height});
79
80 mem_dc.SetTextForeground(obtained ? *wxWHITE : *wxRED);
81 wxSize item_extent = mem_dc.GetTextExtent(text);
82 mem_dc.DrawText(
83 text, wxPoint{10 + 32 + 10,
84 cur_height + (32 - mem_dc.GetFontMetrics().height) / 2});
85
86 cur_height += 10 + 32;
87 }
88}
89
90void ReportPopup::OnPaint(wxPaintEvent& event) {
91 if (door_id_ != -1) {
92 wxBufferedPaintDC dc(this);
93 PrepareDC(dc);
94 dc.DrawBitmap(rendered_, 0, 0);
95 }
96
97 event.Skip();
98}
diff --git a/src/report_popup.h b/src/report_popup.h new file mode 100644 index 0000000..9e141bf --- /dev/null +++ b/src/report_popup.h
@@ -0,0 +1,30 @@
1#ifndef REPORT_POPUP_H_E065BED4
2#define REPORT_POPUP_H_E065BED4
3
4#include <wx/wxprec.h>
5
6#ifndef WX_PRECOMP
7#include <wx/wx.h>
8#endif
9
10class ReportPopup : public wxScrolledCanvas {
11 public:
12 explicit ReportPopup(wxWindow* parent);
13
14 void SetDoorId(int door_id);
15
16 void Reset();
17
18 void UpdateIndicators();
19
20 private:
21 void OnPaint(wxPaintEvent& event);
22
23 int door_id_ = -1;
24
25 wxBitmap unchecked_eye_;
26 wxBitmap checked_eye_;
27 wxBitmap rendered_;
28};
29
30#endif /* end of include guard: REPORT_POPUP_H_E065BED4 */
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index 0a250fb..c554b16 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -9,6 +9,7 @@
9#include "ap_state.h" 9#include "ap_state.h"
10#include "game_data.h" 10#include "game_data.h"
11#include "global.h" 11#include "global.h"
12#include "report_popup.h"
12#include "tracker_state.h" 13#include "tracker_state.h"
13 14
14constexpr int AREA_ACTUAL_SIZE = 21; 15constexpr int AREA_ACTUAL_SIZE = 21;
@@ -31,14 +32,6 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
31 return; 32 return;
32 } 33 }
33 34
34 unchecked_eye_ =
35 wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(),
36 wxBITMAP_TYPE_PNG)
37 .Scale(32, 32));
38 checked_eye_ = wxBitmap(
39 wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG)
40 .Scale(32, 32));
41
42 tree_ = std::make_unique<quadtree::Quadtree<int, GetItemBox>>( 35 tree_ = std::make_unique<quadtree::Quadtree<int, GetItemBox>>(
43 quadtree::Box<float>{0, 0, static_cast<float>(map_image_.GetWidth()), 36 quadtree::Box<float>{0, 0, static_cast<float>(map_image_.GetWidth()),
44 static_cast<float>(map_image_.GetHeight())}); 37 static_cast<float>(map_image_.GetHeight())});
@@ -63,6 +56,8 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) {
63 help_button_ = new wxButton(this, wxID_ANY, "Help"); 56 help_button_ = new wxButton(this, wxID_ANY, "Help");
64 help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this); 57 help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this);
65 SetUpHelpButton(); 58 SetUpHelpButton();
59
60 report_popup_ = new ReportPopup(this);
66} 61}
67 62
68void SubwayMap::OnConnect() { 63void SubwayMap::OnConnect() {
@@ -202,6 +197,8 @@ void SubwayMap::UpdateIndicators() {
202 } 197 }
203 } 198 }
204 199
200 report_popup_->UpdateIndicators();
201
205 Redraw(); 202 Redraw();
206} 203}
207 204
@@ -310,67 +307,6 @@ void SubwayMap::OnPaint(wxPaintEvent &event) {
310 } 307 }
311 308
312 if (hovered_item_) { 309 if (hovered_item_) {
313 // Note that these requirements are duplicated on OnMouseClick so that it
314 // knows when an item has a hover effect.
315 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_);
316 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
317
318 if (subway_door && !GetDoorRequirements(*subway_door).empty()) {
319 const std::map<std::string, bool> &report =
320 GetDoorRequirements(*subway_door);
321
322 int acc_height = 10;
323 int col_width = 0;
324
325 for (const auto &[text, obtained] : report) {
326 wxSize item_extent = dc.GetTextExtent(text);
327 int item_height = std::max(32, item_extent.GetHeight()) + 10;
328 acc_height += item_height;
329
330 if (item_extent.GetWidth() > col_width) {
331 col_width = item_extent.GetWidth();
332 }
333 }
334
335 int item_width = col_width + 10 + 32;
336 int full_width = item_width + 20;
337
338 wxPoint popup_pos =
339 MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2,
340 subway_item.y + AREA_ACTUAL_SIZE / 2});
341
342 if (popup_pos.x + full_width > GetSize().GetWidth()) {
343 popup_pos.x = GetSize().GetWidth() - full_width;
344 }
345 if (popup_pos.y + acc_height > GetSize().GetHeight()) {
346 popup_pos.y = GetSize().GetHeight() - acc_height;
347 }
348
349 dc.SetPen(*wxTRANSPARENT_PEN);
350 dc.SetBrush(*wxBLACK_BRUSH);
351 dc.DrawRectangle(popup_pos, {full_width, acc_height});
352
353 dc.SetFont(GetFont());
354
355 int cur_height = 10;
356
357 for (const auto &[text, obtained] : report) {
358 wxBitmap *eye_ptr = obtained ? &checked_eye_ : &unchecked_eye_;
359
360 dc.DrawBitmap(*eye_ptr, popup_pos + wxPoint{10, cur_height});
361
362 dc.SetTextForeground(obtained ? *wxWHITE : *wxRED);
363 wxSize item_extent = dc.GetTextExtent(text);
364 dc.DrawText(
365 text,
366 popup_pos +
367 wxPoint{10 + 32 + 10,
368 cur_height + (32 - dc.GetFontMetrics().height) / 2});
369
370 cur_height += 10 + 32;
371 }
372 }
373
374 if (networks_.IsItemInNetwork(*hovered_item_)) { 310 if (networks_.IsItemInNetwork(*hovered_item_)) {
375 dc.SetBrush(*wxTRANSPARENT_BRUSH); 311 dc.SetBrush(*wxTRANSPARENT_BRUSH);
376 312
@@ -470,9 +406,7 @@ void SubwayMap::OnMouseMove(wxMouseEvent &event) {
470 } 406 }
471 407
472 if (!sticky_hover_ && actual_hover_ != hovered_item_) { 408 if (!sticky_hover_ && actual_hover_ != hovered_item_) {
473 hovered_item_ = actual_hover_; 409 EvaluateHover();
474
475 Refresh();
476 } 410 }
477 411
478 if (scroll_mode_) { 412 if (scroll_mode_) {
@@ -514,13 +448,11 @@ void SubwayMap::OnMouseClick(wxMouseEvent &event) {
514 if ((subway_door && !GetDoorRequirements(*subway_door).empty()) || 448 if ((subway_door && !GetDoorRequirements(*subway_door).empty()) ||
515 networks_.IsItemInNetwork(*hovered_item_)) { 449 networks_.IsItemInNetwork(*hovered_item_)) {
516 if (actual_hover_ != hovered_item_) { 450 if (actual_hover_ != hovered_item_) {
517 hovered_item_ = actual_hover_; 451 EvaluateHover();
518 452
519 if (!hovered_item_) { 453 if (!hovered_item_) {
520 sticky_hover_ = false; 454 sticky_hover_ = false;
521 } 455 }
522
523 Refresh();
524 } else { 456 } else {
525 sticky_hover_ = !sticky_hover_; 457 sticky_hover_ = !sticky_hover_;
526 } 458 }
@@ -723,6 +655,51 @@ void SubwayMap::EvaluateScroll(wxPoint pos) {
723 SetScrollSpeed(scroll_x, scroll_y); 655 SetScrollSpeed(scroll_x, scroll_y);
724} 656}
725 657
658void SubwayMap::EvaluateHover() {
659 hovered_item_ = actual_hover_;
660
661 if (hovered_item_) {
662 // Note that these requirements are duplicated on OnMouseClick so that it
663 // knows when an item has a hover effect.
664 const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_);
665 std::optional<int> subway_door = GetRealSubwayDoor(subway_item);
666
667 if (subway_door && !GetDoorRequirements(*subway_door).empty()) {
668 report_popup_->SetDoorId(*subway_door);
669
670 wxPoint popupPos =
671 MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2,
672 subway_item.y + AREA_ACTUAL_SIZE / 2});
673
674 report_popup_->SetClientSize(
675 report_popup_->GetVirtualSize().GetWidth(),
676 std::min(GetSize().GetHeight(),
677 report_popup_->GetVirtualSize().GetHeight()));
678
679 if (popupPos.x + report_popup_->GetSize().GetWidth() >
680 GetSize().GetWidth()) {
681 popupPos.x = GetSize().GetWidth() - report_popup_->GetSize().GetWidth();
682 }
683 if (popupPos.y + report_popup_->GetSize().GetHeight() >
684 GetSize().GetHeight()) {
685 popupPos.y =
686 GetSize().GetHeight() - report_popup_->GetSize().GetHeight();
687 }
688 report_popup_->SetPosition(popupPos);
689
690 report_popup_->Show();
691 } else {
692 report_popup_->Reset();
693 report_popup_->Hide();
694 }
695 } else {
696 report_popup_->Reset();
697 report_popup_->Hide();
698 }
699
700 Refresh();
701}
702
726wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { 703wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const {
727 return {static_cast<int>(pos.x * render_width_ * zoom_ / 704 return {static_cast<int>(pos.x * render_width_ * zoom_ /
728 map_image_.GetSize().GetWidth() + 705 map_image_.GetSize().GetWidth() +
diff --git a/src/subway_map.h b/src/subway_map.h index 6aa31f5..b04c2fd 100644 --- a/src/subway_map.h +++ b/src/subway_map.h
@@ -19,6 +19,8 @@
19#include "game_data.h" 19#include "game_data.h"
20#include "network_set.h" 20#include "network_set.h"
21 21
22class ReportPopup;
23
22class SubwayMap : public wxPanel { 24class SubwayMap : public wxPanel {
23 public: 25 public:
24 SubwayMap(wxWindow *parent); 26 SubwayMap(wxWindow *parent);
@@ -46,6 +48,7 @@ class SubwayMap : public wxPanel {
46 wxPoint RenderPosToMapPos(wxPoint pos) const; 48 wxPoint RenderPosToMapPos(wxPoint pos) const;
47 49
48 void EvaluateScroll(wxPoint pos); 50 void EvaluateScroll(wxPoint pos);
51 void EvaluateHover();
49 52
50 void SetZoomPos(wxPoint pos); 53 void SetZoomPos(wxPoint pos);
51 void SetScrollSpeed(int scroll_x, int scroll_y); 54 void SetScrollSpeed(int scroll_x, int scroll_y);
@@ -55,8 +58,6 @@ class SubwayMap : public wxPanel {
55 58
56 wxImage map_image_; 59 wxImage map_image_;
57 wxImage owl_image_; 60 wxImage owl_image_;
58 wxBitmap unchecked_eye_;
59 wxBitmap checked_eye_;
60 61
61 wxBitmap rendered_; 62 wxBitmap rendered_;
62 int render_x_ = 0; 63 int render_x_ = 0;
@@ -88,6 +89,8 @@ class SubwayMap : public wxPanel {
88 std::optional<int> actual_hover_; 89 std::optional<int> actual_hover_;
89 bool sticky_hover_ = false; 90 bool sticky_hover_ = false;
90 91
92 ReportPopup *report_popup_;
93
91 NetworkSet networks_; 94 NetworkSet networks_;
92 std::set<std::string> checked_paintings_; 95 std::set<std::string> checked_paintings_;
93 96