(************************************************************************)
(*                                                                      *)
(* Logical.EXE                                                          *)
(*                                                                      *)
(* This program is a logical operations calculator.  It lets the user	*)
(* enter two binary or hexadecimal values and it will compute the logi-	*)
(* cal AND, OR, or XOR of these two numbers.  This calculator also sup-	*)
(* ports several unary operations including NOT, NEG, SHL, SHR, ROL and	*)
(* ROR.									*)
(*									*)
(* Randall L. Hyde							*)
(* 11/3/95								*)
(* Copyright 1995, All Rights Reserved.					*)
(*									*)
(************************************************************************)

unit logicalu;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, ExtCtrls,

  (* Converts is a special unit developed for this program that	*)
  (* provides decimal <-> binary <-> hexadecimal conversions	*)
  (* and data checking.						*)

  Converts;


  (* The Delphi Class for this form *)

type
  TLogicalOps = class(TForm)
    BinEntry1: TEdit; 		{Entry box for first binary value	}
    BinEntry2: TEdit;		{Entry box for second binary value	}
    HexEntry1: TEdit;		{Entry box for first hexadecimal value	}
    HexEntry2: TEdit;		{Entry box for second hexadecimal value	}

    BinResult: TLabel;		{Binary result goes here		}
    HexResult: TLabel;		{Hexadecimal result goes here		}

    Panel1: TPanel;

    { Buttons that appear on the form: }

    ExitBtn: TButton;
    AboutBtn: TButton;
    AndBtn: TButton;
    OrBtn: TButton;
    XorBtn: TButton;
    NotBtn: TButton;
    NegBtn: TButton;
    SHLBtn: TButton;
    SHRBtn: TButton;
    ROLBtn: TButton;
    RORBtn: TButton;

    { These labels hold text that appears on the form }

    Label1: TLabel;
    CurOpLbl: TLabel;
    CurrentOp: TLabel;

    { The methods that handle events occurring on this form }

    procedure ExitBtnClick(Sender: TObject);
    procedure AboutBtnClick(Sender: TObject);
    procedure BinEntry1KeyUp(Sender:TObject; var Key:Word; Shift:TShiftState);
    procedure BinEntry2KeyUp(Sender:TObject; var Key:Word; Shift:TShiftState);
    procedure HexEntry1KeyUp(Sender:TObject; var Key:Word; Shift:TShiftState);
    procedure HexEntry2KeyUp(Sender:TObject; var Key:Word; Shift:TShiftState);
    procedure AndBtnClick(Sender: TObject);
    procedure OrBtnClick(Sender: TObject);
    procedure XorBtnClick(Sender: TObject);
    procedure NotBtnClick(Sender: TObject);
    procedure NegBtnClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure SHLBtnClick(Sender: TObject);
    procedure SHRBtnClick(Sender: TObject);
    procedure ROLBtnClick(Sender: TObject);
    procedure RORBtnClick(Sender: TObject);
    procedure FormClick(Sender: TObject);

  private
  public

    { Value1 and Value2 hold the results obtained by converting between	}
    { hex/binary and integer forms.					}

    value1,
    value2:integer;
  end;




var
  LogicalOps: TLogicalOps;

implementation

{$R *.DFM}


{ The types of operations this calculator is capable of appear in the	}
{ following enumerated list.						}

type
    operations = (ANDop, ORop, XORop, NOTop, NEGop, SHLop, SHRop, ROLop, RORop);


var
   operation: operations;



{ DoCalc-  This function does the currently specified operation on	}
{ the value1 and value2 fields.  It displays the results in the binary	}
{ and hexadecimal result fields.					}

procedure DoCalc;
var unsigned:integer;
    carry:boolean;
begin

     { Compute the result of "Value1 op Value2" (for AND, OR, XOR) or	}
     { "op Value1" (for the other operations) and leave the result in	}
     { the "unsigned" variable.						}

     case Operation of

          ANDop: unsigned := LogicalOps.value1 and LogicalOps.value2;
          ORop: unsigned := LogicalOps.value1 or LogicalOps.value2;
          XORop: unsigned := LogicalOps.value1 xor LogicalOps.value2;
          NOTop: unsigned := not LogicalOps.value2;
          NEGop: unsigned := -LogicalOps.value2;
          SHLop: unsigned := LogicalOps.value2 shl 1;
          SHRop: unsigned := LogicalOps.value2 shr 1;
          ROLop: begin
                      carry := (LogicalOps.value2 and $8000) = $8000;
                      unsigned := LogicalOps.value2 shl 1;
                      if carry then inc(unsigned);
                 end;

          RORop: begin
                      carry := odd(LogicalOps.value2);
                      unsigned := LogicalOps.value2 shr 1;
                      if carry then
                         unsigned := unsigned or $8000;
                 end;

     end;

     { Output results to the binary and hexadecimal result fields on	}
     { the form.							}

     LogicalOps.BinResult.Caption := IntToBin(unsigned, 16);
     LogicalOps.HexResult.Caption := IntToHex(unsigned,4);

     end;


{ Reformat is a short utility procedure that redraws all the input	}
{ values whenever the user clicks on one of the operation buttons.	}

procedure Reformat;
begin

     LogicalOps.HexEntry1.text := IntToHex(LogicalOps.value1,4);
     LogicalOps.HexEntry2.text := IntToHex(LogicalOps.value2,4);
     LogicalOps.BinEntry1.text := IntToBin(LogicalOps.value1,16);
     LogicalOps.BinEntry2.text := IntToBin(LogicalOps.value2,16);

end;



{ The following procedure executes when the program first runs.  It	}
{ simply initializes the value1 and value2 variables.			}

procedure TLogicalOps.FormCreate(Sender: TObject);
begin

     Value1 := 0;
     Value2 := 0;

end;



{ The following procedure terminates the program whenever the user	}
{ presses the QUIT button.						}

procedure TLogicalOps.ExitBtnClick(Sender: TObject);
begin
     Halt;
end;



{ Whenever the user releases a key pressed in the first hex data entry	}
{ box, the following procedure runs to convert the string appearing in	}
{ that box to its corresonding integer value.  This procedure also re-	}
{ computes the result using the current operation and updates any nec-	}
{ cessary fields on the form.						}

procedure TLogicalOps.HexEntry1KeyUp(Sender: TObject;
                                 var Key: Word;
                                 Shift: TShiftState);
begin

     { First, see if this is a legal hex value }

     if (CheckHex(HexEntry1.Text)) then begin

        { If legal, convert it to an integer, update the binary field,	}
        { and then calculate the result.  Change the field's background	}
        { colors back to normal since we've got an okay input value.	}

        Value1 := HexToInt(HexEntry1.Text);
        BinEntry1.Text := IntToBin(Value1,16);
        HexEntry1.Color := clWindow;
        BinEntry1.Color := clWindow;
        DoCalc;

     end
     else begin

          { If there was a data entry error, beep the speaker and set	}
          { the background color to red.				}

          MessageBeep($ffff);
          HexEntry1.Color := clRed;

     end;

end;


{ This function handles key up events in the first binary data entry	}
{ field.  It is very similar to HexEntry1KeyUp, so see the comments in	}
{ that procedure for details on how this operates.			}

procedure TLogicalOps.BinEntry1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

     if (CheckBin(BinEntry1.Text)) then begin

        Value1 := BinToInt(BinEntry1.Text);
        HexEntry1.Text := IntToHex(Value1,4);
        BinEntry1.Color := clWindow;
        HexEntry1.Color := clWindow;
        DoCalc;

     end
     else begin

          MessageBeep($ffff);
          BinEntry1.Color := clRed;

     end;
end;


{HexEntry2KeyUp handle key up events in the second hex entry text win-	}
{dow.  See HexEntry1KeyUp for operational details.			}

procedure TLogicalOps.HexEntry2KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

     if (CheckHex(HexEntry2.Text)) then begin

        Value2 := HexToInt(HexEntry2.Text);
        BinEntry2.Text := IntToBin(Value2,16);
        HexEntry2.Color := clWindow;
        BinEntry2.Color := clWindow;
        DoCalc;

     end
     else begin

          MessageBeep($ffff);
          HexEntry2.Color := clRed;

     end;
end;


{BinEntry2KeyUp handles key up events in the second binary data entry	}
{window.  See the HexEntry1KeyUp procedure for operational details.	}

procedure TLogicalOps.BinEntry2KeyUp( Sender: TObject;
                                       var Key: Word;
                                       Shift: TShiftState);
begin

     if (CheckBin(BinEntry2.Text)) then begin

        Value2 := BinToInt(BinEntry2.Text);
        HexEntry2.Text := IntToHex(Value2,4);
        BinEntry2.Color := clWindow;
        HexEntry2.Color := clWindow;
        DoCalc;

     end
     else begin

          MessageBeep($ffff);
          BinEntry2.Color := clRed;

     end;

end;







{ The following procedure executes whenever the user presses the	}
{ "ABOUT" button on the form.						}

procedure TLogicalOps.AboutBtnClick(Sender: TObject);
begin

    MessageDlg(
       'Logical Operations Calculator, Copyright 1995 by Randall Hyde',
       mtInformation, [mbOk], 0);

end;


{ The "AndBtnClick" method runs whenever the user presses the AND but-	}
{ ton on the form.  It sets the global operation to logical AND, enables}
{ input in both data entry text box sets (since this is a dyadic opera-	}
{ tion), and it recalculates results.					}

procedure TLogicalOps.AndBtnClick(Sender: TObject);
begin

     Operation := ANDop;	{Set operation to logical AND.		}
     BinEntry1.Enabled := true;	{Allow entry in the binary entry 1 and	}
     HexEntry1.Enabled := true;	{hex entry 1 text boxes.		}
     DoCalc;			{Recalculate results.			}
     Reformat;			{Reformat the current input values.	}
     CurrentOp.Caption := 'AND';{Display "AND" on the FORM.		}

end;




{ Same as above, but for the logical OR operation.			}

procedure TLogicalOps.OrBtnClick(Sender: TObject);
begin

     Operation := ORop;
     BinEntry1.Enabled := true;
     HexEntry1.Enabled := true;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'OR';

end;


{ Same as above, except this one handles the XOR button.		}

procedure TLogicalOps.XorBtnClick(Sender: TObject);
begin

     Operation := XORop;
     BinEntry1.Enabled := true;
     HexEntry1.Enabled := true;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'XOR';

end;



{ Like the above, but the logical NOT operation is unary only, remember. }
{ Of course, unary vs. binary is handled in the DoCalc procedure.	 }

procedure TLogicalOps.NotBtnClick(Sender: TObject);
begin

     Operation := NOTop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'NOT';

end;


{ Procedure that runs when the user presses the NOT button		}

procedure TLogicalOps.NegBtnClick(Sender: TObject);
begin

     Operation := NEGop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'NEG';

end;


{ Procedure that runs when the user presses the SHL button		}

procedure TLogicalOps.SHLBtnClick(Sender: TObject);
begin

     Operation := SHLop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'SHL';

end;


{ Procedure that runs when the user presses the SHR button		}

procedure TLogicalOps.SHRBtnClick(Sender: TObject);
begin

     Operation := SHRop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'SHR';

end;


{ Procedure that runs when the user presses the ROL button		}

procedure TLogicalOps.ROLBtnClick(Sender: TObject);
begin

     Operation := ROLop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'ROL';

end;


{ Procedure that runs when the user presses the ROR button		}

procedure TLogicalOps.RORBtnClick(Sender: TObject);
begin

     Operation := RORop;
     BinEntry1.Enabled := false;
     HexEntry1.Enabled := false;
     DoCalc;
     Reformat;
     CurrentOp.Caption := 'ROR';

end;


procedure TLogicalOps.FormClick(Sender: TObject);
begin
	Reformat;
end;

end.
