unit yatc_control;
{YATC - Unit gameoptions
Autor : Tobias Mark aka Colenzo (tobiasmark@gmx.de)

Formular zum einstellen der Steuerungsoptionen
(Tastenbelegung)

 bisher nicht speichernd, und nicht für alle tasten

Version
0.1 - 13.12 : - Erste version, mit grundlegender Funktionaliät
0.2 - 21.12 : - alle bisher bekannten Taste aufgenommen
}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,yatc_global, StdCtrls, Grids, Keyboard;

type
  TcontrolForm = class(TForm)
    okButton: TButton;
    cancelButton: TButton;
    keyEdit: TStringGrid;
    statusLabel: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure okButtonClick(Sender: TObject);
    procedure cancelButtonClick(Sender: TObject);
    procedure keyEditDblClick(Sender: TObject);
    procedure keyEditMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure keyEditKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private-Deklarationen }
    cancelGetKey : integer;  //Status eines laufenden Belegungs vorgangs -1 : keiner läuft, 0 : läuft, 1: abbrechen bitte
    keyBindings : array[RKeyAction] of word;  //Tastenbelegung
  public
    { Public-Deklarationen }
    function getkeyaction(key : word) : RKeyAction;  //Ermittelt Aktion aus Taste
    procedure makevisible; //zeigt formular an
  end;

var
  controlForm: TcontrolForm;

implementation

uses yatc_main;

{$R *.dfm}


function TControlForm.getkeyaction(key : word): RKeyAction;

var i : RKeyAction;

begin
  result := knone;
  for i := knone to  kerror do
  begin
    if key = keyBindings[i] then
    begin
      result := i;   //Ereignes Bassirend auf Taste zurückgeben
      break;
    end;
  end;
end;

procedure TcontrolForm.FormCreate(Sender: TObject);

begin
  //demon init
  keyBindings[knone] := 0;
  keyBindings[kright] := ord('D');
  keyBindings[kleft] := ord('A');
  keyBindings[kup] := ord('W');
  keyBindings[kdown] :=  ord('S');
  keyBindings[krotright] :=  ord('Q');
  keyBindings[krotleft] :=  ord('E');
  keyBindings[kfulldown] := ord('X');

  keyBindings[kright2] := VK_RIGHT;
  keyBindings[kleft2] := VK_LEFT;
  keyBindings[kup2] := VK_UP;
  keyBindings[kdown2] :=  VK_DOWN;
  keyBindings[krotright2] :=  VK_SHIFT;
  keyBindings[krotleft2] :=  VK_CONTROL;
  keyBindings[kfulldown2] := VK_END;

  keyBindings[kcameraUp] := VK_PRIOR;
  keyBindings[kcameraDown] := VK_NEXT;
  keyBindings[kcameraUp2] :=  0;
  keyBindings[kcameraDown2] :=  0;

  keyBindings[knew] := VK_F2;
  keyBindings[kstart] := VK_F3;
  keyBindings[khelp]  := VK_F4;
  keyBindings[kdebug] := VK_F10;
  keyBindings[khighscore] := VK_F5;

  keyBindings[kerror] := 0;

  //Tabbelle Beschriften
  keyEdit.Cells[0,0] := 'Aktion';
  keyEdit.Cells[1,0] := 'Spieler 1';
  keyEdit.Cells[2,0] := 'Spieler 2 bzw. Alternativ';
  keyEdit.Cells[0,1] := 'Nach Rechts';
  keyEdit.Cells[0,2] := 'Nach Links';
  keyEdit.Cells[0,3] := 'Nach Oben (Debug)';
  keyEdit.Cells[0,4] := 'Nach Unten';
  keyEdit.Cells[0,5] := 'Nach Rechts Drehen';
  keyEdit.Cells[0,6] := 'Nach Linsk Drehen';
  keyEdit.Cells[0,7] := 'Sofort Nach Unten';

  keyEdit.Cells[0,9] := 'Zoom Out';
  keyEdit.Cells[0,10] := 'Zoom In';

  keyEdit.Cells[0,12] := 'Spiel Neu';
  keyEdit.Cells[0,13] := 'Start/Stop';
  keyEdit.Cells[0,14] := 'Hilfe';
  keyEdit.Cells[0,15] := 'Highscore Liste';
  keyEdit.Cells[0,16] := 'Debug Modus';

  cancelGetKey := -1;
end;

procedure TcontrolForm.okButtonClick(Sender: TObject);
//Sichern und schließen

var i : RKeyAction;

begin
  //Speichern der Daten
  for i := kright to kfulldown do
  begin
    keyBindings[i] := KeyNametoVirtualKeyCode(keyedit.Cells[1,ord(i)]);
  end;

  for i := kright2 to kfulldown2 do
  begin
    keyBindings[i] := KeyNametoVirtualKeyCode(keyedit.Cells[2,ord(i) - 7]);
  end;

  keyBindings[kcameraUp] := KeyNametoVirtualKeyCode(keyedit.Cells[1,9]);
  keyBindings[kcameraDown] := KeyNametoVirtualKeyCode(keyedit.Cells[1,10]);
  keyBindings[kcameraUp2] := KeyNametoVirtualKeyCode(keyedit.Cells[2,9]);
  keyBindings[kcameraDown2] := KeyNametoVirtualKeyCode(keyedit.Cells[2,10]);

  for i := knew to kdebug do
  begin
    keyBindings[i] := KeyNametoVirtualKeyCode(keyedit.Cells[1,ord(i) - 7]);
  end;

  //Dialog verbergen
  self.visible := false;
  form1.enabled := true;
  form1.SetFocus;
  cancelGetKey := 1; //abbrechen der aktuellen belegung

  //Anzeigen der Taste im Hauptformular aktualisieren
  form1.menuNew.ShortCut := keyBindings[knew];
  form1.startstopMenu.ShortCut := keyBindings[kstart];
  form1.menuHigh.ShortCut := keyBindings[khighscore];
end;

procedure TcontrolForm.makevisible;
//Dialog anzeigen

var i : RKeyAction;

begin
  self.Visible := true;
  form1.enabled := false;
  statusLabel.Caption := 'Doppelklicken um einen Eintrag zu editiren';
  //Anzeige aktuallisieren, falls letzte Änderung nicht gespeichert wurden
  for i := kright to kfulldown do
  begin
    keyEdit.Cells[1,ord(i)] := VirtualKeyCodeToKeyName(keyBindings[i]);
  end;

  for i := kright2 to kfulldown2 do
  begin
    keyEdit.Cells[2,ord(i) - 7] := VirtualKeyCodeToKeyName(keyBindings[i]);
  end;

  keyEdit.Cells[1,9] :=  VirtualKeyCodeToKeyName(keyBindings[kcameraUp]);
  keyEdit.Cells[1,10] :=  VirtualKeyCodeToKeyName(keyBindings[kcameraDown]);
  keyEdit.Cells[2,9] :=  VirtualKeyCodeToKeyName(keyBindings[kcameraUp2]);
  keyEdit.Cells[2,10] :=  VirtualKeyCodeToKeyName(keyBindings[kcameraDown2]);

  for i := knew to kdebug do
  begin
    keyEdit.Cells[1,ord(i) - 7] := VirtualKeyCodeToKeyName(keyBindings[i]);
  end;
  cancelGetKey := -1; //init
end;

procedure TcontrolForm.cancelButtonClick(Sender: TObject);

begin
  //nix verändern
  self.visible := false;
  form1.enabled := true;
  form1.SetFocus;
  if cancelGetKey = 0 then
    cancelGetKey := 1; //abbrechen der aktuellen belegung
end;

procedure TcontrolForm.keyEditDblClick(Sender: TObject);

var selection : TGridRect; //angeklichtes teil
    x,y : integer;   //übersetzt in Koordintante
    used : boolean;  //taste schonmal benutzt?
    key : integer;  //erfasster taste
    i : integer;  //zähler

begin
  if cancelGetKey >= 0 then
  begin  //wenn schon einer bei der arbeit ist
    cancelGetKey := 1;  //letzten versuch abbrechen
  end
  else
  begin
    cancelGetKey := 0;     //in use
    //Angeklicktes Feld suchen
    selection := keyedit.Selection;
    x := selection.left;  //nur für einfacheren zugriff
    y := selection.Top;
    if (x > 0) and (y > 0) then
    begin //nur wenn auch editierbar
      statusLabel.Caption := 'Taste drücken zum Belegen von "' + keyedit.Cells[0,y] + '"';
      repeat  //Schleife um auf neue belegung zu warten
        Application.ProcessMessages;
        Sleep(1);
        key := KeyPressed;  //Taste abfassen
      until (key >= 12) or (key = 27) or (cancelGetKey = 1);  //taste im bereich oder abbruch von aussen?
      if (cancelGetKey <> 1) and (key <> 27) then
      begin     //Esc = abbruch
        used := false;         //init der var
        for i := 1 to 16 do
        begin   //Prüfen ob Taste schon verwendet
          if KeyNameToVirtualKeyCode(keyedit.Cells[1,i]) = key then
          begin    //1. Spalte
            used := true;
            break;
          end;
          if KeyNameToVirtualKeyCode(keyedit.Cells[2,i]) = key then
          begin    //2.Spalte
            used := true;
            break;
          end;
        end;
        if used = false then
        begin    //Vorläufig Belegen
          keyedit.cells[x,y] := VirtualKeyCodeToKeyName(key);
          statusLabel.Caption := 'Belegung erfolgreich';
        end
        else
        begin    //Fehler
          statusLabel.Caption := 'Belegung nicht möglich Taste bereits verwendet für "' + keyEdit.Cells[0,ord(i)] + '"';
        end;
      end
      else
      begin   //Abbruch
        statusLabel.Caption := 'Abgebrochen';
      end;
    end;
    cancelGetKey := -1; //freigeben
  end;
end;

procedure TcontrolForm.keyEditMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
//Highlighten das Feld unter der Maus wenn es editierbar ist


var col,row : integer;     //Zeile Spalte
    selection : TGridRect; //auswahl die durch maus gemacht wird
    canSelect : boolean;      //kann gewählt werden?

begin
  keyedit.MouseToCell(x,y,col,row);
  canSelect := true;

  if (Col = 0) or (Row = 0) then
    canSelect := false; //Beschriftungen nicht
  if (Row = 8) or (Row = 11) then
    canSelect := false; //ZwischenZeilen
  if (Row > 11) and (Col = 2) then
    canSelect := false; //Unterer Bereich nur eine Belegung

  if canSelect = true then
  begin
    selection.Left := col;
    selection.top := row;
    selection.right := col;
    selection.Bottom := row;
  end
  else
  begin               //keine gültige Zelle => auswahl nicht anzeigen
    selection.Left := 5;
    selection.top := 1;
    selection.right := 5;
    selection.Bottom := 1;
  end;
  if (keyedit.selection.Left <> selection.Left) or (keyedit.selection.Top <> selection.Top) then
    if cancelGetKey = 0 then
      cancelGetKey := 1; //abbrechen der aktuellen belegung bei feld Wechsel

  keyedit.Selection := selection;
end;

procedure TcontrolForm.keyEditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);

begin
  key := 0;  //andere Tasten deaktivieren im Grid
end;

end.
