diff --git a/src/game/g_gui.pas b/src/game/g_gui.pas
index a97ddeb77a720382a5da623077aca7e1a5a99ab9..325646980cdf833a5e4a52d613ebaeab7a22a40a 100644 (file)
--- a/src/game/g_gui.pas
+++ b/src/game/g_gui.pas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
uses
{$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
uses
{$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
- e_graphics, e_input, e_log, g_playermodel, g_basic, g_touch, MAPDEF, utils;
+ g_base, r_graphics, e_input, e_log, g_playermodel, g_basic, g_touch, MAPDEF, utils;
const
MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
const
MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255);
procedure OnMessage(var Msg: TMessage); override;
procedure Draw(); override;
procedure AddItem(Item: String);
procedure OnMessage(var Msg: TMessage); override;
procedure Draw(); override;
procedure AddItem(Item: String);
+ function ItemExists (item: String): Boolean;
procedure SelectItem(Item: String);
procedure Clear();
function GetWidth(): Integer; override;
procedure SelectItem(Item: String);
procedure Clear();
function GetWidth(): Integer; override;
TGUIFileListBox = class(TGUIListBox)
private
TGUIFileListBox = class(TGUIListBox)
private
- FBasePath: String;
- FPath: String;
+ FSubPath: String;
FFileMask: String;
FDirs: Boolean;
FFileMask: String;
FDirs: Boolean;
+ FBaseList: SSArray; // highter index have highter priority
- procedure OpenDir(path: String);
+ procedure ScanDirs;
public
public
- procedure OnMessage(var Msg: TMessage); override;
- procedure SetBase(path: String);
+ procedure OnMessage (var Msg: TMessage); override;
+ procedure SetBase (dirs: SSArray; path: String = '');
function SelectedItem(): String;
function SelectedItem(): String;
- procedure UpdateFileList();
+ procedure UpdateFileList;
property Dirs: Boolean read FDirs write FDirs;
property FileMask: String read FFileMask write FFileMask;
property Dirs: Boolean read FDirs write FDirs;
property FileMask: String read FFileMask write FFileMask;
- property Path: String read FPath;
end;
TGUIMemo = class(TGUIControl)
end;
TGUIMemo = class(TGUIControl)
implementation
uses
implementation
uses
- {$INCLUDE ../nogl/noGLuses.inc}
- g_textures, g_sound, SysUtils,
- g_game, Math, StrUtils, g_player, g_options,
+ g_textures, g_sound, SysUtils, e_res,
+ g_game, Math, StrUtils, g_player, g_options, g_console, r_playermodel,
g_map, g_weapons, xdynrec, wadreader;
g_map, g_weapons, xdynrec, wadreader;
Box: Array [0..8] of DWORD;
Saved_Windows: SSArray;
Box: Array [0..8] of DWORD;
Saved_Windows: SSArray;
+function GetLines (text: string; FontID: DWORD; MaxWidth: Word): SSArray;
+ var
+ k: Integer = 1;
+ lines: Integer = 0;
+ i, len, lastsep: Integer;
+
+ function PrepareStep (): Boolean; inline;
+ begin
+ // Skip leading spaces.
+ while PChar(text)[k-1] = ' ' do k += 1;
+ Result := k <= len;
+ i := k;
+ end;
+
+ function GetLine (j: Integer; Strip: Boolean): String; inline;
+ begin
+ // Exclude trailing spaces from the line.
+ if Strip then
+ while text[j] = ' ' do j -= 1;
+
+ Result := Copy(text, k, j-k+1);
+ end;
+
+ function LineWidth (): Integer; inline;
+ var w, h: Word;
+ begin
+ e_CharFont_GetSize(FontID, GetLine(i, False), w, h);
+ Result := w;
+ end;
+
+begin
+ Result := nil;
+ len := Length(text);
+ //e_LogWritefln('GetLines @%s len=%s [%s]', [MaxWidth, len, text]);
+
+ while PrepareStep() do
+ begin
+ // Get longest possible sequence (this is not constant because fonts are not monospaced).
+ lastsep := 0;
+ repeat
+ if text[i] in [' ', '.', ',', ':', ';']
+ then lastsep := i;
+ i += 1;
+ until (i > len) or (LineWidth() > MaxWidth);
+
+ // Do not include part of a word if possible.
+ if (lastsep-k > 3) and (i <= len) and (text[i] <> ' ')
+ then i := lastsep + 1;
+
+ // Add line.
+ SetLength(Result, lines + 1);
+ Result[lines] := GetLine(i-1, True);
+ //e_LogWritefln(' -> (%s:%s::%s) [%s]', [k, i, LineWidth(), Result[lines]]);
+ lines += 1;
+
+ k := i;
+ end;
+end;
+
+procedure Sort(var a: SSArray);
+var
+ i, j: Integer;
+ s: string;
+begin
+ if a = nil then Exit;
+
+ for i := High(a) downto Low(a) do
+ for j := Low(a) to High(a)-1 do
+ if LowerCase(a[j]) > LowerCase(a[j+1]) then
+ begin
+ s := a[j];
+ a[j] := a[j+1];
+ a[j+1] := s;
+ end;
+end;
procedure g_GUI_Init();
begin
procedure g_GUI_Init();
begin
if FBackTexture <> '' then // Here goes code duplication from g_game.pas:DrawMenuBackground()
if g_Texture_Get(FBackTexture, ID) then
begin
if FBackTexture <> '' then // Here goes code duplication from g_game.pas:DrawMenuBackground()
if g_Texture_Get(FBackTexture, ID) then
begin
- e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
+ e_Clear(0, 0, 0);
e_GetTextureSize(ID, @tw, @th);
if tw = th then
tw := round(tw * 1.333 * (gScreenHeight / th))
e_GetTextureSize(ID, @tw, @th);
if tw = th then
tw := round(tw * 1.333 * (gScreenHeight / th))
e_DrawSize(ID, (gScreenWidth - tw) div 2, 0, 0, False, False, tw, gScreenHeight);
end
else
e_DrawSize(ID, (gScreenWidth - tw) div 2, 0, 0, False, False, tw, gScreenHeight);
end
else
- e_Clear(GL_COLOR_BUFFER_BIT, 0.5, 0.5, 0.5);
+ e_Clear(0.5, 0.5, 0.5);
// small hack here
if FName = 'AuthorsMenu' then
// small hack here
if FName = 'AuthorsMenu' then
function TGUIMainMenu.AddButton(fProc: Pointer; Caption: string; ShowWindow: string = ''): TGUITextButton;
var
a, _x: Integer;
function TGUIMainMenu.AddButton(fProc: Pointer; Caption: string; ShowWindow: string = ''): TGUITextButton;
var
a, _x: Integer;
- h, hh, lh: Word;
+ h, hh: Word;
+ lh: Word = 0;
begin
FIndex := 0;
begin
FIndex := 0;
else
FIndex := 0;
else
FIndex := 0;
+ g_Sound_PlayEx(SCROLL_ADDSOUND);
+
if @FOnChangeEvent <> nil then
FOnChangeEvent(Self);
end;
if @FOnChangeEvent <> nil then
FOnChangeEvent(Self);
end;
- IK_LEFT, IK_KPLEFT, VK_LEFT,
- JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
- begin
- if FIndex > 0 then
- Dec(FIndex)
- else
- FIndex := High(FItems);
+ IK_LEFT, IK_KPLEFT, VK_LEFT,
+ JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
+ begin
+ if FIndex > 0 then
+ Dec(FIndex)
+ else
+ FIndex := High(FItems);
- if @FOnChangeEvent <> nil then
- FOnChangeEvent(Self);
- end;
+ g_Sound_PlayEx(SCROLL_SUBSOUND);
+
+ if @FOnChangeEvent <> nil then
+ FOnChangeEvent(Self);
+ end;
end;
end;
end;
end;
end;
end;
with Msg do
case Msg of
WM_KEYDOWN:
with Msg do
case Msg of
WM_KEYDOWN:
- case wParam of
- VK_ESCAPE:
- begin
- if FIsQuery then actDefCtl();
- FIsQuery := False;
- end;
- IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
- begin
- if not FIsQuery then
- begin
- with FWindow do
- if FActiveControl <> Self then
- SetActive(Self);
-
- FIsQuery := True;
- end
- else if (wParam < VK_FIRSTKEY) and (wParam > VK_LASTKEY) then
- begin
- // FKey := IK_ENTER; // <Enter>
- FKey := wParam;
- FIsQuery := False;
- actDefCtl();
- end;
- end;
- IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
- begin
- if not FIsQuery then
+ if not FIsQuery then
+ begin
+ case wParam of
+ IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
+ begin
+ with FWindow do
+ if FActiveControl <> Self then
+ SetActive(Self);
+ FIsQuery := True;
+ end;
+ IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
begin
FKey := 0;
actDefCtl();
end;
begin
FKey := 0;
actDefCtl();
end;
- end;
- end;
-
- MESSAGE_DIKEY:
+ else
+ FIsQuery := False;
+ actDefCtl();
+ end;
+ end
+ else
begin
begin
- if not FIsQuery and (wParam = IK_BACKSPACE) then
- begin
- FKey := 0;
+ case wParam of
+ VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
+ begin
+ FIsQuery := False;
+ actDefCtl();
+ end;
+ else
+ if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
+ FKey := wParam;
+ FIsQuery := False;
actDefCtl();
end
actDefCtl();
end
- else if FIsQuery then
- begin
- case wParam of
- IK_ENTER, IK_KPRETURN, VK_FIRSTKEY..VK_LASTKEY, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK: // Not <Enter
- else
- if e_KeyNames[wParam] <> '' then
- FKey := wParam;
- FIsQuery := False;
- actDefCtl();
- end
- end;
end;
end;
end;
end;
with Msg do
case Msg of
WM_KEYDOWN:
with Msg do
case Msg of
WM_KEYDOWN:
- case wParam of
- VK_ESCAPE:
- begin
- if FIsQuery then actDefCtl();
- FIsQuery := False;
- end;
- IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
- begin
- if not FIsQuery then
- begin
- with FWindow do
- if FActiveControl <> Self then
- SetActive(Self);
-
- FIsQuery := True;
- end
- else if (wParam < VK_FIRSTKEY) and (wParam > VK_LASTKEY) then
- begin
- // if (FKeyIdx = 0) then FKey0 := IK_ENTER else FKey1 := IK_ENTER; // <Enter>
- if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
- FIsQuery := False;
- actDefCtl();
- end;
- end;
- IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
- begin
- if not FIsQuery then
+ if not FIsQuery then
+ begin
+ case wParam of
+ IK_RETURN, IK_KPRETURN, VK_FIRE, VK_OPEN, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK:
+ begin
+ with FWindow do
+ if FActiveControl <> Self then
+ SetActive(Self);
+ FIsQuery := True;
+ end;
+ IK_BACKSPACE: // clear keybinding if we aren't waiting for a key
begin
if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
actDefCtl();
end;
begin
if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
actDefCtl();
end;
- end;
- IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
- if not FIsQuery then
- begin
- FKeyIdx := 0;
- actDefCtl();
- end;
- IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
- if not FIsQuery then
- begin
- FKeyIdx := 1;
- actDefCtl();
- end;
- end;
-
- MESSAGE_DIKEY:
- begin
- if not FIsQuery and (wParam = IK_BACKSPACE) then
- begin
- if (FKeyIdx = 0) then FKey0 := 0 else FKey1 := 0;
- actDefCtl();
- end
- else if FIsQuery then
- begin
- case wParam of
- IK_ENTER, IK_KPRETURN, VK_FIRSTKEY..VK_LASTKEY, JOY0_ATTACK, JOY1_ATTACK, JOY2_ATTACK, JOY3_ATTACK: // Not <Enter
- else
- if e_KeyNames[wParam] <> '' then
+ IK_LEFT, IK_KPLEFT, VK_LEFT, JOY0_LEFT, JOY1_LEFT, JOY2_LEFT, JOY3_LEFT:
begin
begin
- if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
+ FKeyIdx := 0;
+ actDefCtl();
end;
end;
- FIsQuery := False;
- actDefCtl()
- end
+ IK_RIGHT, IK_KPRIGHT, VK_RIGHT, JOY0_RIGHT, JOY1_RIGHT, JOY2_RIGHT, JOY3_RIGHT:
+ begin
+ FKeyIdx := 1;
+ actDefCtl();
+ end;
+ else
+ FIsQuery := False;
+ actDefCtl();
end;
end;
+ end
+ else
+ begin
+ case wParam of
+ VK_FIRSTKEY..VK_LASTKEY: // do not allow to bind virtual keys
+ begin
+ FIsQuery := False;
+ actDefCtl();
+ end;
+ else
+ if (e_KeyNames[wParam] <> '') and not g_Console_MatchBind(wParam, 'togglemenu') then
+ begin
+ if (FKeyIdx = 0) then FKey0 := wParam else FKey1 := wParam;
+ end;
+ FIsQuery := False;
+ actDefCtl()
+ end
end;
end;
end;
end;
DrawBox(FX, FY, 4, 4);
DrawBox(FX, FY, 4, 4);
- if FModel <> nil then FModel.Draw(FX+4, FY+4);
+ if FModel <> nil then
+ r_PlayerModel_Draw(FModel, FX+4, FY+4);
end;
procedure TGUIModelView.NextAnim();
end;
procedure TGUIModelView.NextAnim();
SetLength(FItems, Length(FItems)+1);
FItems[High(FItems)] := Item;
SetLength(FItems, Length(FItems)+1);
FItems[High(FItems)] := Item;
- if FSort then g_Basic.Sort(FItems);
+ if FSort then g_gui.Sort(FItems);
+end;
+
+function TGUIListBox.ItemExists (item: String): Boolean;
+ var i: Integer;
+begin
+ i := 0;
+ while (i <= High(FItems)) and (FItems[i] <> item) do Inc(i);
+ result := i <= High(FItems)
end;
end;
-procedure TGUIListBox.Clear();
+procedure TGUIListBox.Clear;
begin
FItems := nil;
begin
FItems := nil;
FStartLine := 0;
FIndex := -1;
FStartLine := 0;
FIndex := -1;
- if FSort then g_Basic.Sort(FItems);
+ if FSort then g_gui.Sort(FItems);
end;
procedure TGUIListBox.SelectItem(Item: String);
end;
procedure TGUIListBox.SelectItem(Item: String);
procedure TGUIFileListBox.OnMessage(var Msg: TMessage);
var
procedure TGUIFileListBox.OnMessage(var Msg: TMessage);
var
- a, b: Integer;
+ a, b: Integer; s: AnsiString;
begin
if not FEnabled then
Exit;
begin
if not FEnabled then
Exit;
begin
if FItems[FIndex][1] = #29 then // Ïàïêà
begin
begin
if FItems[FIndex][1] = #29 then // Ïàïêà
begin
- OpenDir(FPath+Copy(FItems[FIndex], 2, 255));
+ if FItems[FIndex] = #29 + '..' then
+ begin
+ //e_LogWritefln('TGUIFileListBox: Upper dir "%s" -> "%s"', [FSubPath, e_UpperDir(FSubPath)]);
+ FSubPath := e_UpperDir(FSubPath)
+ end
+ else
+ begin
+ s := Copy(AnsiString(FItems[FIndex]), 2);
+ //e_LogWritefln('TGUIFileListBox: Enter dir "%s" -> "%s"', [FSubPath, e_CatPath(FSubPath, s)]);
+ FSubPath := e_CatPath(FSubPath, s);
+ end;
+ ScanDirs;
FIndex := 0;
Exit;
end;
FIndex := 0;
Exit;
end;
end;
end;
end;
end;
-procedure TGUIFileListBox.OpenDir(path: String);
-var
- SR: TSearchRec;
- i: Integer;
- sm, sc: string;
+procedure TGUIFileListBox.ScanDirs;
+ var i, j: Integer; path: AnsiString; SR: TSearchRec; sm, sc: String;
begin
begin
- Clear();
+ Clear;
- path := IncludeTrailingPathDelimiter(path);
- path := ExpandFileName(path);
-
- // Êàòàëîãè:
- if FDirs then
+ i := High(FBaseList);
+ while i >= 0 do
begin
begin
- if FindFirst(path+'*', faDirectory, SR) = 0 then
- repeat
- if not LongBool(SR.Attr and faDirectory) then
- Continue;
- if (SR.Name = '.') or
- ((SR.Name = '..') and (path = ExpandFileName(FBasePath))) then
- Continue;
-
- AddItem(#1 + SR.Name);
- until FindNext(SR) <> 0;
-
- FindClose(SR);
+ path := e_CatPath(FBaseList[i], FSubPath);
+ if FDirs then
+ begin
+ if FindFirst(path + '/' + '*', faDirectory, SR) = 0 then
+ begin
+ repeat
+ if LongBool(SR.Attr and faDirectory) then
+ if (SR.Name <> '.') and ((FSubPath <> '') or (SR.Name <> '..')) then
+ if Self.ItemExists(#1 + SR.Name) = false then
+ Self.AddItem(#1 + SR.Name)
+ until FindNext(SR) <> 0
+ end;
+ FindClose(SR)
+ end;
+ Dec(i)
end;
end;
- // Ôàéëû:
- sm := FFileMask;
- while sm <> '' do
+ i := High(FBaseList);
+ while i >= 0 do
begin
begin
- i := Pos('|', sm);
- if i = 0 then i := length(sm)+1;
- sc := Copy(sm, 1, i-1);
- Delete(sm, 1, i);
- if FindFirst(path+sc, faAnyFile, SR) = 0 then repeat AddItem(SR.Name); until FindNext(SR) <> 0;
- FindClose(SR);
+ path := e_CatPath(FBaseList[i], FSubPath);
+ sm := FFileMask;
+ while sm <> '' do
+ begin
+ j := Pos('|', sm);
+ if j = 0 then
+ j := length(sm) + 1;
+ sc := Copy(sm, 1, j - 1);
+ Delete(sm, 1, j);
+ if FindFirst(path + '/' + sc, faAnyFile, SR) = 0 then
+ begin
+ repeat
+ if Self.ItemExists(SR.Name) = false then
+ AddItem(SR.Name)
+ until FindNext(SR) <> 0
+ end;
+ FindClose(SR)
+ end;
+ Dec(i)
end;
for i := 0 to High(FItems) do
if FItems[i][1] = #1 then
FItems[i][1] := #29;
end;
for i := 0 to High(FItems) do
if FItems[i][1] = #1 then
FItems[i][1] := #29;
-
- FPath := path;
end;
end;
-procedure TGUIFileListBox.SetBase(path: String);
+procedure TGUIFileListBox.SetBase (dirs: SSArray; path: String = '');
begin
begin
- FBasePath := path;
- OpenDir(FBasePath);
+ FBaseList := dirs;
+ FSubPath := path;
+ ScanDirs
end;
end;
-function TGUIFileListBox.SelectedItem(): String;
+function TGUIFileListBox.SelectedItem (): String;
+ var s: AnsiString;
begin
begin
- Result := '';
-
- if (FIndex = -1) or (FItems = nil) or
- (FIndex > High(FItems)) or
- (FItems[FIndex][1] = '/') or
- (FItems[FIndex][1] = '\') then
- Exit;
-
- Result := FPath + FItems[FIndex];
+ result := '';
+ if (FIndex >= 0) and (FIndex <= High(FItems)) and (FItems[FIndex][1] <> '/') and (FItems[FIndex][1] <> '\') then
+ begin
+ s := e_CatPath(FSubPath, FItems[FIndex]);
+ if e_FindResource(FBaseList, s) = true then
+ result := ExpandFileName(s)
+ end;
+ e_LogWritefln('TGUIFileListBox.SelectedItem -> "%s"', [result]);
end;
procedure TGUIFileListBox.UpdateFileList();
end;
procedure TGUIFileListBox.UpdateFileList();
else
fn := FItems[FIndex];
else
fn := FItems[FIndex];
- OpenDir(FPath);
+// OpenDir(FPath);
+ ScanDirs;
if fn <> '' then
SelectItem(fn);
if fn <> '' then
SelectItem(fn);