1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include <algorithm>
16 #include "gui/guimain.h"
17 #include "ac/common.h" // quit()
18 #include "ac/gamesetupstruct.h"
19 #include "gui/guibutton.h"
20 #include "gui/guilabel.h"
21 #include "gui/guislider.h"
22 #include "gui/guiinv.h"
23 #include "gui/guitextbox.h"
24 #include "gui/guilistbox.h"
25 #include "font/fonts.h"
26 #include "ac/spritecache.h"
27 #include "util/stream.h"
28 #include "gfx/bitmap.h"
29 #include "gfx/gfx_def.h"
30 #include "debug/out.h"
31 #include "util/math.h"
32 #include "util/string_utils.h"
33
34 using namespace AGS::Common;
35
36 #define MOVER_MOUSEDOWNLOCKED -4000
37
38 int guis_need_update = 1;
39 int all_buttons_disabled = 0, gui_inv_pic = -1;
40 int gui_disabled_style = 0;
41
42 namespace AGS
43 {
44 namespace Common
45 {
46
FixupGUIName(const String & name)47 /* static */ String GUIMain::FixupGUIName(const String &name)
48 {
49 if (name.GetLength() > 0 && name[0u] != 'g')
50 return String::FromFormat("g%c%s", name[0u], name.Mid(1).Lower().GetCStr());
51 return name;
52 }
53
GUIMain()54 GUIMain::GUIMain()
55 {
56 Init();
57 }
58
Init()59 void GUIMain::Init()
60 {
61 Id = 0;
62 Name.Empty();
63 Flags = 0;
64
65 X = 0;
66 Y = 0;
67 Width = 0;
68 Height = 0;
69 BgColor = 8;
70 BgImage = 0;
71 FgColor = 1;
72 Padding = TEXTWINDOW_PADDING_DEFAULT;
73 PopupStyle = kGUIPopupNone;
74 PopupAtMouseY = -1;
75 Transparency = 0;
76 ZOrder = -1;
77
78 _visibility = kGUIVisibility_On;
79 FocusCtrl = 0;
80 HighlightCtrl = -1;
81 MouseOverCtrl = -1;
82 MouseDownCtrl = -1;
83 MouseWasAt.X = -1;
84 MouseWasAt.Y = -1;
85
86 OnClickHandler.Empty();
87
88 ControlCount = 0;
89 }
90
FindControlUnderMouse(int leeway,bool must_be_clickable) const91 int GUIMain::FindControlUnderMouse(int leeway, bool must_be_clickable) const
92 {
93 if (loaded_game_file_version <= kGameVersion_262)
94 {
95 // Ignore draw order On 2.6.2 and lower
96 for (int i = 0; i < ControlCount; ++i)
97 {
98 if (!Controls[i]->IsVisible())
99 continue;
100 if (!Controls[i]->IsClickable() && must_be_clickable)
101 continue;
102 if (Controls[i]->IsOverControl(mousex, mousey, leeway))
103 return i;
104 }
105 }
106 else
107 {
108 for (int i = ControlCount - 1; i >= 0; --i)
109 {
110 const int ctrl_index = CtrlDrawOrder[i];
111 if (!Controls[ctrl_index]->IsVisible())
112 continue;
113 if (!Controls[ctrl_index]->IsClickable() && must_be_clickable)
114 continue;
115 if (Controls[ctrl_index]->IsOverControl(mousex, mousey, leeway))
116 return ctrl_index;
117 }
118 }
119 return -1;
120 }
121
FindControlUnderMouse() const122 int GUIMain::FindControlUnderMouse() const
123 {
124 return FindControlUnderMouse(0, true);
125 }
126
FindControlUnderMouse(int leeway) const127 int GUIMain::FindControlUnderMouse(int leeway) const
128 {
129 return FindControlUnderMouse(leeway, true);
130 }
131
GetControlType(int index) const132 GUIControlType GUIMain::GetControlType(int index) const
133 {
134 if (index < 0 || index >= ControlCount)
135 return kGUIControlUndefined;
136 return (GUIControlType)((CtrlRefs[index] >> 16) & 0x0000ffff);
137 }
138
IsInteractableAt(int x,int y) const139 bool GUIMain::IsInteractableAt(int x, int y) const
140 {
141 if (!IsVisible())
142 return false;
143 if (Flags & kGUIMain_NoClick)
144 return false;
145 if ((x >= X) & (y >= Y) & (x < X + Width) & (y < Y + Height))
146 return true;
147 return false;
148 }
149
IsTextWindow() const150 bool GUIMain::IsTextWindow() const
151 {
152 return (Flags & kGUIMain_TextWindow) != 0;
153 }
154
BringControlToFront(int index)155 bool GUIMain::BringControlToFront(int index)
156 {
157 return SetControlZOrder(index, ControlCount - 1);
158 }
159
Draw(Common::Bitmap * ds)160 void GUIMain::Draw(Common::Bitmap *ds)
161 {
162 DrawAt(ds, X, Y);
163 }
164
DrawAt(Common::Bitmap * ds,int x,int y)165 void GUIMain::DrawAt(Common::Bitmap *ds, int x, int y)
166 {
167 SET_EIP(375)
168
169 if ((Width < 1) || (Height < 1))
170 return;
171
172 Bitmap subbmp;
173 subbmp.CreateSubBitmap(ds, RectWH(x, y, Width, Height));
174
175 SET_EIP(376)
176 // stop border being transparent, if the whole GUI isn't
177 if ((FgColor == 0) && (BgColor != 0))
178 FgColor = 16;
179
180 if (BgColor != 0)
181 subbmp.Fill(subbmp.GetCompatibleColor(BgColor));
182
183 SET_EIP(377)
184
185 color_t draw_color;
186 if (FgColor != BgColor)
187 {
188 draw_color = subbmp.GetCompatibleColor(FgColor);
189 subbmp.DrawRect(Rect(0, 0, subbmp.GetWidth() - 1, subbmp.GetHeight() - 1), draw_color);
190 if (get_fixed_pixel_size(1) > 1)
191 subbmp.DrawRect(Rect(1, 1, subbmp.GetWidth() - 2, subbmp.GetHeight() - 2), draw_color);
192 }
193
194 SET_EIP(378)
195
196 if (BgImage > 0 && spriteset[BgImage] != NULL)
197 draw_gui_sprite(&subbmp, BgImage, 0, 0, false);
198
199 SET_EIP(379)
200
201 for (int ctrl_index = 0; ctrl_index < ControlCount; ++ctrl_index)
202 {
203 set_eip_guiobj(CtrlDrawOrder[ctrl_index]);
204
205 GUIObject *objToDraw = Controls[CtrlDrawOrder[ctrl_index]];
206
207 if (objToDraw->IsDisabled() && gui_disabled_style == GUIDIS_BLACKOUT)
208 continue;
209 if (!objToDraw->IsVisible())
210 continue;
211
212 objToDraw->Draw(&subbmp);
213
214 int selectedColour = 14;
215
216 if (HighlightCtrl == CtrlDrawOrder[ctrl_index])
217 {
218 if (outlineGuiObjects)
219 selectedColour = 13;
220 draw_color = subbmp.GetCompatibleColor(selectedColour);
221 DrawBlob(&subbmp, objToDraw->x + objToDraw->wid - get_fixed_pixel_size(1) - 1, objToDraw->y, draw_color);
222 DrawBlob(&subbmp, objToDraw->x, objToDraw->y + objToDraw->hit - get_fixed_pixel_size(1) - 1, draw_color);
223 DrawBlob(&subbmp, objToDraw->x, objToDraw->y, draw_color);
224 DrawBlob(&subbmp, objToDraw->x + objToDraw->wid - get_fixed_pixel_size(1) - 1,
225 objToDraw->y + objToDraw->hit - get_fixed_pixel_size(1) - 1, draw_color);
226 }
227 if (outlineGuiObjects)
228 {
229 // draw a dotted outline round all objects
230 draw_color = subbmp.GetCompatibleColor(selectedColour);
231 for (int i = 0; i < objToDraw->wid; i += 2)
232 {
233 subbmp.PutPixel(i + objToDraw->x, objToDraw->y, draw_color);
234 subbmp.PutPixel(i + objToDraw->x, objToDraw->y + objToDraw->hit - 1, draw_color);
235 }
236 for (int i = 0; i < objToDraw->hit; i += 2)
237 {
238 subbmp.PutPixel(objToDraw->x, i + objToDraw->y, draw_color);
239 subbmp.PutPixel(objToDraw->x + objToDraw->wid - 1, i + objToDraw->y, draw_color);
240 }
241 }
242 }
243
244 SET_EIP(380)
245 }
246
DrawBlob(Common::Bitmap * ds,int x,int y,color_t draw_color)247 void GUIMain::DrawBlob(Common::Bitmap *ds, int x, int y, color_t draw_color)
248 {
249 ds->FillRect(Rect(x, y, x + get_fixed_pixel_size(1), y + get_fixed_pixel_size(1)), draw_color);
250 }
251
Poll()252 void GUIMain::Poll()
253 {
254 int mxwas = mousex, mywas = mousey;
255
256 mousex -= X;
257 mousey -= Y;
258 if (mousex != MouseWasAt.X || mousey != MouseWasAt.Y)
259 {
260 int ctrl_index = FindControlUnderMouse();
261
262 if (MouseOverCtrl == MOVER_MOUSEDOWNLOCKED)
263 Controls[MouseDownCtrl]->MouseMove(mousex, mousey);
264 else if (ctrl_index != MouseOverCtrl)
265 {
266 if (MouseOverCtrl >= 0)
267 Controls[MouseOverCtrl]->MouseLeave();
268
269 if (ctrl_index >= 0 && Controls[ctrl_index]->IsDisabled())
270 // the control is disabled - ignore it
271 MouseOverCtrl = -1;
272 else if (ctrl_index >= 0 && !Controls[ctrl_index]->IsClickable())
273 // the control is not clickable - ignore it
274 MouseOverCtrl = -1;
275 else
276 {
277 // over a different control
278 MouseOverCtrl = ctrl_index;
279 if (MouseOverCtrl >= 0)
280 {
281 Controls[MouseOverCtrl]->MouseOver();
282 Controls[MouseOverCtrl]->MouseMove(mousex, mousey);
283 }
284 }
285 guis_need_update = 1;
286 }
287 else if (MouseOverCtrl >= 0)
288 Controls[MouseOverCtrl]->MouseMove(mousex, mousey);
289 }
290
291 MouseWasAt.X = mousex;
292 MouseWasAt.Y = mousey;
293 mousex = mxwas;
294 mousey = mywas;
295 }
296
RebuildArray()297 void GUIMain::RebuildArray()
298 {
299 int thistype, thisnum;
300
301 Controls.resize(ControlCount);
302 for (int i = 0; i < ControlCount; ++i)
303 {
304 thistype = (CtrlRefs[i] >> 16) & 0x000ffff;
305 thisnum = CtrlRefs[i] & 0x0000ffff;
306
307 if (thisnum < 0 || thisnum >= 2000)
308 quit("GUIMain: rebuild array failed (invalid object index)");
309
310 if (thistype == kGUIButton)
311 Controls[i] = &guibuts[thisnum];
312 else if (thistype == kGUILabel)
313 Controls[i] = &guilabels[thisnum];
314 else if (thistype == kGUIInvWindow)
315 Controls[i] = &guiinv[thisnum];
316 else if (thistype == kGUISlider)
317 Controls[i] = &guislider[thisnum];
318 else if (thistype == kGUITextBox)
319 Controls[i] = &guitext[thisnum];
320 else if (thistype == kGUIListBox)
321 Controls[i] = &guilist[thisnum];
322 else
323 quit("guimain: unknown control type found On gui");
324
325 Controls[i]->guin = Id;
326 Controls[i]->objn = i;
327 }
328
329 ResortZOrder();
330 }
331
GUIControlZOrder(const GUIObject * e1,const GUIObject * e2)332 bool GUIControlZOrder(const GUIObject *e1, const GUIObject *e2)
333 {
334 return e1->zorder < e2->zorder;
335 }
336
ResortZOrder()337 void GUIMain::ResortZOrder()
338 {
339 std::vector<GUIObject*> ctrl_sort = Controls;
340 std::sort(ctrl_sort.begin(), ctrl_sort.end(), GUIControlZOrder);
341
342 CtrlDrawOrder.resize(ctrl_sort.size());
343 for (int i = 0; i < ControlCount; ++i)
344 CtrlDrawOrder[i] = ctrl_sort[i]->objn;
345 }
346
SendControlToBack(int index)347 bool GUIMain::SendControlToBack(int index)
348 {
349 return SetControlZOrder(index, 0);
350 }
351
SetControlZOrder(int index,int zorder)352 bool GUIMain::SetControlZOrder(int index, int zorder)
353 {
354 if (index < 0 || index >= ControlCount)
355 return false; // no such control
356
357 zorder = Math::Clamp(0, ControlCount - 1, zorder);
358 const int old_zorder = Controls[index]->zorder;
359 if (old_zorder == zorder)
360 return false; // no change
361
362 const bool move_back = zorder < old_zorder; // back is at zero index
363 const int left = move_back ? zorder : old_zorder;
364 const int right = move_back ? old_zorder : zorder;
365 for (int i = 0; i < ControlCount; ++i)
366 {
367 const int i_zorder = Controls[i]->zorder;
368 if (i_zorder == old_zorder)
369 Controls[i]->zorder = zorder; // the control we are moving
370 else if (i_zorder >= left && i_zorder <= right)
371 {
372 // controls in between old and new positions shift towards free place
373 if (move_back)
374 Controls[i]->zorder++; // move to front
375 else
376 Controls[i]->zorder--; // move to back
377 }
378 }
379 ResortZOrder();
380 OnControlPositionChanged();
381 return true;
382 }
383
SetTransparencyAsPercentage(int percent)384 void GUIMain::SetTransparencyAsPercentage(int percent)
385 {
386 Transparency = GfxDef::Trans100ToLegacyTrans255(percent);
387 }
388
SetVisibility(GUIVisibilityState visibility)389 void GUIMain::SetVisibility(GUIVisibilityState visibility)
390 {
391 _visibility = visibility;
392 }
393
OnControlPositionChanged()394 void GUIMain::OnControlPositionChanged()
395 {
396 // force it to re-check for which control is under the mouse
397 MouseWasAt.X = -1;
398 MouseWasAt.Y = -1;
399 }
400
OnMouseButtonDown()401 void GUIMain::OnMouseButtonDown()
402 {
403 if (MouseOverCtrl < 0)
404 return;
405
406 // don't activate disabled buttons
407 if (Controls[MouseOverCtrl]->IsDisabled() || !Controls[MouseOverCtrl]->IsVisible() ||
408 !Controls[MouseOverCtrl]->IsClickable())
409 return;
410
411 MouseDownCtrl = MouseOverCtrl;
412 if (Controls[MouseOverCtrl]->MouseDown())
413 MouseOverCtrl = MOVER_MOUSEDOWNLOCKED;
414 Controls[MouseDownCtrl]->MouseMove(mousex - X, mousey - Y);
415 guis_need_update = 1;
416 }
417
OnMouseButtonUp()418 void GUIMain::OnMouseButtonUp()
419 {
420 // FocusCtrl was locked - reset it back to normal, but On the
421 // locked object so that a MouseLeave gets fired if necessary
422 if (MouseOverCtrl == MOVER_MOUSEDOWNLOCKED)
423 {
424 MouseOverCtrl = MouseDownCtrl;
425 MouseWasAt.X = -1; // force update
426 }
427
428 if (MouseDownCtrl < 0)
429 return;
430
431 Controls[MouseDownCtrl]->MouseUp();
432 MouseDownCtrl = -1;
433 guis_need_update = 1;
434 }
435
ReadFromFile(Stream * in,GuiVersion gui_version)436 void GUIMain::ReadFromFile(Stream *in, GuiVersion gui_version)
437 {
438 char tw_flags[GUIMAIN_LEGACY_TW_FLAGS_SIZE];
439 in->Read(tw_flags, sizeof(tw_flags));
440 if (gui_version < kGuiVersion_340)
441 {
442 Name.ReadCount(in, GUIMAIN_LEGACY_NAME_LENGTH);
443 OnClickHandler.ReadCount(in, GUIMAIN_LEGACY_EVENTHANDLER_LENGTH);
444 }
445 else
446 {
447 Name = StrUtil::ReadString(in);
448 OnClickHandler = StrUtil::ReadString(in);
449 }
450 X = in->ReadInt32();
451 Y = in->ReadInt32();
452 Width = in->ReadInt32();
453 Height = in->ReadInt32();
454 FocusCtrl = in->ReadInt32();
455 ControlCount = in->ReadInt32();
456 PopupStyle = (GUIPopupStyle)in->ReadInt32();
457 PopupAtMouseY = in->ReadInt32();
458 BgColor = in->ReadInt32();
459 BgImage = in->ReadInt32();
460 FgColor = in->ReadInt32();
461 MouseOverCtrl = in->ReadInt32();
462 MouseWasAt.X = in->ReadInt32();
463 MouseWasAt.Y = in->ReadInt32();
464 MouseDownCtrl = in->ReadInt32();
465 HighlightCtrl = in->ReadInt32();
466 Flags = in->ReadInt32();
467 if (tw_flags[0] == kGUIMain_LegacyTextWindow)
468 {
469 Flags |= kGUIMain_TextWindow;
470 }
471 Transparency = in->ReadInt32();
472 ZOrder = in->ReadInt32();
473 Id = in->ReadInt32();
474 Padding = in->ReadInt32();
475 in->Seek(sizeof(int32_t) * GUIMAIN_RESERVED_INTS);
476 _visibility = (GUIVisibilityState)in->ReadInt32();
477
478 if (gui_version < kGuiVersion_340)
479 {
480 CtrlRefs.resize(LEGACY_MAX_OBJS_ON_GUI);
481 // array of 32-bit pointers; these values are unused
482 in->Seek(LEGACY_MAX_OBJS_ON_GUI * sizeof(int32_t));
483 in->ReadArrayOfInt32(&CtrlRefs.front(), LEGACY_MAX_OBJS_ON_GUI);
484 }
485 else
486 {
487 CtrlRefs.resize(ControlCount);
488 if (ControlCount > 0)
489 in->ReadArrayOfInt32(&CtrlRefs.front(), ControlCount);
490 }
491 }
492
WriteToFile(Stream * out,GuiVersion gui_version) const493 void GUIMain::WriteToFile(Stream *out, GuiVersion gui_version) const
494 {
495 char tw_flags[GUIMAIN_LEGACY_TW_FLAGS_SIZE] = {0};
496 if (Flags & kGUIMain_TextWindow)
497 tw_flags[0] = kGUIMain_LegacyTextWindow;
498 out->Write(tw_flags, sizeof(tw_flags));
499 if (gui_version < kGuiVersion_340)
500 {
501 Name.WriteCount(out, GUIMAIN_LEGACY_NAME_LENGTH);
502 OnClickHandler.WriteCount(out, GUIMAIN_LEGACY_EVENTHANDLER_LENGTH);
503 }
504 else
505 {
506 StrUtil::WriteString(Name, out);
507 StrUtil::WriteString(OnClickHandler, out);
508 }
509 out->WriteInt32(X);
510 out->WriteInt32(Y);
511 out->WriteInt32(Width);
512 out->WriteInt32(Height);
513 out->WriteInt32(FocusCtrl);
514 out->WriteInt32(ControlCount);
515 out->WriteInt32(PopupStyle);
516 out->WriteInt32(PopupAtMouseY);
517 out->WriteInt32(BgColor);
518 out->WriteInt32(BgImage);
519 out->WriteInt32(FgColor);
520 out->WriteInt32(MouseOverCtrl);
521 out->WriteInt32(MouseWasAt.X);
522 out->WriteInt32(MouseWasAt.Y);
523 out->WriteInt32(MouseDownCtrl);
524 out->WriteInt32(HighlightCtrl);
525 out->WriteInt32(Flags);
526 out->WriteInt32(Transparency);
527 out->WriteInt32(ZOrder);
528 out->WriteInt32(Id);
529 out->WriteInt32(Padding);
530 int32_t reserved_ints[GUIMAIN_RESERVED_INTS] = {0};
531 out->WriteArrayOfInt32(reserved_ints, GUIMAIN_RESERVED_INTS);
532 out->WriteInt32(_visibility);
533
534 if (gui_version < kGuiVersion_340)
535 {
536 // array of dummy 32-bit pointers
537 int32_t dummy_arr[LEGACY_MAX_OBJS_ON_GUI] = {0};
538 out->WriteArrayOfInt32(dummy_arr, LEGACY_MAX_OBJS_ON_GUI);
539 out->WriteArrayOfInt32(&CtrlRefs.front(), LEGACY_MAX_OBJS_ON_GUI);
540 }
541 else if (ControlCount > 0)
542 {
543 out->WriteArrayOfInt32(&CtrlRefs.front(), ControlCount);
544 }
545 }
546
547 } // namespace Common
548 } // namespace AGS
549
550 GuiVersion GameGuiVersion = kGuiVersion_Initial;
read_gui(Stream * in,std::vector<GUIMain> & guiread,GameSetupStruct * gss)551 void read_gui(Stream *in, std::vector<GUIMain> &guiread, GameSetupStruct * gss)
552 {
553 int ee;
554
555 if (in->ReadInt32() != (int)GUIMAGIC)
556 quit("read_gui: file is corrupt");
557
558 GameGuiVersion = (GuiVersion)in->ReadInt32();
559 Debug::Printf(kDbgMsg_Init, "Game GUI version: %d", GameGuiVersion);
560 if (GameGuiVersion < kGuiVersion_214) {
561 gss->numgui = (int)GameGuiVersion;
562 GameGuiVersion = kGuiVersion_Initial;
563 }
564 else if (GameGuiVersion > kGuiVersion_Current)
565 quit("read_gui: this game requires a newer version of AGS");
566 else
567 gss->numgui = in->ReadInt32();
568
569 if ((gss->numgui < 0) || (gss->numgui > 1000))
570 quit("read_gui: invalid number of GUIs, file corrupt?");
571
572 guiread.resize(gss->numgui);
573
574 // import the main GUI elements
575 for (int iteratorCount = 0; iteratorCount < gss->numgui; ++iteratorCount)
576 {
577 guiread[iteratorCount].Init();
578 guiread[iteratorCount].ReadFromFile(in, GameGuiVersion);
579 }
580
581 for (ee = 0; ee < gss->numgui; ee++) {
582 if (guiread[ee].Height < 2)
583 guiread[ee].Height = 2;
584
585 if (GameGuiVersion < kGuiVersion_unkn_103)
586 guiread[ee].Name.Format("GUI%d", ee);
587 if (GameGuiVersion < kGuiVersion_260)
588 guiread[ee].ZOrder = ee;
589 if (GameGuiVersion < kGuiVersion_331)
590 guiread[ee].Padding = TEXTWINDOW_PADDING_DEFAULT;
591
592 if (loaded_game_file_version <= kGameVersion_272) // Fix names for 2.x: "GUI" -> "gGui"
593 guiread[ee].Name = GUIMain::FixupGUIName(guiread[ee].Name);
594
595 guiread[ee].Id = ee;
596 }
597
598 // import the buttons
599 numguibuts = in->ReadInt32();
600 guibuts.resize(numguibuts);
601
602 for (ee = 0; ee < numguibuts; ee++)
603 guibuts[ee].ReadFromFile(in, GameGuiVersion);
604
605 // labels
606 numguilabels = in->ReadInt32();
607 guilabels.resize(numguilabels);
608
609 for (ee = 0; ee < numguilabels; ee++)
610 guilabels[ee].ReadFromFile(in, GameGuiVersion);
611
612 // inv controls
613 numguiinv = in->ReadInt32();
614 guiinv.resize(numguiinv);
615
616 for (ee = 0; ee < numguiinv; ee++)
617 guiinv[ee].ReadFromFile(in, GameGuiVersion);
618
619 if (GameGuiVersion >= kGuiVersion_214) {
620 // sliders
621 numguislider = in->ReadInt32();
622 guislider.resize(numguislider);
623
624 for (ee = 0; ee < numguislider; ee++)
625 guislider[ee].ReadFromFile(in, GameGuiVersion);
626 }
627
628 if (GameGuiVersion >= kGuiVersion_222) {
629 // text boxes
630 numguitext = in->ReadInt32();
631 guitext.resize(numguitext);
632
633 for (ee = 0; ee < numguitext; ee++)
634 guitext[ee].ReadFromFile(in, GameGuiVersion);
635 }
636
637 if (GameGuiVersion >= kGuiVersion_230) {
638 // list boxes
639 numguilist = in->ReadInt32();
640 guilist.resize(numguilist);
641
642 for (ee = 0; ee < numguilist; ee++)
643 guilist[ee].ReadFromFile(in, GameGuiVersion);
644 }
645
646 // set up the reverse-lookup array
647 for (ee = 0; ee < gss->numgui; ee++) {
648 guiread[ee].RebuildArray();
649
650 if (GameGuiVersion < kGuiVersion_270)
651 guiread[ee].OnClickHandler.Empty();
652
653 for (int ff = 0; ff < guiread[ee].ControlCount; ff++) {
654 guiread[ee].Controls[ff]->guin = ee;
655 guiread[ee].Controls[ff]->objn = ff;
656
657 if (GameGuiVersion < kGuiVersion_272e)
658 guiread[ee].Controls[ff]->zorder = ff;
659 }
660
661 guiread[ee].ResortZOrder();
662 }
663
664 guis_need_update = 1;
665 }
666
write_gui(Stream * out,const std::vector<GUIMain> & guiwrite,GameSetupStruct * gss,bool savedgame)667 void write_gui(Stream *out, const std::vector<GUIMain> &guiwrite, GameSetupStruct * gss, bool savedgame)
668 {
669 int ee;
670
671 out->WriteInt32(GUIMAGIC);
672
673 GuiVersion write_version;
674 if (savedgame)
675 write_version = GameGuiVersion > kGuiVersion_ForwardCompatible ? GameGuiVersion : kGuiVersion_ForwardCompatible;
676 else
677 write_version = kGuiVersion_Current;
678
679 out->WriteInt32(write_version);
680 out->WriteInt32(gss->numgui);
681
682 for (int iteratorCount = 0; iteratorCount < gss->numgui; ++iteratorCount)
683 {
684 guiwrite[iteratorCount].WriteToFile(out, write_version);
685 }
686
687 out->WriteInt32(numguibuts);
688 for (ee = 0; ee < numguibuts; ee++)
689 guibuts[ee].WriteToFile(out);
690
691 out->WriteInt32(numguilabels);
692 for (ee = 0; ee < numguilabels; ee++)
693 guilabels[ee].WriteToFile(out);
694
695 out->WriteInt32(numguiinv);
696 for (ee = 0; ee < numguiinv; ee++)
697 guiinv[ee].WriteToFile(out);
698
699 out->WriteInt32(numguislider);
700 for (ee = 0; ee < numguislider; ee++)
701 guislider[ee].WriteToFile(out);
702
703 out->WriteInt32(numguitext);
704 for (ee = 0; ee < numguitext; ee++)
705 guitext[ee].WriteToFile(out);
706
707 out->WriteInt32(numguilist);
708 for (ee = 0; ee < numguilist; ee++)
709 guilist[ee].WriteToFile(out);
710 }
711