1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name ui.cpp - The user interface globals. */
12 //
13 // (c) Copyright 1999-2019 by Lutz Sammer, Andreas Arens,
14 // Jimmy Salmon, Pali Rohár and Andrettin
15 //
16 // This program is free software; you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation; only version 2 of the License.
19 //
20 // This program is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software
27 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 // 02111-1307, USA.
29 //
30
31 //@{
32
33 /*----------------------------------------------------------------------------
34 -- Includes
35 ----------------------------------------------------------------------------*/
36
37 #include "stratagus.h"
38
39 #include "ui/ui.h"
40
41 #include "font.h"
42 //Wyrmgus start
43 #include "game.h"
44 #include "grand_strategy.h"
45 //Wyrmgus end
46 #include "iolib.h"
47 #include "map/map.h"
48 #include "map/map_layer.h"
49 #include "menus.h"
50 #include "title.h"
51 #include "translate.h"
52 #include "ui/contenttype.h"
53 #include "ui/interface.h"
54 #include "ui/popup.h"
55 #include "unit/unit.h"
56 #include "video.h"
57 #include "world.h"
58
59 #include <stdarg.h>
60
61 /*----------------------------------------------------------------------------
62 -- Variables
63 ----------------------------------------------------------------------------*/
64
65 bool RightButtonAttacks; /// right button attacks
66
67 static ViewportModeType NewViewportMode = VIEWPORT_SINGLE;
68
69 bool FancyBuildings; /// Mirror buildings 1 yes, 0 now.
70
71 /**
72 ** The user interface configuration
73 */
74 CUserInterface UI;
75
76 /*----------------------------------------------------------------------------
77 -- Functions
78 ----------------------------------------------------------------------------*/
79
80 /**
81 ** Show load progress.
82 **
83 ** @param fmt printf format string.
84 */
ShowLoadProgress(const char * fmt,...)85 void ShowLoadProgress(const char *fmt, ...)
86 {
87 static unsigned int lastProgressUpdate = SDL_GetTicks();
88 if (SDL_GetTicks() < lastProgressUpdate + 16) {
89 // Only show progress updates every c. 1/60th of a second, otherwise we're waiting for the screen too much
90 return;
91 }
92 lastProgressUpdate = SDL_GetTicks();
93
94 UpdateLoadProgress();
95
96 va_list va;
97 char temp[4096];
98
99 va_start(va, fmt);
100 vsnprintf(temp, sizeof(temp) - 1, fmt, va);
101 temp[sizeof(temp) - 1] = '\0';
102 va_end(va);
103
104 if (Video.Depth && IsGameFontReady() && GetGameFont().IsLoaded()) {
105 // Remove non printable chars
106 for (unsigned char *s = (unsigned char *)temp; *s; ++s) {
107 if (*s < 32) {
108 *s = ' ';
109 }
110 }
111 //Wyrmgus start
112 // Video.FillRectangle(ColorBlack, 5, Video.Height - 18, Video.Width - 10, 18);
113 if (loadingBackground == nullptr) {
114 Video.FillRectangle(ColorBlack, 0, Video.Height - 18, Video.Width, 18);
115 }
116 //Wyrmgus end
117 CLabel(GetGameFont()).DrawCentered(Video.Width / 2, Video.Height - 16, temp);
118 //Wyrmgus start
119 // InvalidateArea(5, Video.Height - 18, Video.Width - 10, 18);
120 if (loadingBackground == nullptr) {
121 InvalidateArea(0, Video.Height - 18, Video.Width, 18);
122 } else {
123 InvalidateArea(0, 0, Video.Width, Video.Height);
124 }
125 //Wyrmgus end
126
127 RealizeVideoMemory();
128 } else {
129 DebugPrint("!!!!%s\n" _C_ temp);
130 }
131
132 PollEvents();
133 }
134
135 /**
136 ** @brief Update load progress.
137 */
UpdateLoadProgress()138 void UpdateLoadProgress()
139 {
140 if (Video.Depth && IsGameFontReady() && GetGameFont().IsLoaded()) {
141 UpdateLoadingBar();
142 }
143
144 PollEvents();
145 }
146
~CUnitInfoPanel()147 CUnitInfoPanel::~CUnitInfoPanel()
148 {
149 for (std::vector<CContentType *>::iterator content = Contents.begin();
150 content != Contents.end(); ++content) {
151 delete *content;
152 }
153 delete Condition;
154 }
155
156
CUserInterface()157 CUserInterface::CUserInterface() :
158 MouseScroll(false), KeyScroll(false), KeyScrollSpeed(1),
159 MouseScrollSpeed(1), MouseScrollSpeedDefault(0), MouseScrollSpeedControl(0),
160 NormalFontColor("yellow"), ReverseFontColor("white"),
161 SingleSelectedButton(nullptr),
162 MaxSelectedFont(nullptr), MaxSelectedTextX(0), MaxSelectedTextY(0),
163 SingleTrainingButton(nullptr),
164 SingleTrainingFont(nullptr), SingleTrainingTextX(0), SingleTrainingTextY(0),
165 TrainingFont(nullptr), TrainingTextX(0), TrainingTextY(0),
166 IdleWorkerButton(nullptr), LevelUpUnitButton(nullptr),
167 CompletedBarColor(0), CompletedBarShadow(0),
168 ViewportMode(VIEWPORT_SINGLE), MouseViewport(nullptr),
169 SelectedViewport(nullptr), NumViewports(0),
170 MessageFont(nullptr), MessageScrollSpeed(5),
171 CurrentMapLayer(nullptr), PreviousMapLayer(nullptr),
172 ViewportCursorColor(0), Offset640X(0), Offset480Y(0),
173 VictoryBackgroundG(nullptr), DefeatBackgroundG(nullptr)
174 {
175 MouseWarpPos.x = MouseWarpPos.y = -1;
176
177 Point.Name = "cursor-point";
178 Glass.Name = "cursor-glass";
179 Cross.Name = "cursor-cross";
180 YellowHair.Name = "cursor-yellow-hair";
181 GreenHair.Name = "cursor-green-hair";
182 RedHair.Name = "cursor-red-hair";
183 Scroll.Name = "cursor-scroll";
184
185 ArrowE.Name = "cursor-arrow-e";
186 ArrowNE.Name = "cursor-arrow-ne";
187 ArrowN.Name = "cursor-arrow-n";
188 ArrowNW.Name = "cursor-arrow-nw";
189 ArrowW.Name = "cursor-arrow-w";
190 ArrowSW.Name = "cursor-arrow-sw";
191 ArrowS.Name = "cursor-arrow-s";
192 ArrowSE.Name = "cursor-arrow-se";
193
194 NormalFontColor = "light-blue";
195 ReverseFontColor = "yellow";
196 }
197
198 /**
199 ** Get popup class pointer by string identifier.
200 **
201 ** @param ident Popup identifier.
202 **
203 ** @return popup class pointer.
204 */
PopupByIdent(const std::string & ident)205 CPopup *PopupByIdent(const std::string &ident)
206 {
207 for (std::vector<CPopup *>::iterator i = UI.ButtonPopups.begin(); i < UI.ButtonPopups.end(); ++i) {
208 if ((*i)->Ident == ident) {
209 return *i;
210 }
211 }
212 return nullptr;
213 }
214
215 /**
216 ** Initialize the user interface.
217 */
InitUserInterface()218 void InitUserInterface()
219 {
220 ShowLoadProgress("%s", _("Loading User Interface"));
221
222 UI.Offset640X = (Video.Width - 640) / 2;
223 UI.Offset480Y = (Video.Height - 480) / 2;
224
225 //
226 // Calculations
227 //
228 if (Map.Info.MapWidth) {
229 UI.MapArea.EndX = std::min<int>(UI.MapArea.EndX, UI.MapArea.X + Map.Info.MapWidth * Map.GetCurrentPixelTileSize().x - 1);
230 UI.MapArea.EndY = std::min<int>(UI.MapArea.EndY, UI.MapArea.Y + Map.Info.MapHeight * Map.GetCurrentPixelTileSize().y - 1);
231 }
232
233 UI.SelectedViewport = UI.Viewports;
234
235 SetViewportMode(VIEWPORT_SINGLE);
236
237 UI.CompletedBarColor = Video.MapRGB(TheScreen->format, UI.CompletedBarColorRGB);
238 UI.ViewportCursorColor = ColorWhite;
239 }
240
241 /**
242 ** Load Cursor.
243 */
Load()244 void CursorConfig::Load()
245 {
246 Assert(!Name.empty());
247 Cursor = CursorByIdent(Name);
248 if (Cursor == nullptr) {
249 return ;
250 }
251 Assert(Name == Cursor->Ident);
252 }
253
254 /**
255 ** Load the user interface graphics.
256 */
Load()257 void CUserInterface::Load()
258 {
259 //Wyrmgus start
260 // set the correct UI
261 CleanUserInterfaceFillers();
262 std::vector<CFiller> new_ui_fillers;
263 if (ThisPlayer) {
264 if (ThisPlayer->Faction != -1) {
265 new_ui_fillers = PlayerRaces.GetFactionUIFillers(ThisPlayer->Faction);
266 } else {
267 new_ui_fillers = PlayerRaces.GetCivilizationUIFillers(ThisPlayer->Race);
268 }
269 }
270 for (size_t i = 0; i < new_ui_fillers.size(); ++i) {
271 CFiller filler = CFiller();
272 filler.G = CGraphic::New(new_ui_fillers[i].G->File);
273 filler.X = new_ui_fillers[i].X;
274 filler.Y = new_ui_fillers[i].Y;
275 UI.Fillers.push_back(filler);
276 }
277 //Wyrmgus end
278
279 // Load graphics
280 const int size = (int)Fillers.size();
281 for (int i = 0; i < size; ++i) {
282 Fillers[i].Load();
283 }
284
285 for (int i = 0; i <= FreeWorkersCount; ++i) {
286 if (Resources[i].G) {
287 Resources[i].G->Load();
288 Resources[i].G->UseDisplayFormat();
289 }
290 }
291
292 if (InfoPanel.G) {
293 InfoPanel.G->Load();
294 InfoPanel.G->UseDisplayFormat();
295 }
296 if (ButtonPanel.G) {
297 ButtonPanel.G->Load();
298 ButtonPanel.G->UseDisplayFormat();
299 }
300 if (PieMenu.G) {
301 PieMenu.G->Load();
302 PieMenu.G->UseDisplayFormat();
303 }
304
305 //Wyrmgus start
306 if (Preference.IconFrameG) {
307 Preference.IconFrameG->Load();
308 Preference.IconFrameG->UseDisplayFormat();
309 }
310 if (Preference.PressedIconFrameG) {
311 Preference.PressedIconFrameG->Load();
312 Preference.PressedIconFrameG->UseDisplayFormat();
313 }
314 if (Preference.CommandButtonFrameG) {
315 Preference.CommandButtonFrameG->Load();
316 Preference.CommandButtonFrameG->UseDisplayFormat();
317 }
318 if (Preference.BarFrameG) {
319 Preference.BarFrameG->Load();
320 Preference.BarFrameG->UseDisplayFormat();
321 }
322 if (Preference.InfoPanelFrameG) {
323 Preference.InfoPanelFrameG->Load();
324 Preference.InfoPanelFrameG->UseDisplayFormat();
325 }
326 if (Preference.ProgressBarG) {
327 Preference.ProgressBarG->Load();
328 Preference.ProgressBarG->UseDisplayFormat();
329 }
330 //Wyrmgus end
331
332 // Resolve cursors
333 Point.Load();
334 Glass.Load();
335 Cross.Load();
336 YellowHair.Load();
337 GreenHair.Load();
338 RedHair.Load();
339 Scroll.Load();
340
341 ArrowE.Load();
342 ArrowNE.Load();
343 ArrowN.Load();
344 ArrowNW.Load();
345 ArrowW.Load();
346 ArrowSW.Load();
347 ArrowS.Load();
348 ArrowSE.Load();
349 }
350
351
Contains(const PixelPos & screenPos) const352 bool CMapArea::Contains(const PixelPos &screenPos) const
353 {
354 return this->X <= screenPos.x && screenPos.x <= this->EndX
355 && this->Y <= screenPos.y && screenPos.y <= this->EndY;
356 }
357
358 /**
359 ** Save the viewports.
360 **
361 ** @param file Save file handle
362 ** @param ui User interface to save
363 */
SaveViewports(CFile & file,const CUserInterface & ui)364 static void SaveViewports(CFile &file, const CUserInterface &ui)
365 {
366 // FIXME: don't save the number
367 file.printf("DefineViewports(\"mode\", %d", ui.ViewportMode);
368 for (int i = 0; i < ui.NumViewports; ++i) {
369 const CViewport &vp = ui.Viewports[i];
370 file.printf(",\n \"viewport\", {%d, %d, %d}", vp.MapPos.x, vp.MapPos.y,
371 vp.Unit ? UnitNumber(*vp.Unit) : -1);
372 }
373 file.printf(")\n\n");
374 }
375
376 /**
377 ** Save the user interface module.
378 **
379 ** @param file Save file handle
380 */
SaveUserInterface(CFile & file)381 void SaveUserInterface(CFile &file)
382 {
383 SaveViewports(file, UI);
384 }
385
386 /**
387 ** Clean up a user interface.
388 */
~CUserInterface()389 CUserInterface::~CUserInterface()
390 {
391 }
392
393 /**
394 ** Clean up the user interface module.
395 */
CleanUserInterface()396 void CleanUserInterface()
397 {
398 // Filler
399 //Wyrmgus start
400 /*
401 for (int i = 0; i < (int)UI.Fillers.size(); ++i) {
402 CGraphic::Free(UI.Fillers[i].G);
403 }
404 UI.Fillers.clear();
405 */
406 CleanUserInterfaceFillers();
407 //Wyrmgus end
408
409 // Resource Icons
410 for (int i = 0; i <= FreeWorkersCount; ++i) {
411 CGraphic::Free(UI.Resources[i].G);
412 }
413
414 // Info Panel
415 CGraphic::Free(UI.InfoPanel.G);
416 for (std::vector<CUnitInfoPanel *>::iterator panel = UI.InfoPanelContents.begin();
417 panel != UI.InfoPanelContents.end(); ++panel) {
418 delete *panel;
419 }
420 UI.InfoPanelContents.clear();
421
422 //Wyrmgus start
423 CGraphic::Free(Preference.IconFrameG);
424 CGraphic::Free(Preference.PressedIconFrameG);
425 CGraphic::Free(Preference.CommandButtonFrameG);
426 CGraphic::Free(Preference.BarFrameG);
427 CGraphic::Free(Preference.InfoPanelFrameG);
428 CGraphic::Free(Preference.ProgressBarG);
429 //Wyrmgus end
430
431 // Button Popups
432 for (std::vector<CPopup *>::iterator popup = UI.ButtonPopups.begin();
433 popup != UI.ButtonPopups.end(); ++popup) {
434 delete *popup;
435 }
436 UI.ButtonPopups.clear();
437
438 delete UI.SingleSelectedButton;
439 UI.SelectedButtons.clear();
440 delete UI.SingleTrainingButton;
441 UI.SingleTrainingText.clear();
442 UI.TrainingButtons.clear();
443 UI.TrainingText.clear();
444 delete UI.UpgradingButton;
445 delete UI.ResearchingButton;
446 UI.TransportingButtons.clear();
447 //Wyrmgus start
448 delete UI.IdleWorkerButton;
449 delete UI.LevelUpUnitButton;
450 UI.HeroUnitButtons.clear();
451 UI.InventoryButtons.clear();
452 //Wyrmgus end
453 UI.UserButtons.clear();
454
455 // Button Panel
456 CGraphic::Free(UI.ButtonPanel.G);
457
458 // Pie Menu
459 CGraphic::Free(UI.PieMenu.G);
460
461 // Backgrounds
462 CGraphic::Free(UI.VictoryBackgroundG);
463 CGraphic::Free(UI.DefeatBackgroundG);
464
465 // Title Screens
466 if (TitleScreens) {
467 for (int i = 0; TitleScreens[i]; ++i) {
468 delete TitleScreens[i];
469 }
470 delete[] TitleScreens;
471 TitleScreens = nullptr;
472 }
473 }
474
475 //Wyrmgus start
CleanUserInterfaceFillers()476 void CleanUserInterfaceFillers()
477 {
478 for (int i = 0; i < (int)UI.Fillers.size(); ++i) {
479 CGraphic::Free(UI.Fillers[i].G);
480 }
481 UI.Fillers.clear();
482 }
483
UpdateSurfaceLayerButtons()484 void UpdateSurfaceLayerButtons()
485 {
486 unsigned int last_surface_layer = 0;
487 if (UI.CurrentMapLayer) {
488 for (size_t z = 0; z < Map.MapLayers.size(); ++z) {
489 if (UI.CurrentMapLayer->Plane == Map.MapLayers[z]->Plane && UI.CurrentMapLayer->World == Map.MapLayers[z]->World && Map.MapLayers[z]->SurfaceLayer > (int) last_surface_layer) {
490 last_surface_layer = Map.MapLayers[z]->SurfaceLayer;
491 }
492 }
493 }
494
495 for (size_t i = 0; i < UI.SurfaceLayerButtons.size(); ++i) {
496 if (i <= last_surface_layer && last_surface_layer > 0) {
497 UI.SurfaceLayerButtons[i].X = -2;
498 UI.SurfaceLayerButtons[i].Y = Video.Height - 157 + (19 * i);
499 } else {
500 UI.SurfaceLayerButtons[i].X = -1;
501 UI.SurfaceLayerButtons[i].Y = -1;
502 }
503 }
504 }
505 //Wyrmgus end
506
FreeButtonStyles()507 void FreeButtonStyles()
508 {
509 std::map<std::string, ButtonStyle *>::iterator i;
510 for (i = ButtonStyleHash.begin(); i != ButtonStyleHash.end(); ++i) {
511 delete(*i).second;
512 }
513 ButtonStyleHash.clear();
514 }
515
516 /**
517 ** Takes coordinates of a pixel in stratagus's window and computes
518 ** the map viewport which contains this pixel.
519 **
520 ** @param screenPos pixel coordinate with origin at UL corner of screen
521 **
522 ** @return viewport pointer or null if this pixel is not inside
523 ** any of the viewports.
524 **
525 ** @note This functions only works with rectangular viewports, when
526 ** we support shaped map window, this must be rewritten.
527 */
GetViewport(const PixelPos & screenPos)528 CViewport *GetViewport(const PixelPos &screenPos)
529 {
530 for (CViewport *vp = UI.Viewports; vp < UI.Viewports + UI.NumViewports; ++vp) {
531 if (vp->Contains(screenPos)) {
532 return vp;
533 }
534 }
535 return nullptr;
536 }
537
538 /**
539 ** Takes an array of new Viewports which are supposed to have their
540 ** pixel geometry (CViewport::[XY] and CViewport::End[XY]) already
541 ** computed. Using this information as well as old viewport's
542 ** parameters fills in new viewports' CViewport::Map* parameters.
543 ** Then it replaces the old viewports with the new ones and finishes
544 ** the set-up of the new mode.
545 **
546 ** @param new_vps The array of the new viewports
547 ** @param num_vps The number of elements in the new_vps[] array.
548 */
FinishViewportModeConfiguration(CViewport new_vps[],int num_vps)549 static void FinishViewportModeConfiguration(CViewport new_vps[], int num_vps)
550 {
551 // Compute location of the viewport using oldviewport
552 for (int i = 0; i < num_vps; ++i) {
553 new_vps[i].MapPos.x = 0;
554 new_vps[i].MapPos.y = 0;
555 const CViewport *vp = GetViewport(new_vps[i].GetTopLeftPos());
556 if (vp) {
557 const PixelDiff relDiff = new_vps[i].GetTopLeftPos() - vp->GetTopLeftPos();
558
559 new_vps[i].Offset = relDiff + Map.TilePosToMapPixelPos_TopLeft(vp->MapPos, UI.CurrentMapLayer) + vp->Offset;
560 } else {
561 new_vps[i].Offset.x = 0;
562 new_vps[i].Offset.y = 0;
563 }
564 }
565
566 // Affect the old viewport.
567 for (int i = 0; i < num_vps; ++i) {
568 CViewport &vp = UI.Viewports[i];
569
570 vp.TopLeftPos = new_vps[i].TopLeftPos;
571 vp.BottomRightPos = new_vps[i].BottomRightPos;
572 vp.Set(new_vps[i].MapPos, new_vps[i].Offset);
573 }
574 UI.NumViewports = num_vps;
575
576 //
577 // Update the viewport pointers
578 //
579 UI.MouseViewport = GetViewport(CursorScreenPos);
580 UI.SelectedViewport = std::min(UI.Viewports + UI.NumViewports - 1, UI.SelectedViewport);
581 }
582
583 /**
584 ** Takes a viewport which is supposed to have its CViewport::[XY]
585 ** correctly filled-in and computes CViewport::End[XY] attributes
586 ** according to clipping information passed in other two arguments.
587 **
588 ** @param vp The viewport.
589 ** @param ClipX Maximum x-coordinate of the viewport's right side
590 ** as dictated by current UI's geometry and ViewportMode.
591 ** @param ClipY Maximum y-coordinate of the viewport's bottom side
592 ** as dictated by current UI's geometry and ViewportMode.
593 **
594 ** @note It is supposed that values passed in Clip[XY] will
595 ** never be greater than UI::MapArea::End[XY].
596 ** However, they can be smaller according to the place
597 ** the viewport vp takes in context of current ViewportMode.
598 */
ClipViewport(CViewport & vp,int ClipX,int ClipY)599 static void ClipViewport(CViewport &vp, int ClipX, int ClipY)
600 {
601 // begin with maximum possible viewport size
602 //Wyrmgus start
603 // vp.BottomRightPos.x = vp.TopLeftPos.x + Map.Info.MapWidth * Map.GetCurrentPixelTileSize().x - 1;
604 // vp.BottomRightPos.y = vp.TopLeftPos.y + Map.Info.MapHeight * Map.GetCurrentPixelTileSize().y - 1;
605 vp.BottomRightPos.x = vp.TopLeftPos.x + (Map.Info.MapWidths.size() && UI.CurrentMapLayer ? UI.CurrentMapLayer->GetWidth() : Map.Info.MapWidth) * Map.GetCurrentPixelTileSize().x - 1;
606 vp.BottomRightPos.y = vp.TopLeftPos.y + (Map.Info.MapHeights.size() && UI.CurrentMapLayer ? UI.CurrentMapLayer->GetHeight() : Map.Info.MapHeight) * Map.GetCurrentPixelTileSize().y - 1;
607 //Wyrmgus end
608
609 // first clip it to MapArea size if necessary
610 vp.BottomRightPos.x = std::min<int>(vp.BottomRightPos.x, ClipX);
611 vp.BottomRightPos.y = std::min<int>(vp.BottomRightPos.y, ClipY);
612
613 Assert(vp.BottomRightPos.x <= UI.MapArea.EndX);
614 Assert(vp.BottomRightPos.y <= UI.MapArea.EndY);
615 }
616
617 /**
618 ** Compute viewport parameters for single viewport mode.
619 **
620 ** The parameters include viewport's width and height expressed
621 ** in pixels, its position with respect to Stratagus's window
622 ** origin, and the corresponding map parameters expressed in map
623 ** tiles with origin at map origin (map tile (0,0)).
624 */
SetViewportModeSingle()625 static void SetViewportModeSingle()
626 {
627 CViewport new_vps[MAX_NUM_VIEWPORTS];
628
629 DebugPrint("Single viewport set\n");
630
631 new_vps[0].TopLeftPos.x = UI.MapArea.X;
632 new_vps[0].TopLeftPos.y = UI.MapArea.Y;
633 ClipViewport(new_vps[0], UI.MapArea.EndX, UI.MapArea.EndY);
634
635 FinishViewportModeConfiguration(new_vps, 1);
636 }
637
638 /**
639 ** Compute viewport parameters for horizontally split viewport mode.
640 ** This mode splits the UI::MapArea with a horizontal line to
641 ** 2 (approximately) equal parts.
642 **
643 ** The parameters include viewport's width and height expressed
644 ** in pixels, its position with respect to Stratagus's window
645 ** origin, and the corresponding map parameters expressed in map
646 ** tiles with origin at map origin (map tile (0,0)).
647 */
SetViewportModeSplitHoriz()648 static void SetViewportModeSplitHoriz()
649 {
650 CViewport new_vps[MAX_NUM_VIEWPORTS];
651
652 DebugPrint("Two horizontal viewports set\n");
653
654 new_vps[0].TopLeftPos.x = UI.MapArea.X;
655 new_vps[0].TopLeftPos.y = UI.MapArea.Y;
656 ClipViewport(new_vps[0], UI.MapArea.EndX,
657 UI.MapArea.Y + (UI.MapArea.EndY - UI.MapArea.Y + 1) / 2);
658
659 new_vps[1].TopLeftPos.x = UI.MapArea.X;
660 new_vps[1].TopLeftPos.y = new_vps[0].BottomRightPos.y + 1;
661 ClipViewport(new_vps[1], UI.MapArea.EndX, UI.MapArea.EndY);
662
663 FinishViewportModeConfiguration(new_vps, 2);
664 }
665
666 /**
667 ** Compute viewport parameters for horizontal 3-way split viewport mode.
668 ** This mode splits the UI::MapArea with a horizontal line to
669 ** 2 (approximately) equal parts, then splits the bottom part vertically
670 ** to another 2 parts.
671 **
672 ** The parameters include viewport's width and height expressed
673 ** in pixels, its position with respect to Stratagus's window
674 ** origin, and the corresponding map parameters expressed in map
675 ** tiles with origin at map origin (map tile (0,0)).
676 */
SetViewportModeSplitHoriz3()677 static void SetViewportModeSplitHoriz3()
678 {
679 CViewport new_vps[MAX_NUM_VIEWPORTS];
680
681 DebugPrint("Horizontal 3-way viewport division set\n");
682
683 new_vps[0].TopLeftPos.x = UI.MapArea.X;
684 new_vps[0].TopLeftPos.y = UI.MapArea.Y;
685 ClipViewport(new_vps[0], UI.MapArea.EndX,
686 UI.MapArea.Y + (UI.MapArea.EndY - UI.MapArea.Y + 1) / 2);
687
688 new_vps[1].TopLeftPos.x = UI.MapArea.X;
689 new_vps[1].TopLeftPos.y = new_vps[0].BottomRightPos.y + 1;
690 ClipViewport(new_vps[1],
691 UI.MapArea.X + (UI.MapArea.EndX - UI.MapArea.X + 1) / 2,
692 UI.MapArea.EndY);
693
694 new_vps[2].TopLeftPos.x = new_vps[1].BottomRightPos.x + 1;
695 new_vps[2].TopLeftPos.y = new_vps[0].BottomRightPos.y + 1;
696 ClipViewport(new_vps[2], UI.MapArea.EndX, UI.MapArea.EndY);
697
698 FinishViewportModeConfiguration(new_vps, 3);
699 }
700
701 /**
702 ** Compute viewport parameters for vertically split viewport mode.
703 ** This mode splits the UI::MapArea with a vertical line to
704 ** 2 (approximately) equal parts.
705 **
706 ** The parameters include viewport's width and height expressed
707 ** in pixels, its position with respect to Stratagus's window
708 ** origin, and the corresponding map parameters expressed in map
709 ** tiles with origin at map origin (map tile (0,0)).
710 */
SetViewportModeSplitVert()711 static void SetViewportModeSplitVert()
712 {
713 CViewport new_vps[MAX_NUM_VIEWPORTS];
714
715 DebugPrint("Two vertical viewports set\n");
716
717 new_vps[0].TopLeftPos.x = UI.MapArea.X;
718 new_vps[0].TopLeftPos.y = UI.MapArea.Y;
719 ClipViewport(new_vps[0],
720 UI.MapArea.X + (UI.MapArea.EndX - UI.MapArea.X + 1) / 2,
721 UI.MapArea.EndY);
722
723 new_vps[1].TopLeftPos.x = new_vps[0].BottomRightPos.x + 1;
724 new_vps[1].TopLeftPos.y = UI.MapArea.Y;
725 ClipViewport(new_vps[1], UI.MapArea.EndX, UI.MapArea.EndY);
726
727 FinishViewportModeConfiguration(new_vps, 2);
728 }
729
730 /**
731 ** Compute viewport parameters for 4-way split viewport mode.
732 ** This mode splits the UI::MapArea vertically *and* horizontally
733 ** to 4 (approximately) equal parts.
734 **
735 ** The parameters include viewport's width and height expressed
736 ** in pixels, its position with respect to Stratagus's window
737 ** origin, and the corresponding map parameters expressed in map
738 ** tiles with origin at map origin (map tile (0,0)).
739 */
SetViewportModeQuad()740 static void SetViewportModeQuad()
741 {
742 CViewport new_vps[MAX_NUM_VIEWPORTS];
743
744 DebugPrint("Four viewports set\n");
745
746 new_vps[0].TopLeftPos.x = UI.MapArea.X;
747 new_vps[0].TopLeftPos.y = UI.MapArea.Y;
748 ClipViewport(new_vps[0],
749 UI.MapArea.X + (UI.MapArea.EndX - UI.MapArea.X + 1) / 2,
750 UI.MapArea.Y + (UI.MapArea.EndY - UI.MapArea.Y + 1) / 2);
751
752 new_vps[1].TopLeftPos.x = new_vps[0].BottomRightPos.x + 1;
753 new_vps[1].TopLeftPos.y = UI.MapArea.Y;
754 ClipViewport(new_vps[1],
755 UI.MapArea.EndX,
756 UI.MapArea.Y + (UI.MapArea.EndY - UI.MapArea.Y + 1) / 2);
757
758 new_vps[2].TopLeftPos.x = UI.MapArea.X;
759 new_vps[2].TopLeftPos.y = new_vps[0].BottomRightPos.y + 1;
760 ClipViewport(new_vps[2],
761 UI.MapArea.X + (UI.MapArea.EndX - UI.MapArea.X + 1) / 2,
762 UI.MapArea.EndY);
763
764 new_vps[3].TopLeftPos.x = new_vps[1].TopLeftPos.x;
765 new_vps[3].TopLeftPos.y = new_vps[2].TopLeftPos.y;
766 ClipViewport(new_vps[3], UI.MapArea.EndX, UI.MapArea.EndY);
767
768 FinishViewportModeConfiguration(new_vps, 4);
769 }
770
771 /**
772 ** Sets up (calls geometry setup routines for) a new viewport mode.
773 **
774 ** @param new_mode New mode's number.
775 */
SetViewportMode(ViewportModeType new_mode)776 void SetViewportMode(ViewportModeType new_mode)
777 {
778 switch (UI.ViewportMode = new_mode) {
779 case VIEWPORT_SINGLE:
780 SetViewportModeSingle();
781 break;
782 case VIEWPORT_SPLIT_HORIZ:
783 SetViewportModeSplitHoriz();
784 break;
785 case VIEWPORT_SPLIT_HORIZ3:
786 SetViewportModeSplitHoriz3();
787 break;
788 case VIEWPORT_SPLIT_VERT:
789 SetViewportModeSplitVert();
790 break;
791 case VIEWPORT_QUAD:
792 SetViewportModeQuad();
793 break;
794 default:
795 DebugPrint("trying to set an unknown mode!!\n");
796 break;
797 }
798 }
799
800 /**
801 ** Sets up a new viewport mode.
802 **
803 ** @param new_mode New mode's number.
804 */
SetNewViewportMode(ViewportModeType new_mode)805 void SetNewViewportMode(ViewportModeType new_mode)
806 {
807 NewViewportMode = new_mode;
808 if (NewViewportMode >= NUM_VIEWPORT_MODES) {
809 NewViewportMode = VIEWPORT_SINGLE;
810 }
811 if (NewViewportMode < 0) {
812 NewViewportMode = (ViewportModeType)(NUM_VIEWPORT_MODES - 1);
813 }
814 }
815
816 /**
817 ** Cycles through predefined viewport modes (geometry configurations)
818 ** in order defined by the ViewportMode enumerated type.
819 **
820 ** @param step The size of step used for cycling. Values that
821 ** make sense are mostly 1 (next viewport mode) and
822 ** -1 (previous viewport mode).
823 */
CycleViewportMode(int step)824 void CycleViewportMode(int step)
825 {
826 NewViewportMode = (ViewportModeType)(UI.ViewportMode + step);
827 if (NewViewportMode >= NUM_VIEWPORT_MODES) {
828 NewViewportMode = VIEWPORT_SINGLE;
829 }
830 if (NewViewportMode < 0) {
831 NewViewportMode = (ViewportModeType)(NUM_VIEWPORT_MODES - 1);
832 }
833 }
834
CheckViewportMode()835 void CheckViewportMode()
836 {
837 if (NewViewportMode != UI.ViewportMode) {
838 SetViewportMode(NewViewportMode);
839 }
840 }
841
842 /**
843 ** Check if mouse scrolling is enabled
844 */
GetMouseScroll()845 bool GetMouseScroll()
846 {
847 return UI.MouseScroll;
848 }
849
850 /**
851 ** Enable/disable scrolling with the mouse
852 **
853 ** @param enabled True to enable mouse scrolling, false to disable
854 */
SetMouseScroll(bool enabled)855 void SetMouseScroll(bool enabled)
856 {
857 UI.MouseScroll = enabled;
858 }
859
860 /**
861 ** Check if keyboard scrolling is enabled
862 */
GetKeyScroll()863 bool GetKeyScroll()
864 {
865 return UI.KeyScroll;
866 }
867
868 /**
869 ** Enable/disable scrolling with the keyboard
870 **
871 ** @param enabled True to enable keyboard scrolling, false to disable
872 */
SetKeyScroll(bool enabled)873 void SetKeyScroll(bool enabled)
874 {
875 UI.KeyScroll = enabled;
876 }
877
878 /**
879 ** Check if mouse grabbing is enabled
880 */
GetGrabMouse()881 bool GetGrabMouse()
882 {
883 return SdlGetGrabMouse();
884 }
885
886 /**
887 ** Enable/disable grabbing the mouse
888 **
889 ** @param enabled True to enable mouse grabbing, false to disable
890 */
SetGrabMouse(bool enabled)891 void SetGrabMouse(bool enabled)
892 {
893 ToggleGrabMouse(enabled ? 1 : -1);
894 }
895
896 /**
897 ** Check if scrolling stops when leaving the window
898 */
GetLeaveStops()899 bool GetLeaveStops()
900 {
901 return LeaveStops;
902 }
903
904 /**
905 ** Enable/disable leaving the window stops scrolling
906 **
907 ** @param enabled True to stop scrolling, false to disable
908 */
SetLeaveStops(bool enabled)909 void SetLeaveStops(bool enabled)
910 {
911 LeaveStops = enabled;
912 }
913
914 //@}
915