unit FME_GUI_Unit;
{
Started on 17 June 2009
by Stuart "Stucuk" Carey
Copyright (C) 2009
}
interface
type
//This is effectivly a copy of the TShiftState but in record form
TGUI_Mouse_State = Packed Record
ssShift, ssAlt, ssCtrl, ssLeft,
ssRight, ssMiddle, ssDouble : Boolean;
end;
//This is a copy of TMouseButton
TGUI_Mouse_Button = (GUI_mbLeft, GUI_mbRight, GUI_mbMiddle);
TGUI_Element = Class(TObject)
protected
FParent : Pointer;
FWidth,
FHeight,
FX,
FY : Integer;
FVisible,
FNeedUpdate : Boolean;
FChildren : Array of Pointer;
FMouse_State : TGUI_Mouse_State;
FChildDown : Boolean;
function FindChild(Child : Pointer) : Integer;
function FindFreeChild() : Integer;
function MouseDownInternal(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer) : Boolean;
procedure MouseUpInternal(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
public
//Constructor/Destructor
constructor Create(Parent : Pointer);
destructor Destroy; Override;
//Element
procedure AddChild(Child : Pointer);
procedure RemoveChild(Child : Pointer);
//Render/Update
procedure PreRender;
procedure Render;
procedure Update;
//Set
procedure SetXY(X,Y : Integer);
procedure SetWidthHeight(Width,Height : Integer);
procedure SetVisible(Value : Boolean);
//Get
function GetX : Integer;
function GetY : Integer;
procedure GetTrueXY(var X,Y : Integer);
function GetWidth : Integer;
function GetHeight : Integer;
function GetVisible : Boolean;
//Mouse/Keyboard
function XYInBounds(X,Y : Integer) : Boolean;
function MouseDown(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer) : Boolean;
procedure MouseUp(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
procedure MouseMove(State : TGUI_Mouse_State; X, Y: Integer);
//Events
procedure OnPreRender; Virtual;
procedure OnRender; Virtual;
procedure OnParentSizeChanged(WidthDiff,HeightDiff : Integer); Virtual; // Called by the parent
procedure OnMouseDown(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer); Virtual;
procedure OnMouseUp(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer); Virtual;
procedure OnMouseMove(State : TGUI_Mouse_State; X, Y: Integer); Virtual;
end;
implementation
//## Constructor/Destructor ##//
constructor TGUI_Element.Create(Parent : Pointer);
begin
inherited Create;
SetLength(FChildren,0);
FParent := Parent;
FWidth := -1;
FWidth := -1;
FX := -1;
FY := -1;
FVisible := False;
FNeedUpdate := True;
FillChar(FMouse_State,SizeOf(FMouse_State),0);
if Assigned(FParent) then
TGUI_Element(FParent).AddChild(Self);
end;
destructor TGUI_Element.Destroy;
var
X : Integer;
begin
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if Assigned(FChildren[X]) then
begin
TGUI_Element(FChildren[X]).Free;
FChildren[X] := Nil;
end;
SetLength(FChildren,0);
if Assigned(FParent) then
TGUI_Element(FParent).RemoveChild(Self);
end;
//## Element ##//
function TGUI_Element.FindChild(Child : Pointer) : Integer;
var
X : Integer;
begin
Result := -1;
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if Assigned(FChildren[X]) and (Child = FChildren[X]) then
begin
Result := X;
Break;
end;
end;
function TGUI_Element.FindFreeChild() : Integer;
var
X : Integer;
begin
Result := -1;
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if not Assigned(FChildren[X]) then
begin
Result := X;
Break;
end;
end;
procedure TGUI_Element.AddChild(Child : Pointer);
var
X : Integer;
begin
X := FindChild(Child);
if X > -1 then Exit; //Already a child.
X := FindFreeChild();
if X = -1 then
begin
SetLength(FChildren,High(FChildren)+2);
X := High(FChildren);
end;
FChildren[X] := Child;
end;
procedure TGUI_Element.RemoveChild(Child : Pointer);
var
X : Integer;
begin
X := FindChild(Child);
if X = -1 then Exit;
FChildren[X] := Nil;
end;
//## Render/Update ##//
procedure TGUI_Element.OnPreRender;
begin
//
end;
procedure TGUI_Element.PreRender;
var
X : Integer;
begin
if not FVisible then Exit;
OnPreRender;
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if Assigned(FChildren[X]) then
TGUI_Element(FChildren[X]).PreRender;
end;
procedure TGUI_Element.OnRender;
begin
//
end;
procedure TGUI_Element.Render;
var
X : Integer;
begin
if not FVisible then Exit;
OnRender;
FNeedUpdate := False;
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if Assigned(FChildren[X]) then
TGUI_Element(FChildren[X]).Render;
end;
procedure TGUI_Element.Update;
begin
FNeedUpdate := True;
end;
//## Set ##//
procedure TGUI_Element.SetXY(X,Y : Integer);
var
Z : Integer;
begin
FX := X;
FY := Y;
if High(FChildren) > -1 then
for Z := 0 to High(FChildren) do
if Assigned(FChildren[Z]) then
TGUI_Element(FChildren[Z]).Update;
end;
procedure TGUI_Element.SetWidthHeight(Width,Height : Integer);
var
WidthDiff,
HeightDiff,
X : Integer;
begin
WidthDiff := Width-FWidth;
HeightDiff := Height-FHeight;
FWidth := Width;
FHeight := Height;
if High(FChildren) > -1 then
for X := 0 to High(FChildren) do
if Assigned(FChildren[X]) then
begin
TGUI_Element(FChildren[X]).Update;
TGUI_Element(FChildren[X]).OnParentSizeChanged(WidthDiff,HeightDiff);
end;
end;
procedure TGUI_Element.SetVisible(Value : Boolean);
begin
if (FWidth = -1) or (FHeight = -1) or (FX = -1) or (FY = -1) then
begin
if FVisible then
Update;
FVisible := False;
exit;
end;
if FVisible = Value then Exit;
FVisible := Value;
Update;
end;
//## Get ##//
function TGUI_Element.GetX : Integer;
begin
Result := FX;
end;
function TGUI_Element.GetY : Integer;
begin
Result := FY;
end;
procedure TGUI_Element.GetTrueXY(var X,Y : Integer);
begin
If Assigned(FParent) then
TGUI_Element(FParent).GetTrueXY(X,Y)
else
begin
X := 0;
Y := 0;
end;
Inc(X,FX);
Inc(Y,FY);
end;
function TGUI_Element.GetWidth : Integer;
begin
Result := FWidth;
end;
function TGUI_Element.GetHeight : Integer;
begin
Result := FHeight;
end;
function TGUI_Element.GetVisible : Boolean;
begin
Result := FVisible;
end;
//## Mouse/Keyboard ##//
// Sends the MouseDown to all Children
function TGUI_Element.MouseDownInternal(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer) : Boolean;
var
Z,LX,LY : Integer;
begin
Result := False;
if High(FChildren) > -1 then
for Z := 0 to High(FChildren) do
if Assigned(FChildren[Z]) then
begin
LX := X-TGUI_Element(FChildren[Z]).GetX;
LY := Y-TGUI_Element(FChildren[Z]).GetY;
Result := TGUI_Element(FChildren[Z]).MouseDown(Button,State,LX,LY);
if Result then Break;
end;
end;
procedure TGUI_Element.MouseUpInternal(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
var
Z,LX,LY : Integer;
begin
if High(FChildren) > -1 then
for Z := 0 to High(FChildren) do
if Assigned(FChildren[Z]) then
begin
LX := X-TGUI_Element(FChildren[Z]).GetX;
LY := Y-TGUI_Element(FChildren[Z]).GetY;
TGUI_Element(FChildren[Z]).MouseUp(Button,State,LX,LY);
end;
end;
function TGUI_Element.XYInBounds(X,Y : Integer) : Boolean;
begin
Result := not ((X < 0) or (X > FWidth) or (Y < 0) or (Y > FHeight));
end;
procedure TGUI_Element.OnMouseDown(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
begin
//
end;
function TGUI_Element.MouseDown(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer) : Boolean;
begin
Result := False;
if not FVisible then exit;
if Not Assigned(FParent) then
begin
X := X-GetX;
Y := Y-GetY;
end;
FChildDown := MouseDownInternal(Button, State, X, Y);
if not FChildDown then
if XYInBounds(X,Y) then
begin
case Button of
GUI_mbLeft : FMouse_State.ssLeft := True;
GUI_mbMiddle : FMouse_State.ssMiddle := True;
GUI_mbRight : FMouse_State.ssRight := True;
end;
Result := True;
end;
Result := Result or FChildDown;
OnMouseDown(Button,State,X,Y);
end;
procedure TGUI_Element.OnMouseUp(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
begin
//
end;
procedure TGUI_Element.MouseUp(Button : TGUI_Mouse_Button; State : TGUI_Mouse_State; X, Y: Integer);
begin
if Not Assigned(FParent) then
begin
X := X-GetX;
Y := Y-GetY;
end;
MouseUpInternal(Button, State, X, Y);
case Button of
GUI_mbLeft : FMouse_State.ssLeft := False;
GUI_mbMiddle : FMouse_State.ssMiddle := False;
GUI_mbRight : FMouse_State.ssRight := False;
end;
if FVisible then
OnMouseUp(Button,State,X,Y);
end;
procedure TGUI_Element.OnMouseMove(State : TGUI_Mouse_State; X, Y: Integer);
begin
//
end;
procedure TGUI_Element.MouseMove(State : TGUI_Mouse_State; X, Y: Integer);
var
Z,LX,LY : Integer;
begin
if not FVisible then exit;
if Not Assigned(FParent) then
begin
X := X-GetX;
Y := Y-GetY;
end;
if High(FChildren) > -1 then
for Z := 0 to High(FChildren) do
if Assigned(FChildren[Z]) then
begin
LX := X-TGUI_Element(FChildren[Z]).GetX;
LY := Y-TGUI_Element(FChildren[Z]).GetY;
TGUI_Element(FChildren[Z]).MouseMove(State,LX,LY);
end;
OnMouseMove(State,X,Y);
end;
procedure TGUI_Element.OnParentSizeChanged(WidthDiff,HeightDiff : Integer);
begin
//
end;
end.