saveload: fix read/write unexisting value
[d2df-sdl.git] / src / game / g_gui.pas
blob922a2a119916541b882f987199a0afc5fa00dbf1
1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_gui;
18 interface
20 uses
21 {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
22 e_graphics, e_input, e_log, g_playermodel, g_basic, g_touch, MAPDEF, utils;
24 const
25 MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
26 MAINMENU_ITEMS_COLOR: TRGB = (R:255; G:255; B:255);
27 MAINMENU_UNACTIVEITEMS_COLOR: TRGB = (R:192; G:192; B:192);
28 MAINMENU_CLICKSOUND = 'MENU_SELECT';
29 MAINMENU_CHANGESOUND = 'MENU_CHANGE';
30 MAINMENU_SPACE = 4;
31 MAINMENU_MARKER1 = 'MAINMENU_MARKER1';
32 MAINMENU_MARKER2 = 'MAINMENU_MARKER2';
33 MAINMENU_MARKERDELAY = 24;
34 WINDOW_CLOSESOUND = 'MENU_CLOSE';
35 MENU_HEADERCOLOR: TRGB = (R:255; G:255; B:255);
36 MENU_ITEMSTEXT_COLOR: TRGB = (R:255; G:255; B:255);
37 MENU_UNACTIVEITEMS_COLOR: TRGB = (R:128; G:128; B:128);
38 MENU_ITEMSCTRL_COLOR: TRGB = (R:255; G:0; B:0);
39 MENU_VSPACE = 2;
40 MENU_HSPACE = 32;
41 MENU_CLICKSOUND = 'MENU_SELECT';
42 MENU_CHANGESOUND = 'MENU_CHANGE';
43 MENU_MARKERDELAY = 24;
44 SCROLL_LEFT = 'SCROLL_LEFT';
45 SCROLL_RIGHT = 'SCROLL_RIGHT';
46 SCROLL_MIDDLE = 'SCROLL_MIDDLE';
47 SCROLL_MARKER = 'SCROLL_MARKER';
48 SCROLL_ADDSOUND = 'SCROLL_ADD';
49 SCROLL_SUBSOUND = 'SCROLL_SUB';
50 EDIT_LEFT = 'EDIT_LEFT';
51 EDIT_RIGHT = 'EDIT_RIGHT';
52 EDIT_MIDDLE = 'EDIT_MIDDLE';
53 EDIT_CURSORCOLOR: TRGB = (R:200; G:0; B:0);
54 EDIT_CURSORLEN = 10;
55 KEYREAD_QUERY = '<...>';
56 KEYREAD_CLEAR = '???';
57 KEYREAD_TIMEOUT = 24;
58 MAPPREVIEW_WIDTH = 8;
59 MAPPREVIEW_HEIGHT = 8;
60 BOX1 = 'BOX1';
61 BOX2 = 'BOX2';
62 BOX3 = 'BOX3';
63 BOX4 = 'BOX4';
64 BOX5 = 'BOX5';
65 BOX6 = 'BOX6';
66 BOX7 = 'BOX7';
67 BOX8 = 'BOX8';
68 BOX9 = 'BOX9';
69 BSCROLL_UPA = 'BSCROLL_UP_A';
70 BSCROLL_UPU = 'BSCROLL_UP_U';
71 BSCROLL_DOWNA = 'BSCROLL_DOWN_A';
72 BSCROLL_DOWNU = 'BSCROLL_DOWN_U';
73 BSCROLL_MIDDLE = 'BSCROLL_MIDDLE';
74 WM_KEYDOWN = 101;
75 WM_CHAR = 102;
76 WM_USER = 110;
78 type
79 TMessage = record
80 Msg: DWORD;
81 wParam: LongInt;
82 lParam: LongInt;
83 end;
85 TFontType = (Texture, Character);
87 TFont = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
88 private
89 ID: DWORD;
90 FScale: Single;
91 FFontType: TFontType;
92 public
93 constructor Create(FontID: DWORD; FontType: TFontType);
94 procedure Draw(X, Y: Integer; Text: string; R, G, B: Byte);
95 procedure GetTextSize(Text: string; var w, h: Word);
96 property Scale: Single read FScale write FScale;
97 end;
99 TGUIControl = class;
100 TGUIWindow = class;
102 TOnKeyDownEvent = procedure(Key: Byte);
103 TOnKeyDownEventEx = procedure(win: TGUIWindow; Key: Byte);
104 TOnCloseEvent = procedure;
105 TOnShowEvent = procedure;
106 TOnClickEvent = procedure;
107 TOnChangeEvent = procedure(Sender: TGUIControl);
108 TOnEnterEvent = procedure(Sender: TGUIControl);
110 TGUIControl = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
111 private
112 FX, FY: Integer;
113 FEnabled: Boolean;
114 FWindow : TGUIWindow;
115 FName: string;
116 FUserData: Pointer;
117 FRightAlign: Boolean; //HACK! this works only for "normal" menus, only for menu text labels, and generally sux. sorry.
118 FMaxWidth: Integer; //HACK! used for right-aligning labels
119 public
120 constructor Create;
121 procedure OnMessage(var Msg: TMessage); virtual;
122 procedure Update; virtual;
123 procedure Draw; virtual;
124 function GetWidth(): Integer; virtual;
125 function GetHeight(): Integer; virtual;
126 function WantActivationKey (key: LongInt): Boolean; virtual;
127 property X: Integer read FX write FX;
128 property Y: Integer read FY write FY;
129 property Enabled: Boolean read FEnabled write FEnabled;
130 property Name: string read FName write FName;
131 property UserData: Pointer read FUserData write FUserData;
132 property RightAlign: Boolean read FRightAlign write FRightAlign; // for menu
133 end;
135 TGUIWindow = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
136 private
137 FActiveControl: TGUIControl;
138 FDefControl: string;
139 FPrevWindow: TGUIWindow;
140 FName: string;
141 FBackTexture: string;
142 FMainWindow: Boolean;
143 FOnKeyDown: TOnKeyDownEvent;
144 FOnKeyDownEx: TOnKeyDownEventEx;
145 FOnCloseEvent: TOnCloseEvent;
146 FOnShowEvent: TOnShowEvent;
147 FUserData: Pointer;
148 public
149 Childs: array of TGUIControl;
150 constructor Create(Name: string);
151 destructor Destroy; override;
152 function AddChild(Child: TGUIControl): TGUIControl;
153 procedure OnMessage(var Msg: TMessage);
154 procedure Update;
155 procedure Draw;
156 procedure SetActive(Control: TGUIControl);
157 function GetControl(Name: string): TGUIControl;
158 property OnKeyDown: TOnKeyDownEvent read FOnKeyDown write FOnKeyDown;
159 property OnKeyDownEx: TOnKeyDownEventEx read FOnKeyDownEx write FOnKeyDownEx;
160 property OnClose: TOnCloseEvent read FOnCloseEvent write FOnCloseEvent;
161 property OnShow: TOnShowEvent read FOnShowEvent write FOnShowEvent;
162 property Name: string read FName;
163 property DefControl: string read FDefControl write FDefControl;
164 property BackTexture: string read FBackTexture write FBackTexture;
165 property MainWindow: Boolean read FMainWindow write FMainWindow;
166 property UserData: Pointer read FUserData write FUserData;
167 end;
169 TGUITextButton = class(TGUIControl)
170 private
171 FText: string;
172 FColor: TRGB;
173 FFont: TFont;
174 FSound: string;
175 FShowWindow: string;
176 public
177 Proc: procedure;
178 ProcEx: procedure (sender: TGUITextButton);
179 constructor Create(aProc: Pointer; FontID: DWORD; Text: string);
180 destructor Destroy(); override;
181 procedure OnMessage(var Msg: TMessage); override;
182 procedure Draw(); override;
183 function GetWidth(): Integer; override;
184 function GetHeight(): Integer; override;
185 procedure Click(Silent: Boolean = False);
186 property Caption: string read FText write FText;
187 property Color: TRGB read FColor write FColor;
188 property Font: TFont read FFont write FFont;
189 property ShowWindow: string read FShowWindow write FShowWindow;
190 end;
192 TGUILabel = class(TGUIControl)
193 private
194 FText: string;
195 FColor: TRGB;
196 FFont: TFont;
197 FFixedLen: Word;
198 FOnClickEvent: TOnClickEvent;
199 public
200 constructor Create(Text: string; FontID: DWORD);
201 destructor Destroy(); override;
202 procedure OnMessage(var Msg: TMessage); override;
203 procedure Draw; override;
204 function GetWidth: Integer; override;
205 function GetHeight: Integer; override;
206 property OnClick: TOnClickEvent read FOnClickEvent write FOnClickEvent;
207 property FixedLength: Word read FFixedLen write FFixedLen;
208 property Text: string read FText write FText;
209 property Color: TRGB read FColor write FColor;
210 property Font: TFont read FFont write FFont;
211 end;
213 TGUIScroll = class(TGUIControl)
214 private
215 FValue: Integer;
216 FMax: Word;
217 FLeftID: DWORD;
218 FRightID: DWORD;
219 FMiddleID: DWORD;
220 FMarkerID: DWORD;
221 FOnChangeEvent: TOnChangeEvent;
222 procedure FSetValue(a: Integer);
223 public
224 constructor Create();
225 procedure OnMessage(var Msg: TMessage); override;
226 procedure Draw; override;
227 function GetWidth(): Integer; override;
228 property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
229 property Max: Word read FMax write FMax;
230 property Value: Integer read FValue write FSetValue;
231 end;
233 TGUISwitch = class(TGUIControl)
234 private
235 FFont: TFont;
236 FItems: array of string;
237 FIndex: Integer;
238 FColor: TRGB;
239 FOnChangeEvent: TOnChangeEvent;
240 public
241 constructor Create(FontID: DWORD);
242 destructor Destroy(); override;
243 procedure OnMessage(var Msg: TMessage); override;
244 procedure AddItem(Item: string);
245 procedure Draw; override;
246 function GetWidth(): Integer; override;
247 function GetText: string;
248 property ItemIndex: Integer read FIndex write FIndex;
249 property Color: TRGB read FColor write FColor;
250 property Font: TFont read FFont write FFont;
251 property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
252 end;
254 TGUIEdit = class(TGUIControl)
255 private
256 FFont: TFont;
257 FCaretPos: Integer;
258 FMaxLength: Word;
259 FWidth: Word;
260 FText: string;
261 FColor: TRGB;
262 FOnlyDigits: Boolean;
263 FLeftID: DWORD;
264 FRightID: DWORD;
265 FMiddleID: DWORD;
266 FOnChangeEvent: TOnChangeEvent;
267 FOnEnterEvent: TOnEnterEvent;
268 FInvalid: Boolean;
269 procedure SetText(Text: string);
270 public
271 constructor Create(FontID: DWORD);
272 destructor Destroy(); override;
273 procedure OnMessage(var Msg: TMessage); override;
274 procedure Draw; override;
275 function GetWidth(): Integer; override;
276 property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
277 property OnEnter: TOnEnterEvent read FOnEnterEvent write FOnEnterEvent;
278 property Width: Word read FWidth write FWidth;
279 property MaxLength: Word read FMaxLength write FMaxLength;
280 property OnlyDigits: Boolean read FOnlyDigits write FOnlyDigits;
281 property Text: string read FText write SetText;
282 property Color: TRGB read FColor write FColor;
283 property Font: TFont read FFont write FFont;
284 property Invalid: Boolean read FInvalid write FInvalid;
285 end;
287 TGUIKeyRead = class(TGUIControl)
288 private
289 FFont: TFont;
290 FColor: TRGB;
291 FKey: Word;
292 FIsQuery: Boolean;
293 public
294 constructor Create(FontID: DWORD);
295 destructor Destroy(); override;
296 procedure OnMessage(var Msg: TMessage); override;
297 procedure Draw; override;
298 function GetWidth(): Integer; override;
299 function WantActivationKey (key: LongInt): Boolean; override;
300 property Key: Word read FKey write FKey;
301 property Color: TRGB read FColor write FColor;
302 property Font: TFont read FFont write FFont;
303 end;
305 // can hold two keys
306 TGUIKeyRead2 = class(TGUIControl)
307 private
308 FFont: TFont;
309 FFontID: DWORD;
310 FColor: TRGB;
311 FKey0, FKey1: Word; // this should be an array. sorry.
312 FKeyIdx: Integer;
313 FIsQuery: Boolean;
314 FMaxKeyNameWdt: Integer;
315 public
316 constructor Create(FontID: DWORD);
317 destructor Destroy(); override;
318 procedure OnMessage(var Msg: TMessage); override;
319 procedure Draw; override;
320 function GetWidth(): Integer; override;
321 function WantActivationKey (key: LongInt): Boolean; override;
322 property Key0: Word read FKey0 write FKey0;
323 property Key1: Word read FKey1 write FKey1;
324 property Color: TRGB read FColor write FColor;
325 property Font: TFont read FFont write FFont;
326 end;
328 TGUIModelView = class(TGUIControl)
329 private
330 FModel: TPlayerModel;
331 a: Boolean;
332 public
333 constructor Create;
334 destructor Destroy; override;
335 procedure SetModel(ModelName: string);
336 procedure SetColor(Red, Green, Blue: Byte);
337 procedure NextAnim();
338 procedure NextWeapon();
339 procedure Update; override;
340 procedure Draw; override;
341 property Model: TPlayerModel read FModel;
342 end;
344 TPreviewPanel = record
345 X1, Y1, X2, Y2: Integer;
346 PanelType: Word;
347 end;
349 TGUIMapPreview = class(TGUIControl)
350 private
351 FMapData: array of TPreviewPanel;
352 FMapSize: TDFPoint;
353 FScale: Single;
354 public
355 constructor Create();
356 destructor Destroy(); override;
357 procedure SetMap(Res: string);
358 procedure ClearMap();
359 procedure Draw(); override;
360 function GetScaleStr: String;
361 end;
363 TGUIImage = class(TGUIControl)
364 private
365 FImageRes: string;
366 FDefaultRes: string;
367 public
368 constructor Create();
369 procedure SetImage(Res: string);
370 procedure ClearImage();
371 procedure Draw(); override;
372 property DefaultRes: string read FDefaultRes write FDefaultRes;
373 end;
375 TGUIListBox = class(TGUIControl)
376 private
377 FItems: SSArray;
378 FActiveColor: TRGB;
379 FUnActiveColor: TRGB;
380 FFont: TFont;
381 FStartLine: Integer;
382 FIndex: Integer;
383 FWidth: Word;
384 FHeight: Word;
385 FSort: Boolean;
386 FDrawBack: Boolean;
387 FDrawScroll: Boolean;
388 FOnChangeEvent: TOnChangeEvent;
390 procedure FSetItems(Items: SSArray);
391 procedure FSetIndex(aIndex: Integer);
393 public
394 constructor Create(FontID: DWORD; Width, Height: Word);
395 destructor Destroy(); override;
396 procedure OnMessage(var Msg: TMessage); override;
397 procedure Draw(); override;
398 procedure AddItem(Item: String);
399 function ItemExists (item: String): Boolean;
400 procedure SelectItem(Item: String);
401 procedure Clear();
402 function GetWidth(): Integer; override;
403 function GetHeight(): Integer; override;
404 function SelectedItem(): String;
406 property OnChange: TOnChangeEvent read FOnChangeEvent write FOnChangeEvent;
407 property Sort: Boolean read FSort write FSort;
408 property ItemIndex: Integer read FIndex write FSetIndex;
409 property Items: SSArray read FItems write FSetItems;
410 property DrawBack: Boolean read FDrawBack write FDrawBack;
411 property DrawScrollBar: Boolean read FDrawScroll write FDrawScroll;
412 property ActiveColor: TRGB read FActiveColor write FActiveColor;
413 property UnActiveColor: TRGB read FUnActiveColor write FUnActiveColor;
414 property Font: TFont read FFont write FFont;
415 end;
417 TGUIFileListBox = class(TGUIListBox)
418 private
419 FSubPath: String;
420 FFileMask: String;
421 FDirs: Boolean;
422 FBaseList: SSArray; // highter index have highter priority
424 procedure ScanDirs;
426 public
427 procedure OnMessage (var Msg: TMessage); override;
428 procedure SetBase (dirs: SSArray; path: String = '');
429 function SelectedItem(): String;
430 procedure UpdateFileList();
432 property Dirs: Boolean read FDirs write FDirs;
433 property FileMask: String read FFileMask write FFileMask;
434 end;
436 TGUIMemo = class(TGUIControl)
437 private
438 FLines: SSArray;
439 FFont: TFont;
440 FStartLine: Integer;
441 FWidth: Word;
442 FHeight: Word;
443 FColor: TRGB;
444 FDrawBack: Boolean;
445 FDrawScroll: Boolean;
446 public
447 constructor Create(FontID: DWORD; Width, Height: Word);
448 destructor Destroy(); override;
449 procedure OnMessage(var Msg: TMessage); override;
450 procedure Draw; override;
451 procedure Clear;
452 function GetWidth(): Integer; override;
453 function GetHeight(): Integer; override;
454 procedure SetText(Text: string);
455 property DrawBack: Boolean read FDrawBack write FDrawBack;
456 property DrawScrollBar: Boolean read FDrawScroll write FDrawScroll;
457 property Color: TRGB read FColor write FColor;
458 property Font: TFont read FFont write FFont;
459 end;
461 TGUIMainMenu = class(TGUIControl)
462 private
463 FButtons: array of TGUITextButton;
464 FHeader: TGUILabel;
465 FLogo: DWord;
466 FIndex: Integer;
467 FFontID: DWORD;
468 FCounter: Byte;
469 FMarkerID1: DWORD;
470 FMarkerID2: DWORD;
471 public
472 constructor Create(FontID: DWORD; Logo, Header: string);
473 destructor Destroy; override;
474 procedure OnMessage(var Msg: TMessage); override;
475 function AddButton(fProc: Pointer; Caption: string; ShowWindow: string = ''): TGUITextButton;
476 function GetButton(aName: string): TGUITextButton;
477 procedure EnableButton(aName: string; e: Boolean);
478 procedure AddSpace();
479 procedure Update; override;
480 procedure Draw; override;
481 end;
483 TControlType = class of TGUIControl;
485 PMenuItem = ^TMenuItem;
486 TMenuItem = record
487 Text: TGUILabel;
488 ControlType: TControlType;
489 Control: TGUIControl;
490 end;
492 TGUIMenu = class(TGUIControl)
493 private
494 FItems: array of TMenuItem;
495 FHeader: TGUILabel;
496 FIndex: Integer;
497 FFontID: DWORD;
498 FCounter: Byte;
499 FAlign: Boolean;
500 FLeft: Integer;
501 FYesNo: Boolean;
502 function NewItem(): Integer;
503 public
504 constructor Create(HeaderFont, ItemsFont: DWORD; Header: string);
505 destructor Destroy; override;
506 procedure OnMessage(var Msg: TMessage); override;
507 procedure AddSpace();
508 procedure AddLine(fText: string);
509 procedure AddText(fText: string; MaxWidth: Word);
510 function AddLabel(fText: string): TGUILabel;
511 function AddButton(Proc: Pointer; fText: string; _ShowWindow: string = ''): TGUITextButton;
512 function AddScroll(fText: string): TGUIScroll;
513 function AddSwitch(fText: string): TGUISwitch;
514 function AddEdit(fText: string): TGUIEdit;
515 function AddKeyRead(fText: string): TGUIKeyRead;
516 function AddKeyRead2(fText: string): TGUIKeyRead2;
517 function AddList(fText: string; Width, Height: Word): TGUIListBox;
518 function AddFileList(fText: string; Width, Height: Word): TGUIFileListBox;
519 function AddMemo(fText: string; Width, Height: Word): TGUIMemo;
520 procedure ReAlign();
521 function GetControl(aName: string): TGUIControl;
522 function GetControlsText(aName: string): TGUILabel;
523 procedure Draw; override;
524 procedure Update; override;
525 procedure UpdateIndex();
526 property Align: Boolean read FAlign write FAlign;
527 property Left: Integer read FLeft write FLeft;
528 property YesNo: Boolean read FYesNo write FYesNo;
529 end;
532 g_GUIWindows: array of TGUIWindow;
533 g_ActiveWindow: TGUIWindow = nil;
534 g_GUIGrabInput: Boolean = False;
536 procedure g_GUI_Init();
537 function g_GUI_AddWindow(Window: TGUIWindow): TGUIWindow;
538 function g_GUI_GetWindow(Name: string): TGUIWindow;
539 procedure g_GUI_ShowWindow(Name: string);
540 procedure g_GUI_HideWindow(PlaySound: Boolean = True);
541 function g_GUI_Destroy(): Boolean;
542 procedure g_GUI_SaveMenuPos();
543 procedure g_GUI_LoadMenuPos();
546 implementation
548 uses
549 {$INCLUDE ../nogl/noGLuses.inc}
550 {$IFDEF ENABLE_SOUND}
551 g_sound,
552 {$ENDIF}
553 g_textures, SysUtils, e_res,
554 g_game, Math, StrUtils, g_player, g_options, g_console,
555 g_map, g_weapons, xdynrec, wadreader, Generics.Collections, Generics.Defaults;
559 Box: array[0..8] of DWORD;
560 Saved_Windows: SSArray;
563 procedure g_GUI_Init();
564 begin
565 g_Texture_Get(BOX1, Box[0]);
566 g_Texture_Get(BOX2, Box[1]);
567 g_Texture_Get(BOX3, Box[2]);
568 g_Texture_Get(BOX4, Box[3]);
569 g_Texture_Get(BOX5, Box[4]);
570 g_Texture_Get(BOX6, Box[5]);
571 g_Texture_Get(BOX7, Box[6]);
572 g_Texture_Get(BOX8, Box[7]);
573 g_Texture_Get(BOX9, Box[8]);
574 end;
576 function g_GUI_Destroy(): Boolean;
578 i: Integer;
579 begin
580 Result := (Length(g_GUIWindows) > 0);
582 for i := 0 to High(g_GUIWindows) do
583 g_GUIWindows[i].Free();
585 g_GUIWindows := nil;
586 g_ActiveWindow := nil;
587 end;
589 function g_GUI_AddWindow(Window: TGUIWindow): TGUIWindow;
590 begin
591 SetLength(g_GUIWindows, Length(g_GUIWindows)+1);
592 g_GUIWindows[High(g_GUIWindows)] := Window;
594 Result := Window;
595 end;
597 function g_GUI_GetWindow(Name: string): TGUIWindow;
599 i: Integer;
600 begin
601 Result := nil;
603 if g_GUIWindows <> nil then
604 for i := 0 to High(g_GUIWindows) do
605 if g_GUIWindows[i].FName = Name then
606 begin
607 Result := g_GUIWindows[i];
608 Break;
609 end;
611 Assert(Result <> nil, 'GUI_Window "'+Name+'" not found');
612 end;
614 procedure g_GUI_ShowWindow(Name: string);
616 i: Integer;
617 begin
618 if g_GUIWindows = nil then
619 Exit;
621 for i := 0 to High(g_GUIWindows) do
622 if g_GUIWindows[i].FName = Name then
623 begin
624 g_GUIWindows[i].FPrevWindow := g_ActiveWindow;
625 g_ActiveWindow := g_GUIWindows[i];
627 if g_ActiveWindow.MainWindow then
628 g_ActiveWindow.FPrevWindow := nil;
630 if g_ActiveWindow.FDefControl <> '' then
631 g_ActiveWindow.SetActive(g_ActiveWindow.GetControl(g_ActiveWindow.FDefControl))
632 else
633 g_ActiveWindow.SetActive(nil);
635 if @g_ActiveWindow.FOnShowEvent <> nil then
636 g_ActiveWindow.FOnShowEvent();
638 Break;
639 end;
640 end;
642 procedure g_GUI_HideWindow(PlaySound: Boolean = True);
643 begin
644 if g_ActiveWindow <> nil then
645 begin
646 if @g_ActiveWindow.OnClose <> nil then
647 g_ActiveWindow.OnClose();
648 g_ActiveWindow := g_ActiveWindow.FPrevWindow;
649 {$IFDEF ENABLE_SOUND}
650 if PlaySound then
651 g_Sound_PlayEx(WINDOW_CLOSESOUND);
652 {$ENDIF}
653 end;
654 end;
656 procedure g_GUI_SaveMenuPos();
658 len: Integer;
659 win: TGUIWindow;
660 begin
661 SetLength(Saved_Windows, 0);
662 win := g_ActiveWindow;
664 while win <> nil do
665 begin
666 len := Length(Saved_Windows);
667 SetLength(Saved_Windows, len + 1);
669 Saved_Windows[len] := win.Name;
671 if win.MainWindow then
672 win := nil
673 else
674 win := win.FPrevWindow;
675 end;
676 end;
678 procedure g_GUI_LoadMenuPos();
680 i, j, k, len: Integer;
681 ok: Boolean;
682 begin
683 g_ActiveWindow := nil;
684 len := Length(Saved_Windows);
686 if len = 0 then
687 Exit;
689 // Îêíî ñ ãëàâíûì ìåíþ:
690 g_GUI_ShowWindow(Saved_Windows[len-1]);
692 // Íå ïåðåêëþ÷èëîñü (èëè íåêóäà äàëüøå):
693 if (len = 1) or (g_ActiveWindow = nil) then
694 Exit;
696 // Èùåì êíîïêè â îñòàëüíûõ îêíàõ:
697 for k := len-1 downto 1 do
698 begin
699 ok := False;
701 for i := 0 to Length(g_ActiveWindow.Childs)-1 do
702 begin
703 if g_ActiveWindow.Childs[i] is TGUIMainMenu then
704 begin // GUI_MainMenu
705 with TGUIMainMenu(g_ActiveWindow.Childs[i]) do
706 for j := 0 to Length(FButtons)-1 do
707 if FButtons[j].ShowWindow = Saved_Windows[k-1] then
708 begin
709 FButtons[j].Click(True);
710 ok := True;
711 Break;
712 end;
714 else // GUI_Menu
715 if g_ActiveWindow.Childs[i] is TGUIMenu then
716 with TGUIMenu(g_ActiveWindow.Childs[i]) do
717 for j := 0 to Length(FItems)-1 do
718 if FItems[j].ControlType = TGUITextButton then
719 if TGUITextButton(FItems[j].Control).ShowWindow = Saved_Windows[k-1] then
720 begin
721 TGUITextButton(FItems[j].Control).Click(True);
722 ok := True;
723 Break;
724 end;
726 if ok then
727 Break;
728 end;
730 // Íå ïåðåêëþ÷èëîñü:
731 if (not ok) or
732 (g_ActiveWindow.Name = Saved_Windows[k]) then
733 Break;
734 end;
735 end;
737 procedure DrawBox(X, Y: Integer; Width, Height: Word);
738 begin
739 e_Draw(Box[0], X, Y, 0, False, False);
740 e_DrawFill(Box[1], X+4, Y, Width*4, 1, 0, False, False);
741 e_Draw(Box[2], X+4+Width*16, Y, 0, False, False);
742 e_DrawFill(Box[3], X, Y+4, 1, Height*4, 0, False, False);
743 e_DrawFill(Box[4], X+4, Y+4, Width, Height, 0, False, False);
744 e_DrawFill(Box[5], X+4+Width*16, Y+4, 1, Height*4, 0, False, False);
745 e_Draw(Box[6], X, Y+4+Height*16, 0, False, False);
746 e_DrawFill(Box[7], X+4, Y+4+Height*16, Width*4, 1, 0, False, False);
747 e_Draw(Box[8], X+4+Width*16, Y+4+Height*16, 0, False, False);
748 end;
750 procedure DrawScroll(X, Y: Integer; Height: Word; Up, Down: Boolean);
752 ID: DWORD;
753 begin
754 if Height < 3 then Exit;
756 if Up then
757 g_Texture_Get(BSCROLL_UPA, ID)
758 else
759 g_Texture_Get(BSCROLL_UPU, ID);
760 e_Draw(ID, X, Y, 0, False, False);
762 if Down then
763 g_Texture_Get(BSCROLL_DOWNA, ID)
764 else
765 g_Texture_Get(BSCROLL_DOWNU, ID);
766 e_Draw(ID, X, Y+(Height-1)*16, 0, False, False);
768 g_Texture_Get(BSCROLL_MIDDLE, ID);
769 e_DrawFill(ID, X, Y+16, 1, Height-2, 0, False, False);
770 end;
772 { TGUIWindow }
774 constructor TGUIWindow.Create(Name: string);
775 begin
776 Childs := nil;
777 FActiveControl := nil;
778 FName := Name;
779 FOnKeyDown := nil;
780 FOnKeyDownEx := nil;
781 FOnCloseEvent := nil;
782 FOnShowEvent := nil;
783 end;
785 destructor TGUIWindow.Destroy;
787 i: Integer;
788 begin
789 if Childs = nil then
790 Exit;
792 for i := 0 to High(Childs) do
793 Childs[i].Free();
794 end;
796 function TGUIWindow.AddChild(Child: TGUIControl): TGUIControl;
797 begin
798 Child.FWindow := Self;
800 SetLength(Childs, Length(Childs) + 1);
801 Childs[High(Childs)] := Child;
803 Result := Child;
804 end;
806 procedure TGUIWindow.Update;
808 i: Integer;
809 begin
810 for i := 0 to High(Childs) do
811 if Childs[i] <> nil then Childs[i].Update;
812 end;
814 procedure TGUIWindow.Draw;
816 i: Integer;
817 ID: DWORD;
818 tw, th: Word;
819 begin
820 if FBackTexture <> '' then // Here goes code duplication from g_game.pas:DrawMenuBackground()
821 if g_Texture_Get(FBackTexture, ID) then
822 begin
823 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
824 e_GetTextureSize(ID, @tw, @th);
825 if tw = th then
826 tw := round(tw * 1.333 * (gScreenHeight / th))
827 else
828 tw := trunc(tw * (gScreenHeight / th));
829 e_DrawSize(ID, (gScreenWidth - tw) div 2, 0, 0, False, False, tw, gScreenHeight);
831 else
832 e_Clear(GL_COLOR_BUFFER_BIT, 0.5, 0.5, 0.5);
834 // small hack here
835 if FName = 'AuthorsMenu' then
836 e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150);
838 for i := 0 to High(Childs) do
839 if Childs[i] <> nil then Childs[i].Draw;
840 end;
842 procedure TGUIWindow.OnMessage(var Msg: TMessage);
843 begin
844 if FActiveControl <> nil then FActiveControl.OnMessage(Msg);
845 if @FOnKeyDown <> nil then FOnKeyDown(Msg.wParam);
846 if @FOnKeyDownEx <> nil then FOnKeyDownEx(self, Msg.wParam);
848 if Msg.Msg = WM_KEYDOWN then
849 begin
850 case Msg.wParam of
851 VK_ESCAPE:
852 begin
853 g_GUI_HideWindow;
854 Exit
858 end;
860 procedure TGUIWindow.SetActive(Control: TGUIControl);
861 begin
862 FActiveControl := Control;
863 end;
865 function TGUIWindow.GetControl(Name: String): TGUIControl;
867 i: Integer;
868 begin
869 Result := nil;
871 if Childs <> nil then
872 for i := 0 to High(Childs) do
873 if Childs[i] <> nil then
874 if LowerCase(Childs[i].FName) = LowerCase(Name) then
875 begin
876 Result := Childs[i];
877 Break;
878 end;
880 Assert(Result <> nil, 'Window Control "'+Name+'" not Found!');
881 end;
883 { TGUIControl }
885 constructor TGUIControl.Create();
886 begin
887 FX := 0;
888 FY := 0;
890 FEnabled := True;
891 FRightAlign := false;
892 FMaxWidth := -1;
893 end;
895 procedure TGUIControl.OnMessage(var Msg: TMessage);
896 begin
897 if not FEnabled then
898 Exit;
899 end;
901 procedure TGUIControl.Update();
902 begin
903 end;
905 procedure TGUIControl.Draw();
906 begin
907 end;
909 function TGUIControl.WantActivationKey (key: LongInt): Boolean;
910 begin
911 result := false;
912 end;
914 function TGUIControl.GetWidth(): Integer;
915 begin
916 result := 0;
917 end;
919 function TGUIControl.GetHeight(): Integer;
920 begin
921 result := 0;
922 end;
924 { TGUITextButton }
926 procedure TGUITextButton.Click(Silent: Boolean = False);
927 begin
928 {$IFDEF ENABLE_SOUND}
929 if (FSound <> '') and (not Silent) then g_Sound_PlayEx(FSound);
930 {$ENDIF}
932 if @Proc <> nil then Proc();
933 if @ProcEx <> nil then ProcEx(self);
935 if FShowWindow <> '' then g_GUI_ShowWindow(FShowWindow);
936 end;
938 constructor TGUITextButton.Create(aProc: Pointer; FontID: DWORD; Text: string);
939 begin
940 inherited Create();
942 Self.Proc := aProc;
943 ProcEx := nil;
945 FFont := TFont.Create(FontID, TFontType.Character);
947 FText := Text;
948 end;
950 destructor TGUITextButton.Destroy;
951 begin
952 FFont.Destroy();
953 inherited;
954 end;
956 procedure TGUITextButton.Draw;
957 begin
958 FFont.Draw(FX, FY, FText, FColor.R, FColor.G, FColor.B)
959 end;
961 function TGUITextButton.GetHeight: Integer;
963 w, h: Word;
964 begin
965 FFont.GetTextSize(FText, w, h);
966 Result := h;
967 end;
969 function TGUITextButton.GetWidth: Integer;
971 w, h: Word;
972 begin
973 FFont.GetTextSize(FText, w, h);
974 Result := w;
975 end;
977 procedure TGUITextButton.OnMessage(var Msg: TMessage);
978 begin
979 if not FEnabled then Exit;
981 inherited;
983 case Msg.Msg of
984 WM_KEYDOWN:
985 case Msg.wParam of
986 IK_RETURN, IK_KPRETURN, IK_SELECT,
987 VK_FIRE, VK_OPEN,
988 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK: Click();
989 end;
990 end;
991 end;
993 { TFont }
995 constructor TFont.Create(FontID: DWORD; FontType: TFontType);
996 begin
997 ID := FontID;
999 FScale := 1;
1000 FFontType := FontType;
1001 end;
1003 procedure TFont.Draw(X, Y: Integer; Text: string; R, G, B: Byte);
1004 begin
1005 if FFontType = TFontType.Character
1006 then e_CharFont_PrintEx(ID, X, Y, Text, _RGB(R, G, B), FScale)
1007 else e_TextureFontPrintEx(X, Y, Text, ID, R, G, B, FScale);
1008 end;
1010 procedure TFont.GetTextSize(Text: string; var w, h: Word);
1012 cw, ch: Byte;
1013 begin
1014 if FFontType = TFontType.Character then
1015 e_CharFont_GetSize(ID, Text, w, h)
1016 else
1017 begin
1018 e_TextureFontGetSize(ID, cw, ch);
1019 w := cw*Length(Text);
1020 h := ch;
1021 end;
1023 w := Round(w*FScale);
1024 h := Round(h*FScale);
1025 end;
1027 { TGUIMainMenu }
1029 function TGUIMainMenu.AddButton(fProc: Pointer; Caption: string; ShowWindow: string = ''): TGUITextButton;
1031 a, _x: Integer;
1032 h, hh: Word;
1033 lh: Word = 0;
1034 begin
1035 FIndex := 0;
1037 SetLength(FButtons, Length(FButtons)+1);
1038 FButtons[High(FButtons)] := TGUITextButton.Create(fProc, FFontID, Caption);
1039 FButtons[High(FButtons)].ShowWindow := ShowWindow;
1040 with FButtons[High(FButtons)] do
1041 begin
1042 if (fProc <> nil) or (ShowWindow <> '') then FColor := MAINMENU_ITEMS_COLOR
1043 else FColor := MAINMENU_UNACTIVEITEMS_COLOR;
1044 FSound := MAINMENU_CLICKSOUND;
1045 end;
1047 _x := gScreenWidth div 2;
1049 for a := 0 to High(FButtons) do
1050 if FButtons[a] <> nil then
1051 _x := Min(_x, (gScreenWidth div 2)-(FButtons[a].GetWidth div 2));
1053 if FLogo <> 0 then e_GetTextureSize(FLogo, nil, @lh);
1054 hh := FButtons[High(FButtons)].GetHeight;
1056 if FLogo <> 0 then h := lh + hh * (1 + Length(FButtons)) + MAINMENU_SPACE * (Length(FButtons) - 1)
1057 else h := hh * (2 + Length(FButtons)) + MAINMENU_SPACE * (Length(FButtons) - 1);
1058 h := (gScreenHeight div 2) - (h div 2);
1060 if FHeader <> nil then with FHeader do
1061 begin
1062 FX := _x;
1063 FY := h;
1064 end;
1066 if FLogo <> 0 then Inc(h, lh)
1067 else Inc(h, hh*2);
1069 for a := 0 to High(FButtons) do
1070 begin
1071 if FButtons[a] <> nil then
1072 with FButtons[a] do
1073 begin
1074 FX := _x;
1075 FY := h;
1076 end;
1078 Inc(h, hh+MAINMENU_SPACE);
1079 end;
1081 Result := FButtons[High(FButtons)];
1082 end;
1084 procedure TGUIMainMenu.AddSpace;
1085 begin
1086 SetLength(FButtons, Length(FButtons)+1);
1087 FButtons[High(FButtons)] := nil;
1088 end;
1090 constructor TGUIMainMenu.Create(FontID: DWORD; Logo, Header: string);
1091 begin
1092 inherited Create();
1094 FIndex := -1;
1095 FFontID := FontID;
1096 FCounter := MAINMENU_MARKERDELAY;
1098 g_Texture_Get(MAINMENU_MARKER1, FMarkerID1);
1099 g_Texture_Get(MAINMENU_MARKER2, FMarkerID2);
1101 if not g_Texture_Get(Logo, FLogo) then
1102 begin
1103 FHeader := TGUILabel.Create(Header, FFontID);
1104 with FHeader do
1105 begin
1106 FColor := MAINMENU_HEADER_COLOR;
1107 FX := (gScreenWidth div 2)-(GetWidth div 2);
1108 FY := (gScreenHeight div 2)-(GetHeight div 2);
1109 end;
1110 end;
1111 end;
1113 destructor TGUIMainMenu.Destroy;
1115 a: Integer;
1116 begin
1117 if FButtons <> nil then
1118 for a := 0 to High(FButtons) do
1119 FButtons[a].Free();
1121 FHeader.Free();
1123 inherited;
1124 end;
1126 procedure TGUIMainMenu.Draw;
1128 a: Integer;
1129 w, h: Word;
1131 begin
1132 inherited;
1134 if FHeader <> nil then FHeader.Draw
1135 else begin
1136 e_GetTextureSize(FLogo, @w, @h);
1137 e_Draw(FLogo, ((gScreenWidth div 2) - (w div 2)), FButtons[0].FY - FButtons[0].GetHeight - h, 0, True, False);
1138 end;
1140 if FButtons <> nil then
1141 begin
1142 for a := 0 to High(FButtons) do
1143 if FButtons[a] <> nil then FButtons[a].Draw;
1145 if FIndex <> -1 then
1146 e_Draw(FMarkerID1, FButtons[FIndex].FX-48, FButtons[FIndex].FY, 0, True, False);
1147 end;
1148 end;
1150 procedure TGUIMainMenu.EnableButton(aName: string; e: Boolean);
1152 a: Integer;
1153 begin
1154 if FButtons = nil then Exit;
1156 for a := 0 to High(FButtons) do
1157 if (FButtons[a] <> nil) and (FButtons[a].Name = aName) then
1158 begin
1159 if e then FButtons[a].FColor := MAINMENU_ITEMS_COLOR
1160 else FButtons[a].FColor := MAINMENU_UNACTIVEITEMS_COLOR;
1161 FButtons[a].Enabled := e;
1162 Break;
1163 end;
1164 end;
1166 function TGUIMainMenu.GetButton(aName: string): TGUITextButton;
1168 a: Integer;
1169 begin
1170 Result := nil;
1172 if FButtons = nil then Exit;
1174 for a := 0 to High(FButtons) do
1175 if (FButtons[a] <> nil) and (FButtons[a].Name = aName) then
1176 begin
1177 Result := FButtons[a];
1178 Break;
1179 end;
1180 end;
1182 procedure TGUIMainMenu.OnMessage(var Msg: TMessage);
1184 ok: Boolean;
1185 a: Integer;
1186 begin
1187 if not FEnabled then Exit;
1189 inherited;
1191 if FButtons = nil then Exit;
1193 ok := False;
1194 for a := 0 to High(FButtons) do
1195 if FButtons[a] <> nil then
1196 begin
1197 ok := True;
1198 Break;
1199 end;
1201 if not ok then Exit;
1203 case Msg.Msg of
1204 WM_KEYDOWN:
1205 case Msg.wParam of
1206 IK_UP, IK_KPUP, VK_UP, JOY0_UP, JOY1_UP, JOY2_UP, JOY3_UP:
1207 begin
1208 repeat
1209 Dec(FIndex);
1210 if FIndex < 0 then FIndex := High(FButtons);
1211 until FButtons[FIndex] <> nil;
1213 {$IFDEF ENABLE_SOUND}
1214 g_Sound_PlayEx(MENU_CHANGESOUND);
1215 {$ENDIF}
1216 end;
1217 IK_DOWN, IK_KPDOWN, VK_DOWN, JOY0_DOWN, JOY1_DOWN, JOY2_DOWN, JOY3_DOWN:
1218 begin
1219 repeat
1220 Inc(FIndex);
1221 if FIndex > High(FButtons) then FIndex := 0;
1222 until FButtons[FIndex] <> nil;
1224 {$IFDEF ENABLE_SOUND}
1225 g_Sound_PlayEx(MENU_CHANGESOUND);
1226 {$ENDIF}
1227 end;
1228 IK_RETURN, IK_KPRETURN, IK_SELECT,
1229 VK_FIRE, VK_OPEN, JOY0_ATTACK,
1230 JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
1231 if (FIndex <> -1) and FButtons[FIndex].FEnabled then
1232 FButtons[FIndex].Click;
1233 end;
1234 end;
1235 end;
1237 procedure TGUIMainMenu.Update;
1239 t: DWORD;
1240 begin
1241 inherited;
1243 if FCounter = 0 then
1244 begin
1245 t := FMarkerID1;
1246 FMarkerID1 := FMarkerID2;
1247 FMarkerID2 := t;
1249 FCounter := MAINMENU_MARKERDELAY;
1250 end else Dec(FCounter);
1251 end;
1253 { TGUILabel }
1255 constructor TGUILabel.Create(Text: string; FontID: DWORD);
1256 begin
1257 inherited Create();
1259 FFont := TFont.Create(FontID, TFontType.Character);
1261 FText := Text;
1262 FFixedLen := 0;
1263 FOnClickEvent := nil;
1264 end;
1266 destructor TGUILabel.Destroy();
1267 begin
1268 FFont.Destroy();
1269 inherited;
1270 end;
1272 procedure TGUILabel.Draw;
1274 w, h: Word;
1275 begin
1276 if RightAlign then
1277 begin
1278 FFont.GetTextSize(FText, w, h);
1279 FFont.Draw(FX+FMaxWidth-w, FY, FText, FColor.R, FColor.G, FColor.B);
1281 else
1282 begin
1283 FFont.Draw(FX, FY, FText, FColor.R, FColor.G, FColor.B);
1284 end;
1285 end;
1287 function TGUILabel.GetHeight: Integer;
1289 w, h: Word;
1290 begin
1291 FFont.GetTextSize(FText, w, h);
1292 Result := h;
1293 end;
1295 function TGUILabel.GetWidth: Integer;
1297 w, h: Word;
1298 begin
1299 if FFixedLen = 0 then
1300 FFont.GetTextSize(FText, w, h)
1301 else
1302 w := e_CharFont_GetMaxWidth(FFont.ID)*FFixedLen;
1303 Result := w;
1304 end;
1306 procedure TGUILabel.OnMessage(var Msg: TMessage);
1307 begin
1308 if not FEnabled then Exit;
1310 inherited;
1312 case Msg.Msg of
1313 WM_KEYDOWN:
1314 case Msg.wParam of
1315 IK_RETURN, IK_KPRETURN, IK_SELECT,
1316 VK_FIRE, VK_OPEN,
1317 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
1318 if @FOnClickEvent <> nil then
1319 FOnClickEvent();
1320 end;
1321 end;
1322 end;
1324 { TGUIMenu }
1326 function TGUIMenu.AddButton(Proc: Pointer; fText: string; _ShowWindow: string = ''): TGUITextButton;
1328 i: Integer;
1329 begin
1330 i := NewItem();
1331 with FItems[i] do
1332 begin
1333 Control := TGUITextButton.Create(Proc, FFontID, fText);
1334 with TGUITextButton(Control) do
1335 begin
1336 ShowWindow := _ShowWindow;
1337 FColor := MENU_ITEMSCTRL_COLOR;
1338 end;
1340 Text := nil;
1342 ControlType := TGUITextButton;
1343 Result := TGUITextButton(Control);
1344 end;
1346 if FIndex = -1 then FIndex := i;
1348 ReAlign();
1349 end;
1351 procedure TGUIMenu.AddLine(fText: string);
1353 i: Integer;
1354 begin
1355 i := NewItem();
1356 with FItems[i] do
1357 begin
1358 Text := TGUILabel.Create(fText, FFontID);
1359 with Text do
1360 begin
1361 FColor := MENU_ITEMSTEXT_COLOR;
1362 end;
1364 Control := nil;
1365 end;
1367 ReAlign();
1368 end;
1370 procedure TGUIMenu.AddText(fText: string; MaxWidth: Word);
1372 a, i: Integer;
1373 l: SSArray;
1374 begin
1375 l := GetLines(fText, FFontID, MaxWidth);
1377 if l = nil then Exit;
1379 for a := 0 to High(l) do
1380 begin
1381 i := NewItem();
1382 with FItems[i] do
1383 begin
1384 Text := TGUILabel.Create(l[a], FFontID);
1385 if FYesNo then
1386 begin
1387 with Text do begin FColor := _RGB(255, 0, 0); end;
1389 else
1390 begin
1391 with Text do begin FColor := MENU_ITEMSTEXT_COLOR; end;
1392 end;
1394 Control := nil;
1395 end;
1396 end;
1398 ReAlign();
1399 end;
1401 procedure TGUIMenu.AddSpace;
1403 i: Integer;
1404 begin
1405 i := NewItem();
1406 with FItems[i] do
1407 begin
1408 Text := nil;
1409 Control := nil;
1410 end;
1412 ReAlign();
1413 end;
1415 constructor TGUIMenu.Create(HeaderFont, ItemsFont: DWORD; Header: string);
1416 begin
1417 inherited Create();
1419 FItems := nil;
1420 FIndex := -1;
1421 FFontID := ItemsFont;
1422 FCounter := MENU_MARKERDELAY;
1423 FAlign := True;
1424 FYesNo := false;
1426 FHeader := TGUILabel.Create(Header, HeaderFont);
1427 with FHeader do
1428 begin
1429 FX := (gScreenWidth div 2)-(GetWidth div 2);
1430 FY := 0;
1431 FColor := MAINMENU_HEADER_COLOR;
1432 end;
1433 end;
1435 destructor TGUIMenu.Destroy;
1437 a: Integer;
1438 begin
1439 if FItems <> nil then
1440 for a := 0 to High(FItems) do
1441 with FItems[a] do
1442 begin
1443 Text.Free();
1444 Control.Free();
1445 end;
1447 FItems := nil;
1449 FHeader.Free();
1451 inherited;
1452 end;
1454 procedure TGUIMenu.Draw;
1456 a, locx, locy: Integer;
1457 begin
1458 inherited;
1460 if FHeader <> nil then FHeader.Draw;
1462 if FItems <> nil then
1463 for a := 0 to High(FItems) do
1464 begin
1465 if FItems[a].Text <> nil then FItems[a].Text.Draw;
1466 if FItems[a].Control <> nil then FItems[a].Control.Draw;
1467 end;
1469 if (FIndex <> -1) and (FCounter > MENU_MARKERDELAY div 2) then
1470 begin
1471 locx := 0;
1472 locy := 0;
1474 if FItems[FIndex].Text <> nil then
1475 begin
1476 locx := FItems[FIndex].Text.FX;
1477 locy := FItems[FIndex].Text.FY;
1478 //HACK!
1479 if FItems[FIndex].Text.RightAlign then
1480 begin
1481 locx := locx+FItems[FIndex].Text.FMaxWidth-FItems[FIndex].Text.GetWidth;
1482 end;
1484 else if FItems[FIndex].Control <> nil then
1485 begin
1486 locx := FItems[FIndex].Control.FX;
1487 locy := FItems[FIndex].Control.FY;
1488 end;
1490 locx := locx-e_CharFont_GetMaxWidth(FFontID);
1492 e_CharFont_PrintEx(FFontID, locx, locy, #16, _RGB(255, 0, 0));
1493 end;
1494 end;
1496 function TGUIMenu.GetControl(aName: String): TGUIControl;
1498 a: Integer;
1499 begin
1500 Result := nil;
1502 if FItems <> nil then
1503 for a := 0 to High(FItems) do
1504 if FItems[a].Control <> nil then
1505 if LowerCase(FItems[a].Control.Name) = LowerCase(aName) then
1506 begin
1507 Result := FItems[a].Control;
1508 Break;
1509 end;
1511 Assert(Result <> nil, 'GUI control "'+aName+'" not found!');
1512 end;
1514 function TGUIMenu.GetControlsText(aName: String): TGUILabel;
1516 a: Integer;
1517 begin
1518 Result := nil;
1520 if FItems <> nil then
1521 for a := 0 to High(FItems) do
1522 if FItems[a].Control <> nil then
1523 if LowerCase(FItems[a].Control.Name) = LowerCase(aName) then
1524 begin
1525 Result := FItems[a].Text;
1526 Break;
1527 end;
1529 Assert(Result <> nil, 'GUI control''s text "'+aName+'" not found!');
1530 end;
1532 function TGUIMenu.NewItem: Integer;
1533 begin
1534 SetLength(FItems, Length(FItems)+1);
1535 Result := High(FItems);
1536 end;
1538 procedure TGUIMenu.OnMessage(var Msg: TMessage);
1540 ok: Boolean;
1541 a, c: Integer;
1542 begin
1543 if not FEnabled then Exit;
1545 inherited;
1547 if FItems = nil then Exit;
1549 ok := False;
1550 for a := 0 to High(FItems) do
1551 if FItems[a].Control <> nil then
1552 begin
1553 ok := True;
1554 Break;
1555 end;
1557 if not ok then Exit;
1559 if (Msg.Msg = WM_KEYDOWN) and (FIndex <> -1) and (FItems[FIndex].Control <> nil) and
1560 (FItems[FIndex].Control.WantActivationKey(Msg.wParam)) then
1561 begin
1562 FItems[FIndex].Control.OnMessage(Msg);
1563 {$IFDEF ENABLE_SOUND}
1564 g_Sound_PlayEx(MENU_CLICKSOUND);
1565 {$ENDIF}
1566 exit;
1567 end;
1569 case Msg.Msg of
1570 WM_KEYDOWN:
1571 begin
1572 case Msg.wParam of
1573 IK_UP, IK_KPUP, VK_UP,JOY0_UP, JOY1_UP, JOY2_UP, JOY3_UP:
1574 begin
1575 c := 0;
1576 repeat
1577 c := c+1;
1578 if c > Length(FItems) then
1579 begin
1580 FIndex := -1;
1581 Break;
1582 end;
1584 Dec(FIndex);
1585 if FIndex < 0 then FIndex := High(FItems);
1586 until (FItems[FIndex].Control <> nil) and
1587 (FItems[FIndex].Control.Enabled);
1589 FCounter := 0;
1591 {$IFDEF ENABLE_SOUND}
1592 g_Sound_PlayEx(MENU_CHANGESOUND);
1593 {$ENDIF}
1594 end;
1596 IK_DOWN, IK_KPDOWN, VK_DOWN, JOY0_DOWN, JOY1_DOWN, JOY2_DOWN, JOY3_DOWN:
1597 begin
1598 c := 0;
1599 repeat
1600 c := c+1;
1601 if c > Length(FItems) then
1602 begin
1603 FIndex := -1;
1604 Break;
1605 end;
1607 Inc(FIndex);
1608 if FIndex > High(FItems) then FIndex := 0;
1609 until (FItems[FIndex].Control <> nil) and
1610 (FItems[FIndex].Control.Enabled);
1612 FCounter := 0;
1614 {$IFDEF ENABLE_SOUND}
1615 g_Sound_PlayEx(MENU_CHANGESOUND);
1616 {$ENDIF}
1617 end;
1619 IK_LEFT, IK_RIGHT, IK_KPLEFT, IK_KPRIGHT, VK_LEFT, VK_RIGHT,
1620 JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT,
1621 JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
1622 begin
1623 if FIndex <> -1 then
1624 if FItems[FIndex].Control <> nil then
1625 FItems[FIndex].Control.OnMessage(Msg);
1626 end;
1627 IK_RETURN, IK_KPRETURN, IK_SELECT,
1628 VK_FIRE, VK_OPEN,
1629 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
1630 begin
1631 if FIndex <> -1 then
1632 begin
1633 if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
1634 end;
1635 {$IFDEF ENABLE_SOUND}
1636 g_Sound_PlayEx(MENU_CLICKSOUND);
1637 {$ENDIF}
1638 end;
1639 // dirty hacks
1640 IK_Y:
1641 if FYesNo and (length(FItems) > 1) then
1642 begin
1643 Msg.wParam := IK_RETURN; // to register keypress
1644 FIndex := High(FItems)-1;
1645 if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
1646 end;
1647 IK_N:
1648 if FYesNo and (length(FItems) > 1) then
1649 begin
1650 Msg.wParam := IK_RETURN; // to register keypress
1651 FIndex := High(FItems);
1652 if FItems[FIndex].Control <> nil then FItems[FIndex].Control.OnMessage(Msg);
1653 end;
1654 end;
1655 end;
1656 end;
1657 end;
1659 procedure TGUIMenu.ReAlign();
1661 a, tx, cx, w, h: Integer;
1662 cww: array of Integer; // cached widths
1663 maxcww: Integer;
1664 begin
1665 if FItems = nil then Exit;
1667 SetLength(cww, length(FItems));
1668 maxcww := 0;
1669 for a := 0 to High(FItems) do
1670 begin
1671 if FItems[a].Text <> nil then
1672 begin
1673 cww[a] := FItems[a].Text.GetWidth;
1674 if maxcww < cww[a] then maxcww := cww[a];
1675 end;
1676 end;
1678 if not FAlign then
1679 begin
1680 tx := FLeft;
1682 else
1683 begin
1684 tx := gScreenWidth;
1685 for a := 0 to High(FItems) do
1686 begin
1687 w := 0;
1688 if FItems[a].Text <> nil then w := FItems[a].Text.GetWidth;
1689 if FItems[a].Control <> nil then
1690 begin
1691 w += MENU_HSPACE;
1692 if FItems[a].ControlType = TGUILabel then w += TGUILabel(FItems[a].Control).GetWidth
1693 else if FItems[a].ControlType = TGUITextButton then w += TGUITextButton(FItems[a].Control).GetWidth
1694 else if FItems[a].ControlType = TGUIScroll then w += TGUIScroll(FItems[a].Control).GetWidth
1695 else if FItems[a].ControlType = TGUISwitch then w += TGUISwitch(FItems[a].Control).GetWidth
1696 else if FItems[a].ControlType = TGUIEdit then w += TGUIEdit(FItems[a].Control).GetWidth
1697 else if FItems[a].ControlType = TGUIKeyRead then w += TGUIKeyRead(FItems[a].Control).GetWidth
1698 else if FItems[a].ControlType = TGUIKeyRead2 then w += TGUIKeyRead2(FItems[a].Control).GetWidth
1699 else if FItems[a].ControlType = TGUIListBox then w += TGUIListBox(FItems[a].Control).GetWidth
1700 else if FItems[a].ControlType = TGUIFileListBox then w += TGUIFileListBox(FItems[a].Control).GetWidth
1701 else if FItems[a].ControlType = TGUIMemo then w += TGUIMemo(FItems[a].Control).GetWidth;
1702 end;
1703 tx := Min(tx, (gScreenWidth div 2)-(w div 2));
1704 end;
1705 end;
1707 cx := 0;
1708 for a := 0 to High(FItems) do
1709 begin
1710 with FItems[a] do
1711 begin
1712 if (Text <> nil) and (Control = nil) then Continue;
1713 w := 0;
1714 if Text <> nil then w := tx+Text.GetWidth;
1715 if w > cx then cx := w;
1716 end;
1717 end;
1719 cx += MENU_HSPACE;
1721 h := FHeader.GetHeight*2+MENU_VSPACE*(Length(FItems)-1);
1723 for a := 0 to High(FItems) do
1724 begin
1725 with FItems[a] do
1726 begin
1727 if (ControlType = TGUIListBox) or (ControlType = TGUIFileListBox) then
1728 h += (FItems[a].Control as TGUIListBox).GetHeight() // FIXME: possible mistyping?..
1729 else
1730 h += e_CharFont_GetMaxHeight(FFontID);
1731 end;
1732 end;
1734 h := (gScreenHeight div 2)-(h div 2);
1736 with FHeader do
1737 begin
1738 FX := (gScreenWidth div 2)-(GetWidth div 2);
1739 FY := h;
1741 Inc(h, GetHeight*2);
1742 end;
1744 for a := 0 to High(FItems) do
1745 begin
1746 with FItems[a] do
1747 begin
1748 if Text <> nil then
1749 begin
1750 with Text do
1751 begin
1752 FX := tx;
1753 FY := h;
1754 end;
1755 //HACK!
1756 if Text.RightAlign and (length(cww) > a) then
1757 begin
1758 //Text.FX := Text.FX+maxcww;
1759 Text.FMaxWidth := maxcww;
1760 end;
1761 end;
1763 if Control <> nil then
1764 begin
1765 with Control do
1766 begin
1767 if Text <> nil then
1768 begin
1769 FX := cx;
1770 FY := h;
1772 else
1773 begin
1774 FX := tx;
1775 FY := h;
1776 end;
1777 end;
1778 end;
1780 h += MENU_VSPACE;
1781 if (ControlType = TGUIListBox) or (ControlType = TGUIFileListBox) then
1782 h += (Control as TGUIListBox).GetHeight // FIXME: possible mistyping?..
1783 else if ControlType = TGUIMemo then
1784 h += TGUIMemo(Control).GetHeight
1785 else
1786 h += e_CharFont_GetMaxHeight(FFontID);
1787 end;
1788 end;
1790 // another ugly hack
1791 if FYesNo and (length(FItems) > 1) then
1792 begin
1793 w := -1;
1794 for a := High(FItems)-1 to High(FItems) do
1795 begin
1796 if (FItems[a].Control <> nil) and (FItems[a].ControlType = TGUITextButton) then
1797 begin
1798 cx := TGUITextButton(FItems[a].Control).GetWidth;
1799 if cx > w then w := cx;
1800 end;
1801 end;
1802 if w > 0 then
1803 begin
1804 for a := High(FItems)-1 to High(FItems) do
1805 begin
1806 if (FItems[a].Control <> nil) and (FItems[a].ControlType = TGUITextButton) then
1807 begin
1808 FItems[a].Control.FX := (gScreenWidth-w) div 2;
1809 end;
1810 end;
1811 end;
1812 end;
1813 end;
1815 function TGUIMenu.AddScroll(fText: string): TGUIScroll;
1817 i: Integer;
1818 begin
1819 i := NewItem();
1820 with FItems[i] do
1821 begin
1822 Control := TGUIScroll.Create();
1824 Text := TGUILabel.Create(fText, FFontID);
1825 Text.FColor := MENU_ITEMSTEXT_COLOR;
1827 ControlType := TGUIScroll;
1828 Result := TGUIScroll(Control);
1829 end;
1831 if FIndex = -1 then FIndex := i;
1833 ReAlign();
1834 end;
1836 function TGUIMenu.AddSwitch(fText: string): TGUISwitch;
1838 i: Integer;
1839 begin
1840 i := NewItem();
1841 with FItems[i] do
1842 begin
1843 Control := TGUISwitch.Create(FFontID);
1844 TGUISwitch(Control).FColor := MENU_ITEMSCTRL_COLOR;
1846 Text := TGUILabel.Create(fText, FFontID);
1847 Text.FColor := MENU_ITEMSTEXT_COLOR;
1849 ControlType := TGUISwitch;
1850 Result := TGUISwitch(Control);
1851 end;
1853 if FIndex = -1 then FIndex := i;
1855 ReAlign();
1856 end;
1858 function TGUIMenu.AddEdit(fText: string): TGUIEdit;
1860 i: Integer;
1861 begin
1862 i := NewItem();
1863 with FItems[i] do
1864 begin
1865 Control := TGUIEdit.Create(FFontID);
1866 with TGUIEdit(Control) do
1867 begin
1868 FWindow := Self.FWindow;
1869 FColor := MENU_ITEMSCTRL_COLOR;
1870 end;
1872 if fText = '' then Text := nil else
1873 begin
1874 Text := TGUILabel.Create(fText, FFontID);
1875 Text.FColor := MENU_ITEMSTEXT_COLOR;
1876 end;
1878 ControlType := TGUIEdit;
1879 Result := TGUIEdit(Control);
1880 end;
1882 if FIndex = -1 then FIndex := i;
1884 ReAlign();
1885 end;
1887 procedure TGUIMenu.Update;
1889 a: Integer;
1890 begin
1891 inherited;
1893 if FCounter = 0 then FCounter := MENU_MARKERDELAY else Dec(FCounter);
1895 if FItems <> nil then
1896 for a := 0 to High(FItems) do
1897 if FItems[a].Control <> nil then
1898 (FItems[a].Control as FItems[a].ControlType).Update; // FIXME: improper polymorphism.
1899 end;
1901 function TGUIMenu.AddKeyRead(fText: string): TGUIKeyRead;
1903 i: Integer;
1904 begin
1905 i := NewItem();
1906 with FItems[i] do
1907 begin
1908 Control := TGUIKeyRead.Create(FFontID);
1909 with TGUIKeyRead(Control) do
1910 begin
1911 FWindow := Self.FWindow;
1912 FColor := MENU_ITEMSCTRL_COLOR;
1913 end;
1915 Text := TGUILabel.Create(fText, FFontID);
1916 Text.FColor := MENU_ITEMSTEXT_COLOR;
1918 ControlType := TGUIKeyRead;
1919 Result := TGUIKeyRead(Control);
1920 end;
1922 if FIndex = -1 then FIndex := i;
1924 ReAlign();
1925 end;
1927 function TGUIMenu.AddKeyRead2(fText: string): TGUIKeyRead2;
1929 i: Integer;
1930 begin
1931 i := NewItem();
1932 with FItems[i] do
1933 begin
1934 Control := TGUIKeyRead2.Create(FFontID);
1935 with TGUIKeyRead2(Control) do
1936 begin
1937 FWindow := Self.FWindow;
1938 FColor := MENU_ITEMSCTRL_COLOR;
1939 end;
1941 Text := TGUILabel.Create(fText, FFontID);
1942 with Text do
1943 begin
1944 FColor := MENU_ITEMSCTRL_COLOR; //MENU_ITEMSTEXT_COLOR;
1945 RightAlign := true;
1946 end;
1948 ControlType := TGUIKeyRead2;
1949 Result := TGUIKeyRead2(Control);
1950 end;
1952 if FIndex = -1 then FIndex := i;
1954 ReAlign();
1955 end;
1957 function TGUIMenu.AddList(fText: string; Width, Height: Word): TGUIListBox;
1959 i: Integer;
1960 begin
1961 i := NewItem();
1962 with FItems[i] do
1963 begin
1964 Control := TGUIListBox.Create(FFontID, Width, Height);
1965 with TGUIListBox(Control) do
1966 begin
1967 FWindow := Self.FWindow;
1968 FActiveColor := MENU_ITEMSCTRL_COLOR;
1969 FUnActiveColor := MENU_ITEMSTEXT_COLOR;
1970 end;
1972 Text := TGUILabel.Create(fText, FFontID);
1973 Text.FColor := MENU_ITEMSTEXT_COLOR;
1975 ControlType := TGUIListBox;
1976 Result := TGUIListBox(Control);
1977 end;
1979 if FIndex = -1 then FIndex := i;
1981 ReAlign();
1982 end;
1984 function TGUIMenu.AddFileList(fText: string; Width, Height: Word): TGUIFileListBox;
1986 i: Integer;
1987 begin
1988 i := NewItem();
1989 with FItems[i] do
1990 begin
1991 Control := TGUIFileListBox.Create(FFontID, Width, Height);
1992 with TGUIFileListBox(Control) do
1993 begin
1994 FWindow := Self.FWindow;
1995 FActiveColor := MENU_ITEMSCTRL_COLOR;
1996 FUnActiveColor := MENU_ITEMSTEXT_COLOR;
1997 end;
1999 if fText = '' then Text := nil else
2000 begin
2001 Text := TGUILabel.Create(fText, FFontID);
2002 Text.FColor := MENU_ITEMSTEXT_COLOR;
2003 end;
2005 ControlType := TGUIFileListBox;
2006 Result := TGUIFileListBox(Control);
2007 end;
2009 if FIndex = -1 then FIndex := i;
2011 ReAlign();
2012 end;
2014 function TGUIMenu.AddLabel(fText: string): TGUILabel;
2016 i: Integer;
2017 begin
2018 i := NewItem();
2019 with FItems[i] do
2020 begin
2021 Control := TGUILabel.Create('', FFontID);
2022 with TGUILabel(Control) do
2023 begin
2024 FWindow := Self.FWindow;
2025 FColor := MENU_ITEMSCTRL_COLOR;
2026 end;
2028 Text := TGUILabel.Create(fText, FFontID);
2029 Text.FColor := MENU_ITEMSTEXT_COLOR;
2031 ControlType := TGUILabel;
2032 Result := TGUILabel(Control);
2033 end;
2035 if FIndex = -1 then FIndex := i;
2037 ReAlign();
2038 end;
2040 function TGUIMenu.AddMemo(fText: string; Width, Height: Word): TGUIMemo;
2042 i: Integer;
2043 begin
2044 i := NewItem();
2045 with FItems[i] do
2046 begin
2047 Control := TGUIMemo.Create(FFontID, Width, Height);
2048 with TGUIMemo(Control) do
2049 begin
2050 FWindow := Self.FWindow;
2051 FColor := MENU_ITEMSTEXT_COLOR;
2052 end;
2054 if fText = '' then Text := nil else
2055 begin
2056 Text := TGUILabel.Create(fText, FFontID);
2057 Text.FColor := MENU_ITEMSTEXT_COLOR;
2058 end;
2060 ControlType := TGUIMemo;
2061 Result := TGUIMemo(Control);
2062 end;
2064 if FIndex = -1 then FIndex := i;
2066 ReAlign();
2067 end;
2069 procedure TGUIMenu.UpdateIndex();
2071 res: Boolean;
2072 begin
2073 res := True;
2075 while res do
2076 begin
2077 if (FIndex < 0) or (FIndex > High(FItems)) then
2078 begin
2079 FIndex := -1;
2080 res := False;
2082 else
2083 if FItems[FIndex].Control.Enabled then
2084 res := False
2085 else
2086 Inc(FIndex);
2087 end;
2088 end;
2090 { TGUIScroll }
2092 constructor TGUIScroll.Create;
2093 begin
2094 inherited Create();
2096 FMax := 0;
2097 FOnChangeEvent := nil;
2099 g_Texture_Get(SCROLL_LEFT, FLeftID);
2100 g_Texture_Get(SCROLL_RIGHT, FRightID);
2101 g_Texture_Get(SCROLL_MIDDLE, FMiddleID);
2102 g_Texture_Get(SCROLL_MARKER, FMarkerID);
2103 end;
2105 procedure TGUIScroll.Draw;
2107 a: Integer;
2108 begin
2109 inherited;
2111 e_Draw(FLeftID, FX, FY, 0, True, False);
2112 e_Draw(FRightID, FX+8+(FMax+1)*8, FY, 0, True, False);
2114 for a := 0 to FMax do
2115 e_Draw(FMiddleID, FX+8+a*8, FY, 0, True, False);
2117 e_Draw(FMarkerID, FX+8+FValue*8, FY, 0, True, False);
2118 end;
2120 procedure TGUIScroll.FSetValue(a: Integer);
2121 begin
2122 if a > FMax then FValue := FMax else FValue := a;
2123 end;
2125 function TGUIScroll.GetWidth: Integer;
2126 begin
2127 Result := 16+(FMax+1)*8;
2128 end;
2130 procedure TGUIScroll.OnMessage(var Msg: TMessage);
2131 begin
2132 if not FEnabled then Exit;
2134 inherited;
2136 case Msg.Msg of
2137 WM_KEYDOWN:
2138 begin
2139 case Msg.wParam of
2140 IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
2141 if FValue > 0 then
2142 begin
2143 Dec(FValue);
2144 {$IFDEF ENABLE_SOUND}
2145 g_Sound_PlayEx(SCROLL_SUBSOUND);
2146 {$ENDIF}
2147 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
2148 end;
2149 IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
2150 if FValue < FMax then
2151 begin
2152 Inc(FValue);
2153 {$IFDEF ENABLE_SOUND}
2154 g_Sound_PlayEx(SCROLL_ADDSOUND);
2155 {$ENDIF}
2156 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
2157 end;
2158 end;
2159 end;
2160 end;
2161 end;
2163 { TGUISwitch }
2165 procedure TGUISwitch.AddItem(Item: string);
2166 begin
2167 SetLength(FItems, Length(FItems)+1);
2168 FItems[High(FItems)] := Item;
2170 if FIndex = -1 then FIndex := 0;
2171 end;
2173 constructor TGUISwitch.Create(FontID: DWORD);
2174 begin
2175 inherited Create();
2177 FIndex := -1;
2179 FFont := TFont.Create(FontID, TFontType.Character);
2180 end;
2182 destructor TGUISwitch.Destroy();
2183 begin
2184 FFont.Destroy();
2185 inherited;
2186 end;
2188 procedure TGUISwitch.Draw;
2189 begin
2190 inherited;
2192 FFont.Draw(FX, FY, FItems[FIndex], FColor.R, FColor.G, FColor.B);
2193 end;
2195 function TGUISwitch.GetText: string;
2196 begin
2197 if FIndex <> -1 then Result := FItems[FIndex]
2198 else Result := '';
2199 end;
2201 function TGUISwitch.GetWidth: Integer;
2203 a: Integer;
2204 w, h: Word;
2205 begin
2206 Result := 0;
2208 if FItems = nil then Exit;
2210 for a := 0 to High(FItems) do
2211 begin
2212 FFont.GetTextSize(FItems[a], w, h);
2213 if w > Result then Result := w;
2214 end;
2215 end;
2217 procedure TGUISwitch.OnMessage(var Msg: TMessage);
2218 begin
2219 if not FEnabled then Exit;
2221 inherited;
2223 if FItems = nil then Exit;
2225 case Msg.Msg of
2226 WM_KEYDOWN:
2227 case Msg.wParam of
2228 IK_RETURN, IK_KPRETURN, IK_RIGHT, IK_KPRIGHT, IK_SELECT,
2229 VK_FIRE, VK_OPEN, VK_RIGHT,
2230 JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT,
2231 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
2232 begin
2233 if FIndex < High(FItems) then
2234 Inc(FIndex)
2235 else
2236 FIndex := 0;
2238 {$IFDEF ENABLE_SOUND}
2239 g_Sound_PlayEx(SCROLL_ADDSOUND);
2240 {$ENDIF}
2242 if @FOnChangeEvent <> nil then
2243 FOnChangeEvent(Self);
2244 end;
2246 IK_LEFT, IK_KPLEFT, VK_LEFT,
2247 JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
2248 begin
2249 if FIndex > 0 then
2250 Dec(FIndex)
2251 else
2252 FIndex := High(FItems);
2254 {$IFDEF ENABLE_SOUND}
2255 g_Sound_PlayEx(SCROLL_SUBSOUND);
2256 {$ENDIF}
2258 if @FOnChangeEvent <> nil then
2259 FOnChangeEvent(Self);
2260 end;
2261 end;
2262 end;
2263 end;
2265 { TGUIEdit }
2267 constructor TGUIEdit.Create(FontID: DWORD);
2268 begin
2269 inherited Create();
2271 FFont := TFont.Create(FontID, TFontType.Character);
2273 FMaxLength := 0;
2274 FWidth := 0;
2275 FInvalid := False;
2277 g_Texture_Get(EDIT_LEFT, FLeftID);
2278 g_Texture_Get(EDIT_RIGHT, FRightID);
2279 g_Texture_Get(EDIT_MIDDLE, FMiddleID);
2280 end;
2282 destructor TGUIEdit.Destroy();
2283 begin
2284 FFont.Destroy();
2285 inherited;
2286 end;
2288 procedure TGUIEdit.Draw;
2290 c, w, h: Word;
2291 r, g, b: Byte;
2292 begin
2293 inherited;
2295 e_Draw(FLeftID, FX, FY, 0, True, False);
2296 e_Draw(FRightID, FX+8+FWidth*16, FY, 0, True, False);
2298 for c := 0 to FWidth-1 do
2299 e_Draw(FMiddleID, FX+8+c*16, FY, 0, True, False);
2301 r := FColor.R;
2302 g := FColor.G;
2303 b := FColor.B;
2304 if FInvalid and (FWindow.FActiveControl <> self) then begin r := 128; g := 128; b := 128; end;
2305 FFont.Draw(FX+8, FY, FText, r, g, b);
2307 if (FWindow.FActiveControl = self) then
2308 begin
2309 FFont.GetTextSize(Copy(FText, 1, FCaretPos), w, h);
2310 h := e_CharFont_GetMaxHeight(FFont.ID);
2311 e_DrawLine(2, FX+8+w, FY+h-3, FX+8+w+EDIT_CURSORLEN, FY+h-3,
2312 EDIT_CURSORCOLOR.R, EDIT_CURSORCOLOR.G, EDIT_CURSORCOLOR.B);
2313 end;
2314 end;
2316 function TGUIEdit.GetWidth: Integer;
2317 begin
2318 Result := 16+FWidth*16;
2319 end;
2321 procedure TGUIEdit.OnMessage(var Msg: TMessage);
2322 begin
2323 if not FEnabled then Exit;
2325 inherited;
2327 with Msg do
2328 case Msg of
2329 WM_CHAR:
2330 if FOnlyDigits then
2331 begin
2332 if (wParam in [48..57]) and (Chr(wParam) <> '`') then
2333 if Length(Text) < FMaxLength then
2334 begin
2335 Insert(Chr(wParam), FText, FCaretPos + 1);
2336 Inc(FCaretPos);
2337 end;
2339 else
2340 begin
2341 if (wParam in [32..255]) and (Chr(wParam) <> '`') then
2342 if Length(Text) < FMaxLength then
2343 begin
2344 Insert(Chr(wParam), FText, FCaretPos + 1);
2345 Inc(FCaretPos);
2346 end;
2347 end;
2348 WM_KEYDOWN:
2349 case wParam of
2350 IK_BACKSPACE:
2351 begin
2352 Delete(FText, FCaretPos, 1);
2353 if FCaretPos > 0 then Dec(FCaretPos);
2354 end;
2355 IK_DELETE: Delete(FText, FCaretPos + 1, 1);
2356 IK_END, IK_KPEND: FCaretPos := Length(FText);
2357 IK_HOME, IK_KPHOME: FCaretPos := 0;
2358 IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT: if FCaretPos > 0 then Dec(FCaretPos);
2359 IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT: if FCaretPos < Length(FText) then Inc(FCaretPos);
2360 IK_RETURN, IK_KPRETURN, IK_SELECT,
2361 VK_FIRE, VK_OPEN,
2362 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
2363 with FWindow do
2364 begin
2365 if FActiveControl <> Self then
2366 begin
2367 SetActive(Self);
2368 if @FOnEnterEvent <> nil then FOnEnterEvent(Self);
2370 else
2371 begin
2372 if FDefControl <> '' then SetActive(GetControl(FDefControl))
2373 else SetActive(nil);
2374 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
2375 end;
2376 end;
2377 end;
2378 end;
2380 g_GUIGrabInput := (@FOnEnterEvent = nil) and (FWindow.FActiveControl = Self);
2381 g_Touch_ShowKeyboard(g_GUIGrabInput)
2382 end;
2384 procedure TGUIEdit.SetText(Text: string);
2385 begin
2386 if Length(Text) > FMaxLength then SetLength(Text, FMaxLength);
2387 FText := Text;
2388 FCaretPos := Length(FText);
2389 end;
2391 { TGUIKeyRead }
2393 constructor TGUIKeyRead.Create(FontID: DWORD);
2394 begin
2395 inherited Create();
2396 FKey := 0;
2397 FIsQuery := false;
2399 FFont := TFont.Create(FontID, TFontType.Character);
2400 end;
2402 destructor TGUIKeyRead.Destroy();
2403 begin
2404 FFont.Destroy();
2405 inherited;
2406 end;
2408 procedure TGUIKeyRead.Draw;
2409 begin
2410 inherited;
2412 FFont.Draw(FX, FY, IfThen(FIsQuery, KEYREAD_QUERY, IfThen(FKey <> 0, e_KeyNames[FKey], KEYREAD_CLEAR)),
2413 FColor.R, FColor.G, FColor.B);
2414 end;
2416 function TGUIKeyRead.GetWidth: Integer;
2418 a: Byte;
2419 w, h: Word;
2420 begin
2421 Result := 0;
2423 for a := 0 to 255 do
2424 begin
2425 FFont.GetTextSize(e_KeyNames[a], w, h);
2426 Result := Max(Result, w);
2427 end;
2429 FFont.GetTextSize(KEYREAD_QUERY, w, h);
2430 if w > Result then Result := w;
2432 FFont.GetTextSize(KEYREAD_CLEAR, w, h);
2433 if w > Result then Result := w;
2434 end;
2436 function TGUIKeyRead.WantActivationKey (key: LongInt): Boolean;
2437 begin
2438 result :=
2439 (key = IK_BACKSPACE) or
2440 false; // oops
2441 end;
2443 procedure TGUIKeyRead.OnMessage(var Msg: TMessage);
2444 procedure actDefCtl ();
2445 begin
2446 with FWindow do
2447 if FDefControl <> '' then
2448 SetActive(GetControl(FDefControl))
2449 else
2450 SetActive(nil);
2451 end;
2453 begin
2454 inherited;
2456 if not FEnabled then
2457 Exit;
2459 with Msg do
2460 case Msg of
2461 WM_KEYDOWN:
2462 if not FIsQuery then
2463 begin
2464 case wParam of
2465 IK_RETURN, IK_KPRETURN, IK_SELECT,
2466 VK_FIRE, VK_OPEN,
2467 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
2468 begin
2469 with FWindow do
2470 if FActiveControl <> Self then
2471 SetActive(Self);
2472 FIsQuery := True;
2473 end;
2474 IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
2475 begin
2476 FKey := 0;
2477 actDefCtl();
2478 end;
2479 else
2480 FIsQuery := False;
2481 actDefCtl();
2482 end;
2484 else
2485 begin
2486 case wParam of
2487 VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
2488 begin
2489 FIsQuery := False;
2490 actDefCtl();
2491 end;
2492 else
2493 if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
2494 FKey := wParam;
2495 FIsQuery := False;
2496 actDefCtl();
2498 end;
2499 end;
2501 g_GUIGrabInput := FIsQuery
2502 end;
2504 { TGUIKeyRead2 }
2506 constructor TGUIKeyRead2.Create(FontID: DWORD);
2508 a: Byte;
2509 w, h: Word;
2510 begin
2511 inherited Create();
2513 FKey0 := 0;
2514 FKey1 := 0;
2515 FKeyIdx := 0;
2516 FIsQuery := False;
2518 FFontID := FontID;
2519 FFont := TFont.Create(FontID, TFontType.Character);
2521 FMaxKeyNameWdt := 0;
2522 for a := 0 to 255 do
2523 begin
2524 FFont.GetTextSize(e_KeyNames[a], w, h);
2525 FMaxKeyNameWdt := Max(FMaxKeyNameWdt, w);
2526 end;
2528 FMaxKeyNameWdt := FMaxKeyNameWdt-(FMaxKeyNameWdt div 3);
2530 FFont.GetTextSize(KEYREAD_QUERY, w, h);
2531 if w > FMaxKeyNameWdt then FMaxKeyNameWdt := w;
2533 FFont.GetTextSize(KEYREAD_CLEAR, w, h);
2534 if w > FMaxKeyNameWdt then FMaxKeyNameWdt := w;
2535 end;
2537 destructor TGUIKeyRead2.Destroy();
2538 begin
2539 FFont.Destroy();
2540 inherited;
2541 end;
2543 procedure TGUIKeyRead2.Draw;
2544 procedure drawText (idx: Integer);
2546 x, y: Integer;
2547 r, g, b: Byte;
2548 kk: DWORD;
2549 begin
2550 if idx = 0 then kk := FKey0 else kk := FKey1;
2551 y := FY;
2552 if idx = 0 then x := FX+8 else x := FX+8+FMaxKeyNameWdt+16;
2553 r := 255;
2554 g := 0;
2555 b := 0;
2556 if FKeyIdx = idx then begin r := 255; g := 255; b := 255; end;
2557 if FIsQuery and (FKeyIdx = idx) then
2558 FFont.Draw(x, y, KEYREAD_QUERY, r, g, b)
2559 else
2560 FFont.Draw(x, y, IfThen(kk <> 0, e_KeyNames[kk], KEYREAD_CLEAR), r, g, b);
2561 end;
2563 begin
2564 inherited;
2566 //FFont.Draw(FX+8, FY, IfThen(FIsQuery and (FKeyIdx = 0), KEYREAD_QUERY, IfThen(FKey0 <> 0, e_KeyNames[FKey0], KEYREAD_CLEAR)), FColor.R, FColor.G, FColor.B);
2567 //FFont.Draw(FX+8+FMaxKeyNameWdt+16, FY, IfThen(FIsQuery and (FKeyIdx = 1), KEYREAD_QUERY, IfThen(FKey1 <> 0, e_KeyNames[FKey1], KEYREAD_CLEAR)), FColor.R, FColor.G, FColor.B);
2568 drawText(0);
2569 drawText(1);
2570 end;
2572 function TGUIKeyRead2.GetWidth: Integer;
2573 begin
2574 Result := FMaxKeyNameWdt*2+8+8+16;
2575 end;
2577 function TGUIKeyRead2.WantActivationKey (key: LongInt): Boolean;
2578 begin
2579 case key of
2580 IK_BACKSPACE, IK_LEFT, IK_RIGHT, IK_KPLEFT, IK_KPRIGHT, VK_LEFT, VK_RIGHT,
2581 JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT,
2582 JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
2583 result := True
2584 else
2585 result := False
2587 end;
2589 procedure TGUIKeyRead2.OnMessage(var Msg: TMessage);
2590 procedure actDefCtl ();
2591 begin
2592 with FWindow do
2593 if FDefControl <> '' then
2594 SetActive(GetControl(FDefControl))
2595 else
2596 SetActive(nil);
2597 end;
2599 begin
2600 inherited;
2602 if not FEnabled then
2603 Exit;
2605 with Msg do
2606 case Msg of
2607 WM_KEYDOWN:
2608 if not FIsQuery then
2609 begin
2610 case wParam of
2611 IK_RETURN, IK_KPRETURN, IK_SELECT,
2612 VK_FIRE, VK_OPEN,
2613 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
2614 begin
2615 with FWindow do
2616 if FActiveControl <> Self then
2617 SetActive(Self);
2618 FIsQuery := True;
2619 end;
2620 IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
2621 begin
2622 if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
2623 actDefCtl();
2624 end;
2625 IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
2626 begin
2627 FKeyIdx := 0;
2628 actDefCtl();
2629 end;
2630 IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
2631 begin
2632 FKeyIdx := 1;
2633 actDefCtl();
2634 end;
2635 else
2636 FIsQuery := False;
2637 actDefCtl();
2638 end;
2640 else
2641 begin
2642 case wParam of
2643 VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
2644 begin
2645 FIsQuery := False;
2646 actDefCtl();
2647 end;
2648 else
2649 if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
2650 begin
2651 if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
2652 end;
2653 FIsQuery := False;
2654 actDefCtl()
2656 end;
2657 end;
2659 g_GUIGrabInput := FIsQuery
2660 end;
2663 { TGUIModelView }
2665 constructor TGUIModelView.Create;
2666 begin
2667 inherited Create();
2669 FModel := nil;
2670 end;
2672 destructor TGUIModelView.Destroy;
2673 begin
2674 FModel.Free();
2676 inherited;
2677 end;
2679 procedure TGUIModelView.Draw;
2680 begin
2681 inherited;
2683 DrawBox(FX, FY, 4, 4);
2685 if FModel <> nil then FModel.Draw(FX+4, FY+4);
2686 end;
2688 procedure TGUIModelView.NextAnim();
2689 begin
2690 if FModel = nil then
2691 Exit;
2693 if FModel.Animation < A_PAIN then
2694 FModel.ChangeAnimation(FModel.Animation+1, True)
2695 else
2696 FModel.ChangeAnimation(A_STAND, True);
2697 end;
2699 procedure TGUIModelView.NextWeapon();
2700 begin
2701 if FModel = nil then
2702 Exit;
2704 if FModel.Weapon < WP_LAST
2705 then FModel.SetWeapon(FModel.Weapon+1)
2706 else FModel.SetWeapon(WEAPON_IRONFIST);
2707 end;
2709 procedure TGUIModelView.SetColor(Red, Green, Blue: Byte);
2710 begin
2711 if FModel <> nil then FModel.SetColor(Red, Green, Blue);
2712 end;
2714 procedure TGUIModelView.SetModel(ModelName: string);
2715 begin
2716 FModel.Free();
2718 FModel := g_PlayerModel_Get(ModelName);
2719 end;
2721 procedure TGUIModelView.Update;
2722 begin
2723 inherited;
2725 a := not a;
2726 if a then Exit;
2728 if FModel <> nil then FModel.Update;
2729 end;
2731 { TGUIMapPreview }
2733 constructor TGUIMapPreview.Create();
2734 begin
2735 inherited Create();
2736 ClearMap;
2737 end;
2739 destructor TGUIMapPreview.Destroy();
2740 begin
2741 ClearMap;
2742 inherited;
2743 end;
2745 procedure TGUIMapPreview.Draw();
2747 a: Integer;
2748 r, g, b: Byte;
2749 begin
2750 inherited;
2752 DrawBox(FX, FY, MAPPREVIEW_WIDTH, MAPPREVIEW_HEIGHT);
2754 if (FMapSize.X <= 0) or (FMapSize.Y <= 0) then
2755 Exit;
2757 e_DrawFillQuad(FX+4, FY+4,
2758 FX+4 + Trunc(FMapSize.X / FScale) - 1,
2759 FY+4 + Trunc(FMapSize.Y / FScale) - 1,
2760 32, 32, 32, 0);
2762 if FMapData <> nil then
2763 for a := 0 to High(FMapData) do
2764 with FMapData[a] do
2765 begin
2766 if X1 > MAPPREVIEW_WIDTH*16 then Continue;
2767 if Y1 > MAPPREVIEW_HEIGHT*16 then Continue;
2769 if X2 < 0 then Continue;
2770 if Y2 < 0 then Continue;
2772 if X2 > MAPPREVIEW_WIDTH*16 then X2 := MAPPREVIEW_WIDTH*16;
2773 if Y2 > MAPPREVIEW_HEIGHT*16 then Y2 := MAPPREVIEW_HEIGHT*16;
2775 if X1 < 0 then X1 := 0;
2776 if Y1 < 0 then Y1 := 0;
2778 case PanelType of
2779 PANEL_WALL:
2780 begin
2781 r := 255;
2782 g := 255;
2783 b := 255;
2784 end;
2785 PANEL_CLOSEDOOR:
2786 begin
2787 r := 255;
2788 g := 255;
2789 b := 0;
2790 end;
2791 PANEL_WATER:
2792 begin
2793 r := 0;
2794 g := 0;
2795 b := 192;
2796 end;
2797 PANEL_ACID1:
2798 begin
2799 r := 0;
2800 g := 176;
2801 b := 0;
2802 end;
2803 PANEL_ACID2:
2804 begin
2805 r := 176;
2806 g := 0;
2807 b := 0;
2808 end;
2809 else
2810 begin
2811 r := 128;
2812 g := 128;
2813 b := 128;
2814 end;
2815 end;
2817 if ((X2-X1) > 0) and ((Y2-Y1) > 0) then
2818 e_DrawFillQuad(FX+4 + X1, FY+4 + Y1,
2819 FX+4 + X2 - 1, FY+4 + Y2 - 1, r, g, b, 0);
2820 end;
2821 end;
2823 procedure TGUIMapPreview.SetMap(Res: string);
2825 WAD: TWADFile;
2826 panlist: TDynField;
2827 pan: TDynRecord;
2828 //header: TMapHeaderRec_1;
2829 FileName: string;
2830 Data: Pointer;
2831 Len: Integer;
2832 rX, rY: Single;
2833 map: TDynRecord = nil;
2834 begin
2835 FMapSize.X := 0;
2836 FMapSize.Y := 0;
2837 FScale := 0.0;
2838 FMapData := nil;
2840 FileName := g_ExtractWadName(Res);
2842 WAD := TWADFile.Create();
2843 if not WAD.ReadFile(FileName) then
2844 begin
2845 WAD.Free();
2846 Exit;
2847 end;
2849 //k8: ignores path again
2850 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
2851 begin
2852 WAD.Free();
2853 Exit;
2854 end;
2856 WAD.Free();
2859 map := g_Map_ParseMap(Data, Len);
2860 except
2861 FreeMem(Data);
2862 map.Free();
2863 //raise;
2864 exit;
2865 end;
2867 FreeMem(Data);
2869 if (map = nil) then exit;
2872 panlist := map.field['panel'];
2873 //header := GetMapHeader(map);
2875 FMapSize.X := map.Width div 16;
2876 FMapSize.Y := map.Height div 16;
2878 rX := Ceil(map.Width / (MAPPREVIEW_WIDTH*256.0));
2879 rY := Ceil(map.Height / (MAPPREVIEW_HEIGHT*256.0));
2880 FScale := max(rX, rY);
2882 FMapData := nil;
2884 if (panlist <> nil) then
2885 begin
2886 for pan in panlist do
2887 begin
2888 if (pan.PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or
2889 PANEL_STEP or PANEL_WATER or
2890 PANEL_ACID1 or PANEL_ACID2)) <> 0 then
2891 begin
2892 SetLength(FMapData, Length(FMapData)+1);
2893 with FMapData[High(FMapData)] do
2894 begin
2895 X1 := pan.X div 16;
2896 Y1 := pan.Y div 16;
2898 X2 := (pan.X + pan.Width) div 16;
2899 Y2 := (pan.Y + pan.Height) div 16;
2901 X1 := Trunc(X1/FScale + 0.5);
2902 Y1 := Trunc(Y1/FScale + 0.5);
2903 X2 := Trunc(X2/FScale + 0.5);
2904 Y2 := Trunc(Y2/FScale + 0.5);
2906 if (X1 <> X2) or (Y1 <> Y2) then
2907 begin
2908 if X1 = X2 then
2909 X2 := X2 + 1;
2910 if Y1 = Y2 then
2911 Y2 := Y2 + 1;
2912 end;
2914 PanelType := pan.PanelType;
2915 end;
2916 end;
2917 end;
2918 end;
2919 finally
2920 //writeln('freeing map');
2921 map.Free();
2922 end;
2923 end;
2925 procedure TGUIMapPreview.ClearMap();
2926 begin
2927 SetLength(FMapData, 0);
2928 FMapData := nil;
2929 FMapSize.X := 0;
2930 FMapSize.Y := 0;
2931 FScale := 0.0;
2932 end;
2934 function TGUIMapPreview.GetScaleStr(): String;
2935 begin
2936 if FScale > 0.0 then
2937 begin
2938 Result := FloatToStrF(FScale*16.0, ffFixed, 3, 3);
2939 while (Result[Length(Result)] = '0') do
2940 Delete(Result, Length(Result), 1);
2941 if (Result[Length(Result)] = ',') or (Result[Length(Result)] = '.') then
2942 Delete(Result, Length(Result), 1);
2943 Result := '1 : ' + Result;
2945 else
2946 Result := '';
2947 end;
2949 { TGUIListBox }
2951 procedure TGUIListBox.AddItem(Item: string);
2952 begin
2953 SetLength(FItems, Length(FItems)+1);
2954 FItems[High(FItems)] := Item;
2956 if FSort then
2957 specialize TArrayHelper<ShortString>.Sort(FItems,
2958 specialize TComparer<ShortString>.Construct(@ShortCompareText));
2959 end;
2961 function TGUIListBox.ItemExists (item: String): Boolean;
2962 var i: Integer;
2963 begin
2964 i := 0;
2965 while (i <= High(FItems)) and (FItems[i] <> item) do Inc(i);
2966 result := i <= High(FItems)
2967 end;
2969 procedure TGUIListBox.Clear;
2970 begin
2971 FItems := nil;
2973 FStartLine := 0;
2974 FIndex := -1;
2975 end;
2977 constructor TGUIListBox.Create(FontID: DWORD; Width, Height: Word);
2978 begin
2979 inherited Create();
2981 FFont := TFont.Create(FontID, TFontType.Character);
2983 FWidth := Width;
2984 FHeight := Height;
2985 FIndex := -1;
2986 FOnChangeEvent := nil;
2987 FDrawBack := True;
2988 FDrawScroll := True;
2989 end;
2991 destructor TGUIListBox.Destroy();
2992 begin
2993 FFont.Destroy();
2994 inherited;
2995 end;
2997 procedure TGUIListBox.Draw;
2999 w2, h2: Word;
3000 a: Integer;
3001 s: string;
3002 begin
3003 inherited;
3005 if FDrawBack then DrawBox(FX, FY, FWidth+1, FHeight);
3006 if FDrawScroll then
3007 DrawScroll(FX+4+FWidth*16, FY+4, FHeight, (FStartLine > 0) and (FItems <> nil),
3008 (FStartLine+FHeight-1 < High(FItems)) and (FItems <> nil));
3010 if FItems <> nil then
3011 for a := FStartLine to Min(High(FItems), FStartLine+FHeight-1) do
3012 begin
3013 s := Items[a];
3015 FFont.GetTextSize(s, w2, h2);
3016 while (Length(s) > 0) and (w2 > FWidth*16) do
3017 begin
3018 SetLength(s, Length(s)-1);
3019 FFont.GetTextSize(s, w2, h2);
3020 end;
3022 if a = FIndex then
3023 FFont.Draw(FX+4, FY+4+(a-FStartLine)*16, s, FActiveColor.R, FActiveColor.G, FActiveColor.B)
3024 else
3025 FFont.Draw(FX+4, FY+4+(a-FStartLine)*16, s, FUnActiveColor.R, FUnActiveColor.G, FUnActiveColor.B);
3026 end;
3027 end;
3029 function TGUIListBox.GetHeight: Integer;
3030 begin
3031 Result := 8+FHeight*16;
3032 end;
3034 function TGUIListBox.GetWidth: Integer;
3035 begin
3036 Result := 8+(FWidth+1)*16;
3037 end;
3039 procedure TGUIListBox.OnMessage(var Msg: TMessage);
3041 a: Integer;
3042 begin
3043 if not FEnabled then Exit;
3045 inherited;
3047 if FItems = nil then Exit;
3049 with Msg do
3050 case Msg of
3051 WM_KEYDOWN:
3052 case wParam of
3053 IK_HOME, IK_KPHOME:
3054 begin
3055 FIndex := 0;
3056 FStartLine := 0;
3057 end;
3058 IK_END, IK_KPEND:
3059 begin
3060 FIndex := High(FItems);
3061 FStartLine := Max(High(FItems)-FHeight+1, 0);
3062 end;
3063 IK_UP, IK_LEFT, IK_KPUP, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
3064 if FIndex > 0 then
3065 begin
3066 Dec(FIndex);
3067 if FIndex < FStartLine then Dec(FStartLine);
3068 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
3069 end;
3070 IK_DOWN, IK_RIGHT, IK_KPDOWN, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
3071 if FIndex < High(FItems) then
3072 begin
3073 Inc(FIndex);
3074 if FIndex > FStartLine+FHeight-1 then Inc(FStartLine);
3075 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
3076 end;
3077 IK_RETURN, IK_KPRETURN, IK_SELECT,
3078 VK_FIRE, VK_OPEN,
3079 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
3080 with FWindow do
3081 begin
3082 if FActiveControl <> Self then SetActive(Self)
3083 else
3084 if FDefControl <> '' then SetActive(GetControl(FDefControl))
3085 else SetActive(nil);
3086 end;
3087 end;
3088 WM_CHAR:
3089 for a := 0 to High(FItems) do
3090 if (Length(FItems[a]) > 0) and (LowerCase(FItems[a][1]) = LowerCase(Chr(wParam))) then
3091 begin
3092 FIndex := a;
3093 FStartLine := Min(Max(FIndex-1, 0), Length(FItems)-FHeight);
3094 if @FOnChangeEvent <> nil then FOnChangeEvent(Self);
3095 Break;
3096 end;
3097 end;
3098 end;
3100 function TGUIListBox.SelectedItem(): String;
3101 begin
3102 Result := '';
3104 if (FIndex < 0) or (FItems = nil) or
3105 (FIndex > High(FItems)) then
3106 Exit;
3108 Result := FItems[FIndex];
3109 end;
3111 procedure TGUIListBox.FSetItems(Items: SSArray);
3112 begin
3113 if FItems <> nil then
3114 FItems := nil;
3116 FItems := Items;
3118 FStartLine := 0;
3119 FIndex := -1;
3121 if FSort then
3122 specialize TArrayHelper<ShortString>.Sort(FItems,
3123 specialize TComparer<ShortString>.Construct(@ShortCompareText));
3124 end;
3126 procedure TGUIListBox.SelectItem(Item: String);
3128 a: Integer;
3129 begin
3130 if FItems = nil then
3131 Exit;
3133 FIndex := 0;
3134 Item := LowerCase(Item);
3136 for a := 0 to High(FItems) do
3137 if LowerCase(FItems[a]) = Item then
3138 begin
3139 FIndex := a;
3140 Break;
3141 end;
3143 if FIndex < FHeight then
3144 FStartLine := 0
3145 else
3146 FStartLine := Min(FIndex, Length(FItems)-FHeight);
3147 end;
3149 procedure TGUIListBox.FSetIndex(aIndex: Integer);
3150 begin
3151 if FItems = nil then
3152 Exit;
3154 if (aIndex < 0) or (aIndex > High(FItems)) then
3155 Exit;
3157 FIndex := aIndex;
3159 if FIndex <= FHeight then
3160 FStartLine := 0
3161 else
3162 FStartLine := Min(FIndex, Length(FItems)-FHeight);
3163 end;
3165 { TGUIFileListBox }
3167 procedure TGUIFileListBox.OnMessage(var Msg: TMessage);
3169 a, b: Integer; s: AnsiString;
3170 begin
3171 if not FEnabled then
3172 Exit;
3174 if FItems = nil then
3175 Exit;
3177 with Msg do
3178 case Msg of
3179 WM_KEYDOWN:
3180 case wParam of
3181 IK_HOME, IK_KPHOME:
3182 begin
3183 FIndex := 0;
3184 FStartLine := 0;
3185 if @FOnChangeEvent <> nil then
3186 FOnChangeEvent(Self);
3187 end;
3189 IK_END, IK_KPEND:
3190 begin
3191 FIndex := High(FItems);
3192 FStartLine := Max(High(FItems)-FHeight+1, 0);
3193 if @FOnChangeEvent <> nil then
3194 FOnChangeEvent(Self);
3195 end;
3197 IK_PAGEUP, IK_KPPAGEUP:
3198 begin
3199 if FIndex > FHeight
3200 then FIndex -= FHeight
3201 else FIndex := 0;
3203 if FStartLine > FHeight
3204 then FStartLine -= FHeight
3205 else FStartLine := 0;
3206 end;
3208 IK_PAGEDN, IK_KPPAGEDN:
3209 begin
3210 if FIndex < High(FItems)-FHeight
3211 then FIndex += FHeight
3212 else FIndex := High(FItems);
3214 if FStartLine < High(FItems)-FHeight
3215 then FStartLine += FHeight
3216 else FStartLine := High(FItems)-FHeight+1;
3217 end;
3219 IK_UP, IK_LEFT, IK_KPUP, IK_KPLEFT, VK_UP, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
3220 if FIndex > 0 then
3221 begin
3222 FIndex -= 1;
3223 if FIndex < FStartLine then
3224 FStartLine -= 1;
3225 if @FOnChangeEvent <> nil then
3226 FOnChangeEvent(Self);
3227 end;
3229 IK_DOWN, IK_RIGHT, IK_KPDOWN, IK_KPRIGHT, VK_DOWN, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
3230 if FIndex < High(FItems) then
3231 begin
3232 FIndex += 1;
3233 if FIndex > FStartLine+FHeight-1 then
3234 FStartLine += 1;
3235 if @FOnChangeEvent <> nil then
3236 FOnChangeEvent(Self);
3237 end;
3239 IK_RETURN, IK_KPRETURN, IK_SELECT,
3240 VK_FIRE, VK_OPEN,
3241 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
3242 with FWindow do
3243 begin
3244 if FActiveControl <> Self then
3245 SetActive(Self)
3246 else
3247 begin
3248 if FItems[FIndex][1] = #29 then // Ïàïêà
3249 begin
3250 if FItems[FIndex] = #29 + '..' then
3251 begin
3252 //e_LogWritefln('TGUIFileListBox: Upper dir "%s" -> "%s"', [FSubPath, e_UpperDir(FSubPath)]);
3253 FSubPath := e_UpperDir(FSubPath)
3255 else
3256 begin
3257 s := Copy(AnsiString(FItems[FIndex]), 2);
3258 //e_LogWritefln('TGUIFileListBox: Enter dir "%s" -> "%s"', [FSubPath, e_CatPath(FSubPath, s)]);
3260 // FIXME: hack for improper ConcatPaths(); see commit.
3261 if FSubPath = ''
3262 then FSubPath := s
3263 else FSubPath := ConcatPaths([FSubPath, s]);
3264 end;
3265 ScanDirs();
3266 FIndex := 0;
3267 Exit;
3268 end;
3270 if FDefControl <> ''
3271 then SetActive(GetControl(FDefControl))
3272 else SetActive(nil);
3273 end;
3274 end;
3275 end;
3277 WM_CHAR:
3278 for b := FIndex + 1 to High(FItems) + FIndex do
3279 begin
3280 a := b mod Length(FItems);
3281 if ( (Length(FItems[a]) > 0) and
3282 (LowerCase(FItems[a][1]) = LowerCase(Chr(wParam))) ) or
3283 ( (Length(FItems[a]) > 1) and
3284 (FItems[a][1] = #29) and // Ïàïêà
3285 (LowerCase(FItems[a][2]) = LowerCase(Chr(wParam))) ) then
3286 begin
3287 FIndex := a;
3288 FStartLine := Min(Max(FIndex-1, 0), Length(FItems)-FHeight);
3289 if @FOnChangeEvent <> nil then
3290 FOnChangeEvent(Self);
3291 Break;
3292 end;
3293 end;
3294 end;
3295 end;
3297 procedure TGUIFileListBox.ScanDirs();
3299 i, j: Integer;
3300 path: AnsiString;
3301 SR: TSearchRec;
3302 sm, sc: String;
3303 begin
3304 Clear();
3306 i := High(FBaseList);
3307 while i >= 0 do
3308 begin
3309 // FIXME: hack for improper ConcatPaths(); see commit.
3310 path := AnsiString(FBaseList[i]);
3311 if path = ''
3312 then path := FSubPath
3313 else path := ConcatPaths([path, FSubPath]);
3315 if FDirs then
3316 begin
3317 if FindFirst(path + '/' + '*', faDirectory, SR) = 0 then
3318 repeat
3319 if LongBool(SR.Attr and faDirectory) then
3320 if (SR.Name <> '.') and ((FSubPath <> '') or (SR.Name <> '..')) then
3321 if not Self.ItemExists(#1 + SR.Name) then
3322 Self.AddItem(#1 + SR.Name);
3323 until FindNext(SR) <> 0;
3324 FindClose(SR);
3325 end;
3326 i -= 1;
3327 end;
3329 i := High(FBaseList);
3330 while i >= 0 do
3331 begin
3332 // FIXME: hack for improper ConcatPaths(); see commit.
3333 path := AnsiString(FBaseList[i]);
3334 if path = ''
3335 then path := FSubPath
3336 else path := ConcatPaths([path, FSubPath]);
3338 sm := FFileMask;
3339 while sm <> '' do
3340 begin
3341 j := Pos('|', sm);
3342 if j = 0 then
3343 j := Length(sm) + 1;
3344 sc := Copy(sm, 1, j - 1);
3345 Delete(sm, 1, j);
3346 if FindFirst(path + '/' + sc, faAnyFile, SR) = 0 then
3347 repeat
3348 if not Self.ItemExists(SR.Name) then
3349 AddItem(SR.Name);
3350 until FindNext(SR) <> 0;
3351 FindClose(SR);
3352 end;
3353 i -= 1;
3354 end;
3356 for i := 0 to High(FItems) do
3357 if FItems[i][1] = #1 then
3358 FItems[i][1] := #29;
3359 end;
3361 procedure TGUIFileListBox.SetBase (dirs: SSArray; path: String);
3362 begin
3363 FBaseList := dirs;
3364 FSubPath := path;
3365 ScanDirs();
3366 end;
3368 function TGUIFileListBox.SelectedItem (): String;
3370 s: AnsiString;
3371 begin
3372 Result := '';
3373 if (FIndex >= 0) and (FIndex <= High(FItems)) and (FItems[FIndex][1] <> '/') and (FItems[FIndex][1] <> '\') then
3374 begin
3375 // FIXME: hack for improper ConcatPaths(); see commit.
3376 if FSubPath = ''
3377 then s := FItems[FIndex]
3378 else s := ConcatPaths([FSubPath, FItems[FIndex]]);
3380 if e_FindResource(FBaseList, s) then
3381 Result := ExpandFileName(s)
3382 end;
3383 e_LogWritefln('TGUIFileListBox.SelectedItem -> "%s"', [Result]);
3384 end;
3386 procedure TGUIFileListBox.UpdateFileList();
3388 fn: String;
3389 begin
3390 if (FIndex = -1) or (FItems = nil) or
3391 (FIndex > High(FItems)) or
3392 (FItems[FIndex][1] = '/') or
3393 (FItems[FIndex][1] = '\') then
3394 fn := ''
3395 else
3396 fn := FItems[FIndex];
3398 // OpenDir(FPath);
3399 ScanDirs();
3401 if fn <> '' then
3402 SelectItem(fn);
3403 end;
3405 { TGUIMemo }
3407 procedure TGUIMemo.Clear;
3408 begin
3409 FLines := nil;
3410 FStartLine := 0;
3411 end;
3413 constructor TGUIMemo.Create(FontID: DWORD; Width, Height: Word);
3414 begin
3415 inherited Create();
3417 FFont := TFont.Create(FontID, TFontType.Character);
3419 FWidth := Width;
3420 FHeight := Height;
3421 FDrawBack := True;
3422 FDrawScroll := True;
3423 end;
3425 destructor TGUIMemo.Destroy();
3426 begin
3427 FFont.Destroy();
3428 inherited;
3429 end;
3431 procedure TGUIMemo.Draw;
3433 a: Integer;
3434 begin
3435 inherited;
3437 if FDrawBack then DrawBox(FX, FY, FWidth+1, FHeight);
3438 if FDrawScroll then
3439 DrawScroll(FX+4+FWidth*16, FY+4, FHeight, (FStartLine > 0) and (FLines <> nil),
3440 (FStartLine+FHeight-1 < High(FLines)) and (FLines <> nil));
3442 if FLines <> nil then
3443 for a := FStartLine to Min(High(FLines), FStartLine+FHeight-1) do
3444 FFont.Draw(FX+4, FY+4+(a-FStartLine)*16, FLines[a], FColor.R, FColor.G, FColor.B);
3445 end;
3447 function TGUIMemo.GetHeight: Integer;
3448 begin
3449 Result := 8+FHeight*16;
3450 end;
3452 function TGUIMemo.GetWidth: Integer;
3453 begin
3454 Result := 8+(FWidth+1)*16;
3455 end;
3457 procedure TGUIMemo.OnMessage(var Msg: TMessage);
3458 begin
3459 if not FEnabled then Exit;
3461 inherited;
3463 if FLines = nil then Exit;
3465 with Msg do
3466 case Msg of
3467 WM_KEYDOWN:
3468 case wParam of
3469 IK_UP, IK_LEFT, IK_KPUP, IK_KPLEFT, VK_UP, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
3470 if FStartLine > 0 then
3471 Dec(FStartLine);
3472 IK_DOWN, IK_RIGHT, IK_KPDOWN, IK_KPRIGHT, VK_DOWN, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
3473 if FStartLine < Length(FLines)-FHeight then
3474 Inc(FStartLine);
3475 IK_RETURN, IK_KPRETURN, IK_SELECT,
3476 VK_FIRE, VK_OPEN,
3477 JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
3478 with FWindow do
3479 begin
3480 if FActiveControl <> Self then
3481 begin
3482 SetActive(Self);
3483 {FStartLine := 0;}
3485 else
3486 if FDefControl <> '' then SetActive(GetControl(FDefControl))
3487 else SetActive(nil);
3488 end;
3489 end;
3490 end;
3491 end;
3493 procedure TGUIMemo.SetText(Text: string);
3494 begin
3495 FStartLine := 0;
3496 FLines := GetLines(Text, FFont.ID, FWidth*16);
3497 end;
3499 { TGUIimage }
3501 procedure TGUIimage.ClearImage();
3502 begin
3503 if FImageRes = '' then Exit;
3505 g_Texture_Delete(FImageRes);
3506 FImageRes := '';
3507 end;
3509 constructor TGUIimage.Create();
3510 begin
3511 inherited Create();
3513 FImageRes := '';
3514 end;
3516 procedure TGUIimage.Draw();
3518 ID: DWORD;
3519 Res: String;
3520 begin
3521 inherited;
3523 if FImageRes = ''
3524 then Res := FDefaultRes
3525 else Res := FImageRes;
3527 if g_Texture_Get(Res, ID) then
3528 e_Draw(ID, FX, FY, 0, True, False);
3529 end;
3531 procedure TGUIimage.SetImage(Res: string);
3532 begin
3533 ClearImage();
3535 if g_Texture_CreateWADEx(Res, Res) then FImageRes := Res;
3536 end;
3538 end.