unit BinaryF;
//*******************************************************
// Example program demonstrating binary trees.
//*******************************************************
// Copyright (C) 1998 John Wiley & Sons, Inc.
// All rights reserved. See additional copyright
// information in Readme.txt.
//*******************************************************

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus,
  BinaryC, StdCtrls;

type
  TBinaryForm = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    mnuExit: TMenuItem;
    Help1: TMenuItem;
    mnuAbout: TMenuItem;
    CmdAddLeft: TButton;
    CmdAddRight: TButton;
    CmdRemove: TButton;
    procedure mnuExitClick(Sender: TObject);
    procedure mnuAboutClick(Sender: TObject);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure SetButtons;
    procedure SelectNode(new_selection : TBinaryNode);
    procedure CmdAddLeftClick(Sender: TObject);
    procedure CmdAddRightClick(Sender: TObject);
    procedure CmdRemoveClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  BinaryForm: TBinaryForm;

implementation

var
    root, selected  : TBinaryNode;
    x0, y0, node_id : Integer;

{$R *.DFM}

procedure TBinaryForm.mnuExitClick(Sender: TObject);
begin
    Close;
end;

procedure TBinaryForm.mnuAboutClick(Sender: TObject);
const
    CRCR = #13#10#13#10;
begin
    MessageDlg(
        'This program allows you to manipulate a binary tree.' + CRCR +
        'Select a node and the program will enable the appropriate buttons.' + CRCR +
        'If you remove a node, all of its descendants are removed as well.'
        , mtInformation, [mbOK], 0);
end;

procedure TBinaryForm.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
    // Select the node at the given point.
    SelectNode(
        root.NodeAtPoint(X, Y));
end;

// Create the root node.
procedure TBinaryForm.FormCreate(Sender: TObject);
var
    xmin : Integer;
begin
    // Create a one node tree.
    root := TBinaryNode.Create;
    root.Id := 'Root';
    node_id := 0;

    // Save the coordinates where we will start drawing.
    x0 := 3;
    y0 := CmdAddLeft.Top + CmdAddLeft.Height + 3;

    // Use bold text.
    Canvas.Font.Style := [fsBold];

    // Position the initial one node tree.
    xmin := x0;
    root.SetPosition(xmin, y0);
end;

// Draw the tree.
procedure TBinaryForm.FormPaint(Sender: TObject);
var
    rect : TRect;
begin
    // Erase the canvas.
    rect.Left := 0;
    rect.Right := Width;
    rect.Top := 0;
    rect.Bottom := Height;
    Canvas.Brush.Color := clLtGray;
    Canvas.FillRect(rect);

    // Draw the tree.
    root.DrawSubtree(Canvas, selected);
end;

// Enable the correct buttons for the selected node.
procedure TBinaryForm.SetButtons;
begin
    if (selected = nil) then
    begin
        CmdAddLeft.Enabled  := False;
        CmdAddRight.Enabled := False;
        CmdRemove.Enabled   := False;
    end else begin
        CmdAddLeft.Enabled  := (selected.LeftChild  = nil);
        CmdAddRight.Enabled := (selected.RightChild = nil);
        CmdRemove.Enabled   := (selected <> root);
    end;
end;

procedure TBinaryForm.SelectNode(new_selection : TBinaryNode);
begin
    // Unselect the previously selected node.
    if (selected <> nil) then
        selected.DrawNode(Canvas, nil);

    // Select the new node.
    selected := new_selection;
    // Highlight the selected node.
    if (selected <> nil) then
        selected.DrawNode(Canvas, selected);
    SetButtons;
end;

// Add a left child to the selected node.
procedure TBinaryForm.CmdAddLeftClick(Sender: TObject);
var
    xmin : Integer;
begin
    node_id := node_id + 1;
    selected.LeftChild := TBinaryNode.Create;
    selected.LeftChild.Id := IntToStr(node_id);
    selected.LeftChild.ParentNode := selected;

    // Reposition the nodes.
    xmin := x0;
    root.SetPosition(xmin, y0);

    // Enable the correct buttons.
    SetButtons;

    Refresh;
end;

procedure TBinaryForm.CmdAddRightClick(Sender: TObject);
var
    xmin : Integer;
begin
    node_id := node_id + 1;
    selected.RightChild := TBinaryNode.Create;
    selected.RightChild.Id := IntToStr(node_id);
    selected.RightChild.ParentNode := selected;

    // Reposition the nodes.
    xmin := x0;
    root.SetPosition(xmin, y0);

    // Enable the correct buttons.
    SetButtons;

    Refresh;
end;

// Remove the selected node and its descendants.
procedure TBinaryForm.CmdRemoveClick(Sender: TObject);
var
    xmin   : Integer;
    target : TBinaryNode;
begin
    // Unselect the node.
    target := selected;
    SelectNode(nil);

    // Remove the selected node from the tree.
    if (target = target.ParentNode.LeftChild) then
        target.ParentNode.LeftChild := nil
    else
        target.ParentNode.RightChild := nil;

    // Free the node and its descendants.
    target.Free;

    // Reposition the remaining nodes.
    xmin := x0;
    root.SetPosition(xmin, y0);

    Refresh;
end;

end.
