1 /*
2    Copyright (C) 2004 by James Gregory
3    Part of the GalaxyHack project
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.
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY.
9 
10    See the COPYING file for more details.
11 */
12 
13 #include "GenWindow.h"
14 #include "Globals.h"
15 #include "MainMenu.h"
16 #include "ForceSelect.h"
17 #include "SetupBattle.h"
18 #include "RTS.h"
19 #include "Score.h"
20 
21 #include <string>
22 #include <list>
23 
24 using std::string;
25 using std::list;
26 
27 /*IMPORTANT NOTE:
28 WinMouseD() and WinKeyboard() rely upon windows returning true if they are going to do anything. The fact that a window can create another window in the same list as itself can otherwise cause issues. It would seem adding a window mid loop moves the reverse iterator back one somehow, meaning a window can accidently get input twice.
29 
30 For mouse input this is automatically handled by GenWindow_Base::MouseD(), which will always return true if the mouse is over a given window.
31 
32 Another way of doing this would be to make a copy of the myWindows list each frame, make it so windows only push back new windows on to this copy, and then at the end of each frame have the copied (and maybe altered) list assigned back to the real list. The fact that GenWindows are a handle class means this wouldn't actually literally copy the entire contents of the window list twice each frame, but it would seem rather inefficient to me, nonetheless.
33 */
34 
35 /*ANOTHER NOTE:
36 Any pushing back of keyboard-reading windows must come after WinKeyboard(), or the new window will get the keyboard input too
37 */
38 
UpdateWindows()39 void UpdateWindows() {
40 	if (globalSettings.batch)
41 		return;
42 
43 	//altering list whilst iterating through it, dodgy, see note above, some hackery here
44 	list<GenWindow>::iterator endIter = myWindows.end();
45 
46 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != endIter; ) {
47 		if (iter->TakeActivate()) {
48 			myWindows.splice(myWindows.end(), myWindows, iter);
49 			iter = myWindows.begin();
50 			endIter = myWindows.end();
51 		}
52 		else
53 			++iter;
54 	}
55 
56 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != myWindows.end();) {
57 		if (iter->GetClosed())
58 			iter = myWindows.erase(iter);
59 		else
60 			++iter;
61 	}
62 
63 	for (list<GenWindow>::reverse_iterator iter = myWindows.rbegin(); iter != myWindows.rend(); ++iter)
64 		iter->Update();
65 }
66 
WinMouseD(Uint8 button,Uint16 x,Uint16 y)67 bool WinMouseD(Uint8 button, Uint16 x, Uint16 y) {
68 	//means no windowed input
69 	bool ret = false;
70 
71 	//break as soon as the front most window returns true
72 	for (list<GenWindow>::reverse_iterator iter = myWindows.rbegin(); iter != myWindows.rend(); ++iter) {
73 		if (iter->MouseD(button, x, y)) {
74 			ret = true;
75 			break;
76 		}
77 	}
78 
79 	return ret;
80 }
81 
WinMouseM(Uint8 state,Uint16 x,Uint16 y)82 void WinMouseM(Uint8 state, Uint16 x, Uint16 y) {
83 	//break as soon as the front most window deals with motion
84 	for (list<GenWindow>::reverse_iterator iter = myWindows.rbegin(); iter != myWindows.rend(); ++iter) {
85 		if (iter->MouseM(state, x, y))
86 			return;
87 	}
88 }
89 
WinKeyboard(SDL_keysym & keysym)90 bool WinKeyboard(SDL_keysym& keysym) {
91 	bool ret = false;
92 
93 	//break as soon as the front most window has some keyboard input
94 	for (list<GenWindow>::reverse_iterator iter = myWindows.rbegin(); iter != myWindows.rend(); ++iter) {
95 		if (iter->Keyboard(keysym)) {
96 			ret = true;
97 			break;
98 		}
99 	}
100 
101 	return ret;
102 }
103 
MessageWindows(WindowChoice theMessage,int paremOne,int paremTwo,int targetID,int sourceID)104 void MessageWindows(WindowChoice theMessage, int paremOne, int paremTwo, int targetID, int sourceID) {
105 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != myWindows.end(); ++iter)
106 		iter->WinMessage(theMessage, paremOne, paremTwo, targetID, sourceID);
107 }
108 
CreateInfoString(const string & iTheString,bool force)109 void CreateInfoString(const string& iTheString, bool force) {
110 	if (!anInfoString || force)
111 		myWindows.push_back(GenWindow(iTheString));
112 }
113 
DrawAllWindows()114 void DrawAllWindows() {
115 	if (globalSettings.batch)
116 		return;
117 
118 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != myWindows.end(); ++iter)
119 		iter->DrawSelf();
120 }
121 
KillAllWindows()122 void KillAllWindows() {
123 	//we can't use clear because with clear the size of the list
124 	//isn't set to 0 until the clearing has finished, yet
125 	//the base window destructor has to find the size
126 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != myWindows.end();)
127 		iter = myWindows.erase(iter);
128 }
129 
LocateWindow(int findID)130 GenWindow_Base* LocateWindow(int findID) {
131 	for (list<GenWindow>::iterator iter = myWindows.begin(); iter != myWindows.end(); ++iter) {
132 		GenWindow_Base* winPointer = iter->GetPointer();
133 		if (winPointer->myID == findID)
134 			return winPointer;
135 	}
136 
137 	char output[80];
138 	sprintf(output, "Unable to find window with ID %d", findID);
139 	throw runtime_error(output);
140 
141 	return 0;
142 }
143 
GenWindow(int ix,int iy,WindowChoice iType,int paremOne,int paremTwo,int flags)144 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, int paremOne, int paremTwo, int flags) {
145 	switch (iType) {
146 	case MM_MainSM:
147 		hWindow = new MainMenu::MainSM();
148 		break;
149 
150 	case MM_Options:
151 		hWindow = new MainMenu::MainOptions(ix, iy);
152 		break;
153 
154 	case Opt_StandardOptions:
155 		hWindow = new StandardOptions(ix, iy, none_constant, flags);
156 		break;
157 
158 	case Opt_SetResolution:
159 		hWindow = new ChooseResolution();
160 		break;
161 
162 	case Opt_SetWindowColor:
163 		hWindow = new WindowColorSlider(ix, iy, flags);
164 		break;
165 
166 	case FS_LoadSideDW:
167 		hWindow = new ForceSelect::LoadSideDW();
168 		break;
169 
170 	case FS_LoadSideMenu:
171 		hWindow = new ForceSelect::LoadSideSM(paremOne);
172 		break;
173 
174 	case FS_NewSideName:
175 		hWindow = new ForceSelect::NewSideName();
176 		break;
177 
178 	case FS_Commander:
179 		hWindow = new ForceSelect::ChangeCommanderName();
180 		break;
181 
182 	case FS_WhichSaveGroup:
183 		hWindow = new ForceSelect::WhichSaveGroup(paremOne, static_cast<bool>(paremTwo));
184 		break;
185 
186 	case FS_BasePU:
187 		hWindow = new ForceSelect::BasePU(ix, iy);
188 		break;
189 
190 	case FS_AddGroupMenu:
191 		hWindow = new ForceSelect::AddGroupMenu(paremOne);
192 		break;
193 
194 	case FS_CapShipTypeSlider:
195 		hWindow = new ForceSelect::CapShipTypeSlider(ix, iy, paremOne, flags);
196 		break;
197 
198 	case FS_SideOptions:
199 		hWindow = new ForceSelect::SideOptions(ix, iy, flags);
200 		break;
201 
202 	case FS_SideOptionsPU:
203 		hWindow = new ForceSelect::SideOptionsPU(ix, iy);
204 		break;
205 
206 	case FS_ExitNoSaveQ:
207 		hWindow = new ForceSelect::ExitNoSaveQ();
208 		break;
209 
210 	case FS_EditGroup:
211 		hWindow = new ForceSelect::EditGroup(ix, iy, paremOne, flags & WFLAG_TILED);
212 		break;
213 
214 	case FS_EditGroupPU:
215 		hWindow = new ForceSelect::EditGroupPU(ix, iy, paremOne);
216 		break;
217 
218 	case FS_AIScriptMenu:
219 		hWindow = new ForceSelect::SetAIScriptMenu(paremOne, paremTwo);
220 		break;
221 
222 	case FS_EditUnit:
223 		hWindow = new ForceSelect::EditUnit(ix, iy, paremOne);
224 		break;
225 
226 	case FS_EditUnitPU:
227 		hWindow = new ForceSelect::EditUnitPU(ix, iy, paremOne);
228 		break;
229 
230 	case FS_PictureMenu:
231 		hWindow = new ForceSelect::SetUnitPicMenu(paremOne, paremTwo);
232 		break;
233 
234 		//0 is small weapons, 1 is big weapons
235 	case FS_WeaponsDW:
236 		hWindow = new ForceSelect::WeaponsDW(ix, ix, paremOne, paremTwo);
237 		break;
238 
239 	case FS_SmallWeaponsMenu:
240 		hWindow = new ForceSelect::SmallWeaponsMenu(ix, ix, paremOne, paremTwo);
241 		break;
242 
243 	case FS_BigWeaponsMenu:
244 		hWindow = new ForceSelect::BigWeaponsMenu(ix, ix, paremOne, paremTwo);
245 		break;
246 
247 	case FS_EquipmentDW:
248 		hWindow = new ForceSelect::EquipmentDW(ix, ix, paremOne, paremTwo);
249 		break;
250 
251 	case FS_EngineMenu:
252 		hWindow = new ForceSelect::EngineMenu(ix, ix, paremOne, paremTwo);
253 		break;
254 
255 	case FS_ArmourMenu:
256 		hWindow = new ForceSelect::ArmourMenu(ix, ix, paremOne, paremTwo);
257 		break;
258 
259 	case FS_ShieldMenu:
260 		hWindow = new ForceSelect::ShieldMenu(ix, ix, paremOne, paremTwo);
261 		break;
262 
263 	case FS_CSType:
264 		hWindow = new ForceSelect::CSTypeMenu(ix, ix, paremOne);
265 		break;
266 
267 	case SB_BasePU:
268 		hWindow = new SetupBattle::BasePU(ix, iy);
269 		break;
270 
271 	case SB_LoadSideMenu:
272 		hWindow = new SetupBattle::LoadSideMenu(paremOne, paremTwo);
273 		break;
274 
275 	case SB_PlayerList:
276 		hWindow = new SetupBattle::PlayerList(ix, iy, flags);
277 		break;
278 
279 	case SB_RandomSeed:
280 		hWindow = new SetupBattle::RandomSeed(ix, iy, flags);
281 		break;
282 
283 	case RTS_BasePU:
284 		hWindow = new RTS::BasePU(ix, iy);
285 		break;
286 
287 	case RTS_OptPU:
288 		hWindow = new RTS::OptPU(ix, iy);
289 		break;
290 
291 	case RTS_GameInfo:
292 		hWindow = new RTS::GameInfo(ix, iy, flags);
293 		break;
294 
295 	case RTS_SideStats:
296 		hWindow = new RTS::SideStatsInfo(ix, iy, paremOne);
297 		break;
298 
299 	case RTS_SideVars:
300 		hWindow = new RTS::SideVarsInfo(ix, iy, paremOne);
301 		break;
302 
303 	case RTS_SideSaveGroups:
304 		hWindow = new RTS::SideSaveGroupsInfo(ix, iy, paremOne);
305 		break;
306 
307 	case RTS_SideAIDebug:
308 		hWindow = new RTS::SideAIErrors(ix, iy, paremOne);
309 		break;
310 
311 	case RTS_InfoChoicePU:
312 		hWindow = new RTS::InfoChoicePU(ix, iy, paremOne, paremTwo);
313 		break;
314 
315 	case RTS_GroupStats:
316 		hWindow = new RTS::GroupStatsInfo(ix, iy, paremOne, paremTwo, flags);
317 		break;
318 
319 	case RTS_GroupShieldsInfo:
320 		hWindow = new RTS::GroupShieldsInfo(ix, iy, paremOne, paremTwo, flags);
321 		break;
322 
323 	case RTS_GroupStatusReport:
324 		hWindow = new RTS::GroupStatusReport(ix, iy, paremOne, paremTwo, flags);
325 		break;
326 
327 	case RTS_GroupAIReport:
328 		hWindow = new RTS::GroupAIReport(ix, iy, paremOne, paremTwo, flags);
329 		break;
330 
331 	case RTS_GroupVars:
332 		hWindow = new RTS::GroupVarsInfo(ix, iy, paremOne, paremTwo, flags);
333 		break;
334 
335 	case RTS_GroupSaveGroups:
336 		hWindow = new RTS::GroupSaveGroupsInfo(ix, iy, paremOne, paremTwo, flags);
337 		break;
338 
339 	case RTS_GroupTimers:
340 		hWindow = new RTS::GroupTimersInfo(ix, iy, paremOne, paremTwo, flags);
341 		break;
342 
343 	case RTS_RestartQ:
344 		hWindow = new RTS::RestartQ();
345 		break;
346 
347 	case RTS_SetGameSpeed:
348 		hWindow = new RTS::GameSpeedSlider(ix, iy, flags);
349 		break;
350 
351 	case RTS_SetScrollSpeed:
352 		hWindow = new RTS::ScrollSpeedSlider(ix, iy, flags);
353 		break;
354 
355 	case Score_BasePU:
356 		hWindow = new Score::BasePU(ix, iy);
357 		break;
358 
359 	default:
360 		throw runtime_error("GenWindow standard constructor didn't recognise window type");
361 		break;
362 	}
363 }
364 
GenWindow(int ix,int iy,WindowChoice iType,int paremOne,int paremTwo,int paremThree,int paremFour,int flags)365 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, int paremOne, int paremTwo, int paremThree, int paremFour, int flags) {
366 	switch (iType) {
367 	case RTS_InfoChoicePU:
368 		hWindow = new RTS::InfoChoicePU(ix, iy, paremOne, paremTwo, paremThree, paremFour);
369 		break;
370 
371 	default:
372 		throw runtime_error("GenWindow four parems constructor didn't recognise window type");
373 		break;
374 	}
375 }
376 
GenWindow(WindowChoice iType,int iMySide,int iMyGroup,WindowChoice iChoiceType)377 GenWindow::GenWindow(WindowChoice iType, int iMySide, int iMyGroup, WindowChoice iChoiceType) {
378 	hWindow = new SidePU(iMySide, iMyGroup, iChoiceType);
379 }
380 
GenWindow(WindowChoice iType,int iMySide,int iMyGroup,WindowChoice iChoiceType,int iWhichSaveGroup)381 GenWindow::GenWindow(WindowChoice iType, int iMySide, int iMyGroup, WindowChoice iChoiceType, int iWhichSaveGroup) {
382 	hWindow = new SidePU(iMySide, iMyGroup, iChoiceType, iWhichSaveGroup);
383 }
384 
385 
GenWindow(int ix,int iy,WindowChoice iType,const string & iString,int paremOne,int paremTwo)386 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, const string& iString, int paremOne, int paremTwo) {
387 	switch (iType) {
388 	case WC_LargeBlankDW:
389 		hWindow = new LargeBlankDW(iString);
390 		break;
391 
392 	case FS_LoadSidePU:
393 		hWindow = new ForceSelect::LoadSidePU(ix, iy, iString, paremOne);
394 		break;
395 
396 	case FS_DeleteFleet:
397 		hWindow = new ForceSelect::DeleteFleet(iString, paremOne);
398 		break;
399 
400 	case FS_CopyFleet:
401 		hWindow = new ForceSelect::CopyFleet(iString, paremOne);
402 		break;
403 
404 	case FS_AddGroupPU:
405 		hWindow = new ForceSelect::AddGroupPU(ix, iy, iString, paremOne);
406 		break;
407 
408 	case FS_ForceExitQ:
409 		hWindow = new ForceSelect::ForceExitQ(iString);
410 		break;
411 
412 	case FS_ChangeAIScriptPU:
413 		hWindow = new ForceSelect::SetAIScriptPU(iString, paremOne, paremTwo);
414 		break;
415 
416 	default:
417 		throw runtime_error("GenWindow int, int, WC, string, int constructor didn't recognise window type");
418 		break;
419 	}
420 }
421 
GenWindow(int ix,int iy,WindowChoice iType,const string & iString,UnitType iUnitType,int paremOne,int paremTwo,int paremThree)422 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, const string& iString, UnitType iUnitType, int paremOne, int paremTwo, int paremThree) {
423 	switch (iType) {
424 	case FS_NewGroupChoicesOK:
425 		hWindow = new ForceSelect::NewGroupChoicesOK(ix, iy, iString, iUnitType, paremOne, paremTwo, paremThree);
426 		break;
427 
428 	case FS_NewGroupParentPU:
429 		hWindow = new ForceSelect::NewGroupParentPU(iString, iUnitType, paremOne);
430 		break;
431 
432 	default:
433 		throw runtime_error("int, int, WC, string, UT, int, int, int windows constructor didn't recognise window type");
434 		break;
435 	}
436 }
437 
GenWindow(int ix,int iy,WindowChoice iType,int iSliderVar,int iVarMin,int iVarMax,const string & iVarName,const string & iVarUnits,int iParentID,int flags)438 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, int iSliderVar, int iVarMin, int iVarMax, const string& iVarName, const string& iVarUnits, int iParentID, int flags) {
439 	hWindow = new SliderWithUnits(ix, iy, iSliderVar, iVarMin, iVarMax, iVarName, iVarUnits, iParentID, flags);
440 }
441 
GenWindow(int ix,int iy,WindowChoice iType,int * iVarPointer,int iVarMin,int iVarMax,const string & iVarName,const string & iVarUnits,int iParentID,int flags)442 GenWindow::GenWindow(int ix, int iy, WindowChoice iType, int* iVarPointer, int iVarMin, int iVarMax, const string& iVarName, const string& iVarUnits, int iParentID, int flags) {
443 	hWindow = new SliderWithUnits(ix, iy, iVarPointer, iVarMin, iVarMax, iVarName, iVarUnits, iParentID, flags);
444 }
445 
GenWindow(const string & iTheString)446 GenWindow::GenWindow(const string& iTheString) {
447 	hWindow = new InfoString(iTheString);
448 }
449 
GenWindow(WindowChoice iType,UnitType iUnitType,int paremOne)450 GenWindow::GenWindow(WindowChoice iType, UnitType iUnitType, int paremOne) {
451 	switch (iType) {
452 	case FS_NewUnitName:
453 		hWindow = new ForceSelect::NewUnitName(iUnitType, paremOne);
454 		break;
455 
456 	default:
457 		throw runtime_error("GenWindow WC, UT, int constructor didn't recognise window type");
458 		break;
459 	}
460 }
461 
GenWindow(WindowChoice iType,const string & stringOne,const string & stringTwo,int iParentID)462 GenWindow::GenWindow(WindowChoice iType, const string& stringOne, const string& stringTwo, int iParentID) {
463 	switch (iType) {
464 	case WC_DeleteBox:
465 		hWindow = new DeleteBox(stringOne, stringTwo, iParentID);
466 		break;
467 
468 	case WC_CopyBox:
469 		hWindow = new CopyBox(stringOne, stringTwo, iParentID);
470 		break;
471 
472 	default:
473 		throw runtime_error("GenWindow Copy/DeleteBox constructor didn't recognise window type");
474 		break;
475 	}
476 }
477 
478 ////
479 
TakeActivate()480 bool GenWindow::TakeActivate() {
481 	bool ret = hWindow->activate;
482 	hWindow->activate = 0;
483 	return ret;
484 }
485 
WinMessage(WindowChoice theMessage,int paremOne,int paremTwo,int targetID,int sourceID)486 void GenWindow::WinMessage(WindowChoice theMessage, int paremOne, int paremTwo, int targetID, int sourceID) {
487 	if (sourceID != hWindow->myID)
488 		hWindow->WinMessage(theMessage, paremOne, paremTwo, targetID, sourceID);
489 }
490 
491