diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/report_popup.cpp | 98 | ||||
| -rw-r--r-- | src/report_popup.h | 30 | ||||
| -rw-r--r-- | src/subway_map.cpp | 127 | ||||
| -rw-r--r-- | src/subway_map.h | 7 |
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 | ) |
| 56 | set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20) | 57 | set_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 | |||
| 11 | ReportPopup::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 | |||
| 31 | void ReportPopup::SetDoorId(int door_id) { | ||
| 32 | door_id_ = door_id; | ||
| 33 | |||
| 34 | UpdateIndicators(); | ||
| 35 | } | ||
| 36 | |||
| 37 | void ReportPopup::Reset() { | ||
| 38 | door_id_ = -1; | ||
| 39 | } | ||
| 40 | |||
| 41 | void 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 | |||
| 90 | void 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 | |||
| 10 | class 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 | ||
| 14 | constexpr int AREA_ACTUAL_SIZE = 21; | 15 | constexpr 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 | ||
| 68 | void SubwayMap::OnConnect() { | 63 | void 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 | ||
| 658 | void 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 | |||
| 726 | wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { | 703 | wxPoint 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 | ||
| 22 | class ReportPopup; | ||
| 23 | |||
| 22 | class SubwayMap : public wxPanel { | 24 | class 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 | ||
