1 #include "QueueListBox.h"
2
3 #include "../util/i18n.h"
4 #include "../util/Logger.h"
5
6 #include <GG/WndEvent.h>
7
8 #include <boost/cast.hpp>
9
10 ////////////////////////////////////////////////////////////
11 // PromptRow
12 ////////////////////////////////////////////////////////////
PromptRow(GG::X w,const std::string & prompt)13 PromptRow::PromptRow(GG::X w, const std::string& prompt) :
14 GG::ListBox::Row(w, GG::Y(20)),
15 m_prompt(
16 GG::Wnd::Create<CUILabel>(
17 prompt,
18 GG::FORMAT_TOP | GG::FORMAT_LEFT | GG::FORMAT_LINEWRAP | GG::FORMAT_WORDBREAK))
19 {}
20
CompleteConstruction()21 void PromptRow::CompleteConstruction() {
22 GG::ListBox::Row::CompleteConstruction();
23
24 m_prompt->MoveTo(GG::Pt(GG::X(2), GG::Y(2)));
25 m_prompt->Resize(GG::Pt(Width() - 10, Height()));
26 m_prompt->SetTextColor(GG::LightenClr(ClientUI::TextColor()));
27 m_prompt->ClipText(true);
28 Resize(GG::Pt(Width(), m_prompt->Height()));
29 push_back(m_prompt);
30 }
31
SizeMove(const GG::Pt & ul,const GG::Pt & lr)32 void PromptRow::SizeMove(const GG::Pt& ul, const GG::Pt& lr) {
33 const GG::Pt old_size = Size();
34 GG::ListBox::Row::SizeMove(ul, lr);
35 if (!empty() && old_size != Size() && m_prompt)
36 m_prompt->Resize(Size());
37 }
38
39
40 ////////////////////////////////////////////////////////////
41 // QueueListBox
42 ////////////////////////////////////////////////////////////
QueueListBox(const boost::optional<std::string> & drop_type_str,const std::string & prompt_str)43 QueueListBox::QueueListBox(const boost::optional<std::string>& drop_type_str, const std::string& prompt_str) :
44 CUIListBox(),
45 m_drop_point(end()),
46 m_show_drop_point(false),
47 m_order_issuing_enabled(true),
48 m_showing_prompt(false),
49 m_prompt_str(prompt_str)
50 {
51 if (drop_type_str)
52 AllowDropType(*drop_type_str);
53 }
54
CompleteConstruction()55 void QueueListBox::CompleteConstruction() {
56 CUIListBox::CompleteConstruction();
57
58 SetNumCols(1);
59 ManuallyManageColProps();
60 NormalizeRowsOnInsert(false);
61
62 ShowPromptSlot();
63
64 #if BOOST_VERSION >= 106000
65 using boost::placeholders::_1;
66 using boost::placeholders::_2;
67 using boost::placeholders::_3;
68 #endif
69
70 BeforeInsertRowSignal.connect(
71 boost::bind(&QueueListBox::EnsurePromptHiddenSlot, this, _1));
72 AfterEraseRowSignal.connect(
73 boost::bind(&QueueListBox::ShowPromptConditionallySlot, this, _1));
74 ClearedRowsSignal.connect(
75 boost::bind(&QueueListBox::ShowPromptSlot, this));
76 GG::ListBox::RightClickedRowSignal.connect(
77 boost::bind(&QueueListBox::ItemRightClicked, this, _1, _2, _3));
78 }
79
RowWidth() const80 GG::X QueueListBox::RowWidth() const
81 { return ClientWidth(); }
82
KeyPress(GG::Key key,std::uint32_t key_code_point,GG::Flags<GG::ModKey> mod_keys)83 void QueueListBox::KeyPress(GG::Key key, std::uint32_t key_code_point, GG::Flags<GG::ModKey> mod_keys)
84 {
85 if (Disabled()) {
86 CUIListBox::KeyPress(key, key_code_point, mod_keys);
87 return;
88 }
89 if (key == GG::GGK_DELETE) {
90 QueueListBox::iterator it = Caret();
91 if (it == end())
92 return;
93 QueueItemDeletedSignal(it);
94 } else {
95 CUIListBox::KeyPress(key, key_code_point, mod_keys);
96 }
97 }
98
AcceptDrops(const GG::Pt & pt,std::vector<std::shared_ptr<GG::Wnd>> wnds,GG::Flags<GG::ModKey> mod_keys)99 void QueueListBox::AcceptDrops(const GG::Pt& pt, std::vector<std::shared_ptr<GG::Wnd>> wnds, GG::Flags<GG::ModKey> mod_keys) {
100 if (wnds.size() > 1)
101 ErrorLogger() << "QueueListBox::AcceptDrops given multiple wnds unexpectedly...";
102 auto& wnd = *wnds.begin();
103 const std::string& drop_type = wnd->DragDropDataType();
104 const auto& row = std::dynamic_pointer_cast<GG::ListBox::Row>(wnd);
105 if (!AllowedDropType(drop_type) ||
106 !row ||
107 !std::count(begin(), end(), row))
108 {
109 return;
110 }
111 ListBox::AcceptDrops(pt, std::vector<std::shared_ptr<GG::Wnd>>{wnd}, mod_keys);
112 }
113
Render()114 void QueueListBox::Render() {
115 ListBox::Render();
116 // render drop point line
117 if (m_show_drop_point && m_order_issuing_enabled) {
118 auto&& row = m_drop_point == end() ? (--end())->get() : m_drop_point->get();
119 if (!row)
120 return;
121 GG::Pt ul = row->UpperLeft(), lr = row->LowerRight();
122 if (m_drop_point == end())
123 ul.y = lr.y;
124 if (!row->empty()) {
125 GG::Control* panel = row->at(0);
126 ul.x = panel->Left();
127 lr.x = panel->Right();
128 }
129 GG::FlatRectangle(GG::Pt(ul.x, ul.y - 1), GG::Pt(lr.x, ul.y), GG::CLR_ZERO, GG::CLR_WHITE, 1);
130 }
131 }
132
SizeMove(const GG::Pt & ul,const GG::Pt & lr)133 void QueueListBox::SizeMove(const GG::Pt& ul, const GG::Pt& lr) {
134 const GG::Pt old_size = Size();
135 CUIListBox::SizeMove(ul, lr);
136 if (old_size != Size() && !Empty()) {
137 const GG::Pt row_size(RowWidth(), (*begin())->Height());
138 for (auto& row : *this)
139 row->Resize(row_size);
140 }
141 }
142
DragDropHere(const GG::Pt & pt,std::map<const Wnd *,bool> & drop_wnds_acceptable,GG::Flags<GG::ModKey> mod_keys)143 void QueueListBox::DragDropHere(const GG::Pt& pt, std::map<const Wnd*, bool>& drop_wnds_acceptable,
144 GG::Flags<GG::ModKey> mod_keys)
145 {
146 CUIListBox::DragDropHere(pt, drop_wnds_acceptable, mod_keys);
147
148 if (drop_wnds_acceptable.size() == 1 &&
149 AllowedDropType(drop_wnds_acceptable.begin()->first->DragDropDataType()))
150 {
151 m_drop_point = RowUnderPt(pt);
152 m_show_drop_point = true;
153 } else {
154 m_drop_point = end();
155 m_show_drop_point = false;
156 }
157 }
158
DragDropLeave()159 void QueueListBox::DragDropLeave() {
160 m_drop_point = end();
161 m_show_drop_point = false;
162 }
163
IteraterIndex(const const_iterator it)164 int QueueListBox::IteraterIndex(const const_iterator it) {
165 if (it == this->end())
166 return -1;
167
168 size_t dist = 0;
169 for (auto qit = this->begin(); qit != this->end(); ++qit) {
170 if (qit == it)
171 return dist;
172 dist++;
173 }
174 return -1;
175 }
176
EnableOrderIssuing(bool enable)177 void QueueListBox::EnableOrderIssuing(bool enable/* = true*/) {
178 m_order_issuing_enabled = enable;
179 AllowDrops(enable);
180 for (auto& row : *this)
181 row->Disable(!enable);
182 }
183
DisplayingValidQueueItems()184 bool QueueListBox::DisplayingValidQueueItems()
185 { return !m_showing_prompt; }
186
Clear()187 void QueueListBox::Clear() {
188 CUIListBox::Clear();
189 DragDropLeave();
190 }
191
SetEmptyPromptText(const std::string prompt)192 void QueueListBox::SetEmptyPromptText(const std::string prompt) {
193 if (m_prompt_str == prompt)
194 return;
195
196 m_prompt_str = prompt;
197
198 if (m_showing_prompt)
199 ShowPromptSlot();
200 }
201
MoveToTopAction(GG::ListBox::iterator it)202 std::function<void()> QueueListBox::MoveToTopAction(GG::ListBox::iterator it) {
203 return [it, this]() {
204 if (OrderIssuingEnabled())
205 ListBox::Insert(*it, begin(), true);
206 };
207 }
208
MoveToBottomAction(GG::ListBox::iterator it)209 std::function<void()> QueueListBox::MoveToBottomAction(GG::ListBox::iterator it) {
210 return [it, this]() {
211 if (OrderIssuingEnabled())
212 ListBox::Insert(*it, end(), true);
213 };
214 }
215
DeleteAction(GG::ListBox::iterator it) const216 std::function<void()> QueueListBox::DeleteAction(GG::ListBox::iterator it) const {
217 return [it, this]() {
218 if (OrderIssuingEnabled())
219 QueueItemDeletedSignal(it);
220 };
221 }
222
ItemRightClicked(GG::ListBox::iterator it,const GG::Pt & pt,const GG::Flags<GG::ModKey> & modkeys)223 void QueueListBox::ItemRightClicked(GG::ListBox::iterator it, const GG::Pt& pt, const GG::Flags<GG::ModKey>& modkeys)
224 { this->ItemRightClickedImpl(it, pt, modkeys); }
225
ItemRightClickedImpl(GG::ListBox::iterator it,const GG::Pt & pt,const GG::Flags<GG::ModKey> & modkeys)226 void QueueListBox::ItemRightClickedImpl(GG::ListBox::iterator it, const GG::Pt& pt, const GG::Flags<GG::ModKey>& modkeys) {
227 auto popup = GG::Wnd::Create<CUIPopupMenu>(pt.x, pt.y);
228
229 bool disabled = !OrderIssuingEnabled();
230
231 popup->AddMenuItem(GG::MenuItem(UserString("MOVE_UP_QUEUE_ITEM"), disabled, false, MoveToTopAction(it)));
232 popup->AddMenuItem(GG::MenuItem(UserString("MOVE_DOWN_QUEUE_ITEM"), disabled, false, MoveToBottomAction(it)));
233 popup->AddMenuItem(GG::MenuItem(UserString("DELETE_QUEUE_ITEM"), disabled, false, DeleteAction(it)));
234 popup->Run();
235 }
236
EnsurePromptHiddenSlot(iterator it)237 void QueueListBox::EnsurePromptHiddenSlot(iterator it) {
238 if (m_showing_prompt) {
239 Erase(begin(), false, false); // if the prompt is shown, it must be the only row in the ListBox
240 m_showing_prompt = false;
241 }
242 }
243
ShowPromptSlot()244 void QueueListBox::ShowPromptSlot() {
245 Insert(GG::Wnd::Create<PromptRow>(Width() - 4, m_prompt_str), begin(), false);
246 m_showing_prompt = true;
247 }
248
ShowPromptConditionallySlot(iterator it)249 void QueueListBox::ShowPromptConditionallySlot(iterator it) {
250 if (begin() == end()) {
251 ShowPromptSlot();
252 }
253 }
254