1 /******************************************************************************
2 * Warmux is a convivial mass murder game.
3 * Copyright (C) 2001-2011 Warmux Team.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 ******************************************************************************
19 * Teams selection box
20 *****************************************************************************/
21
22 #include "game/config.h"
23 #include "game/game_mode.h"
24 #include "menu/teams_selection_box.h"
25 #include "menu/team_box.h"
26 #include "gui/grid_box.h"
27 #include "gui/label.h"
28 #include "gui/scroll_box.h"
29 #include "gui/null_widget.h"
30 #include "gui/picture_widget.h"
31 #include "gui/spin_button.h"
32 #include "gui/spin_button_picture.h"
33 #include "gui/text_box.h"
34 #include "gui/vertical_box.h"
35 #include "team/teams_list.h"
36 #include "team/team.h"
37
38 #include <iostream>
39
TeamScrollBox(const std::vector<TeamBox * > & teams,const Point2i & size)40 TeamScrollBox::TeamScrollBox(const std::vector<TeamBox*>& teams, const Point2i &size)
41 : ScrollBox(size)
42 , teams(teams)
43 , count(2)
44 {
45 // SetNbTeams not called immediately
46 AddWidget(teams[0]);
47 AddWidget(teams[1]);
48 }
49
~TeamScrollBox()50 TeamScrollBox::~TeamScrollBox()
51 {
52 // Don't let the vbox delete the items, we're doing it ourselves
53 vbox->Empty();
54
55 // Destroy widgets
56 for (uint i=0; i<teams.size() ; i++)
57 delete (teams[i]);
58
59 teams.clear();
60 }
61
SetNbTeams(uint nb)62 void TeamScrollBox::SetNbTeams(uint nb)
63 {
64 // Reset the list and readd the widget
65 count = 0;
66 vbox->Empty();
67
68 for (uint i = 0; count < nb; i++) {
69 ASSERT(i < teams.size());
70
71 // It is easy to have hole in the selection
72 // with network game
73 if (teams[i]->GetTeam()) {
74 AddWidget(teams[i]);
75 count++;
76 }
77 }
78 ASSERT(count == nb);
79
80 Pack();
81 NeedRedrawing();
82 }
83
TeamsSelectionBox(const Point2i & _size,bool network,bool w_border)84 TeamsSelectionBox::TeamsSelectionBox(const Point2i &_size, bool network, bool w_border) :
85 HBox(_size.y, w_border, false)
86 {
87 if (!w_border)
88 SetNoBorder();
89 SetMargin(0);
90
91 // How many teams ?
92 VBox *tmp = new VBox(120, false, false, true);
93 if (network) {
94 local_teams_nb =
95 new SpinButtonWithPicture(_("Local teams:"), "menu/team_number",
96 Point2i(100, 130), 0, 1, 0, MAX_NB_TEAMS);
97 } else {
98 local_teams_nb =
99 new SpinButtonWithPicture(_("Number of teams:"), "menu/team_number",
100 Point2i(100, 130), 2, 1, 2, MAX_NB_TEAMS);
101 }
102 tmp->AddWidget(local_teams_nb);
103 //tmp->AddWidget(new NullWidget(Point2i(120, 120)));
104 AddWidget(tmp);
105
106 uint box_w = _size.x - local_teams_nb->GetSizeX() - 10;
107 Point2i grid_size = Point2i(box_w, _size.y);
108 Point2i grid_dim = grid_size / Point2i(300 + 10, 130 + 10);
109 Point2i box_size;
110 bool use_list;
111 if (grid_dim.x*grid_dim.y < (int)MAX_NB_TEAMS) {
112 use_list = true;
113 box_size.SetValues(box_w - 40, 120);
114 } else {
115 use_list = false;
116 box_size.SetValues((grid_size / grid_dim) - 10);
117 }
118
119 for (uint i=0; i < MAX_NB_TEAMS; i++) {
120 std::string player_name = _("Player") ;
121 char num_player[4];
122 sprintf(num_player, " %d", i+1);
123 player_name += num_player;
124 teams_selections.push_back(new TeamBox(player_name, box_size));
125 }
126
127 // If the intended gridbox would be too big for the intended size,
128 // instead create a listbox
129 if (use_list) {
130 // Warning: this box takes the ownership of the widgets in teams_selections:
131 // while any other Box will delete the ones it contains, TeamScrollBox
132 // doesn't really contain them as widgets. They therefore aren't released
133 // through this mechanism, but with a manual one. This manual mechanism
134 // requires we have a *real* copy of the vector for when it is destroyed.
135 list_box = new TeamScrollBox(teams_selections, Point2i(box_w-20, _size.y-10));
136 list_box->SetNbTeams(0);
137
138 AddWidget(list_box);
139 } else {
140 list_box = NULL;
141 Box * teams_grid_box = new GridBox(grid_dim.y, grid_dim.x, 10, false);
142 teams_grid_box->SetNoBorder();
143
144 for (uint i=0; i<MAX_NB_TEAMS; i++)
145 teams_grid_box->AddWidget(teams_selections[i]);
146
147 AddWidget(teams_grid_box);
148 }
149
150 // Load Teams' list
151 GetTeamsList().full_list.sort(compareTeams);
152 }
153
Draw(const Point2i & mousePosition)154 void TeamsSelectionBox::Draw(const Point2i& mousePosition)
155 {
156 if (list_box)
157 list_box->Draw(mousePosition);
158 }
159
Click(const Point2i & mousePosition,uint button)160 Widget* TeamsSelectionBox::Click(const Point2i &mousePosition, uint button)
161 {
162 return (list_box) ? list_box->Click(mousePosition, button) : NULL;
163 }
164
165 // =============================================================================
166
LocalTeamsSelectionBox(const Point2i & size,bool border)167 LocalTeamsSelectionBox::LocalTeamsSelectionBox(const Point2i &size, bool border) :
168 TeamsSelectionBox(size, false, border)
169 {
170 GetTeamsList().InitList(Config::GetInstance()->AccessTeamList());
171
172 TeamsList::iterator it = GetTeamsList().playing_list.begin(),
173 end = GetTeamsList().playing_list.end();
174
175 uint j=0;
176 for (; it != end && j<teams_selections.size(); ++it, j++) {
177 teams_selections.at(j)->SetTeam((**it), true);
178 }
179
180 // we need at least 2 teams
181 if (j < 2) {
182 SetNbTeams(2);
183 local_teams_nb->SetValue(2);
184 teams_selections.at(1)->SetAIName(DEFAULT_AI_NAME);
185 } else {
186 SetNbTeams(j);
187 local_teams_nb->SetValue(j);
188 }
189 }
190
ClickUp(const Point2i & mousePosition,uint button)191 Widget* LocalTeamsSelectionBox::ClickUp(const Point2i &mousePosition, uint button)
192 {
193 if (!Contains(mousePosition))
194 return NULL;
195
196 if (local_teams_nb->ClickUp(mousePosition, button)) {
197 SetNbTeams(local_teams_nb->GetValue());
198 } else {
199 Widget *w = (list_box) ? list_box->ClickUp(mousePosition, button)
200 : WidgetList::ClickUp(mousePosition, button);
201
202 for (uint i=0; i<teams_selections.size() ; i++) {
203
204 if (teams_selections[i]->Contains(mousePosition)) {
205 Widget * at = teams_selections[i];
206 Rectanglei r(at->GetPosition(), Point2i(38, 38));
207
208 // Validate where the click really landed
209 if (r.Contains(mousePosition)) {
210 if (button == Mouse::BUTTON_LEFT() || button == SDL_BUTTON_WHEELDOWN) {
211 NextTeam(i);
212 } else if (button == Mouse::BUTTON_RIGHT() || button == SDL_BUTTON_WHEELUP) {
213 PrevTeam(i);
214 }
215 return at;
216 } else {
217 Rectanglei r2(at->GetPositionX(), at->GetPositionY() + 39,
218 38, 30);
219 if (r2.Contains(mousePosition)) {
220 teams_selections[i]->SwitchPlayerType();
221 return at;
222 }
223 }
224
225 return w;
226 }
227 }
228
229 return w;
230 }
231
232 return NULL;
233 }
234
PrevTeam(int i)235 void LocalTeamsSelectionBox::PrevTeam(int i)
236 {
237 if (!teams_selections.at(i)->GetTeam())
238 return;
239
240 bool stop;
241 int previous_index = -1, index;
242
243 GetTeamsList().FindById(teams_selections.at(i)->GetTeam()->GetId(), previous_index);
244
245 index = previous_index-1;
246
247 do {
248 stop = true;
249
250 // select the last team if we are outside list
251 if (index < 0)
252 index = int(GetTeamsList().full_list.size())-1;
253
254 // Get the team at current index
255 Team *tmp = GetTeamsList().FindByIndex(index);
256
257 // Check if that team is already selected
258 for (int j = 0; j < local_teams_nb->GetValue(); j++) {
259 if (j!= i && tmp == teams_selections.at(j)->GetTeam()) {
260 index--;
261 stop = false;
262 break;
263 }
264 }
265
266 // We have found a team which is not selected
267 if (tmp && stop)
268 teams_selections.at(i)->SetTeam(*tmp);
269 } while (index != previous_index && !stop);
270 }
271
NextTeam(int i)272 void LocalTeamsSelectionBox::NextTeam(int i)
273 {
274 if (!teams_selections.at(i)->GetTeam())
275 return;
276
277 bool to_continue;
278 Team* tmp;
279 int previous_index = -1, index;
280
281 GetTeamsList().FindById(teams_selections.at(i)->GetTeam()->GetId(), previous_index);
282
283 index = previous_index+1;
284
285 do {
286 to_continue = false;
287
288 // select the first team if we are outside list
289 if (index >= int(GetTeamsList().full_list.size()))
290 index = 0;
291
292 // Get the team at current index
293 tmp = GetTeamsList().FindByIndex(index);
294
295 // Check if that team is already selected
296 for (int j = 0; j < local_teams_nb->GetValue(); j++) {
297 if (j!= i && tmp == teams_selections.at(j)->GetTeam()) {
298 index++;
299 to_continue = true;
300 break;
301 }
302 }
303
304 // We have found a team which is not selected
305 if (tmp != NULL && !to_continue)
306 teams_selections.at(i)->SetTeam(*tmp);
307 } while (index != previous_index && to_continue);
308 }
309
SetNbTeams(uint nb_teams)310 void LocalTeamsSelectionBox::SetNbTeams(uint nb_teams)
311 {
312 // we hide the useless teams selector
313 for (uint i=nb_teams; i<teams_selections.size(); i++) {
314 teams_selections[i]->ClearTeam();
315 }
316
317 for (uint i=0; i<nb_teams;i++) {
318 if (!teams_selections.at(i)->GetTeam()) {
319 // we should find an available team
320 teams_selections.at(i)->SetTeam(*(GetTeamsList().FindByIndex(i)));
321 NextTeam(i);
322 }
323 }
324
325 if (list_box)
326 list_box->SetNbTeams(nb_teams);
327 }
328
ValidTeamsSelection()329 void LocalTeamsSelectionBox::ValidTeamsSelection()
330 {
331 uint nb_teams=0;
332 for (uint i=0; i < teams_selections.size(); i++) {
333 if (teams_selections.at(i)->GetTeam() != NULL) {
334 nb_teams++;
335 }
336 }
337
338 if (nb_teams >= 2) {
339 std::list<uint> selection;
340
341 for (uint i=0; i < teams_selections.size(); i++) {
342
343 if (teams_selections.at(i)->GetTeam() != NULL) {
344
345 int index = -1;
346 teams_selections.at(i)->ValidOptions();
347 GetTeamsList().FindById(teams_selections.at(i)->GetTeam()->GetId(), index);
348 if (index > -1)
349 {
350 selection.push_back(uint(index));
351
352 }
353 }
354 }
355
356 GetTeamsList().ChangeSelection(selection);
357 }
358 }
359