{******************************************************************************}
{ }
{ Tulip - User Interface Library }
{ }
{ Copyright(c) 2012 - 2013 Marcos Gomes. All rights Reserved. }
{ }
{ -------------------------------------------------------------------------- }
{ }
{ This product is based on Asphyre Sphinx (c) 2000 - 2012 Yuriy Kotsarenko. }
{ All rights reserved. Official web site: http://www.afterwarp.net }
{ }
{******************************************************************************}
{ }
{ Important Notice: }
{ }
{ If you modify/use this code or one of its parts either in original or }
{ modified form, you must comply with Mozilla Public License Version 2.0, }
{ including section 3, "Responsibilities". Failure to do so will result in }
{ the license breach, which will be resolved in the court. Remember that }
{ violating author's rights either accidentally or intentionally is }
{ considered a serious crime in many countries. Thank you! }
{ }
{ !! Please *read* Mozilla Public License 2.0 document located at: }
{ http://www.mozilla.org/MPL/ }
{ }
{ -------------------------------------------------------------------------- }
{ }
{ The contents of this file are subject to the Mozilla Public License }
{ Version 2.0 (the "License"); you may not use this file except in }
{ compliance with the License. You may obtain a copy of the License at }
{ http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" }
{ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the }
{ License for the specific language governing rights and limitations }
{ under the License. }
{ }
{ The Original Code is Tulip.UI.Controls.pas. }
{ }
{ The Initial Developer of the Original Code is Marcos Gomes. }
{ Portions created by Marcos Gomes are Copyright (C) 2012, Marcos Gomes. }
{ All Rights Reserved. }
{ }
{******************************************************************************}
{ }
{ Tulip.UI.Controls.pas Modified: 23-Mar-2013 }
{ -------------------------------------------------------------------------- }
{ }
{ Base Implementations for Controls and ControlManager }
{ }
{ Version 1.03 }
{ }
{******************************************************************************}
unit Tulip.UI.Controls;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes,
// Asphyre units
AbstractDevices, AbstractCanvas, AsphyreArchives, AsphyreFonts, AsphyreImages,
AsphyreTypes,
// Tulip UI Units
Tulip.UI.Types, Tulip.UI.Classes, Tulip.UI.Utils, Tulip.UI.Helpers;
type
{$REGION 'Forward declarations'}
TAControl = class;
TWControl = class;
TCustomManager = class;
{$ENDREGION}
{$REGION 'TAControl'}
TAControl = class(TComponent)
private
FControlManager: Pointer;
FControlState: TControlState;
FLeft: Integer;
FTop: Integer;
FWidth: Integer;
FHandle: Pointer;
FHeight: Integer;
FEnabled: Boolean;
FVisible: Boolean;
FParent: Pointer;
FOnClick: TNotifyEvent;
FOnDblClick: TNotifyEvent;
FOnMouseLeave: TNotifyEvent;
FOnMouseEnter: TNotifyEvent;
FOnMouseDown: TMouseEvent;
FOnMouseMove: TMouseMoveEvent;
FOnMouseUp: TMouseEvent;
FOnMouseWheel: TMouseWheelEvent;
FOnMouseWheelDown: TMouseWheelUpDownEvent;
FOnMouseWheelUp: TMouseWheelUpDownEvent;
FOnResize: TNotifyEvent;
FWheelAccumulator: Integer;
function GetControlManager: TCustomManager;
function GetParent: TWControl;
procedure SetVisible(Value: Boolean);
procedure SetZOrderPosition(Position: Integer);
protected
function GetClientLeft: Integer; virtual;
function GetClientRect: TRect; virtual;
function GetClientTop: Integer; virtual;
function GetEnabled: Boolean; virtual;
function GetHandle: TWControl; virtual;
procedure AssignTo(Dest: TPersistent); override;
procedure Paint; dynamic; abstract;
procedure ReadState(Reader: TReader); override;
procedure Resize; dynamic;
procedure SetControlManager(AControlManager: TCustomManager); virtual;
procedure SetEnabled(Value: Boolean); virtual;
procedure SetHeight(Value: Integer); virtual;
procedure SetLeft(Value: Integer); virtual;
procedure SetParent(AParent: TWControl); virtual;
procedure SetParentComponent(Value: TComponent); override;
procedure SetTop(Value: Integer); virtual;
procedure SetWidth(Value: Integer); virtual;
procedure SetZOrder(TopMost: Boolean); dynamic;
public
procedure Click; dynamic;
procedure DblClick; dynamic;
procedure MouseEnter; dynamic;
procedure MouseLeave; dynamic;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); dynamic;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); dynamic;
function MouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean; dynamic;
function MouseWheelDown(Shift: TShiftState; MousePos: TPoint)
: Boolean; dynamic;
function MouseWheelUp(Shift: TShiftState; MousePos: TPoint)
: Boolean; dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetParentComponent: TComponent; override;
function IsVisible: Boolean; virtual;
function HasParent: Boolean; override;
procedure Assign(Source: TPersistent); override;
procedure BringToFront;
procedure SendToBack;
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual;
property ClientLeft: Integer read GetClientLeft;
property ClientTop: Integer read GetClientTop;
property ClientRect: TRect read GetClientRect;
property ControlManager: TCustomManager read GetControlManager;
property ControlState: TControlState read FControlState write FControlState;
property Handle: TWControl read GetHandle;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel
write FOnMouseWheel;
property OnMouseWheelDown: TMouseWheelUpDownEvent read FOnMouseWheelDown
write FOnMouseWheelDown;
property OnMouseWheelUp: TMouseWheelUpDownEvent read FOnMouseWheelUp
write FOnMouseWheelUp;
property OnResize: TNotifyEvent read FOnResize write FOnResize;
property Parent: TWControl read GetParent;
property WheelAccumulator: Integer read FWheelAccumulator
write FWheelAccumulator;
published
property Enabled: Boolean read GetEnabled write SetEnabled;
property Height: Integer read FHeight write SetHeight;
property Left: Integer read FLeft write SetLeft;
property Top: Integer read FTop write SetTop;
property Width: Integer read FWidth write SetWidth;
property Visible: Boolean read FVisible write SetVisible;
end;
TAControlClass = class of TAControl;
{$ENDREGION}
{$REGION 'TWControl'}
TWControl = class(TAControl)
private
FControls: TList;
FTabList: TList;
FTabStop: Boolean;
FWControls: TList;
FOnEnter: TNotifyEvent;
FOnExit: TNotifyEvent;
FOnKeyDown: TKeyEvent;
FOnKeyPress: TKeyPressEvent;
FOnKeyUp: TKeyEvent;
function GetControl(Index: Integer): TAControl;
function GetControlCount: Integer;
function GetTabOrder: TTabOrder;
procedure Insert(AControl: TAControl);
procedure Remove(AControl: TAControl);
procedure SetTabOrder(Value: TTabOrder);
procedure SetTabStop(Value: Boolean);
procedure SetZOrderPosition(Position: Integer);
procedure UpdateTabOrder(Value: TTabOrder);
protected
function FindNextControl(CurControl: TWControl;
GoForward, CheckTabStop, CheckParent: Boolean): TWControl;
function GetChildOwner: TComponent; override;
procedure AssignTo(Dest: TPersistent); override;
procedure Paint; override;
procedure SetChildOrder(Child: TComponent; Order: Integer); override;
procedure SetZOrder(TopMost: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function CanFocus: Boolean; dynamic;
function ControlAtPos(const Pos: TPoint; AllowDisabled: Boolean;
AllowWControls: Boolean = False; AllLevels: Boolean = False): TAControl;
function FindChildControl(const ControlName: string;
AllLevels: Boolean = False): TAControl;
function GetControls: TList;
function GetWControls: TList;
procedure DoEnter; dynamic;
procedure DoExit; dynamic;
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
procedure GetTabOrderList(List: TList); dynamic;
procedure InsertControl(AControl: TAControl);
procedure KeyDown(var Key: Word; Shift: TShiftState); dynamic;
procedure KeyUp(var Key: Word; Shift: TShiftState); dynamic;
procedure KeyPress(var Key: Char); dynamic;
procedure RemoveControl(AControl: TAControl);
procedure SelectFirst;
procedure SelectNext(CurControl: TWControl;
GoForward, CheckTabStop: Boolean);
procedure SetFocus; virtual;
property Controls[Index: Integer]: TAControl read GetControl;
property ControlCount: Integer read GetControlCount;
property OnEnter: TNotifyEvent read FOnEnter write FOnEnter;
property OnExit: TNotifyEvent read FOnExit write FOnExit;
property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
property OnKeyPress: TKeyPressEvent read FOnKeyPress write FOnKeyPress;
property OnKeyUp: TKeyEvent read FOnKeyUp write FOnKeyUp;
published
property TabOrder: TTabOrder read GetTabOrder write SetTabOrder;
property TabStop: Boolean read FTabStop write SetTabStop;
end;
TWControlClass = class of TWControl;
{$ENDREGION}
{$REGION 'TWRoot'}
TWRoot = class(TWControl)
private
FFonts: TAStringList;
FImages: TAStringList;
procedure SetFonts(Value: TAStringList);
procedure SetImages(Value: TAStringList);
protected
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Fonts: TAStringList read FFonts write SetFonts;
property Images: TAStringList read FImages write SetImages;
end;
{$ENDREGION}
{$REGION 'TCustomManager'}
TCustomManager = class(TObject)
private
FDevice: TAsphyreDevice;
FCanvas: TAsphyreCanvas;
FImages: TAsphyreImages;
FFonts: TAsphyreFonts;
FActiveControl: TWControl;
FPrevControl: TAControl;
FRoot: TWRoot;
FActive: Boolean;
FLoading: Boolean;
FDesign: Boolean;
FOwnerClick: TNotifyEvent;
FOwnerDblClick: TNotifyEvent;
FOwnerKeyDown: TKeyEvent;
FOwnerKeyPress: TKeyPressEvent;
FOwnerKeyUp: TKeyEvent;
FOwnerMouseLeave: TNotifyEvent;
FOwnerMouseEnter: TNotifyEvent;
FOwnerMouseDown: TMouseEvent;
FOwnerMouseUp: TMouseEvent;
FOwnerMouseMove: TMouseMoveEvent;
FOwnerMouseWheel: TMouseWheelEvent;
FOwnerMouseWheelDown: TMouseWheelUpDownEvent;
FOwnerMouseWheelUp: TMouseWheelUpDownEvent;
FOwnerShortCut: TShortCutEvent;
procedure SetActiveControl(const Control: TWControl);
procedure SetDesign(const Value: Boolean);
procedure SetLoading(const Value: Boolean);
protected
FParent: TComponent;
procedure SetParent(const AParent: TComponent); virtual;
property OwnerClick: TNotifyEvent read FOwnerClick write FOwnerClick;
property OwnerDblClick: TNotifyEvent read FOwnerDblClick
write FOwnerDblClick;
property OwnerKeyDown: TKeyEvent read FOwnerKeyDown write FOwnerKeyDown;
property OwnerKeyPress: TKeyPressEvent read FOwnerKeyPress
write FOwnerKeyPress;
property OwnerKeyUp: TKeyEvent read FOwnerKeyUp write FOwnerKeyUp;
property OwnerMouseEnter: TNotifyEvent read FOwnerMouseEnter
write FOwnerMouseEnter;
property OwnerMouseLeave: TNotifyEvent read FOwnerMouseLeave
write FOwnerMouseLeave;
property OwnerMouseDown: TMouseEvent read FOwnerMouseDown
write FOwnerMouseDown;
property OwnerMouseUp: TMouseEvent read FOwnerMouseUp write FOwnerMouseUp;
property OwnerMouseMove: TMouseMoveEvent read FOwnerMouseMove
write FOwnerMouseMove;
property OwnerMouseWheel: TMouseWheelEvent read FOwnerMouseWheel
write FOwnerMouseWheel;
property OwnerMouseWheelDown: TMouseWheelUpDownEvent
read FOwnerMouseWheelDown write FOwnerMouseWheelDown;
property OwnerMouseWheelUp: TMouseWheelUpDownEvent read FOwnerMouseWheelUp
write FOwnerMouseWheelUp;
property OwnerShortCut: TShortCutEvent read FOwnerShortCut
write FOwnerShortCut;
public
constructor Create(const AOwner: TComponent; const ADevice: TAsphyreDevice;
const ACanvas: TAsphyreCanvas); virtual;
destructor Destroy; override;
function LoadFromArchive(const Archive: TAsphyreArchive): Boolean;
function LoadFromArchiveFile(const FileName: string): Boolean;
function SaveToArchive(const Archive: TAsphyreArchive): Boolean;
function SaveToArchiveFile(const FileName: string): Boolean;
procedure Render; // Render all Controls.
procedure Clear;
property Active: Boolean read FActive write FActive;
property ActiveControl: TWControl read FActiveControl
write SetActiveControl;
property PreviousControl: TAControl read FPrevControl write FPrevControl;
property DesignMode: Boolean read FDesign write SetDesign;
property Loading: Boolean read FLoading write SetLoading;
property Root: TWRoot read FRoot;
// The root container that contains all the components
property Device: TAsphyreDevice read FDevice write FDevice;
property Canvas: TAsphyreCanvas read FCanvas write FCanvas;
property Fonts: TAsphyreFonts read FFonts write FFonts;
property Images: TAsphyreImages read FImages;
property Parent: TComponent read FParent write SetParent;
end;
TCustomManagerClass = class of TCustomManager;
{$ENDREGION}
var
VirtualPoint: TPoint;
implementation
{$REGION 'TAControl'}
{ TAControl }
procedure TAControl.Assign(Source: TPersistent);
begin
ControlState := ControlState + [csReadingState];
inherited;
ControlState := ControlState - [csReadingState];
end;
procedure TAControl.AssignTo(Dest: TPersistent);
begin
if Dest is TAControl then
with TAControl(Dest) do
begin
// inherited properties
try
Name := Self.Name;
except
on EComponentError do
begin
end;
end;
Tag := Self.Tag;
Enabled := Self.Enabled;
Height := Self.Height;
Left := Self.Left;
OnClick := Self.OnClick;
OnDblClick := Self.OnDblClick;
OnMouseLeave := Self.OnMouseLeave;
OnMouseEnter := Self.OnMouseEnter;
OnMouseDown := Self.OnMouseDown;
OnMouseMove := Self.OnMouseMove;
OnMouseUp := Self.OnMouseUp;
OnMouseWheel := Self.OnMouseWheel;
OnMouseWheelDown := Self.OnMouseWheelDown;
OnMouseWheelUp := Self.OnMouseWheelUp;
OnResize := Self.OnResize;
Top := Self.Top;
WheelAccumulator := Self.WheelAccumulator;
Width := Self.Width;
Visible := Self.Visible;
end
else
inherited AssignTo(Dest);
end;
procedure TAControl.BringToFront;
begin
SetZOrder(True);
end;
procedure TAControl.Click;
var
BoundsRect: TRect;
begin
BoundsRect := Rect(ClientLeft, ClientTop, ClientLeft + Width,
ClientTop + Height);
if (PtInRect(BoundsRect, VirtualPoint)) then
if Assigned(FOnClick) then
FOnClick(Self);
end;
constructor TAControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FLeft := 0;
FTop := 0;
FWidth := 0;
FHeight := 0;
FHandle := Self;
FEnabled := True;
FVisible := True;
if (AOwner <> nil) and (AOwner <> Self) and (AOwner is TWControl) then
begin
TWControl(AOwner).InsertControl(Self);
SetControlManager(TWControl(AOwner).ControlManager);
end;
end;
procedure TAControl.DblClick;
var
BoundsRect: TRect;
begin
BoundsRect := Rect(ClientLeft, ClientTop, ClientLeft + Width,
ClientTop + Height);
if (PtInRect(BoundsRect, VirtualPoint)) then
if Assigned(FOnDblClick) then
FOnDblClick(Self);
end;
destructor TAControl.Destroy;
begin
inherited;
end;
function TAControl.GetClientLeft: Integer;
var
Temp: TWControl;
begin
Temp := Parent;
Result := FLeft;
while Temp <> nil do
begin
Result := Result + Temp.FLeft;
Temp := Temp.Parent;
end;
end;
function TAControl.GetClientRect: TRect;
begin
Result.Left := 0;
Result.Top := 0;
Result.Right := Width;
Result.Bottom := Height;
end;
function TAControl.GetClientTop: Integer;
var
Temp: TWControl;
begin
Temp := Parent;
Result := FTop;
while Temp <> nil do
begin
Result := Result + Temp.FTop;
Temp := Temp.Parent;
end;
end;
function TAControl.GetControlManager: TCustomManager;
begin
Result := FControlManager;
end;
function TAControl.GetEnabled: Boolean;
begin
Result := FEnabled;
end;
function TAControl.GetHandle: TWControl;
begin
Result := FHandle;
end;
function TAControl.GetParent: TWControl;
begin
Result := FParent;
end;
function TAControl.GetParentComponent: TComponent;
begin
Result := FParent;
end;
function TAControl.HasParent: Boolean;
begin
Result := FParent <> nil;
end;
function TAControl.IsVisible: Boolean;
var
Temp: TAControl;
begin
Temp := Self;
Result := FVisible;
while Temp.Parent <> nil do
begin
Result := (Result and Temp.FVisible);
Temp := Temp.Parent;
end;
end;
procedure TAControl.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
Include(FControlState, csClicked);
// get the down point
VirtualPoint.X := X;
VirtualPoint.Y := Y;
if ControlManager.ActiveControl <> Self then
begin
// Bring Handle to front and set focus
Handle.BringToFront;
if ControlManager.ActiveControl <> nil then
begin
if (Self is TWControl) then
begin
if TWControl(Self).FindChildControl(ControlManager.ActiveControl.Name) = nil
then
begin
TWControl(Self).SetFocus;
TWControl(Self).SelectFirst;
end;
end
else
begin
if Handle.FindChildControl(ControlManager.ActiveControl.Name) = nil then
begin
Handle.SetFocus;
Handle.SelectFirst;
end;
end;
end
else
begin
Handle.SetFocus;
Handle.SelectFirst;
end;
end;
if Assigned(FOnMouseDown) then
FOnMouseDown(Self, Button, Shift, X, Y);
end;
procedure TAControl.MouseEnter;
begin
if Assigned(FOnMouseEnter) then
FOnMouseEnter(Self);
end;
procedure TAControl.MouseLeave;
begin
if Assigned(FOnMouseLeave) then
FOnMouseLeave(Self);
end;
procedure TAControl.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
// get the current point
VirtualPoint.X := X;
VirtualPoint.Y := Y;
if Assigned(FOnMouseMove) then
FOnMouseMove(Self, Shift, X, Y);
end;
procedure TAControl.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
Exclude(FControlState, csClicked);
// get the release point
VirtualPoint.X := X;
VirtualPoint.Y := Y;
if Assigned(FOnMouseUp) then
FOnMouseUp(Self, Button, Shift, X, Y);
end;
function TAControl.MouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean;
var
IsNeg: Boolean;
begin
Result := False;
if Assigned(FOnMouseWheel) then
FOnMouseWheel(Self, Shift, WheelDelta, MousePos, Result);
if not Result then
begin
Inc(FWheelAccumulator, WheelDelta);
while Abs(FWheelAccumulator) >= WHEEL_DELTA do
begin
IsNeg := FWheelAccumulator < 0;
FWheelAccumulator := Abs(FWheelAccumulator) - WHEEL_DELTA;
if IsNeg then
begin
if FWheelAccumulator <> 0 then
FWheelAccumulator := -FWheelAccumulator;
Result := MouseWheelDown(Shift, MousePos);
end
else
Result := MouseWheelUp(Shift, MousePos);
end;
end;
end;
function TAControl.MouseWheelDown(Shift: TShiftState; MousePos: TPoint)
: Boolean;
begin
Result := False;
if Assigned(FOnMouseWheelDown) then
FOnMouseWheelDown(Self, Shift, MousePos, Result);
end;
function TAControl.MouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
begin
Result := False;
if Assigned(FOnMouseWheelUp) then
FOnMouseWheelUp(Self, Shift, MousePos, Result);
end;
procedure TAControl.ReadState(Reader: TReader);
begin
Include(FControlState, csReadingState);
inherited ReadState(Reader);
Exclude(FControlState, csReadingState);
end;
procedure TAControl.Resize;
begin
if Assigned(FOnResize) then
FOnResize(Self);
end;
procedure TAControl.SendToBack;
begin
SetZOrder(False);
end;
procedure TAControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
if ((ALeft <> FLeft) or (ATop <> FTop) or (AWidth <> FWidth) or
(AHeight <> FHeight)) then
begin
FLeft := ALeft;
FTop := ATop;
FWidth := AWidth;
FHeight := AHeight;
// if not(csLoading in ComponentState) then
Resize;
end;
end;
procedure TAControl.SetControlManager(AControlManager: TCustomManager);
begin
FControlManager := AControlManager;
end;
procedure TAControl.SetEnabled(Value: Boolean);
begin
if FEnabled <> Value then
begin
FEnabled := Value;
end;
end;
procedure TAControl.SetHeight(Value: Integer);
begin
SetBounds(FLeft, FTop, FWidth, Value);
end;
procedure TAControl.SetLeft(Value: Integer);
begin
SetBounds(Value, FTop, FWidth, FHeight);
end;
procedure TAControl.SetParent(AParent: TWControl);
begin
if FParent <> AParent then
begin
if AParent = Self then
Exit;
if FParent <> nil then
Parent.RemoveControl(Self);
if AParent <> nil then
begin
AParent.InsertControl(Self);
end;
end;
end;
procedure TAControl.SetParentComponent(Value: TComponent);
begin
if (Parent <> Value) and (Value is TWControl) then
SetParent(TWControl(Value));
end;
procedure TAControl.SetTop(Value: Integer);
begin
SetBounds(FLeft, Value, FWidth, FHeight);
end;
procedure TAControl.SetVisible(Value: Boolean);
begin
if FVisible <> Value then
begin
FVisible := Value;
// Execute events that possible haven't been executed yet.
if Value = False then
begin
MouseLeave;
if Self is TWControl then
TWControl(Self).DoExit;
end;
end;
end;
procedure TAControl.SetWidth(Value: Integer);
begin
SetBounds(FLeft, FTop, Value, FHeight);
end;
procedure TAControl.SetZOrder(TopMost: Boolean);
var
AParent: TWControl;
begin
AParent := Parent;
if AParent <> nil then
begin
if TopMost then
begin
SetZOrderPosition(AParent.FControls.Count - 1)
end
else
SetZOrderPosition(0);
end;
end;
procedure TAControl.SetZOrderPosition(Position: Integer);
var
I, Count: Integer;
AParent: TWControl;
begin
AParent := Parent;
if AParent <> nil then
begin
I := AParent.FControls.IndexOf(Self);
if I >= 0 then
begin
Count := AParent.FControls.Count;
if Position < 0 then
Position := 0;
if Position >= Count then
Position := Count - 1;
if Position <> I then
begin
AParent.FControls.Delete(I);
AParent.FControls.Insert(Position, Self);
end;
end;
end;
end;
{$ENDREGION}
{$REGION 'TWControl'}
{ TWControl }
procedure TWControl.AssignTo(Dest: TPersistent);
var
I: Integer;
AClass: TAControlClass;
Control: TAControl;
begin
inherited AssignTo(Dest);
if Dest is TWControl then
with TWControl(Dest) do
begin
TabStop := Self.TabStop;
OnEnter := Self.OnEnter;
OnExit := Self.OnExit;
OnKeyDown := Self.OnKeyDown;
OnKeyPress := Self.OnKeyPress;
OnKeyUp := Self.OnKeyUp;
if Self.ControlCount <> 0 then
begin
for I := 0 to Self.ControlCount - 1 do
begin
AClass := TAControlClass(Self.Controls[I].ClassType);
Control := AClass.Create(TWControl(Dest));
Control.Assign(Self.Controls[I]);
end;
end;
end;
end;
function TWControl.CanFocus: Boolean;
var
Control: TWControl;
begin
Result := False;
Control := Self;
while Control.Parent <> ControlManager.Root do
begin
if not(Control.FVisible and Control.Enabled) then
Exit;
Control := Control.Parent;
end;
Result := True;
end;
function TWControl.ControlAtPos(const Pos: TPoint;
AllowDisabled, AllowWControls, AllLevels: Boolean): TAControl;
var
I: Integer;
P: TPoint;
LControl: TAControl;
function GetControlAtPos(AControl: TAControl): Boolean;
begin
with AControl do
begin
P := Point(Pos.X - ClientLeft, Pos.Y - ClientTop);
Result := (PtInRect(ClientRect, P) and
(IsVisible or (IsVisible and (Enabled or AllowDisabled))))
{ or ((IsVisible or (Parent <> ControlManager.Root)) and
PtInRect(ClientRect, P) and (ControlManager.DesignMode)) };
if Result then
LControl := AControl;
end;
end;
begin
LControl := nil;
// // do not check for child controls if self control is not visible
// if (IsVisible = false) {and
// ((Parent = ControlManager.Root) or (ControlManager.DesignMode = False))} then
// begin
// Result := LControl;
// Exit;
// end;
if AllowWControls and (FWControls <> nil) then
for I := FWControls.Count - 1 downto 0 do
begin
if AllLevels then
if TWControl(FWControls[I]).FWControls <> nil then
LControl := TWControl(FWControls[I]).ControlAtPos(Pos, AllowDisabled,
True, True);
// if found a WControl on Sub Level
if (LControl <> nil) then
begin
Break;
end;
// Not found on sub Level, check curent level
if (LControl = nil) and GetControlAtPos(TWControl(FWControls[I])) then
Break;
end;
// find FControls on result WControl
if (LControl <> nil) and (LControl is TWControl) then
if (TWControl(LControl).FControls <> nil) then
for I := TWControl(LControl).FControls.Count - 1 downto 0 do
if GetControlAtPos(TWControl(LControl).FControls[I]) then
Break;
// if nothing found and has FControls, search in FControls list
if (FControls <> nil) and (LControl = nil) then
begin
for I := FControls.Count - 1 downto 0 do
if GetControlAtPos(FControls[I]) then
Break;
end;
Result := LControl;
end;
constructor TWControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FTabStop := False;
end;
destructor TWControl.Destroy;
var
I: Integer;
Instance: TAControl;
begin
Destroying;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
FreeAndNil(Instance);
I := ControlCount;
end;
inherited Destroy;
end;
procedure TWControl.DoEnter;
begin
if Assigned(FOnEnter) then
FOnEnter(Self);
end;
procedure TWControl.DoExit;
begin
if Assigned(FOnExit) then
FOnExit(Self);
end;
function TWControl.FindChildControl(const ControlName: string;
AllLevels: Boolean): TAControl;
var
I: Integer;
begin
Result := nil;
if FControls <> nil then
for I := 0 to FControls.Count - 1 do
if CompareText(TWControl(FControls[I]).Name, ControlName) = 0 then
begin
Result := TAControl(FControls[I]);
Exit;
end;
if FWControls <> nil then
for I := 0 to FWControls.Count - 1 do
begin
if CompareText(TWControl(FWControls[I]).Name, ControlName) = 0 then
begin
Result := TAControl(FWControls[I]);
Exit;
end;
if AllLevels = True then
if TWControl(FWControls[I]).FindChildControl(ControlName, AllLevels) <> nil
then
begin
Result := TWControl(FWControls[I]).FindChildControl(ControlName,
AllLevels);
Exit;
end;
end;
end;
function TWControl.FindNextControl(CurControl: TWControl;
GoForward, CheckTabStop, CheckParent: Boolean): TWControl;
var
I, StartIndex: Integer;
List: TList;
begin
Result := nil;
List := TList.Create;
try
GetTabOrderList(List);
if List.Count > 0 then
begin
StartIndex := List.IndexOf(CurControl);
if StartIndex = -1 then
if GoForward then
StartIndex := List.Count - 1
else
StartIndex := 0;
I := StartIndex;
repeat
if GoForward then
begin
Inc(I);
if I = List.Count then
I := 0;
end
else
begin
if I = 0 then
I := List.Count;
Dec(I);
end;
CurControl := TWControl(List[I]);
if CurControl.CanFocus and (not CheckTabStop or CurControl.TabStop) and
(not CheckParent or (CurControl.Parent = Self)) then
Result := CurControl;
until (Result <> nil) or (I = StartIndex);
end;
finally
List.Free;
end;
end;
function TWControl.GetChildOwner: TComponent;
begin
Result := Self;
end;
procedure TWControl.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
I: Integer;
Control: TAControl;
begin
for I := 0 to ControlCount - 1 do
begin
Control := Controls[I];
// if Control.Owner = Root then
Proc(Control);
end;
end;
function TWControl.GetControl(Index: Integer): TAControl;
var
N: Integer;
begin
if FControls <> nil then
N := FControls.Count
else
N := 0;
if Index < N then
Result := FControls[Index]
else
Result := FWControls[Index - N];
end;
function TWControl.GetControlCount: Integer;
begin
Result := 0;
if FControls <> nil then
Inc(Result, FControls.Count);
if FWControls <> nil then
Inc(Result, FWControls.Count);
end;
function TWControl.GetControls: TList;
begin
Result := FControls;
end;
function TWControl.GetTabOrder: TTabOrder;
begin
if FParent <> nil then
Result := Parent.FTabList.IndexOf(Self)
else
Result := -1;
end;
procedure TWControl.GetTabOrderList(List: TList);
var
I: Integer;
Control: TWControl;
begin
if FTabList <> nil then
for I := 0 to FTabList.Count - 1 do
begin
Control := TWControl(FTabList[I]);
List.Add(Control);
Control.GetTabOrderList(List);
end;
end;
function TWControl.GetWControls: TList;
begin
Result := FWControls
end;
procedure TWControl.Insert(AControl: TAControl);
var
Form: TWControl;
begin
if AControl <> nil then
begin
if AControl is TWControl then
begin
ListAdd(FWControls, AControl);
ListAdd(FTabList, AControl);
end
else
ListAdd(FControls, AControl);
AControl.FParent := Self;
// Get the parent Form from Engine.Root and set it as handler
Form := Self;
if (ControlManager <> nil) then
begin
if not(Form = ControlManager.Root) then
begin
while Form.Parent <> ControlManager.Root do
Form := Form.Parent;
AControl.FHandle := Form;
end
else
begin
AControl.FHandle := AControl;
end;
end;
end;
end;
procedure TWControl.InsertControl(AControl: TAControl);
begin
AControl.ValidateContainer(Self);
Insert(AControl);
end;
procedure TWControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
if (Shift = [ssShift, ssCtrl]) or (Shift = [ssShift]) then
begin
case Key of
vk_Tab:
Self.Handle.SelectNext(Self, False, True);
end;
end;
if (Shift = [ssCtrl]) or (Shift = []) then
begin
case Key of
vk_Tab:
Self.Handle.SelectNext(Self, True, True);
end;
end;
if Assigned(FOnKeyDown) then
FOnKeyDown(Self, Key, Shift);
end;
procedure TWControl.KeyPress(var Key: Char);
begin
if Assigned(FOnKeyPress) then
FOnKeyPress(Self, Key);
end;
procedure TWControl.KeyUp(var Key: Word; Shift: TShiftState);
begin
if Assigned(FOnKeyUp) then
FOnKeyUp(Self, Key, Shift);
end;
procedure TWControl.Paint;
var
Control, WControl: Integer;
begin
if FControls <> nil then
begin
for Control := 0 to FControls.Count - 1 do
begin
with TAControl(FControls[Control]) do
if (Visible) { or (Self.ControlManager.FDesign) } then
Paint;
end;
end;
if FWControls <> nil then
begin
for WControl := 0 to FWControls.Count - 1 do
begin
with TWControl(FWControls[WControl]) do
if (Visible) { or (Self.ControlManager.FDesign) } then
Paint;
end;
end;
end;
procedure TWControl.Remove(AControl: TAControl);
begin
if AControl is TWControl then
begin
ListRemove(FTabList, AControl);
ListRemove(FWControls, AControl);
end
else
ListRemove(FControls, AControl);
AControl.FParent := nil;
AControl.FHandle := AControl;
end;
procedure TWControl.RemoveControl(AControl: TAControl);
begin
Remove(AControl);
end;
procedure TWControl.SelectFirst;
var
Control: TWControl;
begin
Control := FindNextControl(nil, True, True, False);
if Control = nil then
Control := FindNextControl(nil, True, False, False);
if Control <> nil then
begin
Control.SetFocus;
end;
end;
procedure TWControl.SelectNext(CurControl: TWControl;
GoForward, CheckTabStop: Boolean);
begin
CurControl := FindNextControl(CurControl, GoForward, CheckTabStop,
not CheckTabStop);
if CurControl <> nil then
CurControl.SetFocus;
end;
procedure TWControl.SetChildOrder(Child: TComponent; Order: Integer);
begin
if Child is TWControl then
TWControl(Child).SetZOrderPosition(Order)
else if Child is TAControl then
TAControl(Child).SetZOrderPosition(Order);
end;
procedure TWControl.SetFocus;
var
Control: TWControl;
begin
Control := Self;
if Control.CanFocus then
begin
if ControlManager.ActiveControl <> nil then
if ControlManager.ActiveControl <> Control then
ControlManager.ActiveControl.DoExit;
ControlManager.ActiveControl := Control;
Control.DoEnter;
end;
end;
procedure TWControl.SetTabOrder(Value: TTabOrder);
begin
UpdateTabOrder(Value);
end;
procedure TWControl.SetTabStop(Value: Boolean);
begin
if FTabStop <> Value then
begin
FTabStop := Value;
end;
end;
procedure TWControl.SetZOrder(TopMost: Boolean);
var
N, M: Integer;
begin
if FParent <> nil then
begin
if TopMost then
N := Parent.FWControls.Count - 1
else
N := 0;
M := 0;
if Parent.FControls <> nil then
M := Parent.FControls.Count;
SetZOrderPosition(M + N);
end;
end;
procedure TWControl.SetZOrderPosition(Position: Integer);
var
I, Count: Integer;
begin
if FParent <> nil then
begin
if Parent.FControls <> nil then
Dec(Position, Parent.FControls.Count);
I := Parent.FWControls.IndexOf(Self);
if I >= 0 then
begin
Count := Parent.FWControls.Count;
if Position < 0 then
Position := 0;
if Position >= Count then
Position := Count - 1;
if Position <> I then
begin
Parent.FWControls.Delete(I);
Parent.FWControls.Insert(Position, Self);
end;
end;
end;
end;
procedure TWControl.UpdateTabOrder(Value: TTabOrder);
var
CurIndex, Count: Integer;
begin
CurIndex := GetTabOrder;
if CurIndex >= 0 then
begin
Count := Parent.FTabList.Count;
if Value < 0 then
Value := 0;
if Value >= Count then
Value := Count - 1;
if Value <> CurIndex then
begin
Parent.FTabList.Delete(CurIndex);
Parent.FTabList.Insert(Value, Self);
end;
end;
end;
{$ENDREGION}
{$REGION 'TWRoot'}
{ TWRoot }
procedure TWRoot.AssignTo(Dest: TPersistent);
begin
inherited AssignTo(Dest);
if Dest is TWRoot then
with TWRoot(Dest) do
begin
Fonts := Self.Fonts;
Images := Self.Images;
end;
end;
constructor TWRoot.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFonts := TAStringList.Create;
FImages := TAStringList.Create;
end;
destructor TWRoot.Destroy;
begin
FFonts.Free;
FImages.Free;
inherited;
end;
procedure TWRoot.SetFonts(Value: TAStringList);
begin
if (Value <> nil) then
FFonts.Assign(Value);
end;
procedure TWRoot.SetImages(Value: TAStringList);
begin
if Value <> nil then
FImages.Assign(Value);
end;
{$ENDREGION}
{$REGION 'TCustomManager'}
{ TCustomManager }
procedure TCustomManager.Clear;
var
I: Integer;
Instance: TAControl;
begin
FActiveControl := nil;
FPrevControl := nil;
I := FRoot.ControlCount;
while I <> 0 do
begin
Instance := FRoot.Controls[I - 1];
FRoot.Remove(Instance);
FreeAndNil(Instance);
I := FRoot.ControlCount;
end;
// Clear Font and Image Lists
FRoot.Fonts.Clear;
FRoot.Images.Clear;
// free current fonts
FFonts.RemoveAll;
FFonts.Images.RemoveAll;
FFonts.Canvas := FCanvas;
// free current images
FImages.RemoveAll;
end;
constructor TCustomManager.Create(const AOwner: TComponent;
const ADevice: TAsphyreDevice; const ACanvas: TAsphyreCanvas);
begin
FDevice := ADevice;
FCanvas := ACanvas;
FFonts := TAsphyreFonts.Create;
FFonts.Images := TAsphyreImages.Create;
FImages := TAsphyreImages.Create;
Parent := AOwner;
FRoot := TWRoot.Create(nil);
FRoot.Left := 0;
FRoot.Top := 0;
if ADevice <> nil then
begin
FRoot.Width := ADevice.SwapChains.Items[0].Width;
FRoot.Height := ADevice.SwapChains.Items[0].Height;
end
else
begin
FRoot.Width := 0;
FRoot.Height := 0;
end;
FRoot.FControlManager := Self;
FDesign := False;
FActive := True;
FLoading := False;
end;
destructor TCustomManager.Destroy;
begin
FDevice := nil;
FCanvas := nil;
FParent := nil;
FFonts.Images.RemoveAll;
FFonts.Images.Free;
FImages.RemoveAll;
FreeAndNil(FFonts);
FreeAndNil(FImages);
FreeAndNil(FRoot);
inherited Destroy;
end;
function TCustomManager.LoadFromArchive(const Archive: TAsphyreArchive)
: Boolean;
var
AControl: TWRoot;
Stream: TMemoryStream;
I: Integer;
begin
// Clear all controls
Self.Clear;
Stream := TMemoryStream.Create();
Result := Archive.ReadMemStream('Interface.ui', Stream);
if Result = True then
begin
try
AControl := Stream.ReadComponent(nil) as TWRoot;
Root.Assign(AControl);
finally
FreeAndNil(AControl);
end;
// Set Device size again
if FDevice <> nil then
begin
FRoot.Width := FDevice.SwapChains.Items[0].Width;
FRoot.Height := FDevice.SwapChains.Items[0].Height;
end;
if FRoot.Fonts.Count > 0 then
begin
for I := 0 to FRoot.Fonts.Count - 1 do
FFonts.InsertFromArchive(FRoot.Fonts.Items[I], Archive, foFonts);
end;
if FRoot.Images.Count > 0 then
begin
for I := 0 to FRoot.Images.Count - 1 do
FImages.InsertFromArchive(FRoot.Images.Items[I], Archive, foImages);
end;
end;
Stream.Free();
end;
function TCustomManager.LoadFromArchiveFile(const FileName: string): Boolean;
var
Media: TAsphyreArchive;
begin
Media := TAsphyreArchive.Create;
ArchiveTypeAccess := ataAnyFile;
Media.OpenMode := aomReadOnly;
Result := Media.OpenFile(FileName);
if Result = True then
begin
LoadFromArchive(Media);
end;
Media.Free;
end;
procedure TCustomManager.Render;
begin
if FLoading then
Exit;
FRoot.Paint;
end;
function TCustomManager.SaveToArchive(const Archive: TAsphyreArchive): Boolean;
var
Stream: TMemoryStream;
I: Integer;
begin
Result := False;
if Archive = nil then
Exit;
if (FFonts.Count > 0) then
begin
if not(FFonts.SaveAllToArchive(Archive, foFonts)) then
begin
Exit;
end;
FRoot.Fonts.Clear;
for I := 0 to FFonts.Count - 1 do
begin
FRoot.Fonts.Add(FFonts.Items[I].Name);
end;
end;
if (FImages.ItemCount > 0) then
begin
if not(FImages.SaveAllToArchive(Archive, foImages)) then
begin
Exit;
end;
FRoot.Images.Clear;
for I := 0 to FImages.ItemCount - 1 do
begin
if not (Assigned(Self.Images[I])) then
begin
Continue;
end;
FRoot.Images.Add(FImages.Items[I].Name);
end;
end;
Stream := TMemoryStream.Create();
Stream.WriteComponent(FRoot);
Result := Archive.WriteRecord('Interface.ui', Stream.Memory,
Stream.Size, artFile);
Stream.Free();
end;
function TCustomManager.SaveToArchiveFile(const FileName: string): Boolean;
var
Media: TAsphyreArchive;
begin
Media := TAsphyreArchive.Create;
ArchiveTypeAccess := ataAnyFile;
Media.OpenMode := aomOverwrite;
Result := Media.OpenFile(FileName);
if (Result = True) then
begin
SaveToArchive(Media);
end;
Media.Free;
end;
procedure TCustomManager.SetActiveControl(const Control: TWControl);
begin
if FActiveControl <> Control then
FActiveControl := Control;
end;
procedure TCustomManager.SetDesign(const Value: Boolean);
begin
if FDesign <> Value then
FDesign := Value;
end;
procedure TCustomManager.SetLoading(const Value: Boolean);
begin
if FLoading <> Value then
FLoading := Value;
end;
procedure TCustomManager.SetParent(const AParent: TComponent);
begin
if FParent <> AParent then
begin
FParent := AParent;
end;
end;
{$ENDREGION}
initialization
RegisterClasses([TAControl, TWControl, TWRoot]);
finalization
UnRegisterClasses([TAControl, TWControl, TWRoot]);
end.
