You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6969 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1141 lines
32 KiB
ObjectPascal
1141 lines
32 KiB
ObjectPascal
{ Modified for Lazarus by Costas Velissariou (velissariouc@gmail.com) 04/01/2011}
|
|
|
|
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (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/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvDesingSurface.pas, released on 2005-08-21.
|
|
|
|
The Initial Developer of the Original Code is Scott J Miles
|
|
Portions created by Scott J Miles are Copyright (C) 2005 Scott J Miles.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s): Olivier Sannier (JVCL Integration)
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL
|
|
home page, located at http://jvcl.delphi-jedi.org
|
|
|
|
Known Issues:
|
|
Mantis 3963: When a design surface is active, the ENTIRE form where it is
|
|
located suffers impacts from being in design mode. This can not
|
|
be circumvented because the Designer property is to be set on
|
|
the parent form and it MUST be set for the design mode to be
|
|
effective. The only workaround is to not have anything else
|
|
on the form being designed.
|
|
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvDesignSurface.pas 12931 2010-11-28 13:36:50Z ahuser $
|
|
|
|
unit JvDesignSurface;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$DEFINE NO_DESIGNHOOK}
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
LCLProc, LCLType, LResources, LCLIntf, LMessages,
|
|
Forms, Controls, Graphics, Dialogs, ExtCtrls;
|
|
|
|
type
|
|
TJvDesignSurface = class;
|
|
|
|
TJvDesignMessage = function(ASender: TControl; var AMsg: TLMessage;
|
|
const APt: TPoint): Boolean of object;
|
|
|
|
TJvDesignCustomMessenger = class(TObject)
|
|
private
|
|
FContainer: TWinControl;
|
|
FOnDesignMessage: TJvDesignMessage;
|
|
protected
|
|
procedure SetContainer(AValue: TWinControl); virtual;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
function IsDesignMessage(ASender: TControl; var AMessage: TLMessage): Boolean; virtual;
|
|
procedure Clear; virtual;
|
|
procedure DesignChildren(AContainer: TWinControl; ADesigning: Boolean);
|
|
procedure DesignComponent({%H-}AComponent: TComponent; {%H-}ADesigning: Boolean); virtual;
|
|
property Container: TWinControl read FContainer write SetContainer;
|
|
property OnDesignMessage: TJvDesignMessage read FOnDesignMessage write FOnDesignMessage;
|
|
end;
|
|
|
|
TJvDesignCustomMessengerClass = class of TJvDesignCustomMessenger;
|
|
|
|
TJvDesignMessageHook = class(TObject)
|
|
private
|
|
FClient: TWinControl;
|
|
FOldProc: TWndMethod;
|
|
FUser: TJvDesignCustomMessenger;
|
|
protected
|
|
procedure HookProc(var AMessage: TLMessage);
|
|
procedure Unhook;
|
|
public
|
|
constructor Create(AUser: TJvDesignCustomMessenger; AClient: TWinControl);
|
|
destructor Destroy; override;
|
|
property Client: TWinControl read FClient;
|
|
end;
|
|
|
|
TJvDesignCustomController = class(TObject)
|
|
private
|
|
FSurface: TJvDesignSurface;
|
|
FShift: TShiftState; //CV
|
|
protected
|
|
function GetDragRect: TRect; virtual; abstract;
|
|
//CV function GetShift: TShiftState;
|
|
function KeyDown(AKeyCode: Cardinal): Boolean; virtual; abstract;
|
|
function KeyUp(AKeyCode: Cardinal): Boolean; virtual; abstract;
|
|
function MouseDown(Button: TMouseButton; X, Y: Integer; TheMessage: TLMMouse): Boolean; virtual; abstract;
|
|
function MouseMove(X, Y: Integer; TheMessage: TLMMouse): Boolean; virtual; abstract;
|
|
function MouseUp(Button: TMouseButton; X, Y: Integer; TheMessage: TLMMouse): Boolean; virtual; abstract;
|
|
public
|
|
constructor Create(ASurface: TJvDesignSurface); virtual;
|
|
property DragRect: TRect read GetDragRect;
|
|
property Shift666: TShiftState read FShift write FShift; //CV
|
|
property Surface: TJvDesignSurface read FSurface;
|
|
end;
|
|
|
|
TJvDesignCustomControllerClass = class of TJvDesignCustomController;
|
|
|
|
TJvDesignHandleId = (dhNone, dhLeftTop, dhMiddleTop, dhRightTop, dhLeftMiddle,
|
|
dhRightMiddle, dhLeftBottom, dhMiddleBottom, dhRightBottom);
|
|
|
|
TJvDesignCustomSelector = class(TComponent)
|
|
private
|
|
FSurface: TJvDesignSurface;
|
|
protected
|
|
function GetCount: Integer; virtual; abstract;
|
|
function GetSelection(AIndex: Integer): TControl; virtual; abstract;
|
|
procedure SetSelection(AIndex: Integer; AValue: TControl); virtual; abstract;
|
|
public
|
|
constructor Create(ASurface: TJvDesignSurface); reintroduce; virtual;
|
|
destructor Destroy; override;
|
|
function IsSelected(AValue: TControl): Boolean; virtual; abstract;
|
|
function GetClientControl(AControl: TControl): TControl; virtual; abstract;
|
|
function GetCursor(AX, AY: Integer): TCursor; virtual; abstract;
|
|
function GetHitHandle(AX, AY: Integer): TJvDesignHandleId; virtual; abstract;
|
|
procedure AddToSelection(AValue: TControl); virtual; abstract;
|
|
procedure ClearSelection; virtual; abstract;
|
|
procedure RemoveFromSelection(AValue: TControl); virtual; abstract;
|
|
procedure ToggleSelection(AValue: TControl);
|
|
procedure Update; virtual; abstract;
|
|
property Count: Integer read GetCount;
|
|
property Selection[AIndex: Integer]: TControl read GetSelection write SetSelection;
|
|
property Surface: TJvDesignSurface read FSurface;
|
|
end;
|
|
|
|
TJvDesignCustomSelectorClass = class of TJvDesignCustomSelector;
|
|
|
|
TJvDesignObjectArray = array of TObject;
|
|
TJvDesignGetAddClassEvent = procedure(Sender: TObject; var ioClass: string) of object;
|
|
{
|
|
TJvDesignOwnerDrawGridEvent = procedure(ASender: TObject; ACanvas: TCanvas;
|
|
ARect: TRect) of object;
|
|
}
|
|
|
|
TJvDesignSurface = class(TComponent)
|
|
private
|
|
FActive: Boolean;
|
|
FAddClass: string;
|
|
FContainer: TWinControl;
|
|
FContainerHook: TJvDesignMessageHook;
|
|
FController: TJvDesignCustomController;
|
|
FControllerClass: TJvDesignCustomControllerClass;
|
|
// FDrawGrid: Boolean;
|
|
FMessenger: TJvDesignCustomMessenger;
|
|
FMessengerClass: TJvDesignCustomMessengerClass;
|
|
FSelector: TJvDesignCustomSelector;
|
|
FSelectorClass: TJvDesignCustomSelectorClass;
|
|
FUpdateOwner: TComponent;
|
|
protected
|
|
FOnChange: TNotifyEvent;
|
|
FOnGetAddClass: TJvDesignGetAddClassEvent;
|
|
// FOnOwnerDrawGrid: TJvDesignOwnerDrawGridEvent;
|
|
FOnSelectionChange: TNotifyEvent;
|
|
function GetAddBounds: TRect;
|
|
function GetCount: Integer;
|
|
function GetSelected: TJvDesignObjectArray;
|
|
function GetSelectedContainer: TWinControl;
|
|
function GetSelection(AIndex: Integer): TControl;
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
procedure NeedContainer;
|
|
procedure NeedController;
|
|
procedure NeedMessenger;
|
|
procedure NeedSelector;
|
|
//procedure PaintContainerBkgnd(ADC: HDC);
|
|
procedure ReaderError({%H-}Reader: TReader; const {%H-}Msg: string; var Handled: Boolean);
|
|
procedure SetActive(AValue: Boolean);
|
|
procedure SetContainer(AValue: TWinControl);
|
|
//procedure SetDrawGrid(const Value: Boolean);
|
|
procedure SetSelection(AIndex: Integer; AValue: TControl);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function Clear: TJvDesignSurface;
|
|
function ContainerToSelectedContainer(const APt: TPoint): TPoint;
|
|
function FindControl(AX, AY: Integer): TControl; virtual;
|
|
function GetCursor(AX, AY: Integer): TCursor; virtual;
|
|
function GetHitHandle(AX, AY: Integer): TJvDesignHandleId; virtual;
|
|
function IsDesignMessage(ASender: TControl; var AMsg: TLMessage; const APt: TPoint): Boolean;
|
|
function LoadFromFile(const AFileName: string): TJvDesignSurface;
|
|
function LoadFromStream(AStream: TStream): TJvDesignSurface;
|
|
procedure AddComponent;
|
|
procedure Change;
|
|
procedure ClearSelection;
|
|
procedure CopyComponents;
|
|
procedure CutComponents;
|
|
procedure DeleteComponents;
|
|
procedure GetAddClass;
|
|
procedure GrowComponents(AGrowWidth, AGrowHeight: Integer);
|
|
procedure NudgeComponents(ANudgeLeft, ANudgeTop: Integer);
|
|
procedure PasteComponents;
|
|
procedure SaveToFile(const AFileName: string);
|
|
procedure SaveToStream(AStream: TStream);
|
|
procedure Select(AControl: TControl);
|
|
procedure SelectionChange;
|
|
procedure SelectParent;
|
|
procedure SetSelected(const AValue: array of TObject);
|
|
procedure UpdateDesigner; virtual;
|
|
property Active: Boolean read FActive write SetActive;
|
|
property AddClass: string read FAddClass write FAddClass;
|
|
property Controller: TJvDesignCustomController read FController;
|
|
property ControllerClass: TJvDesignCustomControllerClass read FControllerClass write FControllerClass;
|
|
property Count: Integer read GetCount;
|
|
property Messenger: TJvDesignCustomMessenger read FMessenger;
|
|
property MessengerClass: TJvDesignCustomMessengerClass read FMessengerClass write FMessengerClass;
|
|
property Selected: TJvDesignObjectArray read GetSelected;
|
|
property SelectedContainer: TWinControl read GetSelectedContainer;
|
|
property Selection[AIndex: Integer]: TControl read GetSelection write SetSelection;
|
|
property Selector: TJvDesignCustomSelector read FSelector;
|
|
property SelectorClass: TJvDesignCustomSelectorClass read FSelectorClass write FSelectorClass;
|
|
published
|
|
property Container: TWinControl read FContainer write SetContainer;
|
|
// property DrawGrid: Boolean read FDrawGrid write SetDrawGrid default True;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnGetAddClass: TJvDesignGetAddClassEvent read FOnGetAddClass write FOnGetAddClass;
|
|
// property OnOwnerDrawGrid: TJvDesignOwnerDrawGridEvent read FOnOwnerDrawGrid write FOnOwnerDrawGrid;
|
|
property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
|
|
end;
|
|
|
|
TJvDesignScrollBox = class(TScrollBox)
|
|
protected
|
|
procedure AutoScrollInView({%H-}AControl: TControl); //CV override;
|
|
end;
|
|
|
|
TJvDesignPanel = class(TPanel)
|
|
private
|
|
FSurface: TJvDesignSurface;
|
|
FOnPaint: TNotifyEvent;
|
|
FDrawRules: Boolean;
|
|
function GetActive: Boolean;
|
|
function GetOnChange: TNotifyEvent;
|
|
function GetOnGetAddClass: TJvDesignGetAddClassEvent;
|
|
function GetOnSelectionChange: TNotifyEvent;
|
|
procedure SetActive(const Value: Boolean);
|
|
procedure SetOnChange(const Value: TNotifyEvent);
|
|
procedure SetOnGetAddClass(const Value: TJvDesignGetAddClassEvent);
|
|
procedure SetOnSelectionChange(const Value: TNotifyEvent);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
procedure Clear;
|
|
procedure LoadFromFile(const AFileName: string);
|
|
procedure LoadFromStream(AStream: TStream);
|
|
procedure Paint; override;
|
|
procedure SaveToFile(const AFileName: string);
|
|
procedure SaveToStream(AStream: TStream);
|
|
procedure SetDrawRules(const Value: Boolean);
|
|
property Active: Boolean read GetActive write SetActive;
|
|
property Canvas;
|
|
property Surface: TJvDesignSurface read FSurface;
|
|
published
|
|
property DrawRules: Boolean read FDrawRules write SetDrawRules default True;
|
|
property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
|
|
property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
|
|
property OnGetAddClass: TJvDesignGetAddClassEvent read GetOnGetAddClass write SetOnGetAddClass;
|
|
property OnSelectionChange: TNotifyEvent read GetOnSelectionChange write SetOnSelectionChange;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
Clipbrd,
|
|
Types, //CV
|
|
JvDesignUtils, JvDesignClip, JvDesignImp, JvResources, JvTypes;
|
|
|
|
|
|
//=== { TJvDesignCustomMessenger } ===========================================
|
|
|
|
constructor TJvDesignCustomMessenger.Create;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
destructor TJvDesignCustomMessenger.Destroy;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TJvDesignCustomMessenger.Clear;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TJvDesignCustomMessenger.DesignComponent(AComponent: TComponent; ADesigning: Boolean);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
procedure TJvDesignCustomMessenger.DesignChildren(AContainer: TWinControl; ADesigning: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to AContainer.ControlCount - 1 do
|
|
DesignComponent(AContainer.Controls[I], ADesigning);
|
|
end;
|
|
|
|
procedure TJvDesignCustomMessenger.SetContainer(AValue: TWinControl);
|
|
begin
|
|
FContainer := AValue;
|
|
end;
|
|
|
|
function TJvDesignCustomMessenger.IsDesignMessage(ASender: TControl;
|
|
var AMessage: TLMessage): Boolean;
|
|
|
|
function MousePoint: TPoint;
|
|
begin
|
|
with TLMMouse(AMessage) do
|
|
MousePoint := Point(XPos, YPos);
|
|
Result := DesignClientToParent(Result, ASender, Container);
|
|
end;
|
|
|
|
begin
|
|
if not Assigned(FOnDesignMessage) then
|
|
Result := False
|
|
else
|
|
case AMessage.Msg of
|
|
LM_MOUSEFIRST..LM_MOUSELAST:
|
|
Result := FOnDesignMessage(ASender, AMessage, MousePoint);
|
|
LM_KEYDOWN..LM_KEYUP, LM_PAINT, LM_ERASEBKGND, LM_WINDOWPOSCHANGED, CN_KEYDOWN..CN_KEYUP:
|
|
Result := FOnDesignMessage(ASender, AMessage, Point(0, 0));
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvDesignMessageHook } ===============================================
|
|
|
|
constructor TJvDesignMessageHook.Create(AUser: TJvDesignCustomMessenger;
|
|
AClient: TWinControl);
|
|
begin
|
|
FUser := AUser;
|
|
FClient := AClient;
|
|
FOldProc := FClient.WindowProc;
|
|
FClient.WindowProc := @HookProc;
|
|
end;
|
|
|
|
destructor TJvDesignMessageHook.Destroy;
|
|
begin
|
|
Unhook;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvDesignMessageHook.Unhook;
|
|
begin
|
|
FClient.WindowProc := FOldProc;
|
|
end;
|
|
|
|
procedure TJvDesignMessageHook.HookProc(var AMessage: TLMessage);
|
|
begin
|
|
if not FUser.IsDesignMessage(FClient, AMessage) then
|
|
FOldProc(AMessage);
|
|
end;
|
|
|
|
//=== { TJvDesignCustomController } ==========================================
|
|
|
|
constructor TJvDesignCustomController.Create(ASurface: TJvDesignSurface);
|
|
begin
|
|
FSurface := ASurface;
|
|
end;
|
|
|
|
//CV
|
|
function KeyboardStateToShiftState(const KeyboardState: TKeyboardState): TShiftState;
|
|
begin
|
|
Result := [];
|
|
if KeyboardState[VK_SHIFT] and $80 <> 0 then Include(Result, ssShift);
|
|
if KeyboardState[VK_CONTROL] and $80 <> 0 then Include(Result, ssCtrl);
|
|
if KeyboardState[VK_MENU] and $80 <> 0 then Include(Result, ssAlt);
|
|
if KeyboardState[VK_LBUTTON] and $80 <> 0 then Include(Result, ssLeft);
|
|
if KeyboardState[VK_RBUTTON] and $80 <> 0 then Include(Result, ssRight);
|
|
if KeyboardState[VK_MBUTTON] and $80 <> 0 then Include(Result, ssMiddle);
|
|
end;
|
|
|
|
{function TJvDesignCustomController.GetShift: TShiftState;
|
|
// obones: For C5/D5 compatibility, we must use a local variable
|
|
// as KeyboardStateToShiftState with no parameters was introduced
|
|
// in D6/C6
|
|
var
|
|
KeyState: TKeyBoardState;
|
|
begin
|
|
//CV GetKeyboardState(KeyState);
|
|
//CV Result := KeyboardStateToShiftState(KeyState);
|
|
end;
|
|
}
|
|
//=== { TJvDesignCustomSelector } ============================================
|
|
|
|
constructor TJvDesignCustomSelector.Create(ASurface: TJvDesignSurface);
|
|
begin
|
|
inherited Create(nil);
|
|
FSurface := ASurface;
|
|
end;
|
|
|
|
destructor TJvDesignCustomSelector.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvDesignCustomSelector.ToggleSelection(AValue: TControl);
|
|
begin
|
|
if IsSelected(AValue) then
|
|
RemoveFromSelection(AValue)
|
|
else
|
|
AddToSelection(AValue);
|
|
end;
|
|
|
|
//=== { TJvDesignSurface } ===================================================
|
|
|
|
constructor TJvDesignSurface.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMessengerClass := TJvDesignDesignerMessenger;
|
|
FControllerClass := TJvDesignController;
|
|
FSelectorClass := TJvDesignSelector;
|
|
//FDrawGrid := True;
|
|
end;
|
|
|
|
destructor TJvDesignSurface.Destroy;
|
|
begin
|
|
FContainerHook.Free;
|
|
Messenger.Free;
|
|
Controller.Free;
|
|
Selector.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.Change;
|
|
begin
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SetContainer(AValue: TWinControl);
|
|
begin
|
|
FContainer := AValue;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.NeedContainer;
|
|
begin
|
|
if (Container = nil) and (Owner is TWinControl) then
|
|
Container := TWinControl(Owner);
|
|
if Container = nil then
|
|
raise EJVCLException.CreateResFmt(@RsEDesignNilFmt, [ClassName, 'Container']);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.NeedController;
|
|
begin
|
|
if (Controller = nil) and (ControllerClass <> nil) then
|
|
FController := ControllerClass.Create(Self);
|
|
if Controller = nil then
|
|
raise EJVCLException.CreateResFmt(@RsEDesignNilFmt, [ClassName, 'Controller']);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.NeedMessenger;
|
|
begin
|
|
if (Messenger = nil) and (MessengerClass <> nil) then
|
|
begin
|
|
FMessenger := MessengerClass.Create;
|
|
Messenger.OnDesignMessage := @IsDesignMessage;
|
|
end;
|
|
if Messenger = nil then
|
|
raise EJVCLException.CreateResFmt(@RsEDesignNilFmt, [ClassName, 'Messenger']);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.NeedSelector;
|
|
begin
|
|
if (Selector = nil) and (SelectorClass <> nil) then
|
|
FSelector := SelectorClass.Create(Self);
|
|
if Selector = nil then
|
|
raise EJVCLException.CreateResFmt(@RsEDesignNilFmt, [ClassName, 'Selector']);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SetActive(AValue: Boolean);
|
|
|
|
procedure Activate;
|
|
begin
|
|
NeedContainer;
|
|
NeedController;
|
|
NeedSelector;
|
|
NeedMessenger;
|
|
Messenger.Container := Container;
|
|
FContainerHook := TJvDesignMessageHook.Create(Messenger, Container);
|
|
end;
|
|
|
|
procedure Deactivate;
|
|
begin
|
|
FreeAndNil(FContainerHook);
|
|
Selector.ClearSelection;
|
|
FreeAndNil(FMessenger);
|
|
end;
|
|
|
|
begin
|
|
if FActive <> AValue then
|
|
begin
|
|
if AValue then
|
|
Activate
|
|
else
|
|
Deactivate;
|
|
FActive := AValue;
|
|
SelectionChange;
|
|
if Assigned(Container) then
|
|
Container.Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.UpdateDesigner;
|
|
begin
|
|
Selector.Update;
|
|
end;
|
|
|
|
function TJvDesignSurface.GetCount: Integer;
|
|
begin
|
|
Result := Selector.Count;
|
|
end;
|
|
|
|
function TJvDesignSurface.GetSelection(AIndex: Integer): TControl;
|
|
begin
|
|
Result := Selector.Selection[AIndex];
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SetSelection(AIndex: Integer; AValue: TControl);
|
|
begin
|
|
Selector.Selection[AIndex] := AValue;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.ClearSelection;
|
|
begin
|
|
Selector.ClearSelection;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SelectionChange;
|
|
begin
|
|
if not (csDestroying in ComponentState) and Assigned(FOnSelectionChange) then
|
|
FOnSelectionChange(Self);
|
|
end;
|
|
|
|
function TJvDesignSurface.GetSelected: TJvDesignObjectArray;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
SetLength(Result, Count);
|
|
for I := 0 to Count - 1 do
|
|
Result[I] := Selector.Selection[I];
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SetSelected(const AValue: array of TObject);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
ClearSelection;
|
|
for I := 0 to Length(AValue) - 1 do
|
|
if AValue[I] is TControl then
|
|
Selector.AddToSelection(TControl(AValue[I]));
|
|
end;
|
|
|
|
procedure TJvDesignSurface.Select(AControl: TControl);
|
|
begin
|
|
ClearSelection;
|
|
if AControl <> nil then
|
|
Selector.AddToSelection(AControl);
|
|
end;
|
|
|
|
function TJvDesignSurface.FindControl(AX, AY: Integer): TControl;
|
|
var
|
|
C, C0: TControl;
|
|
P: TPoint;
|
|
begin
|
|
P := Point(AX, AY);
|
|
C := Container.ControlAtPos(P, True, True);
|
|
while (C <> nil) and (C is TWinControl) do
|
|
begin
|
|
Dec(P.X, C.Left);
|
|
Dec(P.Y, C.Top);
|
|
C0 := TWinControl(C).ControlAtPos(P, True, True);
|
|
if (C0 = nil) or (C0.Owner <> C.Owner) then
|
|
Break;
|
|
C := C0;
|
|
end;
|
|
if C = nil then
|
|
C := Container;
|
|
Result := Selector.GetClientControl(C);
|
|
end;
|
|
|
|
function TJvDesignSurface.GetSelectedContainer: TWinControl;
|
|
begin
|
|
if Count <> 1 then
|
|
Result := Container
|
|
else
|
|
if (Selection[0] is TWinControl) and
|
|
(csAcceptsControls in Selection[0].ControlStyle) then
|
|
Result := TWinControl(Selection[0])
|
|
else
|
|
Result := Selection[0].Parent;
|
|
end;
|
|
|
|
function TJvDesignSurface.ContainerToSelectedContainer(const APt: TPoint): TPoint;
|
|
var
|
|
C: TControl;
|
|
begin
|
|
Result := APt;
|
|
C := SelectedContainer;
|
|
while (C <> Container) and (C <> nil) do
|
|
begin
|
|
Dec(Result.X, C.Left);
|
|
Dec(Result.Y, C.Top);
|
|
C := C.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TJvDesignSurface.GetAddBounds: TRect;
|
|
begin
|
|
with Result, Controller do
|
|
begin
|
|
TopLeft := ContainerToSelectedContainer(DragRect.TopLeft);
|
|
BottomRight := ContainerToSelectedContainer(DragRect.BottomRight);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.GetAddClass;
|
|
begin
|
|
if Assigned(FOnGetAddClass) then
|
|
FOnGetAddClass(Self, FAddClass);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.AddComponent;
|
|
var
|
|
CC: TComponentClass;
|
|
C: TComponent;
|
|
CO: TControl;
|
|
|
|
function GetBounds: TRect;
|
|
begin
|
|
Result := GetAddBounds;
|
|
if DesignRectWidth(Result) = 0 then
|
|
Result.Right := Result.Left + CO.Width;
|
|
if DesignRectHeight(Result) = 0 then
|
|
Result.Bottom := Result.Top + CO.Height;
|
|
end;
|
|
|
|
begin
|
|
CC := TComponentClass(GetClass(AddClass));
|
|
if (CC <> nil) and (SelectedContainer <> nil) then
|
|
begin
|
|
//C := CC.Create(Owner);
|
|
//C.Name := DesignUniqueName(Owner, AddClass);
|
|
C := CC.Create(Container);
|
|
C.Name := DesignUniqueName(Container, AddClass);
|
|
if C is TControl then
|
|
begin
|
|
CO := TControl(C);
|
|
CO.Parent := SelectedContainer;
|
|
CO.BoundsRect := GetBounds;
|
|
Select(CO);
|
|
end;
|
|
Messenger.DesignComponent(C, Active);
|
|
SelectionChange;
|
|
Change;
|
|
AddClass := '';
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.NudgeComponents(ANudgeLeft, ANudgeTop: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
with Selection[I] do
|
|
begin
|
|
Left := Left + ANudgeLeft;
|
|
Top := Top + ANudgeTop;
|
|
end;
|
|
Change;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.GrowComponents(AGrowWidth, AGrowHeight: Integer);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
with Selection[I] do
|
|
begin
|
|
Width := DesignMax(1, Width + AGrowWidth);
|
|
Height := DesignMax(1, Height + AGrowHeight);
|
|
end;
|
|
Change;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.DeleteComponents;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
Selection[I].Free;
|
|
ClearSelection;
|
|
SelectionChange;
|
|
Change;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.CopyComponents;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with TJvDesignComponentClipboard.Create(Container) do
|
|
try
|
|
OpenWrite;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
SetComponent(Selection[I]);
|
|
finally
|
|
CloseWrite;
|
|
end;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.CutComponents;
|
|
begin
|
|
CopyComponents;
|
|
DeleteComponents;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.PasteComponents;
|
|
var
|
|
CO: TControl;
|
|
C: TComponent;
|
|
P: TWinControl;
|
|
|
|
procedure KeepInParent;
|
|
begin
|
|
with P do
|
|
begin
|
|
if CO.Left > ClientWidth then
|
|
CO.Left := ClientWidth - CO.Width;
|
|
if CO.Top > ClientHeight then
|
|
CO.Top := ClientHeight - CO.Height;
|
|
end;
|
|
end;
|
|
|
|
procedure PasteComponent;
|
|
begin
|
|
C.Name := DesignUniqueName(Owner, C.ClassName);
|
|
Owner.InsertComponent(C);
|
|
if C is TControl then
|
|
begin
|
|
CO := TControl(C);
|
|
KeepInParent;
|
|
CO.Parent := P;
|
|
Selector.AddToSelection(CO);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
with TJvDesignComponentClipboard.Create(Container) do
|
|
try
|
|
OpenRead;
|
|
try
|
|
C := GetComponent;
|
|
if (C <> nil) then
|
|
begin
|
|
P := SelectedContainer;
|
|
ClearSelection;
|
|
repeat
|
|
PasteComponent;
|
|
C := GetComponent;
|
|
until C = nil;
|
|
SelectionChange;
|
|
Change;
|
|
end;
|
|
finally
|
|
CloseRead;
|
|
end;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SelectParent;
|
|
begin
|
|
if Count > 0 then
|
|
Select(Selection[0].Parent);
|
|
end;
|
|
|
|
{
|
|
procedure TJvDesignSurface.PaintContainerBkgnd(ADC: HDC);
|
|
var
|
|
r: TRect;
|
|
canvas: TCanvas;
|
|
begin
|
|
if DrawGrid then
|
|
begin
|
|
canvas := TCanvas.Create;
|
|
try
|
|
SelectClipRgn(ADC, 0);
|
|
canvas.Handle := ADC;
|
|
canvas.Brush.Color := Container.Brush.Color;
|
|
r := canvas.ClipRect;
|
|
if Assigned(FOnOwnerDrawGrid) then
|
|
FOnOwnerDrawGrid(Self, canvas, Container.ClientRect)
|
|
else begin
|
|
canvas.FillRect(Container.ClientRect);
|
|
DesignPaintRules(canvas, Container.ClientRect);
|
|
end;
|
|
finally
|
|
canvas.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
}
|
|
|
|
{
|
|
type
|
|
TAccessWinControl = class(TWinControl);
|
|
}
|
|
function TJvDesignSurface.IsDesignMessage(ASender: TControl;
|
|
var AMsg: TLMessage; const APt: TPoint): Boolean;
|
|
|
|
function VirtKey: Cardinal;
|
|
begin
|
|
Result := AMsg.WParam;
|
|
end;
|
|
|
|
{
|
|
function HandlePaint: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function HandleEraseBkgnd: Boolean;
|
|
begin
|
|
if (ASender <> Container) then
|
|
Result := False
|
|
else begin
|
|
PaintContainerBkgnd(TWMPaint(AMsg).DC);
|
|
AMsg.Result := 1;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
PosChangedHandle: HWND;
|
|
I: Integer;
|
|
Control: TAccessWinControl;
|
|
}
|
|
begin
|
|
if not Active then
|
|
Result := False
|
|
else
|
|
case AMsg.Msg of
|
|
{
|
|
WM_ERASEBKGND:
|
|
Result := HandleEraseBkgnd;
|
|
WM_PAINT:
|
|
Result := HandlePaint;
|
|
}
|
|
LM_LBUTTONDOWN:
|
|
Result := Controller.MouseDown(mbLeft, APt.X, APt.Y, TLMMOUSE(AMsg));
|
|
LM_LBUTTONUP:
|
|
Result := Controller.MouseUp(mbLeft, APt.X, APt.Y, TLMMouse( aMsg));
|
|
LM_MOUSEMOVE:
|
|
begin
|
|
Result := Controller.MouseMove(APt.X, APt.Y, TLMMouse( aMsg));
|
|
end;
|
|
LM_KEYDOWN, CN_KEYDOWN:
|
|
Result := Controller.KeyDown(VirtKey);
|
|
LM_KEYUP, CN_KEYUP:
|
|
Result := Controller.KeyUp(VirtKey);
|
|
{LM_WINDOWPOSCHANGED:
|
|
begin
|
|
if AMsg.lParam <> 0 then
|
|
begin
|
|
//CVPosChangedHandle := PWindowPos(AMsg.lParam).hwnd;
|
|
PosChangedHandle := PWindowPos(AMsg.lParam)^.hwnd;
|
|
|
|
// If the window that has changed is a control owned by our container
|
|
// then we must update the designer. This allows to programatically
|
|
// change the location of a control while making the designer handles
|
|
// follow it around (Mantis 4693).
|
|
// For this to work properly, we MUST update the bounds of the
|
|
// control before calling UpdateDesigner because the VCL has not yet
|
|
// processed the WM_WINDOWPOSCHANGED message when this code executes.
|
|
// If we did not, the designer would use the previous position of the
|
|
// control to display the handles.
|
|
// Additionnaly, we must not work with controls that don't have their
|
|
// handle allocated. In some instances, creating the handle may trigger
|
|
// a second WM_WINDOWPOSCHANGED message, thus leading to an infinite
|
|
// loop and a crash (Mantis 5225)
|
|
for I := 0 to Container.ComponentCount - 1 do
|
|
begin
|
|
if Container.Components[I] is TWinControl then
|
|
begin
|
|
Control := TAccessWinControl(Container.Components[I]);
|
|
if Control.HandleAllocated and (PosChangedHandle = Control.Handle) then
|
|
begin
|
|
if not (csDestroyingHandle in Control.ControlState) then
|
|
//$IFDEF DELPHI10_UP
|
|
//CV Control.UpdateBounds;
|
|
//$ELSE
|
|
Control.Dispatch(AMsg);
|
|
//$ENDIF DELPHI10_UP
|
|
|
|
UpdateDesigner;
|
|
end;
|
|
end;
|
|
end;//for
|
|
end;
|
|
|
|
// Must return False to let the VCL do its own work of placing the window
|
|
Result := False;
|
|
end; }
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TJvDesignSurface.GetCursor(AX, AY: Integer): TCursor;
|
|
begin
|
|
// Using FindControl is inefficient.
|
|
// All we really want to know is if Selected[0] contains (AX, AY)
|
|
if (Count > 0) and (FindControl(AX, AY) = Selected[0]) then
|
|
Result := Selector.GetCursor(AX, AY)
|
|
else
|
|
Result := crDefault;
|
|
end;
|
|
|
|
function TJvDesignSurface.GetHitHandle(AX, AY: Integer): TJvDesignHandleId;
|
|
begin
|
|
Result := Selector.GetHitHandle(AX, AY);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.BeginUpdate;
|
|
begin
|
|
Active := False;
|
|
FUpdateOwner := Owner;
|
|
Owner.RemoveComponent(Self);
|
|
end;
|
|
|
|
procedure TJvDesignSurface.EndUpdate;
|
|
begin
|
|
FUpdateOwner.InsertComponent(Self);
|
|
Active := True;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.ReaderError(Reader: TReader; const Msg: string;
|
|
var Handled: Boolean);
|
|
begin
|
|
Handled := True;
|
|
end;
|
|
|
|
function TJvDesignSurface.Clear: TJvDesignSurface;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
Container.DestroyComponents;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
Result := Self;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SaveToStream(AStream: TStream);
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
DesignSaveComponentToStream(Container, AStream);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TJvDesignSurface.LoadFromStream(AStream: TStream): TJvDesignSurface;
|
|
var
|
|
SavedName: string;
|
|
begin
|
|
BeginUpdate;
|
|
SavedName := Container.Name;
|
|
try
|
|
Container.DestroyComponents;
|
|
DesignLoadComponentFromStream(Container, AStream, @ReaderError);
|
|
Container.Name := SavedName;
|
|
finally
|
|
Container.Name := SavedName;
|
|
EndUpdate;
|
|
end;
|
|
Result := Self;
|
|
end;
|
|
|
|
procedure TJvDesignSurface.SaveToFile(const AFileName: string);
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
DesignSaveComponentToFile(Container, AFileName);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TJvDesignSurface.LoadFromFile(const AFileName: string): TJvDesignSurface;
|
|
var
|
|
SavedName: string;
|
|
begin
|
|
BeginUpdate;
|
|
SavedName := Container.Name;
|
|
try
|
|
Container.DestroyComponents;
|
|
DesignLoadComponentFromFile(Container, AFileName, @ReaderError);
|
|
finally
|
|
Container.Name := SavedName;
|
|
EndUpdate;
|
|
end;
|
|
Result := Self;
|
|
end;
|
|
|
|
{
|
|
procedure TJvDesignSurface.SetDrawGrid(const Value: Boolean);
|
|
begin
|
|
FDrawGrid := Value;
|
|
if Active then
|
|
Container.Invalidate;
|
|
end;
|
|
}
|
|
|
|
//=== { TJvDesignScrollBox } =================================================
|
|
|
|
procedure TJvDesignScrollBox.AutoScrollInView(AControl: TControl);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
//=== { TJvDesignPanel } =====================================================
|
|
|
|
constructor TJvDesignPanel.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FDrawRules := True;
|
|
FSurface := TJvDesignSurface.Create(Self);
|
|
Surface.Name := 'Surface';
|
|
Surface.Container := Self;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SetDrawRules(const Value: Boolean);
|
|
begin
|
|
FDrawRules := Value;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.Paint;
|
|
begin
|
|
inherited Paint;
|
|
if Surface.Active or (csDesigning in ComponentState) then
|
|
begin
|
|
if DrawRules then
|
|
DesignPaintRules(Canvas, ClientRect);
|
|
if Assigned(FOnPaint) then
|
|
FOnPaint(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.Clear;
|
|
begin
|
|
// DesignSurface property value is lost on clear.
|
|
// Restore it with the value returned from Clear.
|
|
FSurface := Surface.Clear;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SaveToStream(AStream: TStream);
|
|
begin
|
|
Surface.SaveToStream(AStream);
|
|
end;
|
|
|
|
procedure TJvDesignPanel.LoadFromStream(AStream: TStream);
|
|
begin
|
|
// DesignSurface property value is lost on load.
|
|
// Restore it with the value returned from LoadFromStream.
|
|
FSurface := Surface.LoadFromStream(AStream);
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SaveToFile(const AFileName: string);
|
|
begin
|
|
Surface.SaveToFile(AFileName);
|
|
end;
|
|
|
|
procedure TJvDesignPanel.LoadFromFile(const AFileName: string);
|
|
begin
|
|
// DesignSurface property value is lost on load.
|
|
// Restore it with the value returned from LoadFromFile.
|
|
FSurface := Surface.LoadFromFile(AFileName);
|
|
end;
|
|
|
|
function TJvDesignPanel.GetActive: Boolean;
|
|
begin
|
|
Result := Surface.Active;
|
|
end;
|
|
|
|
function TJvDesignPanel.GetOnChange: TNotifyEvent;
|
|
begin
|
|
Result := Surface.OnChange;
|
|
end;
|
|
|
|
function TJvDesignPanel.GetOnGetAddClass: TJvDesignGetAddClassEvent;
|
|
begin
|
|
Result := Surface.OnGetAddClass;
|
|
end;
|
|
|
|
function TJvDesignPanel.GetOnSelectionChange: TNotifyEvent;
|
|
begin
|
|
Result := Surface.OnSelectionChange;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SetActive(const Value: Boolean);
|
|
begin
|
|
Surface.Active := Value;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SetOnChange(const Value: TNotifyEvent);
|
|
begin
|
|
Surface.OnChange := Value;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SetOnGetAddClass(const Value: TJvDesignGetAddClassEvent);
|
|
begin
|
|
Surface.OnGetAddClass := Value;
|
|
end;
|
|
|
|
procedure TJvDesignPanel.SetOnSelectionChange(const Value: TNotifyEvent);
|
|
begin
|
|
Surface.OnSelectionChange := Value;
|
|
end;
|
|
|
|
|
|
end.
|
|
|