1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (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                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 #include "ui/graphical/menu/windows/windowstorage/windowstorage.h"
21 #include "pcx.h"
22 #include "main.h"
23 #include "video.h"
24 #include "game/data/units/unit.h"
25 #include "game/data/units/building.h"
26 #include "game/data/units/vehicle.h"
27 #include "game/data/base/base.h"
28 #include "game/data/player/player.h"
29 #include "ui/graphical/menu/widgets/label.h"
30 #include "ui/graphical/menu/widgets/pushbutton.h"
31 #include "ui/graphical/menu/widgets/image.h"
32 #include "ui/graphical/menu/widgets/special/resourcebar.h"
33 #include "ui/graphical/menu/dialogs/dialogok.h"
34 #include "ui/graphical/application.h"
35 #include "ui/graphical/game/widgets/unitdetailsstored.h"
36 #include "ui/graphical/game/widgets/turntimeclockwidget.h"
37 
38 //------------------------------------------------------------------------------
cWindowStorage(const cUnit & unit_,std::shared_ptr<const cTurnTimeClock> turnTimeClock)39 cWindowStorage::cWindowStorage (const cUnit& unit_, std::shared_ptr<const cTurnTimeClock> turnTimeClock) :
40 	cWindow (nullptr),
41 	unit (unit_),
42 	canRepairReloadUpgrade (unit_.isABuilding()),
43 	canStorePlanes (unit_.data.storeUnitsImageType == sUnitData::STORE_UNIT_IMG_PLANE),
44 	canStoreShips (unit_.data.storeUnitsImageType == sUnitData::STORE_UNIT_IMG_SHIP),
45 	columns (canStorePlanes ? 2 : 3),
46 	page (0)
47 {
48 	AutoSurface background (LoadPCX (GFXOD_STORAGE));
49 	if (!canStorePlanes)
50 	{
51 		AutoSurface surface (LoadPCX (GFXOD_STORAGE_GROUND));
52 		SDL_BlitSurface (surface.get(), nullptr, background.get(), nullptr);
53 	}
54 	setSurface (std::move (background));
55 
56 	auto turnTimeClockWidget = addChild (std::make_unique<cTurnTimeClockWidget> (cBox<cPosition> (cPosition (523, 17), cPosition (523 + 62, 17 + 10))));
57 	turnTimeClockWidget->setTurnTimeClock (std::move (turnTimeClock));
58 
59 	//
60 	// Units
61 	//
62 	const int stepX = canStorePlanes ? 227 : 155;
63 	const int stepImageX = canStorePlanes ? 227 : 155;
64 	const int startX = canStorePlanes ? 42 : 8;
65 	const int nameLabelX = canStorePlanes ? 190 : 118;
66 
67 	for (size_t x = 0; x < columns; x++)
68 	{
69 		for (size_t y = 0; y < maxRows; y++)
70 		{
71 			const auto index = x + y * columns;
72 			activateButtons[index] = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (startX + x * stepX, 191 + y * 236), ePushButtonType::Angular, lngPack.i18n ("Text~Others~Active"), FONT_LATIN_NORMAL));
73 			signalConnectionManager.connect (activateButtons[index]->clicked, std::bind (&cWindowStorage::activateClicked, this, index));
74 
75 			reloadButtons[index] = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (startX + x * stepX, 191 + 25 + y * 236), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Reload") : "", FONT_LATIN_NORMAL));
76 			signalConnectionManager.connect (reloadButtons[index]->clicked, std::bind (&cWindowStorage::reloadClicked, this, index));
77 
78 			repairButtons[index] = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (75 + startX + x * stepX, 191 + y * 236), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Repair") : "", FONT_LATIN_NORMAL));
79 			signalConnectionManager.connect (repairButtons[index]->clicked, std::bind (&cWindowStorage::repairClicked, this, index));
80 
81 			upgradeButtons[index] = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (75 + startX + x * stepX, 191 + 25 + y * 236), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Upgrade") : "", FONT_LATIN_NORMAL));
82 			signalConnectionManager.connect (upgradeButtons[index]->clicked, std::bind (&cWindowStorage::upgradeClicked, this, index));
83 
84 			unitImages[index] = addChild (std::make_unique<cImage> (getPosition() + cPosition (17 + x * stepImageX, 9 + y * 236)));
85 			unitNames[index] = addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (17 + x * stepImageX + 5, 9 + y * 236 + 5), getPosition() + cPosition (17 + x * stepImageX + 5 + nameLabelX, 9 + y * 236 + 5 + 118)), ""));
86 			unitNames[index]->setWordWrap (true);
87 
88 			unitDetails[index] = addChild (std::make_unique<cUnitDetailsStored> (cBox<cPosition> (getPosition() + cPosition (17 + x * stepImageX + (canStorePlanes ? 35 : 0), 145 + y * 236), getPosition() + cPosition (17 + x * stepImageX + 130 + (canStorePlanes ? 35 : 0), 145 + y * 236 + 40))));
89 		}
90 	}
91 
92 	//
93 	// Metal Bar
94 	//
95 	auto metalValue = 0;
96 	if (unit.isABuilding())
97 	{
98 		const auto& building = static_cast<const cBuilding&> (unit);
99 
100 		metalValue = building.SubBase->getMetal();
101 
102 		signalConnectionManager.connect (building.SubBase->metalChanged, [&]()
103 		{
104 			metalBar->setValue (building.SubBase->getMetal());
105 		});
106 	}
107 
108 	metalBarAmountLabel = addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (536, 85), getPosition() + cPosition (536 + 40, 85 + 10)), iToStr (metalValue), FONT_LATIN_NORMAL, eAlignmentType::CenterHorizontal));
109 	metalBar = addChild (std::make_unique<cResourceBar> (cBox<cPosition> (getPosition() + cPosition (546, 106), getPosition() + cPosition (546 + 20, 106 + 115)), 0, metalValue, eResourceBarType::Metal, eOrientationType::Vertical));
110 	signalConnectionManager.connect (metalBar->valueChanged, [&]() { metalBarAmountLabel->setText (iToStr (metalBar->getValue())); });
111 	metalBar->disable();
112 
113 	//
114 	// Buttons
115 	//
116 	upButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (504, 426), ePushButtonType::ArrowUpBig));
117 	signalConnectionManager.connect (upButton->clicked, std::bind (&cWindowStorage::upClicked, this));
118 
119 	downButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (532, 426), ePushButtonType::ArrowDownBig));
120 	signalConnectionManager.connect (downButton->clicked, std::bind (&cWindowStorage::downClicked, this));
121 
122 	activateAllButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (518, 246), ePushButtonType::Angular, lngPack.i18n ("Text~Others~Active"), FONT_LATIN_NORMAL));
123 	signalConnectionManager.connect (activateAllButton->clicked, std::bind (&cWindowStorage::activateAllClicked, this));
124 
125 	reloadAllButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (518, 246 + 25), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Reload") : "", FONT_LATIN_NORMAL));
126 	signalConnectionManager.connect (reloadAllButton->clicked, std::bind (&cWindowStorage::reloadAllClicked, this));
127 
128 	repairAllButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (518, 246 + 25 * 2), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Repair") : "", FONT_LATIN_NORMAL));
129 	signalConnectionManager.connect (repairAllButton->clicked, std::bind (&cWindowStorage::repairAllClicked, this));
130 
131 	upgradeAllButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (518, 246 + 25 * 3), ePushButtonType::Angular, canRepairReloadUpgrade ? lngPack.i18n ("Text~Others~Upgrade") : "", FONT_LATIN_NORMAL));
132 	signalConnectionManager.connect (upgradeAllButton->clicked, std::bind (&cWindowStorage::upgradeAllClicked, this));
133 
134 	auto doneButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (518, 371), ePushButtonType::Angular, lngPack.i18n ("Text~Others~Done"), FONT_LATIN_NORMAL));
135 	signalConnectionManager.connect (doneButton->clicked, std::bind (&cWindowStorage::doneClicked, this));
136 
137 	updateUnitsWidgets();
138 	updateGlobalButtons();
139 	updateUpDownButtons();
140 
141 	signalConnectionManager.connect (unit.destroyed, std::bind (&cWindowStorage::closeOnUnitDestruction, this));
142 }
143 
144 //------------------------------------------------------------------------------
updateUnitButtons(const cVehicle & storedUnit,size_t positionIndex)145 void cWindowStorage::updateUnitButtons (const cVehicle& storedUnit, size_t positionIndex)
146 {
147 	const auto& upgraded = *storedUnit.getOwner()->getUnitDataCurrentVersion (storedUnit.data.ID);
148 
149 	activateButtons[positionIndex]->unlock();
150 	if (storedUnit.data.getAmmo() != storedUnit.data.getAmmoMax() && metalBar->getValue() >= 1) reloadButtons[positionIndex]->unlock();
151 	else reloadButtons[positionIndex]->lock();
152 	if (storedUnit.data.getHitpoints() != storedUnit.data.getHitpointsMax() && metalBar->getValue() >= 1) repairButtons[positionIndex]->unlock();
153 	else repairButtons[positionIndex]->lock();
154 	if (storedUnit.data.getVersion() != upgraded.getVersion() && metalBar->getValue() >= 1) upgradeButtons[positionIndex]->unlock();
155 	else upgradeButtons[positionIndex]->lock();
156 }
157 
158 //------------------------------------------------------------------------------
updateUnitName(const cVehicle & storedUnit,size_t positionIndex)159 void cWindowStorage::updateUnitName (const cVehicle& storedUnit, size_t positionIndex)
160 {
161 	auto name = storedUnit.getDisplayName();
162 
163 	const auto& upgraded = *storedUnit.getOwner()->getUnitDataCurrentVersion (storedUnit.data.ID);
164 	if (storedUnit.data.getVersion() != upgraded.getVersion())
165 	{
166 		name += "\n(" + lngPack.i18n ("Text~Comp~Dated") + ")";
167 	}
168 	unitNames[positionIndex]->setText (name);
169 }
170 
171 //------------------------------------------------------------------------------
updateUnitsWidgets()172 void cWindowStorage::updateUnitsWidgets()
173 {
174 	unitsSignalConnectionManager.disconnectAll();
175 
176 	for (size_t x = 0; x < columns; x++)
177 	{
178 		for (size_t y = 0; y < maxRows; y++)
179 		{
180 			const auto positionIndex = x + y * columns;
181 			const auto unitIndex = page * columns * maxRows + positionIndex;
182 
183 			if (unitIndex < unit.storedUnits.size())
184 			{
185 				const auto& storedUnit = *unit.storedUnits[unitIndex];
186 
187 				AutoSurface surface (SDL_CreateRGBSurface (0, storedUnit.uiData->storage->w, storedUnit.uiData->storage->h, Video.getColDepth(), 0, 0, 0, 0));
188 				SDL_BlitSurface (storedUnit.uiData->storage.get(), nullptr, surface.get(), nullptr);
189 				unitImages[positionIndex]->setImage (surface.get());
190 
191 				unitDetails[positionIndex]->setUnit (&storedUnit);
192 
193 				updateUnitName (storedUnit, positionIndex);
194 				updateUnitButtons (storedUnit, positionIndex);
195 
196 				unitsSignalConnectionManager.connect (storedUnit.data.versionChanged, std::bind (&cWindowStorage::updateUnitName, this, std::ref (storedUnit), positionIndex));
197 
198 				unitsSignalConnectionManager.connect (storedUnit.data.hitpointsChanged, std::bind (&cWindowStorage::updateUnitButtons, this, std::ref (storedUnit), positionIndex));
199 				unitsSignalConnectionManager.connect (storedUnit.data.ammoChanged, std::bind (&cWindowStorage::updateUnitButtons, this, std::ref (storedUnit), positionIndex));
200 				unitsSignalConnectionManager.connect (storedUnit.data.hitpointsMaxChanged, std::bind (&cWindowStorage::updateUnitButtons, this, std::ref (storedUnit), positionIndex));
201 				unitsSignalConnectionManager.connect (storedUnit.data.ammoMaxChanged, std::bind (&cWindowStorage::updateUnitButtons, this, std::ref (storedUnit), positionIndex));
202 				unitsSignalConnectionManager.connect (storedUnit.data.versionChanged, std::bind (&cWindowStorage::updateUnitButtons, this, std::ref (storedUnit), positionIndex));
203 
204 				unitsSignalConnectionManager.connect (storedUnit.data.hitpointsChanged, std::bind (&cWindowStorage::updateGlobalButtons, this));
205 				unitsSignalConnectionManager.connect (storedUnit.data.ammoChanged, std::bind (&cWindowStorage::updateGlobalButtons, this));
206 				unitsSignalConnectionManager.connect (storedUnit.data.hitpointsMaxChanged, std::bind (&cWindowStorage::updateGlobalButtons, this));
207 				unitsSignalConnectionManager.connect (storedUnit.data.ammoMaxChanged, std::bind (&cWindowStorage::updateGlobalButtons, this));
208 				unitsSignalConnectionManager.connect (storedUnit.data.versionChanged, std::bind (&cWindowStorage::updateGlobalButtons, this));
209 			}
210 			else
211 			{
212 				unitNames[positionIndex]->setText ("");
213 
214 				SDL_Surface* srcSurface;
215 				if (canStoreShips) srcSurface = GraphicsData.gfx_edock.get();
216 				else if (canStorePlanes) srcSurface = GraphicsData.gfx_ehangar.get();
217 				else srcSurface = GraphicsData.gfx_edepot.get();
218 
219 				AutoSurface surface (SDL_CreateRGBSurface (0, srcSurface->w, srcSurface->h, Video.getColDepth(), 0, 0, 0, 0));
220 				SDL_BlitSurface (srcSurface, nullptr, surface.get(), nullptr);
221 				unitImages[positionIndex]->setImage (surface.get());
222 
223 				unitDetails[positionIndex]->setUnit (nullptr);
224 
225 				activateButtons[positionIndex]->lock();
226 				reloadButtons[positionIndex]->lock();
227 				repairButtons[positionIndex]->lock();
228 				upgradeButtons[positionIndex]->lock();
229 			}
230 		}
231 	}
232 }
233 
234 //------------------------------------------------------------------------------
updateGlobalButtons()235 void cWindowStorage::updateGlobalButtons()
236 {
237 	if (unit.storedUnits.empty()) activateAllButton->lock();
238 	else activateAllButton->unlock();
239 
240 	reloadAllButton->lock();
241 	repairAllButton->lock();
242 	upgradeAllButton->lock();
243 	if (canRepairReloadUpgrade && metalBar->getValue() >= 1)
244 	{
245 		for (size_t i = 0; i != unit.storedUnits.size(); ++i)
246 		{
247 			const auto& vehicle = *unit.storedUnits[i];
248 			const auto& upgraded = *vehicle.getOwner()->getUnitDataCurrentVersion (vehicle.data.ID);
249 
250 			if (vehicle.data.getAmmo() != vehicle.data.getAmmoMax()) reloadAllButton->unlock();
251 			if (vehicle.data.getHitpoints() != vehicle.data.getHitpointsMax()) repairAllButton->unlock();
252 			if (vehicle.data.getVersion() != upgraded.getVersion()) upgradeAllButton->unlock();
253 		}
254 	}
255 }
256 
257 //------------------------------------------------------------------------------
updateUpDownButtons()258 void cWindowStorage::updateUpDownButtons()
259 {
260 	if (page > 0) upButton->unlock();
261 	else upButton->lock();
262 
263 	const auto pageSize = columns * maxRows;
264 	const auto maxPage = unit.storedUnits.size() / pageSize;
265 
266 	if (page < maxPage) downButton->unlock();
267 	else downButton->lock();
268 }
269 
270 //------------------------------------------------------------------------------
upClicked()271 void cWindowStorage::upClicked()
272 {
273 	assert (page > 0);
274 	--page;
275 	updateUpDownButtons();
276 	updateUnitsWidgets();
277 }
278 
279 //------------------------------------------------------------------------------
downClicked()280 void cWindowStorage::downClicked()
281 {
282 	++page;
283 	updateUpDownButtons();
284 	updateUnitsWidgets();
285 }
286 
287 //------------------------------------------------------------------------------
activateClicked(size_t index)288 void cWindowStorage::activateClicked (size_t index)
289 {
290 	activate (page * columns * maxRows + index);
291 }
292 
293 //------------------------------------------------------------------------------
reloadClicked(size_t index)294 void cWindowStorage::reloadClicked (size_t index)
295 {
296 	reload (page * columns * maxRows + index);
297 }
298 
299 //------------------------------------------------------------------------------
repairClicked(size_t index)300 void cWindowStorage::repairClicked (size_t index)
301 {
302 	repair (page * columns * maxRows + index);
303 }
304 
305 //------------------------------------------------------------------------------
upgradeClicked(size_t index)306 void cWindowStorage::upgradeClicked (size_t index)
307 {
308 	upgrade (page * columns * maxRows + index);
309 }
310 
311 //------------------------------------------------------------------------------
activateAllClicked()312 void cWindowStorage::activateAllClicked()
313 {
314 	activateAll();
315 }
316 
317 //------------------------------------------------------------------------------
reloadAllClicked()318 void cWindowStorage::reloadAllClicked()
319 {
320 	reloadAll();
321 }
322 
323 //------------------------------------------------------------------------------
repairAllClicked()324 void cWindowStorage::repairAllClicked()
325 {
326 	repairAll();
327 }
328 
329 //------------------------------------------------------------------------------
upgradeAllClicked()330 void cWindowStorage::upgradeAllClicked()
331 {
332 	upgradeAll();
333 }
334 
335 //------------------------------------------------------------------------------
doneClicked()336 void cWindowStorage::doneClicked()
337 {
338 	close();
339 }
340 
341 //------------------------------------------------------------------------------
closeOnUnitDestruction()342 void cWindowStorage::closeOnUnitDestruction()
343 {
344 	close();
345 	auto application = getActiveApplication();
346 	if (application)
347 	{
348 		application->show (std::make_shared<cDialogOk> (lngPack.i18n ("Text~Others~Unit_destroyed")));
349 	}
350 }
351