1 #include "MilitaryPanel.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/Planet.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
MilitaryPanel(GG::X w,int planet_id)29 MilitaryPanel::MilitaryPanel(GG::X w, int planet_id) :
30 AccordionPanel(w, GG::Y(ClientUI::Pts()*2)),
31 m_planet_id(planet_id)
32 {}
33
CompleteConstruction()34 void MilitaryPanel::CompleteConstruction() {
35 AccordionPanel::CompleteConstruction();
36
37 SetName("MilitaryPanel");
38
39 auto planet = Objects().get<Planet>(m_planet_id);
40 if (!planet)
41 throw std::invalid_argument("Attempted to construct a MilitaryPanel with an object id is not a Planet");
42
43 m_expand_button->LeftPressedSignal.connect(
44 boost::bind(&MilitaryPanel::ExpandCollapseButtonPressed, this));
45
46 const auto obj = Objects().get(m_planet_id);
47 if (!obj) {
48 ErrorLogger() << "Invalid object id " << m_planet_id;
49 return;
50 }
51
52 // meter and production indicators
53 std::vector<std::pair<MeterType, MeterType>> meters;
54
55 // small meter indicators - for use when panel is collapsed
56 for (MeterType meter : {METER_SHIELD, METER_DEFENSE, METER_TROOPS, METER_DETECTION, METER_STEALTH}) {
57 auto stat = GG::Wnd::Create<StatisticIcon>(
58 ClientUI::MeterIcon(meter), obj->GetMeter(meter)->Initial(),
59 3, false, MeterIconSize().x, MeterIconSize().y);
60 AttachChild(stat);
61 m_meter_stats.push_back({meter, stat});
62 meters.push_back({meter, AssociatedMeterType(meter)});
63 stat->RightClickedSignal.connect([meter](const GG::Pt& pt) {
64 std::string meter_string = boost::lexical_cast<std::string>(meter);
65
66 auto zoom_action = [meter_string]() { ClientUI::GetClientUI()->ZoomToMeterTypeArticle(meter_string); };
67
68 auto popup = GG::Wnd::Create<CUIPopupMenu>(pt.x, pt.y);
69 std::string popup_label = boost::io::str(FlexibleFormat(UserString("ENC_LOOKUP")) %
70 UserString(meter_string));
71 popup->AddMenuItem(GG::MenuItem(popup_label, false, false, zoom_action));
72 popup->Run();
73 });
74 }
75
76 // attach and show meter bars and large resource indicators
77 m_multi_meter_status_bar = GG::Wnd::Create<MultiMeterStatusBar>(Width() - 2*EDGE_PAD, m_planet_id, meters);
78 m_multi_icon_value_indicator = GG::Wnd::Create<MultiIconValueIndicator>(Width() - 2*EDGE_PAD, m_planet_id, meters);
79
80 // determine if this panel has been created yet.
81 auto it = s_expanded_map.find(m_planet_id);
82 if (it == s_expanded_map.end())
83 s_expanded_map[m_planet_id] = false; // if not, default to collapsed state
84
85 Refresh();
86 }
87
~MilitaryPanel()88 MilitaryPanel::~MilitaryPanel()
89 {}
90
ExpandCollapse(bool expanded)91 void MilitaryPanel::ExpandCollapse(bool expanded) {
92 if (expanded == s_expanded_map[m_planet_id]) return; // nothing to do
93 s_expanded_map[m_planet_id] = expanded;
94
95 DoLayout();
96 }
97
Update()98 void MilitaryPanel::Update() {
99 auto obj = Objects().get(m_planet_id);
100 if (!obj) {
101 ErrorLogger() << "MilitaryPanel::Update coudln't get object with id " << m_planet_id;
102 return;
103 }
104
105 // meter bar displays military stats
106 m_multi_meter_status_bar->Update();
107 m_multi_icon_value_indicator->Update();
108
109 // tooltips
110 for (auto& meter_stat : m_meter_stats) {
111 meter_stat.second->SetValue(obj->GetMeter(meter_stat.first)->Initial());
112
113 auto browse_wnd = GG::Wnd::Create<MeterBrowseWnd>(m_planet_id, meter_stat.first, AssociatedMeterType(meter_stat.first));
114 meter_stat.second->SetBrowseInfoWnd(browse_wnd);
115 m_multi_icon_value_indicator->SetToolTip(meter_stat.first, browse_wnd);
116 }
117 }
118
Refresh()119 void MilitaryPanel::Refresh() {
120 for (auto& meter_stat : m_meter_stats)
121 meter_stat.second->RequirePreRender();
122
123 RequirePreRender();
124 }
125
PreRender()126 void MilitaryPanel::PreRender() {
127 AccordionPanel::PreRender();
128 Update();
129 DoLayout();
130 }
131
ExpandCollapseButtonPressed()132 void MilitaryPanel::ExpandCollapseButtonPressed()
133 { ExpandCollapse(!s_expanded_map[m_planet_id]); }
134
DoLayout()135 void MilitaryPanel::DoLayout() {
136 AccordionPanel::DoLayout();
137
138 for (auto& meter_stat : m_meter_stats) {
139 DetachChild(meter_stat.second);
140 }
141
142 // detach / hide meter bars and large resource indicators
143 DetachChild(m_multi_meter_status_bar);
144 DetachChild(m_multi_icon_value_indicator);
145
146 // update size of panel and position and visibility of widgets
147 if (!s_expanded_map[m_planet_id]) {
148 // position and reattach icons to be shown
149 int n = 0;
150 GG::X stride = MeterIconSize().x * 7/2;
151 for (auto& meter_stat : m_meter_stats) {
152 GG::X x = n * stride;
153
154 auto& icon = meter_stat.second;
155 GG::Pt icon_ul(x, GG::Y0);
156 GG::Pt icon_lr = icon_ul + MeterIconSize();
157 icon->SizeMove(icon_ul, icon_lr);
158
159 if (x + icon->MinUsableSize().x >= ClientWidth())
160 break;
161
162 AttachChild(icon);
163 icon->Show();
164
165 n++;
166 }
167
168 Resize(GG::Pt(Width(), std::max(MeterIconSize().y, m_expand_button->Height())));
169 } else {
170 // attach and show meter bars and large resource indicators
171 GG::Y top = Top();
172
173 AttachChild(m_multi_icon_value_indicator);
174 m_multi_icon_value_indicator->MoveTo(GG::Pt(GG::X(EDGE_PAD), GG::Y(EDGE_PAD)));
175 m_multi_icon_value_indicator->Resize(GG::Pt(Width() - 2*EDGE_PAD, m_multi_icon_value_indicator->Height()));
176
177 AttachChild(m_multi_meter_status_bar);
178 m_multi_meter_status_bar->MoveTo(GG::Pt(GG::X(EDGE_PAD), m_multi_icon_value_indicator->Bottom() + EDGE_PAD - top));
179 m_multi_meter_status_bar->Resize(GG::Pt(Width() - 2*EDGE_PAD, m_multi_meter_status_bar->Height()));
180
181 MoveChildUp(m_expand_button);
182
183 Resize(GG::Pt(Width(), m_multi_meter_status_bar->Bottom() + EDGE_PAD - top));
184 }
185
186 SetCollapsed(!s_expanded_map[m_planet_id]);
187 }
188
189 std::map<int, bool> MilitaryPanel::s_expanded_map;
190