diff options
Diffstat (limited to 'src/area_popup.cpp')
| -rw-r--r-- | src/area_popup.cpp | 188 |
1 files changed, 135 insertions, 53 deletions
| diff --git a/src/area_popup.cpp b/src/area_popup.cpp index 6e70315..c95e492 100644 --- a/src/area_popup.cpp +++ b/src/area_popup.cpp | |||
| @@ -2,62 +2,68 @@ | |||
| 2 | 2 | ||
| 3 | #include <wx/dcbuffer.h> | 3 | #include <wx/dcbuffer.h> |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | |||
| 5 | #include "ap_state.h" | 7 | #include "ap_state.h" |
| 6 | #include "game_data.h" | 8 | #include "game_data.h" |
| 7 | #include "global.h" | 9 | #include "global.h" |
| 10 | #include "icons.h" | ||
| 8 | #include "tracker_config.h" | 11 | #include "tracker_config.h" |
| 12 | #include "tracker_panel.h" | ||
| 9 | #include "tracker_state.h" | 13 | #include "tracker_state.h" |
| 10 | 14 | ||
| 11 | AreaPopup::AreaPopup(wxWindow* parent, int area_id) | 15 | AreaPopup::AreaPopup(wxWindow* parent, int area_id) |
| 12 | : wxScrolledCanvas(parent, wxID_ANY), area_id_(area_id) { | 16 | : wxScrolledCanvas(parent, wxID_ANY), area_id_(area_id) { |
| 13 | SetBackgroundStyle(wxBG_STYLE_PAINT); | 17 | SetBackgroundStyle(wxBG_STYLE_PAINT); |
| 14 | 18 | ||
| 15 | unchecked_eye_ = | 19 | LoadIcons(); |
| 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 | 20 | ||
| 21 | // TODO: This is slow on high-DPI screens. | ||
| 23 | SetScrollRate(5, 5); | 22 | SetScrollRate(5, 5); |
| 24 | 23 | ||
| 25 | SetBackgroundColour(*wxBLACK); | 24 | SetBackgroundColour(*wxBLACK); |
| 26 | Hide(); | 25 | Hide(); |
| 27 | 26 | ||
| 28 | Bind(wxEVT_PAINT, &AreaPopup::OnPaint, this); | 27 | Bind(wxEVT_PAINT, &AreaPopup::OnPaint, this); |
| 28 | Bind(wxEVT_DPI_CHANGED, &AreaPopup::OnDPIChanged, this); | ||
| 29 | 29 | ||
| 30 | UpdateIndicators(); | 30 | ResetIndicators(); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | void AreaPopup::UpdateIndicators() { | 33 | void AreaPopup::ResetIndicators() { |
| 34 | indicators_.clear(); | ||
| 35 | |||
| 34 | const MapArea& map_area = GD_GetMapArea(area_id_); | 36 | const MapArea& map_area = GD_GetMapArea(area_id_); |
| 37 | wxFont the_font = GetFont().Scale(GetDPIScaleFactor()); | ||
| 38 | TrackerPanel* tracker_panel = dynamic_cast<TrackerPanel*>(GetParent()); | ||
| 35 | 39 | ||
| 36 | // Start calculating extents. | 40 | // Start calculating extents. |
| 37 | wxMemoryDC mem_dc; | 41 | wxMemoryDC mem_dc; |
| 38 | mem_dc.SetFont(GetFont().Bold()); | 42 | mem_dc.SetFont(the_font.Bold()); |
| 39 | wxSize header_extent = mem_dc.GetTextExtent(map_area.name); | 43 | header_extent_ = mem_dc.GetTextExtent(map_area.name); |
| 40 | 44 | ||
| 41 | int acc_height = header_extent.GetHeight() + 20; | 45 | int acc_height = header_extent_.GetHeight() + FromDIP(20); |
| 42 | int col_width = 0; | 46 | int col_width = 0; |
| 43 | 47 | ||
| 44 | mem_dc.SetFont(GetFont()); | 48 | mem_dc.SetFont(the_font); |
| 45 | |||
| 46 | std::vector<int> real_locations; | ||
| 47 | 49 | ||
| 48 | for (int section_id = 0; section_id < map_area.locations.size(); | 50 | for (int section_id = 0; section_id < map_area.locations.size(); |
| 49 | section_id++) { | 51 | section_id++) { |
| 50 | const Location& location = map_area.locations.at(section_id); | 52 | const Location& location = map_area.locations.at(section_id); |
| 51 | 53 | if ((!AP_IsLocationVisible(location.classification) || | |
| 52 | if (!AP_IsLocationVisible(location.classification) && | 54 | IsLocationPostgame(location.ap_location_id)) && |
| 53 | !(location.hunt && GetTrackerConfig().show_hunt_panels)) { | 55 | !(location.hunt && |
| 56 | GetTrackerConfig().visible_panels == TrackerConfig::kHUNT_PANELS) && | ||
| 57 | !(location.single_panel && | ||
| 58 | GetTrackerConfig().visible_panels == TrackerConfig::kALL_PANELS)) { | ||
| 54 | continue; | 59 | continue; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 57 | real_locations.push_back(section_id); | 62 | indicators_.emplace_back(section_id, kLOCATION, acc_height); |
| 58 | 63 | ||
| 59 | wxSize item_extent = mem_dc.GetTextExtent(location.name); | 64 | wxSize item_extent = mem_dc.GetTextExtent(location.name); |
| 60 | int item_height = std::max(32, item_extent.GetHeight()) + 10; | 65 | int item_height = |
| 66 | std::max(FromDIP(32), item_extent.GetHeight()) + FromDIP(10); | ||
| 61 | acc_height += item_height; | 67 | acc_height += item_height; |
| 62 | 68 | ||
| 63 | if (item_extent.GetWidth() > col_width) { | 69 | if (item_extent.GetWidth() > col_width) { |
| @@ -65,49 +71,107 @@ void AreaPopup::UpdateIndicators() { | |||
| 65 | } | 71 | } |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | int item_width = col_width + 10 + 32; | 74 | if (AP_IsPaintingShuffle()) { |
| 69 | int full_width = std::max(header_extent.GetWidth(), item_width) + 20; | 75 | for (int painting_id : map_area.paintings) { |
| 70 | 76 | if (IsPaintingPostgame(painting_id)) { | |
| 71 | Fit(); | 77 | continue; |
| 72 | SetVirtualSize(full_width, acc_height); | 78 | } |
| 73 | |||
| 74 | rendered_ = wxBitmap(full_width, acc_height); | ||
| 75 | mem_dc.SelectObject(rendered_); | ||
| 76 | mem_dc.SetPen(*wxTRANSPARENT_PEN); | ||
| 77 | mem_dc.SetBrush(*wxBLACK_BRUSH); | ||
| 78 | mem_dc.DrawRectangle({0, 0}, {full_width, acc_height}); | ||
| 79 | 79 | ||
| 80 | mem_dc.SetFont(GetFont().Bold()); | 80 | indicators_.emplace_back(painting_id, kPAINTING, acc_height); |
| 81 | mem_dc.SetTextForeground(*wxWHITE); | ||
| 82 | mem_dc.DrawText(map_area.name, | ||
| 83 | {(full_width - header_extent.GetWidth()) / 2, 10}); | ||
| 84 | 81 | ||
| 85 | int cur_height = header_extent.GetHeight() + 20; | 82 | const PaintingExit& painting = GD_GetPaintingExit(painting_id); |
| 83 | wxSize item_extent = mem_dc.GetTextExtent(painting.display_name); | ||
| 84 | int item_height = | ||
| 85 | std::max(FromDIP(32), item_extent.GetHeight()) + FromDIP(10); | ||
| 86 | acc_height += item_height; | ||
| 86 | 87 | ||
| 87 | mem_dc.SetFont(GetFont()); | 88 | if (item_extent.GetWidth() > col_width) { |
| 89 | col_width = item_extent.GetWidth(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 88 | 93 | ||
| 89 | for (int section_id : real_locations) { | 94 | int item_width = col_width + FromDIP(10 + 32); |
| 90 | const Location& location = map_area.locations.at(section_id); | 95 | full_width_ = std::max(header_extent_.GetWidth(), item_width) + FromDIP(20); |
| 96 | full_height_ = acc_height; | ||
| 91 | 97 | ||
| 92 | bool checked = | 98 | Fit(); |
| 93 | AP_HasCheckedGameLocation(location.ap_location_id) || | 99 | SetVirtualSize(full_width_, full_height_); |
| 94 | (location.hunt && AP_HasCheckedHuntPanel(location.ap_location_id)) || | ||
| 95 | (IsLocationWinCondition(location) && AP_HasReachedGoal()); | ||
| 96 | 100 | ||
| 97 | wxBitmap* eye_ptr = checked ? &checked_eye_ : &unchecked_eye_; | 101 | UpdateIndicators(); |
| 102 | } | ||
| 98 | 103 | ||
| 99 | mem_dc.DrawBitmap(*eye_ptr, {10, cur_height}); | 104 | void AreaPopup::UpdateIndicators() { |
| 105 | const MapArea& map_area = GD_GetMapArea(area_id_); | ||
| 106 | wxFont the_font = GetFont().Scale(GetDPIScaleFactor()); | ||
| 107 | TrackerPanel* tracker_panel = dynamic_cast<TrackerPanel*>(GetParent()); | ||
| 100 | 108 | ||
| 101 | bool reachable = IsLocationReachable(location.ap_location_id); | 109 | rendered_ = wxBitmap(full_width_, full_height_); |
| 102 | const wxColour* text_color = reachable ? wxWHITE : wxRED; | ||
| 103 | mem_dc.SetTextForeground(*text_color); | ||
| 104 | 110 | ||
| 105 | wxSize item_extent = mem_dc.GetTextExtent(location.name); | 111 | wxMemoryDC mem_dc; |
| 106 | mem_dc.DrawText( | 112 | mem_dc.SelectObject(rendered_); |
| 107 | location.name, | 113 | mem_dc.SetPen(*wxTRANSPARENT_PEN); |
| 108 | {10 + 32 + 10, cur_height + (32 - mem_dc.GetFontMetrics().height) / 2}); | 114 | mem_dc.SetBrush(*wxBLACK_BRUSH); |
| 115 | mem_dc.DrawRectangle({0, 0}, {full_width_, full_height_}); | ||
| 109 | 116 | ||
| 110 | cur_height += 10 + 32; | 117 | mem_dc.SetFont(the_font.Bold()); |
| 118 | mem_dc.SetTextForeground(*wxWHITE); | ||
| 119 | mem_dc.DrawText(map_area.name, | ||
| 120 | {(full_width_ - header_extent_.GetWidth()) / 2, FromDIP(10)}); | ||
| 121 | |||
| 122 | mem_dc.SetFont(the_font); | ||
| 123 | |||
| 124 | for (const IndicatorInfo& indicator : indicators_) { | ||
| 125 | switch (indicator.type) { | ||
| 126 | case kLOCATION: { | ||
| 127 | const Location& location = map_area.locations.at(indicator.id); | ||
| 128 | |||
| 129 | bool checked = false; | ||
| 130 | if (IsLocationWinCondition(location)) { | ||
| 131 | checked = AP_HasReachedGoal(); | ||
| 132 | } else { | ||
| 133 | checked = AP_HasCheckedGameLocation(location.ap_location_id) || | ||
| 134 | (location.single_panel && | ||
| 135 | AP_IsPanelSolved( | ||
| 136 | GD_GetPanel(*location.single_panel).solve_index)); | ||
| 137 | } | ||
| 138 | |||
| 139 | const wxBitmap* eye_ptr = checked ? checked_eye_ : unchecked_eye_; | ||
| 140 | |||
| 141 | mem_dc.DrawBitmap(*eye_ptr, {FromDIP(10), indicator.y}); | ||
| 142 | |||
| 143 | bool reachable = IsLocationReachable(location.ap_location_id); | ||
| 144 | const wxColour* text_color = reachable ? wxWHITE : wxRED; | ||
| 145 | mem_dc.SetTextForeground(*text_color); | ||
| 146 | |||
| 147 | wxSize item_extent = mem_dc.GetTextExtent(location.name); | ||
| 148 | mem_dc.DrawText( | ||
| 149 | location.name, | ||
| 150 | {FromDIP(10 + 32 + 10), | ||
| 151 | indicator.y + (FromDIP(32) - mem_dc.GetFontMetrics().height) / 2}); | ||
| 152 | |||
| 153 | break; | ||
| 154 | } | ||
| 155 | case kPAINTING: { | ||
| 156 | const PaintingExit& painting = GD_GetPaintingExit(indicator.id); | ||
| 157 | |||
| 158 | bool reachable = IsPaintingReachable(indicator.id); | ||
| 159 | const wxColour* text_color = reachable ? wxWHITE : wxRED; | ||
| 160 | mem_dc.SetTextForeground(*text_color); | ||
| 161 | |||
| 162 | bool checked = reachable && AP_IsPaintingChecked(painting.internal_id); | ||
| 163 | const wxBitmap* eye_ptr = checked ? checked_owl_ : unchecked_owl_; | ||
| 164 | mem_dc.DrawBitmap(*eye_ptr, {FromDIP(10), indicator.y}); | ||
| 165 | |||
| 166 | wxSize item_extent = mem_dc.GetTextExtent(painting.display_name); | ||
| 167 | mem_dc.DrawText( | ||
| 168 | painting.display_name, | ||
| 169 | {FromDIP(10 + 32 + 10), | ||
| 170 | indicator.y + (FromDIP(32) - mem_dc.GetFontMetrics().height) / 2}); | ||
| 171 | |||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 111 | } | 175 | } |
| 112 | } | 176 | } |
| 113 | 177 | ||
| @@ -118,3 +182,21 @@ void AreaPopup::OnPaint(wxPaintEvent& event) { | |||
| 118 | 182 | ||
| 119 | event.Skip(); | 183 | event.Skip(); |
| 120 | } | 184 | } |
| 185 | |||
| 186 | void AreaPopup::OnDPIChanged(wxDPIChangedEvent& event) { | ||
| 187 | LoadIcons(); | ||
| 188 | ResetIndicators(); | ||
| 189 | |||
| 190 | event.Skip(); | ||
| 191 | } | ||
| 192 | |||
| 193 | void AreaPopup::LoadIcons() { | ||
| 194 | unchecked_eye_ = GetTheIconCache().GetIcon("assets/unchecked.png", | ||
| 195 | FromDIP(wxSize{32, 32})); | ||
| 196 | checked_eye_ = | ||
| 197 | GetTheIconCache().GetIcon("assets/checked.png", FromDIP(wxSize{32, 32})); | ||
| 198 | unchecked_owl_ = | ||
| 199 | GetTheIconCache().GetIcon("assets/owl.png", FromDIP(wxSize{32, 32})); | ||
| 200 | checked_owl_ = GetTheIconCache().GetIcon("assets/checked_owl.png", | ||
| 201 | FromDIP(wxSize{32, 32})); | ||
| 202 | } | ||
