1 /*
2 * Copyright (C) 2011-2020 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "wui/portdockwaresdisplay.h"
21
22 #include "economy/expedition_bootstrap.h"
23 #include "economy/portdock.h"
24 #include "logic/player.h"
25 #include "ui_basic/icon.h"
26 #include "wui/inputqueuedisplay.h"
27
28 using Widelands::InputQueue;
29 using Widelands::PortDock;
30 using Widelands::Warehouse;
31
32 namespace {
33
34 /**
35 * Display wares or workers that are waiting to be shipped from a port.
36 */
37 struct PortDockWaresDisplay : AbstractWaresDisplay {
38 PortDockWaresDisplay(Panel* parent,
39 uint32_t width,
40 const PortDock& pd,
41 Widelands::WareWorker type);
42
43 std::string info_for_ware(Widelands::DescriptionIndex ware) override;
44
45 private:
46 const PortDock& portdock_;
47 };
48
PortDockWaresDisplay(Panel * parent,uint32_t width,const PortDock & pd,Widelands::WareWorker type)49 PortDockWaresDisplay::PortDockWaresDisplay(Panel* parent,
50 uint32_t width,
51 const PortDock& pd,
52 Widelands::WareWorker type)
53 : AbstractWaresDisplay(parent, 0, 0, pd.owner().tribe(), type, false), portdock_(pd) {
54 set_inner_size(width, 0);
55 }
56
info_for_ware(Widelands::DescriptionIndex ware)57 std::string PortDockWaresDisplay::info_for_ware(Widelands::DescriptionIndex ware) {
58 const uint32_t count = portdock_.count_waiting(get_type(), ware);
59 return boost::lexical_cast<std::string>(count);
60 }
61
62 } // anonymous namespace
63
64 /**
65 * Create a panel that displays the wares or workers that are waiting to be shipped from a port.
66 */
create_portdock_wares_display(UI::Panel * parent,uint32_t width,const PortDock & pd,Widelands::WareWorker type)67 AbstractWaresDisplay* create_portdock_wares_display(UI::Panel* parent,
68 uint32_t width,
69 const PortDock& pd,
70 Widelands::WareWorker type) {
71 return new PortDockWaresDisplay(parent, width, pd, type);
72 }
73
74 static char const* kPicWarePresent = "images/wui/buildings/high_priority_button.png";
75 static char const* kPicWareComing = "images/wui/buildings/normal_priority_button.png";
76 static char const* kPicWareMissing = "images/wui/buildings/low_priority_button.png";
77 static char const* kNoWare = "images/wui/editor/no_ware.png";
78 static const auto kEmptySlot = std::make_pair(Widelands::wwWARE, Widelands::INVALID_INDEX);
79
80 struct PortDockAdditionalItemsDisplay : UI::Box {
81 public:
PortDockAdditionalItemsDisplayPortDockAdditionalItemsDisplay82 PortDockAdditionalItemsDisplay(
83 Widelands::Game& g, Panel* parent, bool can_act, PortDock& pd, const uint32_t capacity)
84 : UI::Box(parent, 0, 0, UI::Box::Horizontal), game_(g), portdock_(pd), capacity_(capacity) {
85 assert(capacity_ > 0);
86 assert(portdock_.expedition_bootstrap());
87 assert(portdock_.expedition_bootstrap()->count_additional_queues() <= capacity_);
88 for (uint32_t c = 0; c < capacity_; ++c) {
89 UI::Box* box = new UI::Box(this, 0, 0, UI::Box::Vertical);
90
91 UI::Dropdown<std::pair<Widelands::WareWorker, Widelands::DescriptionIndex>>& d =
92 *new UI::Dropdown<std::pair<Widelands::WareWorker, Widelands::DescriptionIndex>>(
93 box, (boost::format("additional_%u") % c).str(), 0, 0, kWareMenuPicWidth, 8,
94 kWareMenuPicHeight, _("Additional item"), UI::DropdownType::kPictorial,
95 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiSecondary);
96 d.add(_("(Empty)"), kEmptySlot, g_gr->images().get(kNoWare), true, _("(Empty)"));
97 for (Widelands::DescriptionIndex i : pd.owner().tribe().wares()) {
98 const Widelands::WareDescr& w = *pd.owner().tribe().get_ware_descr(i);
99 d.add(
100 w.descname(), std::make_pair(Widelands::wwWARE, i), w.icon(), false, w.descname());
101 }
102 for (Widelands::DescriptionIndex i : pd.owner().tribe().workers()) {
103 const Widelands::WorkerDescr& w = *pd.owner().tribe().get_worker_descr(i);
104 d.add(
105 w.descname(), std::make_pair(Widelands::wwWORKER, i), w.icon(), false, w.descname());
106 }
107 d.set_enabled(can_act);
108 d.selected.connect([this, c]() { select(c); });
109
110 UI::Icon* icon = new UI::Icon(box, g_gr->images().get(kNoWare));
111 icon->set_handle_mouse(true);
112 boxes_.push_back(box);
113 icons_.push_back(icon);
114 dropdowns_.push_back(&d);
115 box->add(&d);
116 box->add(icon);
117 add(box);
118 }
119 update_selection();
120 }
121
thinkPortDockAdditionalItemsDisplay122 void think() override {
123 UI::Box::think();
124 if (!portdock_.expedition_bootstrap()) {
125 return die();
126 }
127 update_selection();
128
129 for (uint32_t c = 0; c < capacity_; ++c) {
130 const InputQueue* iq = portdock_.expedition_bootstrap()->inputqueue(c);
131 assert(!iq || (iq->get_max_size() == 1 && iq->get_max_fill() == 1));
132 icons_[c]->set_icon(g_gr->images().get(
133 iq ?
134 iq->get_filled() ? kPicWarePresent : iq->get_missing() ? kPicWareMissing :
135 kPicWareComing :
136 kNoWare));
137 icons_[c]->set_tooltip(
138 iq ?
139 iq->get_filled() ?
140 /** TRANSLATORS: Tooltip for a ware that is present in the building */
141 _("Present") :
142 iq->get_missing() ?
143 /** TRANSLATORS: Tooltip for a ware that is neither present in the
144 building nor being transported there */
145 _("Missing") :
146 /** TRANSLATORS: Tooltip for a ware that is not present in the
147 building, but already being transported there */
148 _("Coming") :
149 "");
150 }
151 }
152
update_selectionPortDockAdditionalItemsDisplay153 void update_selection() {
154 for (uint32_t c = 0; c < capacity_; ++c) {
155 if (dropdowns_[c]->is_expanded()) {
156 continue;
157 }
158 const InputQueue* iq = portdock_.expedition_bootstrap()->inputqueue(c);
159 if (!iq) {
160 dropdowns_[c]->select(kEmptySlot);
161 } else {
162 dropdowns_[c]->select(std::make_pair(iq->get_type(), iq->get_index()));
163 }
164 assert(dropdowns_[c]->has_selection());
165 }
166 }
167
selectPortDockAdditionalItemsDisplay168 void select(uint32_t index) {
169 assert(index < dropdowns_.size());
170 const auto& new_sel = dropdowns_[index]->get_selected();
171 const InputQueue* iq = portdock_.expedition_bootstrap()->inputqueue(index);
172 if (new_sel.second == Widelands::INVALID_INDEX && !iq) {
173 return;
174 }
175 if (iq && iq->get_type() == new_sel.first && iq->get_index() == new_sel.second) {
176 return;
177 }
178 if (iq) {
179 game_.send_player_expedition_config(portdock_, iq->get_type(), iq->get_index(), false);
180 }
181 if (new_sel.second != Widelands::INVALID_INDEX) {
182 game_.send_player_expedition_config(portdock_, new_sel.first, new_sel.second, true);
183 }
184 }
185
186 private:
187 Widelands::Game& game_;
188 PortDock& portdock_;
189 uint32_t capacity_;
190 std::vector<UI::Box*> boxes_;
191 std::vector<UI::Icon*> icons_;
192 std::vector<UI::Dropdown<std::pair<Widelands::WareWorker, Widelands::DescriptionIndex>>*>
193 dropdowns_;
194 };
195
196 /// Create a panel that displays the wares and the builder waiting for the expedition to start.
197 UI::Box*
create_portdock_expedition_display(UI::Panel * parent,Warehouse & wh,InteractiveGameBase & igb)198 create_portdock_expedition_display(UI::Panel* parent, Warehouse& wh, InteractiveGameBase& igb) {
199 UI::Box& box = *new UI::Box(parent, 0, 0, UI::Box::Vertical);
200
201 // Add the input queues.
202 int32_t capacity =
203 igb.egbase().tribes().get_ship_descr(wh.get_owner()->tribe().ship())->get_default_capacity();
204 for (const InputQueue* wq : wh.get_portdock()->expedition_bootstrap()->queues(false)) {
205 InputQueueDisplay* iqd = new InputQueueDisplay(&box, 0, 0, igb, wh, *wq, true);
206 box.add(iqd);
207 capacity -= wq->get_max_size();
208 }
209 assert(capacity >= 0);
210
211 if (capacity > 0) {
212 const bool can_act = igb.can_act(wh.get_owner()->player_number());
213 box.add(new PortDockAdditionalItemsDisplay(
214 igb.game(), &box, can_act, *wh.get_portdock(), capacity),
215 UI::Box::Resizing::kAlign, UI::Align::kCenter);
216 }
217
218 return &box;
219 }
220