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/dialogs/dialogtransfer.h"
21
22 #include "ui/graphical/menu/dialogs/dialogok.h"
23 #include "ui/graphical/menu/widgets/label.h"
24 #include "ui/graphical/menu/widgets/pushbutton.h"
25 #include "ui/graphical/menu/widgets/image.h"
26 #include "ui/graphical/application.h"
27 #include "pcx.h"
28 #include "main.h"
29 #include "game/data/units/unit.h"
30 #include "game/data/units/building.h"
31 #include "game/data/units/vehicle.h"
32 #include "game/data/map/map.h"
33 #include "video.h"
34 #include "game/data/base/base.h"
35
36 //------------------------------------------------------------------------------
cNewDialogTransfer(const cUnit & sourceUnit,const cUnit & destinationUnit)37 cNewDialogTransfer::cNewDialogTransfer (const cUnit& sourceUnit, const cUnit& destinationUnit) :
38 cWindow (LoadPCX (GFXOD_DIALOG_TRANSFER), eWindowBackgrounds::Alpha),
39 resourceType (getCommonResourceType (sourceUnit, destinationUnit))
40 {
41 transferLabel = addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (142, 48), getPosition() + cPosition (142 + 32, 48 + 15)), "", FONT_LATIN_BIG, eAlignmentType::CenterHorizontal));
42
43 arrowImage = addChild (std::make_unique<cImage> (getPosition() + cPosition (140, 77)));
44
45 addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (20, 105), getPosition() + cPosition (40 + 80, 105 + 10)), sourceUnit.data.name, FONT_LATIN_SMALL_WHITE, eAlignmentType::CenterHorizontal));
46 addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (190, 105), getPosition() + cPosition (210 + 80, 105 + 10)), destinationUnit.data.name, FONT_LATIN_SMALL_WHITE, eAlignmentType::CenterHorizontal));
47
48 sourceUnitCargoLabel = addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (18, 60), getPosition() + cPosition (18 + 20, 60 + 10)), "", FONT_LATIN_SMALL_WHITE, eAlignmentType::CenterHorizontal));
49 destinationUnitCargoLabel = addChild (std::make_unique<cLabel> (cBox<cPosition> (getPosition() + cPosition (272, 60), getPosition() + cPosition (272 + 20, 60 + 10)), "", FONT_LATIN_SMALL_WHITE, eAlignmentType::CenterHorizontal));
50
51 auto sourceUnitImage = addChild (std::make_unique<cImage> (getPosition() + cPosition (39, 26)));
52 auto destinationUnitImage = addChild (std::make_unique<cImage> (getPosition() + cPosition (208, 26)));
53
54 resourceBar = addChild (std::make_unique<cResourceBar> (cBox<cPosition> (getPosition() + cPosition (43, 159), getPosition() + cPosition (43 + 223, 159 + 16)), 0, 100, getResourceBarType (sourceUnit, destinationUnit), eOrientationType::Horizontal));
55 signalConnectionManager.connect (resourceBar->valueChanged, std::bind (&cNewDialogTransfer::transferValueChanged, this));
56 auto increaseButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (279, 159), ePushButtonType::ArrowRightSmall));
57 signalConnectionManager.connect (increaseButton->clicked, [&]() { resourceBar->increase (1); });
58 auto decreaseButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (17, 159), ePushButtonType::ArrowLeftSmall));
59 signalConnectionManager.connect (decreaseButton->clicked, [&]() { resourceBar->decrease (1); });
60
61 auto doneButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (159, 200), ePushButtonType::Angular, lngPack.i18n ("Text~Others~Done"), FONT_LATIN_NORMAL));
62 doneButton->addClickShortcut (cKeySequence (cKeyCombination (eKeyModifierType::None, SDLK_RETURN)));
63 signalConnectionManager.connect (doneButton->clicked, [&]() { done(); });
64
65 auto cancelButton = addChild (std::make_unique<cPushButton> (getPosition() + cPosition (71, 200), ePushButtonType::Angular, lngPack.i18n ("Text~Others~Cancel"), FONT_LATIN_NORMAL));
66 cancelButton->addClickShortcut (cKeySequence (cKeyCombination (eKeyModifierType::None, SDLK_ESCAPE)));
67 signalConnectionManager.connect (cancelButton->clicked, [&]() { close(); });
68
69 initUnitImage (*sourceUnitImage, sourceUnit);
70 initUnitImage (*destinationUnitImage, destinationUnit);
71
72 initCargo (sourceCargo, sourceMaxCargo, sourceUnit, destinationUnit);
73 initCargo (destinationCargo, destinationMaxCargo, destinationUnit, sourceUnit);
74
75 resourceBar->setMinValue (0);
76 resourceBar->setMaxValue (destinationMaxCargo);
77
78 auto maxTransferToDestination = std::min (destinationCargo + sourceCargo, destinationMaxCargo) - destinationCargo;
79 auto maxTransferToSource = std::min (sourceCargo + destinationCargo, sourceMaxCargo) - sourceCargo;
80
81 resourceBar->setFixedMinValue (destinationCargo - maxTransferToSource);
82 resourceBar->setFixedMaxValue (destinationCargo + maxTransferToDestination);
83
84 resourceBar->setValue (destinationCargo + maxTransferToDestination);
85
86 transferValueChanged();
87
88 signalConnectionManager.connect (sourceUnit.destroyed, std::bind (&cNewDialogTransfer::closeOnUnitDestruction, this));
89 signalConnectionManager.connect (destinationUnit.destroyed, std::bind (&cNewDialogTransfer::closeOnUnitDestruction, this));
90 }
91
92 //------------------------------------------------------------------------------
getCommonResourceType(const cUnit & sourceUnit,const cUnit & destinationUnit) const93 sUnitData::eStorageResType cNewDialogTransfer::getCommonResourceType (const cUnit& sourceUnit, const cUnit& destinationUnit) const
94 {
95 sUnitData::eStorageResType commonResourceType = sUnitData::STORE_RES_NONE;
96 const auto sourceResource = sourceUnit.data.storeResType;
97 const auto destinationResource = destinationUnit.data.storeResType;
98 if (sourceResource == destinationResource)
99 {
100 commonResourceType = destinationResource;
101 }
102 else
103 {
104 if (sourceUnit.isAVehicle() && destinationUnit.isABuilding()) commonResourceType = sourceResource;
105 if (sourceUnit.isABuilding() && destinationUnit.isAVehicle()) commonResourceType = destinationResource;
106 }
107
108 return commonResourceType;
109 }
110
111 //------------------------------------------------------------------------------
getResourceBarType(const cUnit & sourceUnit,const cUnit & destinationUnit) const112 eResourceBarType cNewDialogTransfer::getResourceBarType (const cUnit& sourceUnit, const cUnit& destinationUnit) const
113 {
114 switch (getCommonResourceType (sourceUnit, destinationUnit))
115 {
116 default:
117 case sUnitData::STORE_RES_METAL:
118 return eResourceBarType::MetalSlim;
119 case sUnitData::STORE_RES_OIL:
120 return eResourceBarType::OilSlim;
121 case sUnitData::STORE_RES_GOLD:
122 return eResourceBarType::GoldSlim;
123 }
124 }
125
126 //------------------------------------------------------------------------------
initUnitImage(cImage & image,const cUnit & unit)127 void cNewDialogTransfer::initUnitImage (cImage& image, const cUnit& unit)
128 {
129 const int unitImageWidth = 64;
130 const int unitImageHeight = 64;
131
132 const auto zoom = (float)unitImageWidth / (unit.data.isBig ? cStaticMap::tilePixelWidth * 2 : cStaticMap::tilePixelWidth);
133
134 AutoSurface unitImageSurface (SDL_CreateRGBSurface (0, unitImageWidth, unitImageHeight, Video.getColDepth(), 0, 0, 0, 0));
135 SDL_FillRect (unitImageSurface.get(), nullptr, 0xFF00FF);
136 SDL_SetColorKey (unitImageSurface.get(), SDL_TRUE, 0xFF00FF);
137
138 SDL_Rect dest = {0, 0, 0, 0};
139
140 if (unit.isABuilding())
141 {
142 const auto& building = static_cast<const cBuilding&> (unit);
143 building.render (0, unitImageSurface.get(), dest, zoom, false, false);
144 }
145 else if (unit.isAVehicle())
146 {
147 const auto& vehicle = static_cast<const cVehicle&> (unit);
148 vehicle.render (nullptr, 0, nullptr, unitImageSurface.get(), dest, zoom, false);
149 }
150
151 image.setImage (unitImageSurface.get());
152 }
153
154 //------------------------------------------------------------------------------
initCargo(int & cargo,int & maxCargo,const cUnit & unit1,const cUnit & unit2)155 void cNewDialogTransfer::initCargo (int& cargo, int& maxCargo, const cUnit& unit1, const cUnit& unit2)
156 {
157 if (unit1.isABuilding())
158 {
159 const auto& building = static_cast<const cBuilding&> (unit1);
160
161 if (unit2.isAVehicle())
162 {
163 switch (unit2.data.storeResType)
164 {
165 default:
166 case sUnitData::STORE_RES_METAL:
167 maxCargo = building.SubBase->MaxMetal;
168 cargo = building.SubBase->getMetal();
169 break;
170 case sUnitData::STORE_RES_OIL:
171 maxCargo = building.SubBase->MaxOil;
172 cargo = building.SubBase->getOil();
173 break;
174 case sUnitData::STORE_RES_GOLD:
175 maxCargo = building.SubBase->MaxGold;
176 cargo = building.SubBase->getGold();
177 break;
178 }
179 }
180 else if (unit2.isABuilding())
181 {
182 maxCargo = building.data.storageResMax;
183 cargo = building.data.getStoredResources();
184 }
185 }
186 else if (unit1.isAVehicle())
187 {
188 maxCargo = unit1.data.storageResMax;
189 cargo = unit1.data.getStoredResources();
190 }
191 }
192
193 namespace
194 {
195
196 // TODO: move function into a better file ?
FlipSurfaceHorizontally(SDL_Surface * surface)197 void FlipSurfaceHorizontally (SDL_Surface* surface)
198 {
199 assert (surface);
200 if (SDL_MUSTLOCK (surface)) SDL_LockSurface (surface);
201
202 // Assume surface format uses Uint32*
203 // TODO: check surface format (or support more format).
204 Uint32* p = static_cast<Uint32*> (surface->pixels);
205
206 for (int h = 0; h != surface->h; ++h)
207 for (int w = 0; w != surface->w / 2; ++w)
208 std::swap (p[h * surface->w + w], p[ (h + 1) * surface->w - w - 1]);
209
210 if (SDL_MUSTLOCK (surface)) SDL_UnlockSurface (surface);
211 }
212 }
213
214
215 //------------------------------------------------------------------------------
getTransferValue() const216 int cNewDialogTransfer::getTransferValue() const
217 {
218 return resourceBar->getValue() - destinationCargo;;
219 }
220
221 //------------------------------------------------------------------------------
getResourceType() const222 sUnitData::eStorageResType cNewDialogTransfer::getResourceType() const
223 {
224 return resourceType;
225 }
226
227 //------------------------------------------------------------------------------
transferValueChanged()228 void cNewDialogTransfer::transferValueChanged()
229 {
230 const auto transferValue = getTransferValue();
231 transferLabel->setText (iToStr (std::abs (transferValue)));
232
233 sourceUnitCargoLabel->setText (iToStr (sourceCargo - transferValue));
234 destinationUnitCargoLabel->setText (iToStr (destinationCargo + transferValue));
235
236 if (transferValue >= 0) arrowImage->hide();
237 else
238 {
239 arrowImage->show();
240 // Set right to left arrow image.
241 // little hack: flip part of the image that represent the arrow
242 const unsigned int w = 40;
243 const unsigned int h = 20;
244 AutoSurface arrowSurface (SDL_CreateRGBSurface (0, w, h, Video.getColDepth(), 0, 0, 0, 0));
245 const Sint16 x = arrowImage->getPosition().x() - getPosition().x(); // 140
246 const Sint16 y = arrowImage->getPosition().y() - getPosition().y(); // 77
247 SDL_Rect src = {x, y, w, h};
248 SDL_BlitSurface (getSurface(), &src, arrowSurface.get(), nullptr);
249 FlipSurfaceHorizontally (arrowSurface.get());
250
251 arrowImage->setImage (arrowSurface.get());
252 }
253 }
254
255 //------------------------------------------------------------------------------
closeOnUnitDestruction()256 void cNewDialogTransfer::closeOnUnitDestruction()
257 {
258 close();
259 auto application = getActiveApplication();
260 if (application)
261 {
262 application->show (std::make_shared<cDialogOk> (lngPack.i18n ("Text~Others~Unit_destroyed")));
263 }
264 }
265