From 712313d825db7ce7c9d4457f7564b27d3dd4ce64 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 8 Feb 2025 15:11:23 -0500 Subject: Added a scrollbar to subway reports --- src/report_popup.cpp | 98 +++++++++++++++++++++++++++++++++++++++ src/report_popup.h | 30 ++++++++++++ src/subway_map.cpp | 127 +++++++++++++++++++++------------------------------ src/subway_map.h | 7 ++- 4 files changed, 185 insertions(+), 77 deletions(-) create mode 100644 src/report_popup.cpp create mode 100644 src/report_popup.h (limited to 'src') 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 @@ +#include "report_popup.h" + +#include + +#include +#include + +#include "global.h" +#include "tracker_state.h" + +ReportPopup::ReportPopup(wxWindow* parent) + : wxScrolledCanvas(parent, wxID_ANY) { + SetBackgroundStyle(wxBG_STYLE_PAINT); + + unchecked_eye_ = + wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(), + wxBITMAP_TYPE_PNG) + .Scale(32, 32)); + checked_eye_ = wxBitmap( + wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG) + .Scale(32, 32)); + + SetScrollRate(5, 5); + + SetBackgroundColour(*wxBLACK); + Hide(); + + Bind(wxEVT_PAINT, &ReportPopup::OnPaint, this); +} + +void ReportPopup::SetDoorId(int door_id) { + door_id_ = door_id; + + UpdateIndicators(); +} + +void ReportPopup::Reset() { + door_id_ = -1; +} + +void ReportPopup::UpdateIndicators() { + wxMemoryDC mem_dc; + + const std::map& report = GetDoorRequirements(door_id_); + + int acc_height = 10; + int col_width = 0; + + for (const auto& [text, obtained] : report) { + wxSize item_extent = mem_dc.GetTextExtent(text); + int item_height = std::max(32, item_extent.GetHeight()) + 10; + acc_height += item_height; + + if (item_extent.GetWidth() > col_width) { + col_width = item_extent.GetWidth(); + } + } + + int item_width = col_width + 10 + 32; + int full_width = item_width + 20; + + Fit(); + SetVirtualSize(full_width, acc_height); + + rendered_ = wxBitmap(full_width, acc_height); + mem_dc.SelectObject(rendered_); + mem_dc.SetPen(*wxTRANSPARENT_PEN); + mem_dc.SetBrush(*wxBLACK_BRUSH); + mem_dc.DrawRectangle({0, 0}, {full_width, acc_height}); + + mem_dc.SetFont(GetFont()); + + int cur_height = 10; + + for (const auto& [text, obtained] : report) { + wxBitmap* eye_ptr = obtained ? &checked_eye_ : &unchecked_eye_; + + mem_dc.DrawBitmap(*eye_ptr, wxPoint{10, cur_height}); + + mem_dc.SetTextForeground(obtained ? *wxWHITE : *wxRED); + wxSize item_extent = mem_dc.GetTextExtent(text); + mem_dc.DrawText( + text, wxPoint{10 + 32 + 10, + cur_height + (32 - mem_dc.GetFontMetrics().height) / 2}); + + cur_height += 10 + 32; + } +} + +void ReportPopup::OnPaint(wxPaintEvent& event) { + if (door_id_ != -1) { + wxBufferedPaintDC dc(this); + PrepareDC(dc); + dc.DrawBitmap(rendered_, 0, 0); + } + + event.Skip(); +} 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 @@ +#ifndef REPORT_POPUP_H_E065BED4 +#define REPORT_POPUP_H_E065BED4 + +#include + +#ifndef WX_PRECOMP +#include +#endif + +class ReportPopup : public wxScrolledCanvas { + public: + explicit ReportPopup(wxWindow* parent); + + void SetDoorId(int door_id); + + void Reset(); + + void UpdateIndicators(); + + private: + void OnPaint(wxPaintEvent& event); + + int door_id_ = -1; + + wxBitmap unchecked_eye_; + wxBitmap checked_eye_; + wxBitmap rendered_; +}; + +#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 @@ #include "ap_state.h" #include "game_data.h" #include "global.h" +#include "report_popup.h" #include "tracker_state.h" constexpr int AREA_ACTUAL_SIZE = 21; @@ -31,14 +32,6 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { return; } - unchecked_eye_ = - wxBitmap(wxImage(GetAbsolutePath("assets/unchecked.png").c_str(), - wxBITMAP_TYPE_PNG) - .Scale(32, 32)); - checked_eye_ = wxBitmap( - wxImage(GetAbsolutePath("assets/checked.png").c_str(), wxBITMAP_TYPE_PNG) - .Scale(32, 32)); - tree_ = std::make_unique>( quadtree::Box{0, 0, static_cast(map_image_.GetWidth()), static_cast(map_image_.GetHeight())}); @@ -63,6 +56,8 @@ SubwayMap::SubwayMap(wxWindow *parent) : wxPanel(parent, wxID_ANY) { help_button_ = new wxButton(this, wxID_ANY, "Help"); help_button_->Bind(wxEVT_BUTTON, &SubwayMap::OnClickHelp, this); SetUpHelpButton(); + + report_popup_ = new ReportPopup(this); } void SubwayMap::OnConnect() { @@ -202,6 +197,8 @@ void SubwayMap::UpdateIndicators() { } } + report_popup_->UpdateIndicators(); + Redraw(); } @@ -310,67 +307,6 @@ void SubwayMap::OnPaint(wxPaintEvent &event) { } if (hovered_item_) { - // Note that these requirements are duplicated on OnMouseClick so that it - // knows when an item has a hover effect. - const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_); - std::optional subway_door = GetRealSubwayDoor(subway_item); - - if (subway_door && !GetDoorRequirements(*subway_door).empty()) { - const std::map &report = - GetDoorRequirements(*subway_door); - - int acc_height = 10; - int col_width = 0; - - for (const auto &[text, obtained] : report) { - wxSize item_extent = dc.GetTextExtent(text); - int item_height = std::max(32, item_extent.GetHeight()) + 10; - acc_height += item_height; - - if (item_extent.GetWidth() > col_width) { - col_width = item_extent.GetWidth(); - } - } - - int item_width = col_width + 10 + 32; - int full_width = item_width + 20; - - wxPoint popup_pos = - MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2, - subway_item.y + AREA_ACTUAL_SIZE / 2}); - - if (popup_pos.x + full_width > GetSize().GetWidth()) { - popup_pos.x = GetSize().GetWidth() - full_width; - } - if (popup_pos.y + acc_height > GetSize().GetHeight()) { - popup_pos.y = GetSize().GetHeight() - acc_height; - } - - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(*wxBLACK_BRUSH); - dc.DrawRectangle(popup_pos, {full_width, acc_height}); - - dc.SetFont(GetFont()); - - int cur_height = 10; - - for (const auto &[text, obtained] : report) { - wxBitmap *eye_ptr = obtained ? &checked_eye_ : &unchecked_eye_; - - dc.DrawBitmap(*eye_ptr, popup_pos + wxPoint{10, cur_height}); - - dc.SetTextForeground(obtained ? *wxWHITE : *wxRED); - wxSize item_extent = dc.GetTextExtent(text); - dc.DrawText( - text, - popup_pos + - wxPoint{10 + 32 + 10, - cur_height + (32 - dc.GetFontMetrics().height) / 2}); - - cur_height += 10 + 32; - } - } - if (networks_.IsItemInNetwork(*hovered_item_)) { dc.SetBrush(*wxTRANSPARENT_BRUSH); @@ -470,9 +406,7 @@ void SubwayMap::OnMouseMove(wxMouseEvent &event) { } if (!sticky_hover_ && actual_hover_ != hovered_item_) { - hovered_item_ = actual_hover_; - - Refresh(); + EvaluateHover(); } if (scroll_mode_) { @@ -514,13 +448,11 @@ void SubwayMap::OnMouseClick(wxMouseEvent &event) { if ((subway_door && !GetDoorRequirements(*subway_door).empty()) || networks_.IsItemInNetwork(*hovered_item_)) { if (actual_hover_ != hovered_item_) { - hovered_item_ = actual_hover_; + EvaluateHover(); if (!hovered_item_) { sticky_hover_ = false; } - - Refresh(); } else { sticky_hover_ = !sticky_hover_; } @@ -723,6 +655,51 @@ void SubwayMap::EvaluateScroll(wxPoint pos) { SetScrollSpeed(scroll_x, scroll_y); } +void SubwayMap::EvaluateHover() { + hovered_item_ = actual_hover_; + + if (hovered_item_) { + // Note that these requirements are duplicated on OnMouseClick so that it + // knows when an item has a hover effect. + const SubwayItem &subway_item = GD_GetSubwayItem(*hovered_item_); + std::optional subway_door = GetRealSubwayDoor(subway_item); + + if (subway_door && !GetDoorRequirements(*subway_door).empty()) { + report_popup_->SetDoorId(*subway_door); + + wxPoint popupPos = + MapPosToRenderPos({subway_item.x + AREA_ACTUAL_SIZE / 2, + subway_item.y + AREA_ACTUAL_SIZE / 2}); + + report_popup_->SetClientSize( + report_popup_->GetVirtualSize().GetWidth(), + std::min(GetSize().GetHeight(), + report_popup_->GetVirtualSize().GetHeight())); + + if (popupPos.x + report_popup_->GetSize().GetWidth() > + GetSize().GetWidth()) { + popupPos.x = GetSize().GetWidth() - report_popup_->GetSize().GetWidth(); + } + if (popupPos.y + report_popup_->GetSize().GetHeight() > + GetSize().GetHeight()) { + popupPos.y = + GetSize().GetHeight() - report_popup_->GetSize().GetHeight(); + } + report_popup_->SetPosition(popupPos); + + report_popup_->Show(); + } else { + report_popup_->Reset(); + report_popup_->Hide(); + } + } else { + report_popup_->Reset(); + report_popup_->Hide(); + } + + Refresh(); +} + wxPoint SubwayMap::MapPosToRenderPos(wxPoint pos) const { return {static_cast(pos.x * render_width_ * zoom_ / 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 @@ #include "game_data.h" #include "network_set.h" +class ReportPopup; + class SubwayMap : public wxPanel { public: SubwayMap(wxWindow *parent); @@ -46,6 +48,7 @@ class SubwayMap : public wxPanel { wxPoint RenderPosToMapPos(wxPoint pos) const; void EvaluateScroll(wxPoint pos); + void EvaluateHover(); void SetZoomPos(wxPoint pos); void SetScrollSpeed(int scroll_x, int scroll_y); @@ -55,8 +58,6 @@ class SubwayMap : public wxPanel { wxImage map_image_; wxImage owl_image_; - wxBitmap unchecked_eye_; - wxBitmap checked_eye_; wxBitmap rendered_; int render_x_ = 0; @@ -88,6 +89,8 @@ class SubwayMap : public wxPanel { std::optional actual_hover_; bool sticky_hover_ = false; + ReportPopup *report_popup_; + NetworkSet networks_; std::set checked_paintings_; -- cgit 1.4.1