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