1 #include "PopulationPanel.h"
2
3 #include <GG/Button.h>
4
5 #include "../util/i18n.h"
6 #include "../util/Logger.h"
7 #include "../universe/UniverseObject.h"
8 #include "../universe/PopCenter.h"
9 #include "../universe/Enums.h"
10 #include "../client/human/HumanClientApp.h"
11 #include "ClientUI.h"
12 #include "CUIControls.h"
13 #include "MeterBrowseWnd.h"
14 #include "MultiIconValueIndicator.h"
15 #include "MultiMeterStatusBar.h"
16
17 namespace {
18 const int EDGE_PAD(3);
19
20 /** How big we want meter icons with respect to the current UI font size.
21 * Meters should scale along font size, but not below the size for the
22 * default 12 points font. */
MeterIconSize()23 GG::Pt MeterIconSize() {
24 const int icon_size = std::max(ClientUI::Pts(), 12) * 4/3;
25 return GG::Pt(GG::X(icon_size), GG::Y(icon_size));
26 }
27 }
28
PopulationPanel(GG::X w,int object_id)29 PopulationPanel::PopulationPanel(GG::X w, int object_id) :
30 AccordionPanel(w, GG::Y(ClientUI::Pts()*2)),
31 m_popcenter_id(object_id)
32 {}
33
CompleteConstruction()34 void PopulationPanel::CompleteConstruction() {
35 AccordionPanel::CompleteConstruction();
36 SetName("PopulationPanel");
37
38 m_expand_button->LeftPressedSignal.connect(
39 boost::bind(&PopulationPanel::ExpandCollapseButtonPressed, this));
40
41 auto pop = Objects().get<PopCenter>(m_popcenter_id);
42 if (!pop) {
43 ErrorLogger() << "Attempted to construct a PopulationPanel with an object id that is not a popcenter: " << m_popcenter_id;
44 return;
45 }
46
47 // small meter indicators - for use when panel is collapsed
48 m_meter_stats.push_back({
49 METER_POPULATION,
50 GG::Wnd::Create<StatisticIcon>(ClientUI::SpeciesIcon(pop->SpeciesName()),
51 pop->GetMeter(METER_POPULATION)->Initial(), 3, false,
52 MeterIconSize().x, MeterIconSize().y)});
53 m_meter_stats.push_back({
54 METER_HAPPINESS,
55 GG::Wnd::Create<StatisticIcon>(ClientUI::MeterIcon(METER_HAPPINESS),
56 pop->GetMeter(METER_HAPPINESS)->Initial(), 3, false,
57 MeterIconSize().x, MeterIconSize().y)});
58 m_meter_stats.push_back({
59 METER_CONSTRUCTION,
60 GG::Wnd::Create<StatisticIcon>(ClientUI::MeterIcon(METER_CONSTRUCTION),
61 pop->GetMeter(METER_CONSTRUCTION)->Initial(), 3, false,
62 MeterIconSize().x, MeterIconSize().y)});
63
64 // meter and production indicators
65 std::vector<std::pair<MeterType, MeterType>> meters;
66
67 for (auto& meter_stat : m_meter_stats) {
68 MeterType meter_type = meter_stat.first;
69
70 meter_stat.second->RightClickedSignal.connect([this, meter_type](const GG::Pt& pt) {
71 std::string meter_string = boost::lexical_cast<std::string>(meter_type);
72
73 auto popup = GG::Wnd::Create<CUIPopupMenu>(pt.x, pt.y);
74 auto pc = Objects().get<PopCenter>(m_popcenter_id);
75 if (meter_type == METER_POPULATION && pc) {
76 std::string species_name = pc->SpeciesName();
77 if (!species_name.empty()) {
78 auto zoom_species_action = [species_name]() { ClientUI::GetClientUI()->ZoomToSpecies(species_name); };
79 std::string species_label = boost::io::str(FlexibleFormat(UserString("ENC_LOOKUP")) %
80 UserString(species_name));
81 popup->AddMenuItem(GG::MenuItem(species_label, false, false, zoom_species_action));
82 }
83 }
84
85 auto pedia_meter_type_action = [meter_string]() { ClientUI::GetClientUI()->ZoomToMeterTypeArticle(meter_string); };
86 std::string popup_label = boost::io::str(FlexibleFormat(UserString("ENC_LOOKUP")) %
87 UserString(meter_string));
88 popup->AddMenuItem(GG::MenuItem(popup_label, false, false, pedia_meter_type_action));
89
90 popup->Run();
91 });
92 AttachChild(meter_stat.second);
93 meters.push_back({meter_stat.first, AssociatedMeterType(meter_stat.first)});
94 }
95
96 // attach and show meter bars and large resource indicators
97 m_multi_icon_value_indicator = GG::Wnd::Create<MultiIconValueIndicator>(Width() - 2*EDGE_PAD, m_popcenter_id, meters);
98 m_multi_meter_status_bar = GG::Wnd::Create<MultiMeterStatusBar>(Width() - 2*EDGE_PAD, m_popcenter_id, meters);
99
100 // determine if this panel has been created yet.
101 std::map<int, bool>::iterator it = s_expanded_map.find(m_popcenter_id);
102 if (it == s_expanded_map.end())
103 s_expanded_map[m_popcenter_id] = false; // if not, default to collapsed state
104
105 Refresh();
106 }
107
~PopulationPanel()108 PopulationPanel::~PopulationPanel()
109 {}
110
ExpandCollapse(bool expanded)111 void PopulationPanel::ExpandCollapse(bool expanded) {
112 if (expanded == s_expanded_map[m_popcenter_id]) return; // nothing to do
113 s_expanded_map[m_popcenter_id] = expanded;
114
115 DoLayout();
116 }
117
Update()118 void PopulationPanel::Update() {
119 // remove any old browse wnds
120 for (auto& meter_stat : m_meter_stats) {
121 meter_stat.second->ClearBrowseInfoWnd();
122 m_multi_icon_value_indicator->ClearToolTip(meter_stat.first);
123 }
124
125 auto pop = Objects().get<PopCenter>(m_popcenter_id);
126 if (!pop) {
127 ErrorLogger() << "PopulationPanel::Update couldn't get PopCenter or couldn't get UniverseObject";
128 return;
129 }
130
131 // meter bar displays population stats
132 if (m_multi_meter_status_bar)
133 m_multi_meter_status_bar->Update();
134 if (m_multi_icon_value_indicator)
135 m_multi_icon_value_indicator->Update();
136
137 // tooltips
138 for (auto& meter_stat : m_meter_stats) {
139 meter_stat.second->SetValue(pop->GetMeter(meter_stat.first)->Initial());
140
141 auto browse_wnd = GG::Wnd::Create<MeterBrowseWnd>(m_popcenter_id, meter_stat.first, AssociatedMeterType(meter_stat.first));
142 meter_stat.second->SetBrowseInfoWnd(browse_wnd);
143 m_multi_icon_value_indicator->SetToolTip(meter_stat.first, browse_wnd);
144 }
145 }
146
Refresh()147 void PopulationPanel::Refresh() {
148 for (auto& meter_stat : m_meter_stats)
149 meter_stat.second->RequirePreRender();
150
151 RequirePreRender();
152 }
153
PreRender()154 void PopulationPanel::PreRender() {
155 AccordionPanel::PreRender();
156 Update();
157 DoLayout();
158 }
159
ExpandCollapseButtonPressed()160 void PopulationPanel::ExpandCollapseButtonPressed()
161 { ExpandCollapse(!s_expanded_map[m_popcenter_id]); }
162
DoLayout()163 void PopulationPanel::DoLayout() {
164 AccordionPanel::DoLayout();
165
166 for (const auto& meter_stat : m_meter_stats)
167 DetachChild(meter_stat.second);
168
169 // detach / hide meter bars and large resource indicators
170 DetachChild(m_multi_meter_status_bar);
171 DetachChild(m_multi_icon_value_indicator);
172
173 // update size of panel and position and visibility of widgets
174 if (!s_expanded_map[m_popcenter_id]) {
175 // position and reattach icons to be shown
176 int n = 0;
177 GG::X stride = MeterIconSize().x * 7/2;
178 for (const auto& meter_stat : m_meter_stats) {
179 GG::X x = n * stride;
180
181 auto& icon = meter_stat.second;
182 GG::Pt icon_ul(x, GG::Y0);
183 GG::Pt icon_lr = icon_ul + MeterIconSize();
184 icon->SizeMove(icon_ul, icon_lr);
185
186 if (x + icon->MinUsableSize().x >= ClientWidth())
187 break;
188
189 AttachChild(icon);
190 icon->Show();
191
192 n++;
193 }
194
195 Resize(GG::Pt(Width(), std::max(MeterIconSize().y, m_expand_button->Height())));
196 } else if (m_multi_icon_value_indicator && m_multi_meter_status_bar) {
197 // attach and show meter bars and large resource indicators
198 GG::Y top = Top();
199
200 AttachChild(m_multi_icon_value_indicator);
201 m_multi_icon_value_indicator->MoveTo(GG::Pt(GG::X(EDGE_PAD), GG::Y(EDGE_PAD)));
202 m_multi_icon_value_indicator->Resize(GG::Pt(Width() - 2*EDGE_PAD, m_multi_icon_value_indicator->Height()));
203
204 AttachChild(m_multi_meter_status_bar);
205 m_multi_meter_status_bar->MoveTo(GG::Pt(GG::X(EDGE_PAD), m_multi_icon_value_indicator->Bottom() + EDGE_PAD - top));
206 m_multi_meter_status_bar->Resize(GG::Pt(Width() - 2*EDGE_PAD, m_multi_meter_status_bar->Height()));
207
208 MoveChildUp(m_expand_button);
209
210 Resize(GG::Pt(Width(), m_multi_meter_status_bar->Bottom() + EDGE_PAD - top));
211 }
212
213 SetCollapsed(!s_expanded_map[m_popcenter_id]);
214 }
215
216 std::map<int, bool> PopulationPanel::s_expanded_map;
217