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