unit DebugUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, JvExComCtrls, JvComCtrls, SynEdit, SynMemo, ExtCtrls,
  JvTabBar, StdCtrls, Buttons, Grids, ValEdit,dqe2_types,SynEditTypes,
  SynEditMiscClasses,alkatraz;

type
  TForm_Debug = class(TForm)
    TabBar: TJvTabBar;
    Splitter1: TSplitter;
    Panel1: TPanel;
    SynMemo1: TSynMemo;
    Panel2: TPanel;
    Panel3: TPanel;
    Splitter2: TSplitter;
    Panel4: TPanel;
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    SpeedButton3: TSpeedButton;
    SpeedButton4: TSpeedButton;
    SpeedButton5: TSpeedButton;
    SpeedButton6: TSpeedButton;
    SpeedButton7: TSpeedButton;
    TheLocals: TListView;
    TheWatches: TListView;
    procedure Localize;
    procedure UpdateWatches;
    procedure UpdateLocals;
    procedure ShowStatus;
    procedure UpdateForm;
    procedure OnBreakpoint(Sender:DQE2_Scriptable;var DoBreak:boolean);
    procedure FormCreate(Sender: TObject);
    procedure TabBarTabClosing(Sender: TObject; Item: TJvTabBarItem;
      var AllowClose: Boolean);
    procedure SpeedButton3Click(Sender: TObject);
    procedure TabBarTabClosed(Sender: TObject; Item: TJvTabBarItem);
    procedure SpeedButton5Click(Sender: TObject);
    procedure SpeedButton4Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton6Click(Sender: TObject);
    procedure TabBarTabSelected(Sender: TObject; Item: TJvTabBarItem);
    procedure SynMemo1GutterClick(Sender: TObject; Button: TMouseButton; X, Y,
      Line: Integer; Mark: TSynEditMark);
    procedure SpeedButton7Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form_Debug: TForm_Debug;
  _vars,_values:TStringList;

implementation

uses MainUnit;

var CurScript:DQE2_Scriptable=nil;
var lng:array of string;

{$R *.dfm}

procedure TForm_Debug.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  a:integer;
begin
  for a:=0 to TabBar.Tabs.Count-1 do
    if DQE2_Scriptable(TabBar.Tabs[a].Data).InDebug then
      begin CanClose:=false;exit;end;
  CanClose:=true;
end;

procedure TForm_Debug.FormCreate(Sender: TObject);
begin
  World.OnBreakpoint:=OnBreakpoint;
  Form_Main_DQE.ImageList1.GetBitmap(39,SpeedButton3.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(43,SpeedButton4.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(44,SpeedButton1.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(45,SpeedButton2.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(46,SpeedButton6.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(47,SpeedButton5.Glyph);
  Form_Main_DQE.ImageList1.GetBitmap(48,SpeedButton7.Glyph);
  SetLength(lng,16);
  //
  _values:=TStringList.Create;
  _vars:=TStringList.Create;
end;

procedure TForm_Debug.FormDestroy(Sender: TObject);
begin
  _values.Free;
  _vars.Free;
end;

procedure TForm_Debug.Localize;
begin
  LoadStringsFromIni(MainUnit.lang_ini,Name,lng);
  Caption:=lng[0];
  Label2.Caption:=lng[5]+':';
  TheLocals.Columns[0].Caption:=lng[6];
  TheLocals.Columns[1].Caption:=lng[7];
  Label3.Caption:=lng[8]+':';
  TheWatches.Columns[1].Caption:=lng[9];
  TheWatches.Columns[1].Caption:=lng[10];
  UpdateForm;
end;

procedure TForm_Debug.OnBreakpoint(Sender:DQE2_Scriptable;var DoBreak:boolean);
var
  t:TJvTabBarItem;
  a:integer;
begin
  if Visible=false then Show else BringToFront;
  for a:=0 to TabBar.Tabs.Count-1 do
    if TabBar.Tabs[a].Data=Sender then
    begin
      TabBar.Tabs[a].Selected:=true;
      UpdateForm;
      exit;
    end;
  t:=TJvTabBarItem.Create(TabBar.Tabs);
  t.Caption:=Sender.Name;
  t.Data:=Sender;
  t.Selected:=true;
  UpdateForm;
end;

procedure TForm_Debug.ShowStatus;
var
  s:string;
begin
  if CurScript.InDebug then
    s:=lng[2] else
  if CurScript.Running then
    s:=lng[3]
  else
    s:=lng[4];
  Label1.Caption:=lng[1]+': '+CurScript.Name+' ('+s+')';
end;

procedure TForm_Debug.SpeedButton1Click(Sender: TObject);
var
  s:string;
  i:TListItem;
begin
  if InputQuery(lng[11],lng[12],s) then
  begin
    i:=TheWatches.Items.Add;
    i.Caption:=s;
    i.SubItems.Add('');
    UpdateForm;
  end;
end;

procedure TForm_Debug.SpeedButton2Click(Sender: TObject);
begin
  if TheWatches.Items.Count>0 then
    if TheWatches.Selected<>nil then
      if MessageDlgRus(lng[14],lng[15],MB_ICONQUESTION or MB_OKCANCEL)=mrOk then
        begin
          TheWatches.DeleteSelected;
          UpdateForm;
        end;
end;

procedure TForm_Debug.SpeedButton3Click(Sender: TObject);
begin
  if CurScript<>nil then
    if CurScript.Resume(false)=0 then
      SynMemo1.GotoLineAndCenter(CurScript.CurrentLine);
  UpdateForm;
end;

procedure TForm_Debug.SpeedButton4Click(Sender: TObject);
begin
  if CurScript<>nil then
    CurScript.Stop;
  ShowStatus;
end;

procedure TForm_Debug.SpeedButton5Click(Sender: TObject);
begin
  CurScript:=nil;UpdateForm;
end;

procedure TForm_Debug.SpeedButton6Click(Sender: TObject);
var
  s:string;
begin
  if TheWatches.Items.Count>0 then
    if TheWatches.Selected<>nil then
    begin
      s:=TheWatches.Selected.Caption;
      if InputQuery(lng[11],lng[12],s) then
      begin
        TheWatches.Selected.Caption:=s;
        UpdateForm;
      end;
    end;
end;

procedure TForm_Debug.SpeedButton7Click(Sender: TObject);
begin
  if CurScript<>nil then
    if CurScript.Resume(true)=0 then
      SynMemo1.GotoLineAndCenter(CurScript.CurrentLine);
  UpdateLocals;
  UpdateWatches;
  ShowStatus;
end;

procedure TForm_Debug.SynMemo1GutterClick(Sender: TObject; Button: TMouseButton;
  X, Y, Line: Integer; Mark: TSynEditMark);
var
  m:TSynEditMark;
  marks:TSynEditLineMarks;
begin
  if CurScript<>nil then
  begin
    SynMemo1.marks.GetMarksForLine(Line,marks);
    if marks[0]=nil then
    begin
      m:=TSynEditMark.Create;
      m.Line:=Line;
      m.Visible:=true;
      m.ImageIndex:=42;
      m.InternalImage:=false;
      SynMemo1.Marks.Add(m);
      CurScript.AddBreakpoint(Line);
    end
    else
    begin
      SynMemo1.Marks.ClearLine(Line);
      CurScript.RemoveBreakpoint(Line);
    end;
  end;
end;

procedure TForm_Debug.UpdateForm;
begin
  if TabBar.SelectedTab<>nil then
    if TabBar.SelectedTab.Data<>nil then
    begin
      //if TabBar.SelectedTab.Data<>CurScript then
      //begin
        CurScript:=DQE2_Scriptable(TabBar.SelectedTab.Data);
        SynMemo1.Text:=CurScript.Text;
      //end;
      ShowStatus;
      Form_Main_DQE.SynUpdateGutter(SynMemo1,CurScript);
      SynMemo1.GotoLineAndCenter(CurScript.CurrentLine);
      UpdateLocals;
      UpdateWatches;
    end
    else
      CurScript:=nil
  else
    CurScript:=nil;
end;

procedure TForm_Debug.UpdateLocals;
var
  a:integer;
  i:TListItem;
begin
  CurScript.GetLocals(_vars,_values);
  if _vars.Count=0 then
    TheLocals.Visible:=false
  else
  begin
    TheLocals.Clear;
    for a:=0 to _vars.Count-1 do
    begin
      i:=TheLocals.Items.Add;
      i.Caption:=_vars[a];
      i.SubItems.Add(_values[a]);
    end;
    TheLocals.Visible:=true;
  end;
end;

procedure TForm_Debug.UpdateWatches;
var
  a:integer;
  v:Variant;
begin
  if TheWatches.Items.Count=0 then
    TheWatches.Visible:=false
  else
  begin
    for a:=0 to TheWatches.Items.Count-1 do
    begin
      if CurScript.Eval(TheWatches.Items[a].Caption,v) then
        TheWatches.Items[a].SubItems[0]:=string(v)
      else
        TheWatches.Items[a].SubItems[0]:='<'+lng[13]+'>';
    end;
    TheWatches.Visible:=true;
  end;
end;

procedure TForm_Debug.TabBarTabClosed(Sender: TObject; Item: TJvTabBarItem);
begin
  if TabBar.Tabs.Count=1 then Hide;
end;

procedure TForm_Debug.TabBarTabClosing(Sender: TObject; Item: TJvTabBarItem;
  var AllowClose: Boolean);
begin
  AllowClose:=(DQE2_Scriptable(Item.Data).InDebug=false); // bp
end;

procedure TForm_Debug.TabBarTabSelected(Sender: TObject; Item: TJvTabBarItem);
begin
  UpdateForm;
end;

end.
