3103 lines
81 KiB
ObjectPascal
3103 lines
81 KiB
ObjectPascal
|
{******************************************}
|
||
|
{ }
|
||
|
{ FastReport v4.0 }
|
||
|
{ Common designer workspace }
|
||
|
{ }
|
||
|
{ Copyright (c) 1998-2008 }
|
||
|
{ by Alexander Tzyganenko, }
|
||
|
{ Fast Reports Inc. }
|
||
|
{ }
|
||
|
{******************************************}
|
||
|
|
||
|
unit FMX.frxDesgnWorkspace;
|
||
|
|
||
|
interface
|
||
|
|
||
|
{$I frx.inc}
|
||
|
|
||
|
uses
|
||
|
System.SysUtils, System.Classes, System.Types, System.UITypes, FMX.Platform, FMX.Controls, FMX.Objects, FMX.Types, FMX.Forms,
|
||
|
FMX.Dialogs, FMX.ExtCtrls, FMX.Memo, FMX.frxClass, System.Variants, System.UIConsts
|
||
|
{$IFDEF DELPHI18}
|
||
|
,FMX.StdCtrls
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI19}
|
||
|
, FMX.Graphics
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI20}
|
||
|
, System.Math.Vectors
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI28}
|
||
|
, FMX.BaseTypeAliases, FMX.FormTypeAliases
|
||
|
{$ENDIF};
|
||
|
|
||
|
type
|
||
|
TfrxDesignMode = (dmSelect, dmInsert, dmDrag);
|
||
|
TfrxDesignMode1 = (dmNone, dmMove, dmSize, dmSizeBand, dmScale,
|
||
|
dmSelectionRect, dmInsertObject, dmInsertLine,
|
||
|
dmMoveGuide, dmContainer);
|
||
|
TfrxGridType = (gt1pt, gt1cm, gt1in, gtDialog, gtChar, gtNone);
|
||
|
TfrxCursorType = (ct0, ct1, ct2, ct3, ct4, ct5, ct6, ct7, ct8, ct9, ct10);
|
||
|
TfrxNotifyPositionEvent = procedure (ARect: TfrxRect) of object;
|
||
|
TfrxPopupEvent = procedure(Sender: TObject; X, Y: Single) of object;
|
||
|
|
||
|
TfrxInsertion = packed record
|
||
|
ComponentClass: TfrxComponentClass;
|
||
|
Left: Extended;
|
||
|
Top: Extended;
|
||
|
Width: Extended;
|
||
|
Height: Extended;
|
||
|
OriginalWidth: Extended;
|
||
|
OriginalHeight: Extended;
|
||
|
Flags: Word;
|
||
|
end;
|
||
|
|
||
|
TfrxDesignerWorkspace = class(TPanel)
|
||
|
protected
|
||
|
FBandHeader: Extended;
|
||
|
FCanvas: TCanvas;
|
||
|
FColor: TAlphaColor;
|
||
|
FCT: TfrxCursorType;
|
||
|
FDblClicked: Boolean;
|
||
|
FDisableUpdate: Boolean;
|
||
|
FFreeBandsPlacement: Boolean;
|
||
|
FGapBetweenBands: Integer;
|
||
|
FGridAlign: Boolean;
|
||
|
FGridLCD: Boolean;
|
||
|
FGridType: TfrxGridType;
|
||
|
FGridX: Extended;
|
||
|
FGridY: Extended;
|
||
|
FInplaceMemo: TMemo;
|
||
|
FInplaceObject: TfrxCustomMemoView;
|
||
|
FInsertion: TfrxInsertion;
|
||
|
FLastMousePointX: Extended;
|
||
|
FLastMousePointY: Extended;
|
||
|
FMargins: TRect;
|
||
|
FMarginsPanel: TPanel;
|
||
|
FMode: TfrxDesignMode;
|
||
|
FMode1: TfrxDesignMode1;
|
||
|
FModifyFlag: Boolean;
|
||
|
FMouseDown: Boolean;
|
||
|
FObjects: TList;
|
||
|
FOffsetX: Extended;
|
||
|
FOffsetY: Extended;
|
||
|
FPage: TfrxPage;
|
||
|
FPageHeight: Integer;
|
||
|
FPageWidth: Integer;
|
||
|
FScale: Extended;
|
||
|
FScaleRect: TfrxRect;
|
||
|
FScaleRect1: TfrxRect;
|
||
|
FSelectedObjects: TList;
|
||
|
FSavedAlign: TList;
|
||
|
FSelectionRect: TfrxRect;
|
||
|
FShowBandCaptions: Boolean;
|
||
|
FShowEdges: Boolean;
|
||
|
FShowGrid: Boolean;
|
||
|
FSizedBand: TfrxBand;
|
||
|
FOnModify: TNotifyEvent;
|
||
|
FOnEdit: TNotifyEvent;
|
||
|
FOnInsert: TNotifyEvent;
|
||
|
FOnNotifyPosition: TfrxNotifyPositionEvent;
|
||
|
FOnSelectionChanged: TNotifyEvent;
|
||
|
FDrawSelection: Boolean;
|
||
|
FDrawInsertion: Boolean;
|
||
|
FOnPopup: TfrxPopupEvent;
|
||
|
FFastCanvas: TCanvas;
|
||
|
FParentForm: TFmxObject;
|
||
|
procedure DoModify;
|
||
|
procedure AdjustBandHeight(Bnd: TfrxBand);
|
||
|
procedure CheckGuides(var kx, ky: Extended; var Result: Boolean); virtual;
|
||
|
procedure DoNudge(dx, dy: Extended; Smooth: Boolean);
|
||
|
procedure DoSize(dx, dy: Extended);
|
||
|
procedure DoStick(dx, dy: Integer);
|
||
|
procedure DoTab;
|
||
|
procedure DrawBackground;
|
||
|
procedure DrawCross;
|
||
|
procedure DrawInsertionRect;
|
||
|
procedure DrawObjects; virtual;
|
||
|
procedure DrawSelectionRect;
|
||
|
procedure FindNearest(dx, dy: Integer);
|
||
|
procedure MouseLeave;
|
||
|
procedure NormalizeCoord(c: TfrxComponent);
|
||
|
procedure NormalizeRect(var R: TfrxRect);
|
||
|
procedure SelectionChanged;
|
||
|
procedure SetScale(Value: Extended);
|
||
|
procedure SetShowBandCaptions(const Value: Boolean);
|
||
|
procedure UpdateBandHeader;
|
||
|
procedure DblClick; override;
|
||
|
procedure KeyDown(var Key: Word; var KeyChar: WideChar; Shift: TShiftState); override;
|
||
|
procedure KeyUp(var Key: Word; var KeyChar: WideChar; Shift: TShiftState); override;
|
||
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||
|
procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
|
||
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||
|
|
||
|
// debug
|
||
|
procedure PrepareShiftTree(Band: TfrxBand);
|
||
|
|
||
|
procedure SetColor(const Value: TAlphaColor);
|
||
|
procedure SetGridType(const Value: TfrxGridType);
|
||
|
procedure SetOrigin(const Value: TPoint);
|
||
|
procedure SetParent(const Value: TFmxObject); override;
|
||
|
procedure SetShowGrid(const Value: Boolean);
|
||
|
function GetOrigin: TPoint;
|
||
|
function GetRightBottomObject: TfrxComponent;
|
||
|
function GetSelectionBounds: TfrxRect;
|
||
|
function ListsEqual(List1, List2: TList): Boolean;
|
||
|
function SelectedCount: Integer;
|
||
|
procedure DoDraw(ACanvas: TCanvas); virtual;
|
||
|
procedure DoDeactivate;{$IFDEF Delphi19} override;{$ENDIF}
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure DoPaint; override;
|
||
|
procedure AdjustBands(AttachObjects: Boolean = True);
|
||
|
procedure DeleteObjects; virtual;
|
||
|
procedure DisableUpdate;
|
||
|
procedure EnableUpdate;
|
||
|
procedure EditObject; virtual;
|
||
|
procedure GroupObjects;
|
||
|
procedure UngroupObjects;
|
||
|
procedure SetInsertion(AClass: TfrxComponentClass;
|
||
|
AWidth, AHeight: Extended; AFlag: Word); virtual;
|
||
|
procedure SetPageDimensions(AWidth, AHeight: Integer; AMargins: TRect);
|
||
|
procedure UpdateView;
|
||
|
|
||
|
property BandHeader: Extended read FBandHeader write FBandHeader;
|
||
|
property Color: TAlphaColor read FColor write SetColor;
|
||
|
property FastCanvas: TCanvas read FFastCanvas;
|
||
|
property FreeBandsPlacement: Boolean read FFreeBandsPlacement write FFreeBandsPlacement;
|
||
|
property GapBetweenBands: Integer read FGapBetweenBands write FGapBetweenBands;
|
||
|
property GridAlign: Boolean read FGridAlign write FGridAlign;
|
||
|
property GridLCD: Boolean read FGridLCD write FGridLCD;
|
||
|
property GridType: TfrxGridType read FGridType write SetGridType;
|
||
|
property GridX: Extended read FGridX write FGridX;
|
||
|
property GridY: Extended read FGridY write FGridY;
|
||
|
property Insertion: TfrxInsertion read FInsertion;
|
||
|
property IsMouseDown: Boolean read FMouseDown;
|
||
|
property Mode: TfrxDesignMode1 read FMode1;
|
||
|
property Objects: TList read FObjects write FObjects;
|
||
|
property OffsetX: Extended read FOffsetX write FOffsetX;
|
||
|
property OffsetY: Extended read FOffsetY write FOffsetY;
|
||
|
property Origin: TPoint read GetOrigin write SetOrigin;
|
||
|
property Page: TfrxPage read FPage write FPage;
|
||
|
property Scale: Extended read FScale write SetScale;
|
||
|
property SelectedObjects: TList read FSelectedObjects write FSelectedObjects;
|
||
|
property ShowBandCaptions: Boolean read FShowBandCaptions write SetShowBandCaptions;
|
||
|
property ShowEdges: Boolean read FShowEdges write FShowEdges;
|
||
|
property ShowGrid: Boolean read FShowGrid write SetShowGrid;
|
||
|
property OnModify: TNotifyEvent read FOnModify write FOnModify;
|
||
|
property OnEdit: TNotifyEvent read FOnEdit write FOnEdit;
|
||
|
property OnInsert: TNotifyEvent read FOnInsert write FOnInsert;
|
||
|
property OnNotifyPosition: TfrxNotifyPositionEvent read FOnNotifyPosition write
|
||
|
FOnNotifyPosition;
|
||
|
property OnSelectionChanged: TNotifyEvent read FOnSelectionChanged write
|
||
|
FOnSelectionChanged;
|
||
|
property OnPopup: TfrxPopupEvent read FOnPopup write FOnPopup;
|
||
|
end;
|
||
|
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses FMX.frxRes, FMX.frxDMPClass, FMX.frxUtils, FMX.frxCtrls, FMX.frxFMX;
|
||
|
|
||
|
const
|
||
|
DefFontName = 'Tahoma';
|
||
|
|
||
|
|
||
|
type
|
||
|
TMarginsPanel = class(TPanel)
|
||
|
private
|
||
|
FColor: TAlphaColor;
|
||
|
protected
|
||
|
FWorkspace: TfrxDesignerWorkspace;
|
||
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||
|
procedure MouseMove(Shift: TShiftState; x, y: Single); override;
|
||
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; x, y: Single); override;
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
procedure DoPaint; override;
|
||
|
property Color: TAlphaColor read FColor write FColor default claWhite;
|
||
|
end;
|
||
|
|
||
|
THackComponent = class(TfrxComponent);
|
||
|
|
||
|
|
||
|
{ TMarginsPanel }
|
||
|
|
||
|
constructor TMarginsPanel.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited;
|
||
|
Color := claWhite;
|
||
|
StyleLookup := 'backgroundstyle';
|
||
|
end;
|
||
|
|
||
|
procedure TMarginsPanel.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||
|
begin
|
||
|
inherited;
|
||
|
FWorkspace.MouseDown(Button, Shift, X - (FWorkspace.Left - Left),
|
||
|
Y - (FWorkspace.Top - Top));
|
||
|
end;
|
||
|
|
||
|
procedure TMarginsPanel.MouseMove(Shift: TShiftState; x, y: Single);
|
||
|
begin
|
||
|
inherited;
|
||
|
|
||
|
if FWorkspace.FMode = dmSelect then
|
||
|
FWorkspace.MouseMove(Shift, X - (FWorkspace.Left - Left),
|
||
|
Y - (FWorkspace.Top - Top)) else
|
||
|
FWorkspace.MouseLeave;
|
||
|
Cursor := FWorkspace.Cursor;
|
||
|
end;
|
||
|
|
||
|
procedure TMarginsPanel.MouseUp(Button: TMouseButton; Shift: TShiftState; x, y: Single);
|
||
|
begin
|
||
|
inherited;
|
||
|
FWorkspace.MouseUp(Button, Shift, X - (FWorkspace.Left - Left),
|
||
|
Y - (FWorkspace.Top - Top));
|
||
|
end;
|
||
|
|
||
|
procedure TMarginsPanel.DoPaint;
|
||
|
var
|
||
|
r: TRectF;
|
||
|
poly: TPolygon;
|
||
|
Sstate: TCanvasSaveState;
|
||
|
oldM: TMatrix;
|
||
|
begin
|
||
|
Sstate := Canvas.SaveState;
|
||
|
oldM := Canvas.Matrix;
|
||
|
try
|
||
|
Canvas.SetMatrix(CreateTranslateMatrix(AbsoluteRect.Left, AbsoluteRect.Top));
|
||
|
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Fill.Color := Color;
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := $FF505050;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
|
||
|
FillRect(RectF(0, 0, Self.Width - 1, Self.Height - 1), 1, 1, AllCorners, 1);
|
||
|
SetLength(poly, 4);
|
||
|
poly[0] := PointF(1, Self.Height - 1);
|
||
|
poly[1] := PointF(Self.Width - 1, Self.Height - 1);
|
||
|
poly[2] := PointF(Self.Width - 1, 1);
|
||
|
poly[3] := PointF(1, 1);
|
||
|
DrawPolygon(poly, 1);
|
||
|
|
||
|
Stroke.Color := claSilver;
|
||
|
with FWorkspace, FWorkspace.FMargins do
|
||
|
r := RectF(Round(Left * FScale) + 0.5, Round(Top * FScale) + 0.5,
|
||
|
Self.Width - Round(Right * FScale) + 1.5,
|
||
|
Self.Height - Round(Bottom * FScale) + 1.5);
|
||
|
SetLength(poly, 5);
|
||
|
|
||
|
poly[0] := PointF(r.Left - 1, r.Top - 1);
|
||
|
poly[1] := PointF(r.Left - 1, r.Bottom);
|
||
|
poly[2] := PointF(r.Right, r.Bottom);
|
||
|
poly[3] := PointF(r.Right, r.Top - 1);
|
||
|
poly[4] := PointF(r.Left - 1, r.Top - 1);
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Dash := TStrokeDash.sdDash;
|
||
|
{$ELSE}
|
||
|
StrokeDash := TStrokeDash.sdDash;
|
||
|
{$ENDIF}
|
||
|
DrawPolygon(poly, 1);
|
||
|
end;
|
||
|
finally
|
||
|
Canvas.SetMatrix(oldM);
|
||
|
Canvas.RestoreState(sstate);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxDesignerWorkspace }
|
||
|
|
||
|
constructor TfrxDesignerWorkspace.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited Create(AOwner);
|
||
|
FSavedAlign := TList.Create;
|
||
|
FDrawSelection := False;
|
||
|
FMarginsPanel := TMarginsPanel.Create(AOwner);
|
||
|
TMarginsPanel(FMarginsPanel).FWorkspace := Self;
|
||
|
|
||
|
FBandHeader := fr01cm * 5;
|
||
|
FColor := claWhite;
|
||
|
FGridAlign := True;
|
||
|
FGridType := gt1cm;
|
||
|
FGridX := fr01cm;
|
||
|
FGridY := fr01cm;
|
||
|
FMode := dmSelect;
|
||
|
FMode1 := dmNone;
|
||
|
FScale := 1;
|
||
|
FShowGrid := True;
|
||
|
FShowEdges := True;
|
||
|
FGridLCD := True;
|
||
|
StyleLookup := 'backgroundstyle';
|
||
|
CanFocus := True;
|
||
|
AutoCapture := True;
|
||
|
FFastCanvas := nil;
|
||
|
FParentForm := nil;
|
||
|
if frxCanvasClass <> nil then
|
||
|
FFastCanvas := frxCanvasClass.Create;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxDesignerWorkspace.Destroy;
|
||
|
begin
|
||
|
FSavedAlign.Free;
|
||
|
FreeAndNil(FFastCanvas);
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetParent(const Value: TFmxObject);
|
||
|
begin
|
||
|
if not (csDestroying in ComponentState) then
|
||
|
FMarginsPanel.Parent := Value;
|
||
|
inherited;
|
||
|
FParentForm := nil;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DisableUpdate;
|
||
|
begin
|
||
|
FDisableUpdate := True;
|
||
|
FMode := dmSelect;
|
||
|
FMode1 := dmNone;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.EnableUpdate;
|
||
|
begin
|
||
|
FDisableUpdate := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.UpdateView;
|
||
|
var
|
||
|
NotifyRect: TfrxRect;
|
||
|
begin
|
||
|
Repaint;
|
||
|
if SelectedCount = 0 then
|
||
|
NotifyRect := frxRect(0, 0, 0, 0) else
|
||
|
NotifyRect := GetSelectionBounds;
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(NotifyRect);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetInsertion(AClass: TfrxComponentClass;
|
||
|
AWidth, AHeight: Extended; AFlag: Word);
|
||
|
begin
|
||
|
with FInsertion do
|
||
|
begin
|
||
|
ComponentClass := AClass;
|
||
|
Width := AWidth;
|
||
|
Height := AHeight;
|
||
|
OriginalWidth := AWidth;
|
||
|
OriginalHeight := AHeight;
|
||
|
Flags := AFlag;
|
||
|
end;
|
||
|
|
||
|
FMode := dmInsert;
|
||
|
if AClass = nil then
|
||
|
begin
|
||
|
Cursor := crDefault;
|
||
|
FMode := dmSelect;
|
||
|
FMode1 := dmNone;
|
||
|
end
|
||
|
else if AClass.InheritsFrom(TfrxCustomLineView) then
|
||
|
begin
|
||
|
FMode1 := dmInsertLine;
|
||
|
if FGridType = gtChar then
|
||
|
begin
|
||
|
FInsertion.Left := - FGridX / 2;
|
||
|
FInsertion.Top := - FGridY / 2;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
FInsertion.Left := - FGridX;
|
||
|
FInsertion.Top := - FGridY;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Cursor := crCross;
|
||
|
FMode1 := dmInsertObject;
|
||
|
FInsertion.Left := -1000 * FGridX;
|
||
|
FInsertion.Top := -1000 * FGridY;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetScale(Value: Extended);
|
||
|
begin
|
||
|
FScale := Value;
|
||
|
FMarginsPanel.Width := Round(FPageWidth * FScale);
|
||
|
FMarginsPanel.Height := Round(FPageHeight * FScale);
|
||
|
|
||
|
SetBounds(FMarginsPanel.Position.X + Round(FMargins.Left * FScale),
|
||
|
FMarginsPanel.Position.Y + Round(FMargins.Top * FScale),
|
||
|
FMarginsPanel.Width - Round((FMargins.Left + FMargins.Right - 1) * FScale),
|
||
|
FMarginsPanel.Height - Round((FMargins.Top + FMargins.Bottom - 1) * FScale));
|
||
|
|
||
|
FMarginsPanel.Repaint;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetPageDimensions(AWidth, AHeight: Integer;
|
||
|
AMargins: TRect);
|
||
|
begin
|
||
|
FPageWidth := AWidth;
|
||
|
FPageHeight := AHeight;
|
||
|
FMargins := AMargins;
|
||
|
SetScale(FScale);
|
||
|
AdjustBands;
|
||
|
Resize;
|
||
|
{$IFNDEF Delphi17}
|
||
|
if Parent is TControl then
|
||
|
TControl(Parent).Realign;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetShowGrid(const Value: Boolean);
|
||
|
begin
|
||
|
FShowGrid := Value;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.UpdateBandHeader;
|
||
|
begin
|
||
|
case FGridType of
|
||
|
gt1pt, gtDialog:
|
||
|
FBandHeader := 16;
|
||
|
gt1cm:
|
||
|
FBandHeader := fr01cm * 5;
|
||
|
gt1in:
|
||
|
FBandHeader := fr01in * 2;
|
||
|
gtChar:
|
||
|
FBandHeader := fr1CharY;
|
||
|
end;
|
||
|
|
||
|
if not FShowBandCaptions then
|
||
|
FBandHeader := 0;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetGridType(const Value: TfrxGridType);
|
||
|
begin
|
||
|
FGridType := Value;
|
||
|
UpdateBandHeader;
|
||
|
if FSelectedObjects.Count <> 0 then
|
||
|
MouseMove([], 0, 0);
|
||
|
AdjustBands;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetShowBandCaptions(const Value: Boolean);
|
||
|
begin
|
||
|
FShowBandCaptions := Value;
|
||
|
UpdateBandHeader;
|
||
|
AdjustBands;
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
function TfrxDesignerWorkspace.GetOrigin: TPoint;
|
||
|
begin
|
||
|
Result.X := Round(FMarginsPanel.Position.X);
|
||
|
Result.Y := Round(FMarginsPanel.Position.Y);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetOrigin(const Value: TPoint);
|
||
|
begin
|
||
|
FMarginsPanel.Position.X := Value.X;
|
||
|
FMarginsPanel.Position.Y := Value.Y;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SetColor(const Value: TAlphaColor);
|
||
|
begin
|
||
|
FColor := Value;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoDeactivate;
|
||
|
begin
|
||
|
inherited;
|
||
|
if FMouseDown then
|
||
|
MouseUp(TMouseButton.mbLeft, [], FLastMousePointX * FScale, FLastMousePointY * FScale);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoDraw(ACanvas: TCanvas);
|
||
|
begin
|
||
|
ACanvas.Fill.Color := FColor;
|
||
|
ACanvas.Fill.Kind := TBrushKind.bkSolid;
|
||
|
DrawBackground;
|
||
|
if not FDisableUpdate then
|
||
|
begin
|
||
|
if (FPage <> nil) and (FPage is TfrxReportPage) then
|
||
|
TfrxReportPage(FPage).Draw(ACanvas, FScale, FScale,
|
||
|
-FMargins.Left * FScale, -FMargins.Top * FScale);
|
||
|
DrawObjects;
|
||
|
end;
|
||
|
DrawSelectionRect;
|
||
|
DrawInsertionRect;
|
||
|
DrawCross;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoModify;
|
||
|
begin
|
||
|
if FModifyFlag then
|
||
|
if Assigned(FOnModify) then
|
||
|
FOnModify(Self);
|
||
|
FModifyFlag := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.SelectionChanged;
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
c, c1: TfrxComponent;
|
||
|
begin
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
if (c is TfrxReportComponent) and (c.GroupIndex <> 0) then
|
||
|
for j := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c1 := FObjects[j];
|
||
|
if (c1 is TfrxReportComponent) and (c1.GroupIndex = c.GroupIndex) then
|
||
|
begin
|
||
|
if FSelectedObjects.IndexOf(c1) = -1 then
|
||
|
FSelectedObjects.Add(c1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if Assigned(FOnSelectionChanged) then
|
||
|
FOnSelectionChanged(Self);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
function TfrxDesignerWorkspace.GetSelectionBounds: TfrxRect;
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
begin
|
||
|
if SelectedCount = 1 then
|
||
|
begin
|
||
|
with TfrxComponent(FSelectedObjects[0]) do
|
||
|
Result := frxRect(Left, Top, Width, Height);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
Result := frxRect(1e10, 1e10, -1e10, -1e10);
|
||
|
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
|
||
|
if c.AbsLeft < Result.Left then
|
||
|
Result.Left := c.AbsLeft;
|
||
|
if c.AbsTop < Result.Top then
|
||
|
Result.Top := c.AbsTop;
|
||
|
if c.AbsLeft + c.Width > Result.Right then
|
||
|
Result.Right := c.AbsLeft + c.Width;
|
||
|
if c.AbsTop + c.Height > Result.Bottom then
|
||
|
Result.Bottom := c.AbsTop + c.Height;
|
||
|
end;
|
||
|
|
||
|
with Result do
|
||
|
Result := frxRect(Left, Top, Right - Left, Bottom - Top);
|
||
|
end;
|
||
|
|
||
|
function TfrxDesignerWorkspace.GetRightBottomObject: TfrxComponent;
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
maxx, maxy: Extended;
|
||
|
begin
|
||
|
maxx := 0;
|
||
|
maxy := 0;
|
||
|
Result := nil;
|
||
|
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
if (c.AbsLeft + c.Width > maxx) or
|
||
|
((c.AbsLeft + c.Width = maxx) and (c.AbsTop + c.Height > maxy)) then
|
||
|
begin
|
||
|
maxx := c.AbsLeft + c.Width;
|
||
|
maxy := c.AbsTop + c.Height;
|
||
|
Result := c;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxDesignerWorkspace.SelectedCount: Integer;
|
||
|
begin
|
||
|
Result := FSelectedObjects.Count;
|
||
|
if (Result = 1) and
|
||
|
((FSelectedObjects[0] = FPage) or (TObject(FSelectedObjects[0]) is TfrxReport)) then
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoPaint;
|
||
|
var
|
||
|
Sstate: TCanvasSaveState;
|
||
|
oldM: TMatrix;
|
||
|
begin
|
||
|
FCanvas := Canvas;
|
||
|
Sstate := FCanvas.SaveState;
|
||
|
oldM := FCanvas.Matrix;
|
||
|
try
|
||
|
FCanvas.SetMatrix(CreateTranslateMatrix(AbsoluteRect.Left, AbsoluteRect.Top));
|
||
|
DoDraw(FCanvas);
|
||
|
finally
|
||
|
FCanvas.SetMatrix(oldM);
|
||
|
FCanvas.RestoreState(Sstate);
|
||
|
end;
|
||
|
FCanvas := nil;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DrawObjects;
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
|
||
|
procedure DrawPoint(x, y: Extended);
|
||
|
var
|
||
|
i, w: Integer;
|
||
|
begin
|
||
|
if FScale > 1.7 then
|
||
|
w := 7
|
||
|
else if FScale < 0.7 then
|
||
|
w := 3 else
|
||
|
w := 5;
|
||
|
for i := 0 to w - 1 do
|
||
|
begin
|
||
|
FCanvas.DrawLine(
|
||
|
PointF(Round(x * FScale - w div 2) + 0.5, Round(y * FScale - w div 2 + i) + 0.5),
|
||
|
PointF(Round(x * FScale + w div 2) + 0.5, Round(y * FScale - w div 2 + i) + 0.5), 1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawLineA(x, y, dx, dy: Extended);
|
||
|
begin
|
||
|
FCanvas.DrawLine(PointF(Round(x * FScale) + 0.5, Round(y * FScale) + 0.5),
|
||
|
PointF(Round((x + dx) * FScale) + 0.5, Round((y + dy) * FScale) + 0.5), 1);
|
||
|
end;
|
||
|
|
||
|
procedure DrawSqares(c: TfrxComponent);
|
||
|
var
|
||
|
px, py: Extended;
|
||
|
begin
|
||
|
with c, FCanvas do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Stroke.Color := claBlack;
|
||
|
px := AbsLeft + c.Width / 2;
|
||
|
py := AbsTop + c.Height / 2;
|
||
|
|
||
|
DrawPoint(AbsLeft, AbsTop);
|
||
|
if not (c is TfrxCustomLineView) then
|
||
|
begin
|
||
|
DrawPoint(AbsLeft + c.Width, AbsTop);
|
||
|
DrawPoint(AbsLeft, AbsTop + c.Height);
|
||
|
end;
|
||
|
if (SelectedCount > 1) and (c = GetRightBottomObject) then
|
||
|
Stroke.Color := claTeal;
|
||
|
DrawPoint(AbsLeft + c.Width, AbsTop + c.Height);
|
||
|
|
||
|
Stroke.Color := claBlack;
|
||
|
if (SelectedCount = 1) and not (c is TfrxCustomLineView) then
|
||
|
begin
|
||
|
DrawPoint(px, AbsTop); DrawPoint(px, AbsTop + c.Height);
|
||
|
DrawPoint(AbsLeft, py); DrawPoint(AbsLeft + c.Width, py);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawDialogPageSquares;
|
||
|
begin
|
||
|
with FCanvas, TfrxDialogPage(FPage) do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Stroke.Color := claBlack;
|
||
|
|
||
|
DrawPoint(ClientWidth - 2, ClientHeight - 2);
|
||
|
DrawPoint(ClientWidth - 2, ClientHeight / 2 - 1);
|
||
|
DrawPoint(ClientWidth / 2 - 1, ClientHeight - 2);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawScriptSign(c: TfrxReportComponent);
|
||
|
var
|
||
|
NeedDraw: Boolean;
|
||
|
Offs: Extended;
|
||
|
begin
|
||
|
NeedDraw := False;
|
||
|
Offs := 0;
|
||
|
if c is TfrxReportComponent then
|
||
|
with c do
|
||
|
if (OnBeforePrint <> '') or (OnAfterPrint <> '') or
|
||
|
(OnAfterData <> '') or (OnPreviewClick <> '') then
|
||
|
NeedDraw := True;
|
||
|
if c is TfrxDialogControl then
|
||
|
with TfrxDialogControl(c) do
|
||
|
if (OnClick <> '') or (OnDblClick <> '') or
|
||
|
(OnEnter <> '') or (OnExit <> '') or
|
||
|
(OnKeyDown <> '') or (OnKeyPress <> '') or
|
||
|
(OnKeyUp <> '') or (OnMouseDown <> '') or
|
||
|
(OnMouseMove <> '') or (OnMouseUp <> '') then
|
||
|
NeedDraw := True;
|
||
|
if c is TfrxBand then
|
||
|
with TfrxBand(c) do
|
||
|
begin
|
||
|
if (OnAfterCalcHeight <> '') then
|
||
|
NeedDraw := True;
|
||
|
if not Vertical then
|
||
|
Offs := -FBandHeader + 2;
|
||
|
end;
|
||
|
|
||
|
if NeedDraw then
|
||
|
with c, FCanvas do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claRed;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
DrawLineA(AbsLeft + 2, AbsTop + Offs + 1, 0, 7);
|
||
|
DrawLineA(AbsLeft + 3, AbsTop + Offs + 2, 0, 5);
|
||
|
DrawLineA(AbsLeft + 4, AbsTop + Offs + 3, 0, 3);
|
||
|
DrawLineA(AbsLeft + 5, AbsTop + Offs + 4, 0, 1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawObject(c: TfrxReportComponent);
|
||
|
var
|
||
|
s: String;
|
||
|
i, x: Integer;
|
||
|
y, w: Single;
|
||
|
d: TfrxDataBand;
|
||
|
MatrixR: TMatrix;
|
||
|
StateSave: TCanvasSaveState;
|
||
|
bName: String;
|
||
|
begin
|
||
|
c.IsDesigning := True;
|
||
|
if c is TfrxView then
|
||
|
TfrxView(c).SetFastCanvas(FFastCanvas);
|
||
|
c.Draw(FCanvas, FScale, FScale, FOffsetX, FOffsetY);
|
||
|
if c is TfrxBand then
|
||
|
with c as TfrxBand, FCanvas do
|
||
|
begin
|
||
|
if Vertical then
|
||
|
begin
|
||
|
Top := 0;
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claGray;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
x := Round((Left - FBandHeader) * FScale);
|
||
|
DrawRect(RectF(x, 0, Round((Left + c.Width) * FScale) + 1, Round((c.Height) * FScale)), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
|
||
|
if FShowBandCaptions then
|
||
|
begin
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
if c is TfrxDataBand then
|
||
|
Fill.Color := $FFEEBB00 else
|
||
|
Fill.Color := claGray;
|
||
|
FillRect(RectF(x + 1, 1, Round(Left * FScale), Round(c.Height * FScale)), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
end;
|
||
|
|
||
|
Font.Family := DefFontName;
|
||
|
Font.Size := Round(8 * FScale);
|
||
|
Font.Style := [];
|
||
|
MatrixR := CreateRotationMatrix(90);
|
||
|
StateSave := SaveState;
|
||
|
y := TextWidth(Name) + 4;
|
||
|
FillText(RectF(x + 2, y, 20, y * 2), Name, False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
Font.Style := [TFontStyle.fsBold];
|
||
|
bName := frxResources.Get(BandName);
|
||
|
FillText(RectF(x + 2, y + TextWidth(bName + ': ') + 2, 20, (y + TextWidth(bName + ': ') + 2) * 2), bName + ': ', False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
RestoreState(StateSave);
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Left := 0;
|
||
|
//if (Page is TfrxReportPage) and (TfrxReportPage(Page).Columns > 1) then
|
||
|
//if BandNumber in [4..16] then
|
||
|
//Width := TfrxReportPage(Page).ColumnWidth * fr01cm;
|
||
|
//todo
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claGray;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Fill.Kind := TBrushKind.bkNone;
|
||
|
y := Round((Top - FBandHeader) * FScale);
|
||
|
DrawRect(RectF(0.5, y + 0.5, Round(c.Width * FScale) + 0.5, Round((c.Top + c.Height) * FScale) + 0.5), 1, 1, AllCorners, 1);
|
||
|
|
||
|
if FShowBandCaptions then
|
||
|
begin
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
if c is TfrxDataBand then
|
||
|
Fill.Color := $FFE0A730
|
||
|
else
|
||
|
Fill.Color := claLightgray;
|
||
|
FillRect(RectF(1, y + 1, Round(c.Width * FScale), Round(c.Top * FScale)), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
end;
|
||
|
|
||
|
Font.Family := DefFontName;
|
||
|
Font.Size := Round(10 * FScale);
|
||
|
Font.Style := [TFontStyle.fsBold];
|
||
|
bName := frxResources.Get(BandName);
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
Fill.Color := claBlack;
|
||
|
FillText(RectF(6, y + 2, c.Width, y + 22), bName, False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
|
||
|
w := TextWidth(bName);
|
||
|
Font.Style := [];
|
||
|
FillText(RectF(6 + w, y + 2, c.Width, y + 22), ': ' + Name, False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
|
||
|
if c is TfrxDataBand then
|
||
|
begin
|
||
|
d := TfrxDataBand(c);
|
||
|
|
||
|
if FShowBandCaptions then
|
||
|
begin
|
||
|
if (d.DataSet <> nil) and (c.Report <> nil) then
|
||
|
s := c.Report.GetAlias(d.DataSet)
|
||
|
else if d.RowCount <> 0 then
|
||
|
s := IntToStr(d.RowCount)
|
||
|
else
|
||
|
s := '';
|
||
|
w := TextWidth(s);
|
||
|
//if FScale > 0.7 then
|
||
|
// frxResources.MainButtonImages.Draw(FCanvas,
|
||
|
// Round(Width * FScale - w - 24), Round(y + 2 * FScale), 53);
|
||
|
if s <> '' then
|
||
|
FillText(RectF(c.Width * FScale - w - 3, y + 3, c.Width, (y + 3) * 2), s, False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
end;
|
||
|
|
||
|
if d.Columns > 1 then
|
||
|
begin
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Dash := TStrokeDash.sdDot;
|
||
|
{$ELSE}
|
||
|
StrokeDash := TStrokeDash.sdDot;
|
||
|
{$ENDIF}
|
||
|
Stroke.Color := claBlack;
|
||
|
Fill.Kind := TBrushKind.bkNone;
|
||
|
for i := 1 to d.Columns do
|
||
|
DrawRect(RectF((i - 1) * (d.ColumnWidth + d.ColumnGap) * FScale, Top * FScale, ((i - 1) * (d.ColumnWidth + d.ColumnGap) + d.ColumnWidth) * FScale, (Top + c.Height) * FScale), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
end;
|
||
|
end;
|
||
|
if c is TfrxGroupHeader then
|
||
|
begin
|
||
|
s := TfrxGroupHeader(c).Condition;
|
||
|
if s <> '' then
|
||
|
if FShowBandCaptions then
|
||
|
FillText(RectF(c.Width * FScale - TextWidth(s) - 3, y + 3, 20, (c.Width * FScale - TextWidth(s) - 3) * 2), s, False, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);
|
||
|
end;
|
||
|
end
|
||
|
end
|
||
|
else if not (c is TfrxCustomLineView) and not (c is TfrxDialogComponent) and
|
||
|
not (c is TfrxDialogControl) then
|
||
|
with c, FCanvas do
|
||
|
if FShowEdges and not (FPage is TfrxDataPage) and (c is TfrxView) and
|
||
|
(TfrxView(c).Frame.Typ <> [ftLeft, ftRight, ftTop, ftBottom]) then
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claBlack;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
DrawLineA(AbsLeft, AbsTop + 3, 0, -3);
|
||
|
DrawLineA(AbsLeft, AbsTop, 4, 0);
|
||
|
DrawLineA(AbsLeft, AbsTop + c.Height - 3, 0, 3);
|
||
|
DrawLineA(AbsLeft, AbsTop + c.Height, 4, 0);
|
||
|
DrawLineA(AbsLeft + c.Width - 3, AbsTop, 3, 0);
|
||
|
DrawLineA(AbsLeft + c.Width, AbsTop, 0, 4);
|
||
|
DrawLineA(AbsLeft + c.Width - 3, AbsTop + c.Height, 3, 0);
|
||
|
DrawLineA(AbsLeft + c.Width, AbsTop + c.Height, 0, -4);
|
||
|
end;
|
||
|
if c is TfrxView then
|
||
|
TfrxView(c).SetFastCanvas(nil);
|
||
|
DrawScriptSign(c);
|
||
|
|
||
|
{ if c.IsAncestor then
|
||
|
frxResources.MainButtonImages.Draw(FCanvas,
|
||
|
Round((c.AbsLeft + 2) * FScale), Round((c.AbsTop + 1) * FScale), 99);}
|
||
|
end;
|
||
|
|
||
|
// debug
|
||
|
procedure DrawShiftTree(c: TfrxReportComponent);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c1: TfrxReportComponent;
|
||
|
begin
|
||
|
for i := 0 to c.FShiftChildren.Count - 1 do
|
||
|
begin
|
||
|
c1 := c.FShiftChildren[i];
|
||
|
with FCanvas do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claRed;
|
||
|
//Pen.Mode := pmCopy;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
if c is TfrxBand then
|
||
|
DrawLine(PointF(c.AbsLeft + c.Width / 2, c.AbsTop), PointF(c1.AbsLeft + c1.Width / 2, c1.AbsTop), 1)
|
||
|
else
|
||
|
DrawLine(PointF(c.AbsLeft + c.Width / 2, c.AbsTop + c.Height), PointF(c1.AbsLeft + c1.Width / 2, c1.AbsTop), 1);
|
||
|
end;
|
||
|
DrawShiftTree(c1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
begin
|
||
|
if Assigned(FFastCanvas)then
|
||
|
begin
|
||
|
TfrxFastCanvasLayer(FFastCanvas).UpdateHandle(Parent);
|
||
|
TfrxFastCanvasLayer(FFastCanvas).Canvas := Canvas;
|
||
|
end;
|
||
|
{ update aligned objects }
|
||
|
if Page is TfrxReportPage then
|
||
|
Page.AlignChildren;
|
||
|
|
||
|
{ draw objects }
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if c is TfrxReportComponent then
|
||
|
DrawObject(TfrxReportComponent(c));
|
||
|
end;
|
||
|
|
||
|
// debug
|
||
|
{ for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if c is TfrxBand then
|
||
|
begin
|
||
|
PrepareShiftTree(TfrxBand(c));
|
||
|
DrawShiftTree(TfrxReportComponent(c));
|
||
|
end;
|
||
|
end;}
|
||
|
|
||
|
|
||
|
{ draw selection }
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
if not FMouseDown then
|
||
|
DrawSqares(FSelectedObjects[i]);
|
||
|
if (FSelectedObjects.Count = 1) and (TObject(FSelectedObjects[0]) is TfrxDialogPage) then
|
||
|
DrawDialogPageSquares;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DrawBackground;
|
||
|
|
||
|
procedure Line(x, y, x1, y1: Extended);
|
||
|
begin
|
||
|
FCanvas.DrawLine(PointF(x, y), PointF(x1, y1), 1);
|
||
|
end;
|
||
|
|
||
|
procedure DrawPoints;
|
||
|
var
|
||
|
GridBmp: TBitmap;
|
||
|
{$IFDEF Delphi17}
|
||
|
map: TBitmapData;
|
||
|
{$ENDIF}
|
||
|
i: Extended;
|
||
|
c: TAlphaColor;
|
||
|
dx, dy: Extended;
|
||
|
begin
|
||
|
if FGridType = gtDialog then
|
||
|
c := claBlack else
|
||
|
c := claGray;
|
||
|
dx := FGridX * FScale;
|
||
|
dy := FGridY * FScale;
|
||
|
if (dx > 2) and (dy > 2) then
|
||
|
begin
|
||
|
GridBmp := TBitmap.Create(Round(Width), 1);
|
||
|
|
||
|
GridBmp.Canvas.BeginScene();
|
||
|
GridBmp.Canvas.Stroke.Color := FColor;
|
||
|
GridBmp.Canvas.DrawLine(PointF(0, 0), PointF(Width, 0), 1);
|
||
|
|
||
|
{$IFDEF Delphi17}
|
||
|
if GridBmp.Map(TMapAccess.maReadWrite, map) then
|
||
|
begin
|
||
|
i := 0;
|
||
|
while i < Width do
|
||
|
begin
|
||
|
map.SetPixel(Round(i), 0, c);
|
||
|
i := i + dx;
|
||
|
end;
|
||
|
GridBmp.UnMap(map);
|
||
|
end;
|
||
|
{$ELSE}
|
||
|
i := 0;
|
||
|
while i < Width do
|
||
|
begin
|
||
|
GridBmp.Pixels[Round(i), 0] := c;
|
||
|
i := i + dx;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
GridBmp.Canvas.EndScene;
|
||
|
i := 0;
|
||
|
while i < Height do
|
||
|
begin
|
||
|
FCanvas.DrawBitmap(GridBmp, RectF(0, 0, Width, 1), RectF(0, i, Width, i + 1), 1, True);
|
||
|
i := i + dy;
|
||
|
end;
|
||
|
|
||
|
GridBmp.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DrawMM;
|
||
|
var
|
||
|
i, dx, maxi: Extended;
|
||
|
i1: Integer;
|
||
|
Color5, Color10: TAlphaColor;
|
||
|
SState: TCanvasSaveState;
|
||
|
begin
|
||
|
if FGridLCD then
|
||
|
begin
|
||
|
Color5 := $FFF2F2F2;
|
||
|
Color10 := $FFE2E2E2;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
Color5 := $FFF8F8F8;
|
||
|
Color10 := $FFE8E8E8;
|
||
|
end;
|
||
|
|
||
|
with FCanvas do
|
||
|
begin
|
||
|
SState := SaveState;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Canvas.IntersectClipRect(RectF(0,0,(Self.FPageWidth - (FMargins.Left + FMargins.Right)) * FScale, (Self.FPageHeight - (FMargins.Top + FMargins.Bottom)) * FScale));
|
||
|
if FGridType = gt1cm then
|
||
|
dx := fr01cm * FScale else
|
||
|
dx := fr01in * FScale;
|
||
|
|
||
|
if Self.Width > Self.Height then
|
||
|
maxi := Self.FPageWidth * FScale else
|
||
|
maxi := Self.FPageHeight * FScale;
|
||
|
|
||
|
i := 0;
|
||
|
i1 := 0;
|
||
|
while i < maxi do
|
||
|
begin
|
||
|
if i1 mod 10 = 0 then
|
||
|
Stroke.Color := Color10
|
||
|
else if i1 mod 5 = 0 then
|
||
|
Stroke.Color := Color5
|
||
|
else if FGridType = gt1in then
|
||
|
Stroke.Color := Color5
|
||
|
else
|
||
|
Stroke.Color := claWhite;
|
||
|
if Stroke.Color <> claWhite then
|
||
|
begin
|
||
|
if Self.Width >= Round(i) then
|
||
|
Line(Round(i) + 0.5, 0, Round(i) + 0.5, Round(Self.FPageHeight) * FScale);
|
||
|
if Self.Height >= Round(i) then
|
||
|
Line(0, Round(i) + 0.5, Round(Self.FPageWidth) * FScale, Round(i) + 0.5);
|
||
|
end;
|
||
|
i := i + dx;
|
||
|
Inc(i1);
|
||
|
end;
|
||
|
RestoreState(SState);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
FCanvas.Fill.Color := FColor;
|
||
|
FCanvas.Fill.Kind := TBrushKind.bkSolid;
|
||
|
FCanvas.FillRect(RectF(0, 0, Width, Height), 1, 1, AllCorners, 1, TCornerType.ctBevel);
|
||
|
|
||
|
if FShowGrid then
|
||
|
case FGridType of
|
||
|
gt1pt, gtDialog, gtChar:
|
||
|
DrawPoints;
|
||
|
gt1cm, gt1in:
|
||
|
DrawMM;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DrawSelectionRect;
|
||
|
var
|
||
|
sLeft, sTop, sRight, sBottom: Single;
|
||
|
begin
|
||
|
if not FDrawSelection then Exit;
|
||
|
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claBlack;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
Stroke.Dash := TStrokeDash.sdDot;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
StrokeDash := TStrokeDash.sdDot;
|
||
|
{$ENDIF}
|
||
|
Fill.Kind := TBrushKind.bkNone;
|
||
|
with FSelectionRect do
|
||
|
begin
|
||
|
sLeft := Left;
|
||
|
sRight := Right;
|
||
|
sTop := Top;
|
||
|
sBottom := Bottom;
|
||
|
if Right < Left then
|
||
|
begin
|
||
|
sLeft := Right;
|
||
|
sRight := Left;
|
||
|
end;
|
||
|
if Bottom < Top then
|
||
|
begin
|
||
|
sTop := Bottom;
|
||
|
sBottom := Top;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
DrawRect(RectF(Round(sLeft) + 0.5, Round(sTop) + 0.5, Round(sRight) + 0.5, Round(sBottom) + 0.5), 1, 1, AllCorners, 0.5);
|
||
|
Fill.Kind := TBrushKind.bkSolid;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DrawInsertionRect;
|
||
|
var
|
||
|
R: TfrxRect;
|
||
|
begin
|
||
|
if not FDrawInsertion then Exit;
|
||
|
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
Stroke.Color := claBlack;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
Stroke.Dash := TStrokeDash.sdDot;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
StrokeDash := TStrokeDash.sdDot;
|
||
|
{$ENDIF}
|
||
|
with FInsertion do
|
||
|
R := frxRect(Left, Top, Left + FInsertion.Width, Top + FInsertion.Height);
|
||
|
NormalizeRect(R);
|
||
|
DrawRect(RectF(Round(R.Left * FScale) + 0.5, Round(R.Top * FScale) + 0.5, Round(R.Right * FScale) + 0.5, Round(R.Bottom * FScale) + 0.5), 1, 1, AllCorners, 1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DrawCross;
|
||
|
var
|
||
|
x, y: Extended;
|
||
|
begin
|
||
|
if FMode1 <> dmInsertLine then
|
||
|
Exit;
|
||
|
|
||
|
with FInsertion do
|
||
|
if FMouseDown then
|
||
|
begin
|
||
|
if Flags <> 0 then
|
||
|
begin
|
||
|
x := (Left + Width) * FScale;
|
||
|
y := (Top + Height) * FScale;
|
||
|
end
|
||
|
else if Abs(Width) > Abs(Height) then
|
||
|
begin
|
||
|
x := (Left + Width) * FScale;
|
||
|
y := Top * FScale;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
x := Left * FScale;
|
||
|
y := (Top + Height) * FScale;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
x := Left * FScale;
|
||
|
y := Top * FScale;
|
||
|
end;
|
||
|
|
||
|
with Canvas do
|
||
|
begin
|
||
|
Stroke.Color := claBlack;
|
||
|
{$IFDEF Delphi25}
|
||
|
Stroke.Thickness := 1;
|
||
|
{$ELSE}
|
||
|
StrokeThickness := 1;
|
||
|
{$ENDIF}
|
||
|
Stroke.Kind := TBrushKind.bkSolid;
|
||
|
|
||
|
DrawLine(PointF(Round(x) - 3.5, Round(y) + 0.5), PointF(Round(x) + 4.5, Round(y) + 0.5), 1);
|
||
|
DrawLine(PointF(Round(x) + 0.5, Round(y) - 3.5), PointF(Round(x) + 0.5, Round(y) + 4.5), 1);
|
||
|
|
||
|
if FMouseDown then
|
||
|
DrawLine(PointF(Round(FInsertion.Left * FScale) + 0.5, Round(FInsertion.Top * FScale) + 0.5),
|
||
|
PointF(Round(x) + 0.5, Round(y) + 0.5), 1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.FindNearest(dx, dy: Integer);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c, sel, found: TfrxComponent;
|
||
|
min, dist, dist_dx, dist_dy: Extended;
|
||
|
r1, r2, r3: TfrxRect;
|
||
|
|
||
|
function RectsIntersect(r1, r2: TfrxRect): Boolean;
|
||
|
begin
|
||
|
Result := not ((r2.Left > r1.Right) or (r2.Right < r1.Left) or
|
||
|
(r2.Top > r1.Bottom) or (r2.Bottom < r1.Top));
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
if SelectedCount <> 1 then Exit;
|
||
|
|
||
|
found := nil;
|
||
|
sel := FSelectedObjects[0];
|
||
|
min := 1e10;
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if not (c is TfrxReportComponent) or (c is TfrxBand) or (c = sel) then continue;
|
||
|
|
||
|
r1 := frxRect(c.AbsLeft, c.AbsTop, c.AbsLeft + c.Width, c.AbsTop + c.Height);
|
||
|
dist := 0;
|
||
|
dist_dx := 0;
|
||
|
dist_dy := 0;
|
||
|
with sel do
|
||
|
if dx = 1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, AbsTop, 1e10, AbsTop + Height);
|
||
|
r3 := frxRect(AbsLeft, 0, 1e10, 1e10);
|
||
|
dist := r1.Left - r2.Left;
|
||
|
dist_dx := r1.Left - (AbsLeft + Width);
|
||
|
if r1.Top > r2.Top then
|
||
|
dist_dy := r1.Top - r2.Bottom else
|
||
|
dist_dy := r2.Top - r1.Bottom;
|
||
|
end
|
||
|
else if dx = -1 then
|
||
|
begin
|
||
|
r2 := frxRect(-1e10, AbsTop, AbsLeft + Width, AbsTop + Height);
|
||
|
r3 := frxRect(0, 0, AbsLeft + Width, 1e10);
|
||
|
dist := r2.Right - r1.Right;
|
||
|
dist_dx := AbsLeft - r1.Right;
|
||
|
if r1.Top > r2.Top then
|
||
|
dist_dy := r1.Top - r2.Bottom else
|
||
|
dist_dy := r2.Top - r1.Bottom;
|
||
|
end
|
||
|
else if dy = 1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, AbsTop, AbsLeft + Width, 1e10);
|
||
|
r3 := frxRect(0, AbsTop, 1e10, 1e10);
|
||
|
dist := r1.Top - r2.Top;
|
||
|
dist_dy := r1.Top - (AbsTop + Height);
|
||
|
if r1.Left > r2.Left then
|
||
|
dist_dx := r1.Left - r2.Right else
|
||
|
dist_dx := r2.Left - r1.Right;
|
||
|
end
|
||
|
else if dy = -1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, -1e10, AbsLeft + Width, AbsTop + Height);
|
||
|
r3 := frxRect(0, 0, 1e10, AbsTop + Height);
|
||
|
dist := r2.Bottom - r1.Bottom;
|
||
|
dist_dy := AbsTop - r1.Bottom;
|
||
|
if r1.Left > r2.Left then
|
||
|
dist_dx := r1.Left - r2.Right else
|
||
|
dist_dx := r2.Left - r1.Right;
|
||
|
end;
|
||
|
|
||
|
if not RectsIntersect(r1, r2) then
|
||
|
begin
|
||
|
if (not RectsIntersect(r1, r3)) or
|
||
|
((dx <> 0) and (dist_dx < dist_dy)) or
|
||
|
((dy <> 0) and (dist_dy < dist_dx)) or
|
||
|
((dist_dx = 0) and (dist_dy = 0)) then continue;
|
||
|
dist := sqrt(dist_dx * dist_dx + dist_dy * dist_dy) * (Width + Height);
|
||
|
end;
|
||
|
|
||
|
if dist < min then
|
||
|
begin
|
||
|
found := c;
|
||
|
min := dist;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if found <> nil then
|
||
|
begin
|
||
|
FSelectedObjects.Clear;
|
||
|
FSelectedObjects.Add(found);
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(GetSelectionBounds);
|
||
|
SelectionChanged;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.NormalizeCoord(c: TfrxComponent);
|
||
|
begin
|
||
|
if c.Width < 0 then
|
||
|
begin
|
||
|
c.Width := -c.Width;
|
||
|
c.Left := c.Left - c.Width;
|
||
|
end;
|
||
|
if c.Height < 0 then
|
||
|
begin
|
||
|
c.Height := -c.Height;
|
||
|
c.Top := c.Top - c.Height;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.NormalizeRect(var R: TfrxRect);
|
||
|
var
|
||
|
i: Extended;
|
||
|
begin
|
||
|
with R do
|
||
|
begin
|
||
|
if Left > Right then
|
||
|
begin
|
||
|
i := Left;
|
||
|
Left := Right;
|
||
|
Right := i
|
||
|
end;
|
||
|
if Top > Bottom then
|
||
|
begin
|
||
|
i := Top;
|
||
|
Top := Bottom;
|
||
|
Bottom := i
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.AdjustBands(AttachObjects: Boolean = True);
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
sl: TfrxStringList;
|
||
|
b: TfrxBand;
|
||
|
c, c0: TfrxComponent;
|
||
|
add, add1: Extended;
|
||
|
l: TList;
|
||
|
ch: TfrxChild;
|
||
|
|
||
|
procedure DoBand(Bnd: TfrxBand);
|
||
|
var
|
||
|
y: Extended;
|
||
|
begin
|
||
|
if Bnd.Vertical then Exit;
|
||
|
|
||
|
if Bnd is TfrxPageHeader then
|
||
|
y := 0
|
||
|
else if Bnd is TfrxReportTitle then
|
||
|
y := 0.01
|
||
|
else if Bnd is TfrxColumnHeader then
|
||
|
y := 0.02
|
||
|
else if Bnd is TfrxColumnFooter then
|
||
|
y := 99999
|
||
|
else if Bnd is TfrxReportSummary then
|
||
|
y := 100000
|
||
|
else if Bnd is TfrxPageFooter then
|
||
|
y := 100001
|
||
|
else
|
||
|
y := Abs(Bnd.Top);
|
||
|
|
||
|
if TfrxReportPage(FPage).TitleBeforeHeader then
|
||
|
begin
|
||
|
if Bnd is TfrxReportTitle then
|
||
|
y := 0
|
||
|
else if Bnd is TfrxPageHeader then
|
||
|
y := 0.01
|
||
|
end;
|
||
|
|
||
|
sl.AddObject(Format('%9.2f', [y]), Bnd);
|
||
|
end;
|
||
|
|
||
|
procedure TossObjects(Bnd: TfrxBand);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
SaveRestrictions: TfrxRestrictions;
|
||
|
begin
|
||
|
if Bnd.Vertical then Exit;
|
||
|
|
||
|
while Bnd.Objects.Count > 0 do
|
||
|
begin
|
||
|
c := Bnd.Objects[0];
|
||
|
SaveRestrictions := c.Restrictions;
|
||
|
c.Restrictions := [];
|
||
|
c.Top := c.AbsTop;
|
||
|
c.Restrictions := SaveRestrictions;
|
||
|
c.Parent := Bnd.Parent;
|
||
|
end;
|
||
|
|
||
|
if AttachObjects then
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (c is TfrxView) and (c.AbsTop >= Bnd.Top - 1e-4) and (c.AbsTop < Bnd.Top + Bnd.Height + 1e-4) then
|
||
|
begin
|
||
|
SaveRestrictions := c.Restrictions;
|
||
|
c.Restrictions := [];
|
||
|
c.Top := c.AbsTop - Bnd.Top;
|
||
|
c.Restrictions := SaveRestrictions;
|
||
|
c.Parent := Bnd;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function Round8(e: Extended): Extended;
|
||
|
begin
|
||
|
Result := Round(e * 100000000) / 100000000;
|
||
|
end;
|
||
|
|
||
|
procedure AdjustParent(Ctrl: TfrxComponent; Index: Integer);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
found: Boolean;
|
||
|
begin
|
||
|
found := False;
|
||
|
for i := Index - 1 downto 0 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (c <> Ctrl) and (c is TfrxDialogControl) {and
|
||
|
(csAcceptsControls in TfrxDialogControl(c).Control.ComponentStyle) }then
|
||
|
if (Ctrl.AbsLeft >= c.AbsLeft) and
|
||
|
(Ctrl.AbsTop >= c.AbsTop) and (Ctrl.AbsLeft < c.AbsLeft + c.Width) and
|
||
|
(Ctrl.AbsTop < c.AbsTop + c.Height) then
|
||
|
begin
|
||
|
Ctrl.Top := Ctrl.AbsTop - c.AbsTop;
|
||
|
Ctrl.Left := Ctrl.AbsLeft - c.AbsLeft;
|
||
|
Ctrl.Parent := c;
|
||
|
found := True;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if not found and (Ctrl.Parent <> Page) then
|
||
|
begin
|
||
|
Ctrl.Top := Ctrl.AbsTop;
|
||
|
Ctrl.Left := Ctrl.AbsLeft;
|
||
|
Ctrl.Parent := Page;
|
||
|
BringToFront;
|
||
|
end;
|
||
|
//if Ctrl is TfrxDialogComponent then
|
||
|
// Ctrl.Parent := Self;
|
||
|
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
sl := TfrxStringList.Create;
|
||
|
sl.Sorted := True;
|
||
|
sl.Duplicates := dupAccept;
|
||
|
|
||
|
{ sort bands }
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
if TObject(FObjects[i]) is TfrxBand then
|
||
|
DoBand(FObjects[i]);
|
||
|
|
||
|
{ arrange child bands }
|
||
|
sl.Sorted := False;
|
||
|
i := 0;
|
||
|
while i < sl.Count do
|
||
|
begin
|
||
|
sl[i] := '';
|
||
|
b := TfrxBand(sl.Objects[i]);
|
||
|
if b.Child <> nil then
|
||
|
begin
|
||
|
j := sl.IndexOfObject(b.Child);
|
||
|
if j <> -1 then
|
||
|
begin
|
||
|
c := TfrxComponent(sl.Objects[j]);
|
||
|
sl.Delete(j);
|
||
|
if j < i then
|
||
|
Dec(i);
|
||
|
sl.InsertObject(i + 1, '', c);
|
||
|
end;
|
||
|
end;
|
||
|
Inc(i);
|
||
|
end;
|
||
|
|
||
|
{ set top/middle/bottom indexes }
|
||
|
i := 0;
|
||
|
while i < sl.Count do
|
||
|
begin
|
||
|
b := TfrxBand(sl.Objects[i]);
|
||
|
if sl[i] = '' then
|
||
|
if (b is TfrxPageHeader) or (b is TfrxReportTitle) or (b is TfrxColumnHeader) then
|
||
|
sl[i] := 'top'
|
||
|
else if (b is TfrxPageFooter) or (b is TfrxReportSummary) or (b is TfrxColumnFooter) then
|
||
|
sl[i] := 'bottom'
|
||
|
else
|
||
|
sl[i] := 'middle';
|
||
|
ch := b.Child;
|
||
|
while ch <> nil do
|
||
|
begin
|
||
|
j := sl.IndexOfObject(ch);
|
||
|
if j <> -1 then
|
||
|
sl[j] := sl[i];
|
||
|
ch := ch.Child;
|
||
|
end;
|
||
|
Inc(i);
|
||
|
end;
|
||
|
|
||
|
add1 := 0;
|
||
|
case FGridType of
|
||
|
gt1pt: add1 := 40;
|
||
|
gt1cm: add1 := fr1cm;
|
||
|
gt1in: add1 := fr1in * 0.4;
|
||
|
gtChar: add1 := fr1CharY;
|
||
|
end;
|
||
|
|
||
|
{ rearrange all bands }
|
||
|
if not FFreeBandsPlacement then
|
||
|
for i := 0 to sl.Count - 1 do
|
||
|
begin
|
||
|
c := TfrxComponent(sl.Objects[i]);
|
||
|
if i = 0 then
|
||
|
c.Top := Round8(FBandHeader)
|
||
|
else
|
||
|
begin
|
||
|
c0 := TfrxComponent(sl.Objects[i - 1]);
|
||
|
if ((sl[i - 1] = 'top') and (sl[i] <> 'top')) or
|
||
|
((sl[i] = 'bottom') and (sl[i - 1] <> 'bottom')) then
|
||
|
add := add1 else
|
||
|
add := 0;
|
||
|
|
||
|
c.Top := Round8(Round((c0.Top + c0.Height + FBandHeader + FGapBetweenBands)
|
||
|
/ FGridY) * FGridY + add);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
sl.Free;
|
||
|
|
||
|
{ toss objects }
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if c is TfrxBand then
|
||
|
TossObjects(TfrxBand(c))
|
||
|
else if c is TfrxDialogControl then
|
||
|
AdjustParent(c, i);
|
||
|
end;
|
||
|
|
||
|
{ move all bands to the begin of objects list }
|
||
|
l := TList.Create;
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
if TObject(FObjects[i]) is TfrxBand then
|
||
|
l.Add(FObjects[i]);
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
if not (TObject(FObjects[i]) is TfrxBand) then
|
||
|
l.Add(FObjects[i]);
|
||
|
|
||
|
FObjects.Clear;
|
||
|
for i := 0 to l.Count - 1 do
|
||
|
FObjects.Add(l[i]);
|
||
|
l.Free;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.PrepareShiftTree(Band: TfrxBand);
|
||
|
var
|
||
|
i, j, k: Integer;
|
||
|
c0, c1, c2, top: TfrxReportComponent;
|
||
|
allObjects: TStringList;
|
||
|
Found: Boolean;
|
||
|
area0, area1, area2, area01: TfrxRectArea;
|
||
|
begin
|
||
|
allObjects := TfrxStringList.Create;
|
||
|
allObjects.Duplicates := dupAccept;
|
||
|
|
||
|
{ temporary top object }
|
||
|
top := TfrxMemoView.Create(nil);
|
||
|
top.SetBounds(0, Band.Top-2, Band.Width, 1);
|
||
|
|
||
|
{ sort objects }
|
||
|
for i := 0 to Band.Objects.Count - 1 do
|
||
|
begin
|
||
|
c0 := Band.Objects[i];
|
||
|
allObjects.AddObject(Format('%9.2f', [c0.Top]), c0);
|
||
|
c0.FShiftChildren.Clear;
|
||
|
end;
|
||
|
allObjects.Sort;
|
||
|
allObjects.InsertObject(0, Format('%10.2f', [top.Top]), top);
|
||
|
|
||
|
for i := 0 to allObjects.Count - 1 do
|
||
|
begin
|
||
|
c0 := TfrxReportComponent(allObjects.Objects[i]);
|
||
|
area0 := TfrxRectArea.Create(c0);
|
||
|
|
||
|
{ find an object under c0 }
|
||
|
for j := i + 1 to allObjects.Count - 1 do
|
||
|
begin
|
||
|
c1 := TfrxReportComponent(allObjects.Objects[j]);
|
||
|
area1 := TfrxRectArea.Create(c1);
|
||
|
|
||
|
if not (area0.InterceptsY(area1)) and (area0.Y < area1.Y) and
|
||
|
area0.InterceptsX(area1) then
|
||
|
begin
|
||
|
area01 := area0.InterceptX(area1);
|
||
|
Found := False;
|
||
|
|
||
|
{ check if there is no other objects between c1 and c0 }
|
||
|
for k := j - 1 downto i + 1 do
|
||
|
begin
|
||
|
c2 := TfrxReportComponent(allObjects.Objects[k]);
|
||
|
area2 := TfrxRectArea.Create(c2);
|
||
|
|
||
|
if not (area0.InterceptsY(area2)) and not (area1.InterceptsY(area2)) and
|
||
|
area01.InterceptsX(area2) then
|
||
|
Found := True;
|
||
|
|
||
|
area2.Free;
|
||
|
if Found then
|
||
|
break;
|
||
|
end;
|
||
|
|
||
|
if not Found then
|
||
|
c0.FShiftChildren.Add(c1);
|
||
|
|
||
|
area01.Free;
|
||
|
end;
|
||
|
|
||
|
area1.Free;
|
||
|
end;
|
||
|
|
||
|
area0.Free;
|
||
|
end;
|
||
|
|
||
|
{ copy children from the top object to the band }
|
||
|
Band.FShiftChildren.Clear;
|
||
|
for i := 0 to top.FShiftChildren.Count - 1 do
|
||
|
Band.FShiftChildren.Add(top.FShiftChildren[i]);
|
||
|
|
||
|
allObjects.Free;
|
||
|
top.Free;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.AdjustBandHeight(Bnd: TfrxBand);
|
||
|
var
|
||
|
i: Integer;
|
||
|
max, min: Extended;
|
||
|
c: TfrxComponent;
|
||
|
begin
|
||
|
max := 0;
|
||
|
min := 0;
|
||
|
for i := 0 to Bnd.Objects.Count - 1 do
|
||
|
begin
|
||
|
c := Bnd.Objects[i];
|
||
|
if (c is TfrxView) and (TfrxView(c).Align in [baClient, baBottom]) then
|
||
|
continue;
|
||
|
if c.Top + c.Height > max then
|
||
|
max := c.Top + c.Height;
|
||
|
if c.Top < min then
|
||
|
min := c.Top;
|
||
|
end;
|
||
|
|
||
|
max := max - min;
|
||
|
if Bnd.Height < max then
|
||
|
Bnd.Height := max;
|
||
|
if min < 0 then
|
||
|
for i := 0 to Bnd.Objects.Count - 1 do
|
||
|
with TfrxComponent(Bnd.Objects[i]) do
|
||
|
Top := Top - min;
|
||
|
end;
|
||
|
|
||
|
function TfrxDesignerWorkspace.ListsEqual(List1, List2: TList): Boolean;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
Result := List1.Count = List2.Count;
|
||
|
if Result then
|
||
|
for i := 0 to List1.Count - 1 do
|
||
|
if List1.List[i] <> List2.List[i] then
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DeleteObjects;
|
||
|
var
|
||
|
c, c1: TfrxComponent;
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if SelectedCount = 0 then exit;
|
||
|
|
||
|
i := 0;
|
||
|
while FSelectedObjects.Count > i do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
|
||
|
if not (rfDontDelete in c.Restrictions) then
|
||
|
begin
|
||
|
if c.IsAncestor then
|
||
|
raise Exception.Create('Could not delete ' + c.Name + ', it was introduced in the ancestor report');
|
||
|
FSelectedObjects.Remove(c);
|
||
|
FObjects.Remove(c);
|
||
|
|
||
|
while c.Objects.Count > 0 do
|
||
|
begin
|
||
|
c1 := c.Objects[0];
|
||
|
FSelectedObjects.Remove(c1);
|
||
|
FObjects.Remove(c1);
|
||
|
c1.Free;
|
||
|
end;
|
||
|
|
||
|
c.Free;
|
||
|
end
|
||
|
else
|
||
|
Inc(i);
|
||
|
end;
|
||
|
|
||
|
if FSelectedObjects.Count = 0 then
|
||
|
FSelectedObjects.Add(FPage);
|
||
|
|
||
|
AdjustBands;
|
||
|
FModifyFlag := True;
|
||
|
DoModify;
|
||
|
SelectionChanged;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.EditObject;
|
||
|
begin
|
||
|
if FSelectedObjects.Count = 1 then
|
||
|
if Assigned(FOnEdit) then
|
||
|
FOnEdit(Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoNudge(dx, dy: Extended; Smooth: Boolean);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
begin
|
||
|
if SelectedCount = 0 then exit;
|
||
|
if not Smooth or (GridType = gtChar) then
|
||
|
begin
|
||
|
dx := dx * FGridX;
|
||
|
dy := dy * FGridY;
|
||
|
end;
|
||
|
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.Left := c.Left + dx;
|
||
|
c.Top := c.Top + dy;
|
||
|
end;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(GetSelectionBounds);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoSize(dx, dy: Extended);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
begin
|
||
|
if SelectedCount = 0 then exit;
|
||
|
dx := dx * FGridX;
|
||
|
dy := dy * FGridY;
|
||
|
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.Width := c.Width + dx;
|
||
|
if c.Width < 0 then
|
||
|
c.Width := c.Width - dx;
|
||
|
c.Height := c.Height + dy;
|
||
|
if c.Height < 0 then
|
||
|
c.Height := c.Height - dy;
|
||
|
end;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(GetSelectionBounds);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoStick(dx, dy: Integer);
|
||
|
var
|
||
|
i: Integer;
|
||
|
c, sel, found: TfrxComponent;
|
||
|
min, dist: Extended;
|
||
|
r1, r2: TfrxRect;
|
||
|
gapLeft, gapRight, gapTop, gapBottom: Extended;
|
||
|
|
||
|
function RectsIntersect(r1, r2: TfrxRect): Boolean;
|
||
|
begin
|
||
|
Result := not ((r2.Left > r1.Right) or (r2.Right < r1.Left) or
|
||
|
(r2.Top > r1.Bottom) or (r2.Bottom < r1.Top));
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
if SelectedCount <> 1 then exit;
|
||
|
|
||
|
found := nil;
|
||
|
sel := FSelectedObjects[0];
|
||
|
min := 1e10;
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if not (c is TfrxReportComponent) or (c is TfrxBand) or (c = sel) then continue;
|
||
|
|
||
|
r1 := frxRect(c.AbsLeft, c.AbsTop, c.AbsLeft + c.Width, c.AbsTop + c.Height);
|
||
|
dist := 0;
|
||
|
with sel do
|
||
|
if dx = 1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, AbsTop, 1e10, AbsTop + Height);
|
||
|
dist := r1.Left - r2.Left;
|
||
|
end
|
||
|
else if dx = -1 then
|
||
|
begin
|
||
|
r2 := frxRect(-1e10, AbsTop, AbsLeft + Width, AbsTop + Height);
|
||
|
dist := r2.Right - r1.Right;
|
||
|
end
|
||
|
else if dy = 1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, AbsTop, AbsLeft + Width, 1e10);
|
||
|
dist := r1.Top - r2.Top;
|
||
|
end
|
||
|
else if dy = -1 then
|
||
|
begin
|
||
|
r2 := frxRect(AbsLeft, -1e10, AbsLeft + Width, AbsTop + Height);
|
||
|
dist := r2.Bottom - r1.Bottom;
|
||
|
end;
|
||
|
|
||
|
if RectsIntersect(r1, r2) then
|
||
|
if dist < min then
|
||
|
begin
|
||
|
found := c;
|
||
|
min := dist;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if found <> nil then
|
||
|
begin
|
||
|
gapLeft := 0;
|
||
|
gapRight := 0;
|
||
|
gapTop := 0;
|
||
|
gapBottom := 0;
|
||
|
if (sel is TfrxDMPMemoView) and (found is TfrxDMPMemoView) then
|
||
|
begin
|
||
|
if (ftLeft in TfrxDMPMemoView(sel).Frame.Typ) or
|
||
|
(ftRight in TfrxDMPMemoView(found).Frame.Typ) then
|
||
|
gapLeft := fr1CharX;
|
||
|
if (ftRight in TfrxDMPMemoView(sel).Frame.Typ) or
|
||
|
(ftLeft in TfrxDMPMemoView(found).Frame.Typ) then
|
||
|
gapRight := fr1CharX;
|
||
|
if (ftTop in TfrxDMPMemoView(sel).Frame.Typ) or
|
||
|
(ftBottom in TfrxDMPMemoView(found).Frame.Typ) then
|
||
|
gapTop := fr1CharY;
|
||
|
if (ftBottom in TfrxDMPMemoView(sel).Frame.Typ) or
|
||
|
(ftTop in TfrxDMPMemoView(found).Frame.Typ) then
|
||
|
gapBottom := fr1CharY;
|
||
|
end;
|
||
|
if dx = 1 then
|
||
|
sel.Left := found.Left - sel.Width - gapRight
|
||
|
else if dx = -1 then
|
||
|
sel.Left := found.Left + found.Width + gapLeft
|
||
|
else if dy = 1 then
|
||
|
sel.Top := found.Top - sel.Height - gapBottom
|
||
|
else if dy = -1 then
|
||
|
sel.Top := found.Top + found.Height + gapTop;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(GetSelectionBounds);
|
||
|
Repaint;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DoTab;
|
||
|
var
|
||
|
c: TfrxComponent;
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if SelectedCount <> 1 then Exit;
|
||
|
|
||
|
c := SelectedObjects[0];
|
||
|
if (c is TfrxBand) and (c.Objects.Count > 0) then
|
||
|
SelectedObjects[0] := c.Objects[0]
|
||
|
else if c is TfrxView then
|
||
|
begin
|
||
|
i := c.Parent.Objects.IndexOf(c);
|
||
|
if i = c.Parent.Objects.Count - 1 then
|
||
|
i := 0
|
||
|
else
|
||
|
Inc(i);
|
||
|
SelectedObjects[0] := c.Parent.Objects[i];
|
||
|
end;
|
||
|
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(GetSelectionBounds);
|
||
|
SelectionChanged;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.KeyDown(var Key: Word; var KeyChar: WideChar; Shift: TShiftState);
|
||
|
var
|
||
|
dx, dy: Integer;
|
||
|
begin
|
||
|
if FDisableUpdate then
|
||
|
Exit;
|
||
|
|
||
|
dx := 0; dy := 0;
|
||
|
|
||
|
//if Shift = [] then
|
||
|
case Key of
|
||
|
vkDelete,
|
||
|
vkBack:
|
||
|
DeleteObjects;
|
||
|
|
||
|
vkReturn:
|
||
|
EditObject;
|
||
|
|
||
|
vkLeft:
|
||
|
dx := -1;
|
||
|
|
||
|
vkRight:
|
||
|
dx := 1;
|
||
|
|
||
|
vkUp:
|
||
|
dy := -1;
|
||
|
|
||
|
vkDown:
|
||
|
dy := 1;
|
||
|
|
||
|
vkTab:
|
||
|
DoTab;
|
||
|
end;
|
||
|
|
||
|
if (dx <> 0) or (dy <> 0) then
|
||
|
begin
|
||
|
if ssCtrl in Shift then
|
||
|
DoNudge(dx, dy, not (ssShift in Shift))
|
||
|
else if ssShift in Shift then
|
||
|
DoSize(dx, dy)
|
||
|
else if ssAlt in Shift then
|
||
|
DoStick(dx, dy)
|
||
|
else
|
||
|
FindNearest(dx, dy);
|
||
|
AdjustBands;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.KeyUp(var Key: Word; var KeyChar: WideChar; Shift: TShiftState);
|
||
|
begin
|
||
|
if FDisableUpdate then exit;
|
||
|
DoModify;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
c, c1: TfrxComponent;
|
||
|
EmptySpace: Boolean;
|
||
|
l: TList;
|
||
|
NeedRepaint: Boolean;
|
||
|
|
||
|
function Contain(c: TfrxComponent): Boolean;
|
||
|
var
|
||
|
w0, w1, w2, w3: Extended;
|
||
|
Left, Top, Right, Bottom, e, k, mx, my: Extended;
|
||
|
begin
|
||
|
Result := False;
|
||
|
w0 := 0;
|
||
|
w1 := 0;
|
||
|
w2 := 0;
|
||
|
if c.Width = 0 then
|
||
|
begin
|
||
|
w0 := 4;
|
||
|
w1 := 4
|
||
|
end
|
||
|
else if c.Height = 0 then
|
||
|
w2 := 4;
|
||
|
w3 := w2;
|
||
|
if c is TfrxBand then
|
||
|
if TfrxBand(c).Vertical then
|
||
|
w0 := FBandHeader
|
||
|
else
|
||
|
w2 := FBandHeader;
|
||
|
|
||
|
Left := c.AbsLeft;
|
||
|
Right := c.AbsLeft + c.Width;
|
||
|
Top := c.AbsTop;
|
||
|
Bottom := c.AbsTop + c.Height;
|
||
|
mx := X / FScale;
|
||
|
my := Y / FScale;
|
||
|
|
||
|
if Right < Left then
|
||
|
begin
|
||
|
e := Right;
|
||
|
Right := Left;
|
||
|
Left := e;
|
||
|
end;
|
||
|
if Bottom < Top then
|
||
|
begin
|
||
|
e := Bottom;
|
||
|
Bottom := Top;
|
||
|
Top := e;
|
||
|
end;
|
||
|
|
||
|
if (c is TfrxLineView) and TfrxLineView(c).Diagonal and
|
||
|
(c.Width <> 0) and (c.Height <> 0) then
|
||
|
begin
|
||
|
k := c.Height / c.Width;
|
||
|
if Abs((k * (mx - c.AbsLeft) - (my - c.AbsTop)) * cos(arctan(k))) < 5 then
|
||
|
Result := True;
|
||
|
if (mx < Left - 5) or (mx > Right + 5) or (my < Top - 5) or (my > Bottom + 5) then
|
||
|
Result := False;
|
||
|
end
|
||
|
else if (mx >= Left - w0) and (mx <= Right + w1) and
|
||
|
(my >= Top - w2) and (my <= Bottom + w3) then
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
inherited;
|
||
|
{$IFDEF MACOS}
|
||
|
X := X - 2;
|
||
|
Y := Y - 2;
|
||
|
{$ENDIF}
|
||
|
|
||
|
if FDisableUpdate or FMouseDown then exit;
|
||
|
if FDblClicked then
|
||
|
begin
|
||
|
FDblClicked := False;
|
||
|
exit;
|
||
|
end;
|
||
|
|
||
|
l := TList.Create;
|
||
|
for i := 0 to FSelectedObjects.Count - 1 do
|
||
|
l.Add(FSelectedObjects[i]);
|
||
|
|
||
|
//if FPage is TfrxReportPage then
|
||
|
// ValidParentForm(Self).ActiveControl := Parent else
|
||
|
// ValidParentForm(Self).ActiveControl := nil;
|
||
|
|
||
|
SetFocus;
|
||
|
|
||
|
FMouseDown := True;
|
||
|
FLastMousePointX := X / FScale;
|
||
|
FLastMousePointY := Y / FScale;
|
||
|
NeedRepaint := False;
|
||
|
|
||
|
// Ctrl was pressed
|
||
|
if (FMode1 = dmNone) and (ssCtrl in Shift) then
|
||
|
begin
|
||
|
FSelectedObjects.Clear;
|
||
|
FSelectedObjects.Add(FPage);
|
||
|
FMode1 := dmSelectionRect;
|
||
|
FDrawSelection := True;
|
||
|
FSelectionRect := frxRect(X, Y, X, Y);
|
||
|
NeedRepaint := True;
|
||
|
end;
|
||
|
|
||
|
// clicked on object or on empty space
|
||
|
if FMode1 = dmNone then
|
||
|
begin
|
||
|
EmptySpace := True;
|
||
|
|
||
|
for i := FObjects.Count - 1 downto 0 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (c is TfrxReportComponent) and Contain(c) then
|
||
|
begin
|
||
|
EmptySpace := False;
|
||
|
|
||
|
if csContainer in c.frComponentStyle then
|
||
|
begin
|
||
|
if c.ContainerMouseDown(Self, Round(X), Round(Y)) then
|
||
|
FMode1 := dmContainer
|
||
|
else
|
||
|
for j := c.ContainerObjects.Count - 1 downto 0 do
|
||
|
begin
|
||
|
c1 := c.ContainerObjects[j];
|
||
|
if c1.Visible and Contain(c1) then
|
||
|
begin
|
||
|
c := c1;
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if ssShift in Shift then
|
||
|
if FSelectedObjects.IndexOf(c) <> -1 then
|
||
|
FSelectedObjects.Remove(c) else
|
||
|
FSelectedObjects.Add(c)
|
||
|
else if FSelectedObjects.IndexOf(c) = -1 then
|
||
|
begin
|
||
|
FSelectedObjects.Clear;
|
||
|
FSelectedObjects.Add(c);
|
||
|
end;
|
||
|
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if EmptySpace then
|
||
|
begin
|
||
|
FSelectedObjects.Clear;
|
||
|
FSelectedObjects.Add(FPage);
|
||
|
FMode1 := dmSelectionRect;
|
||
|
FDrawSelection := True;
|
||
|
FSelectionRect := frxRect(X, Y, X, Y);
|
||
|
end
|
||
|
else if FSelectedObjects.Count = 0 then
|
||
|
begin
|
||
|
FSelectedObjects.Add(FPage);
|
||
|
FMode1 := dmNone;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
FSelectedObjects.Remove(FPage);
|
||
|
if FMode1 <> dmContainer then
|
||
|
FMode1 := dmMove;
|
||
|
end;
|
||
|
|
||
|
NeedRepaint := True;
|
||
|
end;
|
||
|
|
||
|
//band detach band objects
|
||
|
if (FMode1 = dmMove) and (FSelectedObjects.Count = 1) and
|
||
|
(TObject(FSelectedObjects[0]) is TfrxBand) and (ssAlt in Shift) then
|
||
|
AdjustBands(False);
|
||
|
|
||
|
// scaling
|
||
|
if FMode1 = dmScale then
|
||
|
begin
|
||
|
FScaleRect := GetSelectionBounds;
|
||
|
FScaleRect.Right := FScaleRect.Right + FScaleRect.Left;
|
||
|
FScaleRect.Bottom := FScaleRect.Bottom + FScaleRect.Top;
|
||
|
FScaleRect1 := FScaleRect;
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
THackComponent(c).FOriginalRect := frxRect(c.AbsLeft, c.AbsTop, c.Width, c.Height);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
// inserting a line
|
||
|
if FMode1 = dmInsertLine then
|
||
|
begin
|
||
|
FInsertion.Width := 0;
|
||
|
FInsertion.Height := 0;
|
||
|
end;
|
||
|
|
||
|
if NeedRepaint then
|
||
|
if not ListsEqual(l, FSelectedObjects) then
|
||
|
SelectionChanged else
|
||
|
Repaint;
|
||
|
|
||
|
if Button = TMouseButton.mbRight then
|
||
|
begin
|
||
|
FMode1 := dmNone;
|
||
|
FMouseDown := False;
|
||
|
Repaint;
|
||
|
if Assigned(FOnPopup) then
|
||
|
FOnPopup(Self, X, Y);
|
||
|
end;
|
||
|
|
||
|
if FMode1 = dmMove then
|
||
|
begin
|
||
|
for i := 0 to FSelectedObjects.Count - 1 do
|
||
|
if TObject(FSelectedObjects[i]) is TfrxView then
|
||
|
begin
|
||
|
FSavedAlign.Add(Pointer(Integer(TfrxView(FSelectedObjects[i]).Align)));
|
||
|
TfrxView(FSelectedObjects[i]).Align := baNone;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
l.Free;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.MouseMove(Shift: TShiftState; X, Y: Single);
|
||
|
var
|
||
|
c: TfrxComponent;
|
||
|
kx, ky, nx, ny: Extended;
|
||
|
i: Integer;
|
||
|
NotifyRect, SaveBounds: TfrxRect;
|
||
|
dpage: TfrxDialogPage;
|
||
|
|
||
|
function Contain(px, py: Extended): Boolean;
|
||
|
begin
|
||
|
Result := (X / FScale >= px - 2) and (X / FScale <= px + 3) and
|
||
|
(Y / FScale >= py - 2) and (Y / FScale <= py + 3);
|
||
|
end;
|
||
|
|
||
|
function Contain0(py: Extended): Boolean;
|
||
|
begin
|
||
|
Result := (Y / FScale >= py - 2) and (Y / FScale <= py + 2);
|
||
|
end;
|
||
|
|
||
|
function Contain1(px, py: Extended): Boolean;
|
||
|
begin
|
||
|
Result := (FLastMousePointX >= px - 2) and (FLastMousePointX <= px + 3) and
|
||
|
(FLastMousePointY >= py - 2) and (FLastMousePointY <= py + 3);
|
||
|
end;
|
||
|
|
||
|
function Contain2(c: TfrxComponent): Boolean;
|
||
|
var
|
||
|
w1, w2: Integer;
|
||
|
begin
|
||
|
w1 := 0;
|
||
|
w2 := 0;
|
||
|
if c.Width = 0 then
|
||
|
w1 := 4 else
|
||
|
w2 := 4;
|
||
|
if (X / FScale >= c.AbsLeft - w1) and (X / FScale <= c.AbsLeft + c.Width + w1) and
|
||
|
(Y / FScale >= c.AbsTop - w2) and (Y / FScale <= c.AbsTop + c.Height + w2) then
|
||
|
Result := True else
|
||
|
Result := False;
|
||
|
end;
|
||
|
|
||
|
function Contain3(px: Extended): Boolean;
|
||
|
begin
|
||
|
Result := (X / FScale >= px - 2) and (X / FScale <= px + 2);
|
||
|
end;
|
||
|
|
||
|
function GridCheck: Boolean;
|
||
|
begin
|
||
|
Result := (kx >= FGridX) or (kx <= -FGridX) or
|
||
|
(ky >= FGridY) or (ky <= -FGridY);
|
||
|
if Result then
|
||
|
begin
|
||
|
kx := Trunc(kx / FGridX) * FGridX;
|
||
|
ky := Trunc(ky / FGridY) * FGridY;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function CheckMove: Boolean;
|
||
|
var
|
||
|
al: Boolean;
|
||
|
begin
|
||
|
al := FGridAlign;
|
||
|
if ssAlt in Shift then
|
||
|
al := not al;
|
||
|
|
||
|
Result := False;
|
||
|
|
||
|
if (al and not GridCheck) or ((kx = 0) and (ky = 0)) then
|
||
|
Result := True;
|
||
|
|
||
|
CheckGuides(kx, ky, Result);
|
||
|
end;
|
||
|
|
||
|
procedure CheckNegative(c: TfrxComponent);
|
||
|
const
|
||
|
ar1: array[ct1..ct8] of TfrxCursorType = (ct3, ct4, ct1, ct2, ct6, ct5, ct0, ct0);
|
||
|
ar2: array[ct1..ct8] of TfrxCursorType = (ct4, ct3, ct2, ct1, ct0, ct0, ct8, ct7);
|
||
|
ar3: array[ct1..ct8] of TfrxCursorType = (ct2, ct1, ct4, ct3, ct0, ct0, ct0, ct0);
|
||
|
begin
|
||
|
if (c is TfrxLineView) and (TfrxLineView(c).Diagonal = True) then exit;
|
||
|
if (c.Width < 0) and (c.Height < 0) then
|
||
|
FCT := ar3[FCT]
|
||
|
else if c.Width < 0 then
|
||
|
FCT := ar1[FCT]
|
||
|
else if c.Height < 0 then
|
||
|
FCT := ar2[FCT];
|
||
|
NormalizeCoord(c);
|
||
|
end;
|
||
|
|
||
|
procedure CTtoCursor;
|
||
|
const
|
||
|
ar: array[ct0..ct10] of TCursor =
|
||
|
(crDefault, crSizeNWSE, crSizeNWSE, crSizeNESW,
|
||
|
crSizeNESW, crSizeWE, crSizeWE, crSizeNS, crSizeNS, crCross, crCross);
|
||
|
begin
|
||
|
Cursor := ar[FCT];
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
inherited;
|
||
|
if FDisableUpdate then Exit;
|
||
|
{$IFDEF MACOS}
|
||
|
X := X - 2;
|
||
|
Y := Y - 2;
|
||
|
{$ENDIF}
|
||
|
|
||
|
if SelectedCount = 0 then
|
||
|
NotifyRect := frxRect(X / FScale, Y / FScale, 0, 0) else
|
||
|
NotifyRect := GetSelectionBounds;
|
||
|
|
||
|
// cursor shapes
|
||
|
if not FMouseDown and (FMode = dmSelect) then
|
||
|
if SelectedCount = 1 then
|
||
|
begin
|
||
|
FMode1 := dmSize;
|
||
|
c := FSelectedObjects[0];
|
||
|
FCT := ct0;
|
||
|
if Contain(c.AbsLeft, c.AbsTop) then
|
||
|
FCT := ct1
|
||
|
else if Contain(c.AbsLeft + c.Width, c.AbsTop + c.Height) then
|
||
|
FCT := ct2
|
||
|
else if Contain(c.AbsLeft + c.Width, c.AbsTop) then
|
||
|
FCT := ct3
|
||
|
else if Contain(c.AbsLeft, c.AbsTop + c.Height) then
|
||
|
FCT := ct4
|
||
|
else if Contain(c.AbsLeft + c.Width, c.AbsTop + c.Height / 2) then
|
||
|
FCT := ct5
|
||
|
else if Contain(c.AbsLeft, c.AbsTop + c.Height / 2) then
|
||
|
FCT := ct6
|
||
|
else if Contain(c.AbsLeft + c.Width / 2, c.AbsTop) then
|
||
|
FCT := ct7
|
||
|
else if Contain(c.AbsLeft + c.Width / 2, c.AbsTop + c.Height) then
|
||
|
FCT := ct8;
|
||
|
|
||
|
if c is TfrxCustomLineView then
|
||
|
if not TfrxCustomLineView(c).Diagonal then
|
||
|
begin
|
||
|
if c.Width = 0 then
|
||
|
if FCT in [ct1, ct3] then
|
||
|
FCT := ct7
|
||
|
else if FCT in [ct4, ct2] then
|
||
|
FCT := ct8
|
||
|
else
|
||
|
FCT := ct0;
|
||
|
if c.Height = 0 then
|
||
|
if FCT in [ct1, ct4] then
|
||
|
FCT := ct6
|
||
|
else if FCT in [ct3, ct2] then
|
||
|
FCT := ct5
|
||
|
else
|
||
|
FCT := ct0;
|
||
|
end
|
||
|
else
|
||
|
if FCT = ct1 then
|
||
|
FCT := ct9
|
||
|
else if FCT = ct2 then
|
||
|
FCT := ct10
|
||
|
else
|
||
|
FCT := ct0;
|
||
|
|
||
|
|
||
|
if FCT = ct0 then
|
||
|
FMode1 := dmNone;
|
||
|
CTtoCursor;
|
||
|
end
|
||
|
else if SelectedCount > 1 then
|
||
|
begin
|
||
|
FMode1 := dmScale;
|
||
|
c := GetRightBottomObject;
|
||
|
if (c <> nil) and Contain(c.AbsLeft + c.Width, c.AbsTop + c.Height) then
|
||
|
Cursor := crSizeNWSE
|
||
|
else
|
||
|
begin
|
||
|
Cursor := crDefault;
|
||
|
FMode1 := dmNone;
|
||
|
end;
|
||
|
end
|
||
|
else if FPage is TfrxDialogPage then
|
||
|
begin
|
||
|
FMode1 := dmSize;
|
||
|
dpage := TfrxDialogPage(FPage);
|
||
|
FCT := ct0;
|
||
|
if Contain(dpage.ClientWidth - 2, dpage.ClientHeight - 2) then
|
||
|
FCT := ct2
|
||
|
else if Contain(dpage.ClientWidth - 2, dpage.ClientHeight / 2 - 1) then
|
||
|
FCT := ct5
|
||
|
else if Contain(dpage.ClientWidth / 2 - 1, dpage.ClientHeight - 2) then
|
||
|
FCT := ct8;
|
||
|
|
||
|
if FCT = ct0 then
|
||
|
FMode1 := dmNone;
|
||
|
CTtoCursor;
|
||
|
end
|
||
|
else
|
||
|
Cursor := crDefault;
|
||
|
|
||
|
// resizing a band - setup
|
||
|
if not FMouseDown and (FMode = dmSelect) and not (FMode1 in [dmSize, dmScale]) then
|
||
|
begin
|
||
|
Cursor := crDefault;
|
||
|
FMode1 := dmNone;
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
|
||
|
if c is TfrxBand then
|
||
|
if TfrxBand(c).Vertical then
|
||
|
begin
|
||
|
if Contain3(c.Left + c.Width) then
|
||
|
begin
|
||
|
Cursor := crHSplit;
|
||
|
FMode1 := dmSizeBand;
|
||
|
FSizedBand := TfrxBand(c);
|
||
|
break;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if Contain0(c.Top + c.Height) then
|
||
|
begin
|
||
|
Cursor := crVSplit;
|
||
|
FMode1 := dmSizeBand;
|
||
|
FSizedBand := TfrxBand(c);
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
// resizing a band
|
||
|
if FMouseDown and (FMode1 = dmSizeBand) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
if FSizedBand.Vertical then
|
||
|
FSizedBand.Width := FSizedBand.Width + kx
|
||
|
else
|
||
|
FSizedBand.Height := FSizedBand.Height + ky;
|
||
|
AdjustBandHeight(FSizedBand);
|
||
|
AdjustBands;
|
||
|
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
Repaint;
|
||
|
with FSizedBand do
|
||
|
NotifyRect := frxRect(Left, Top, Width, Height);
|
||
|
end;
|
||
|
|
||
|
// inserting
|
||
|
if not FMouseDown and (FMode1 = dmInsertObject) then
|
||
|
begin
|
||
|
kx := X / FScale - FInsertion.Left;
|
||
|
ky := Y / FScale - FInsertion.Top;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FInsertion.Left := FInsertion.Left + kx;
|
||
|
FInsertion.Top := FInsertion.Top + ky;
|
||
|
FDrawInsertion := True;
|
||
|
Repaint;
|
||
|
with FInsertion do
|
||
|
NotifyRect := frxRect(Left, Top, Width, Height);
|
||
|
end;
|
||
|
|
||
|
// inserting + resizing
|
||
|
if FMouseDown and (FMode1 = dmInsertObject) then
|
||
|
begin
|
||
|
kx := X / FScale - FInsertion.Left;
|
||
|
ky := Y / FScale - FInsertion.Top;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FInsertion.Width := kx;
|
||
|
FInsertion.Height := ky;
|
||
|
FDrawInsertion := True;
|
||
|
Repaint;
|
||
|
with FInsertion do
|
||
|
NotifyRect := frxRect(Left, Top, Width, Height);
|
||
|
end;
|
||
|
|
||
|
// moving
|
||
|
if FMouseDown and (FMode1 = dmMove) and not(ssShift in Shift) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
{ vertical band }
|
||
|
if not FModifyFlag and (SelectedCount = 1) and
|
||
|
(TObject(FSelectedObjects[0]) is TfrxBand) and
|
||
|
(TfrxBand(FSelectedObjects[0]).Vertical) then
|
||
|
begin
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (c is TfrxView) and
|
||
|
(c.Left >= TfrxBand(FSelectedObjects[0]).Left - 1e-4) and
|
||
|
(c.Left + c.Width <= TfrxBand(FSelectedObjects[0]).Left +
|
||
|
TfrxBand(FSelectedObjects[0]).Width + 1e-4) then
|
||
|
FSelectedObjects.Add(c);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if (TObject(FSelectedObjects[0]) is TfrxBand) and
|
||
|
(TfrxBand(FSelectedObjects[0]).Vertical) then
|
||
|
ky := 0;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.Left := c.Left + kx;
|
||
|
if FSelectedObjects.IndexOf(c.Parent) = -1 then
|
||
|
begin
|
||
|
if c.IsAncestor and (c is TfrxView) then
|
||
|
if (c.Top + ky < -1e-4) or (c.Top + ky > c.Parent.Height) then
|
||
|
continue;
|
||
|
c.Top := c.Top + ky;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
Repaint;
|
||
|
NotifyRect := GetSelectionBounds;
|
||
|
end;
|
||
|
|
||
|
// resizing one object
|
||
|
if FMouseDown and (FMode1 = dmSize) and (SelectedCount = 1) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
c := FSelectedObjects[0];
|
||
|
SaveBounds := frxRect(c.Left, c.Top, c.Width, c.Height);
|
||
|
case FCT of
|
||
|
ct1, ct9:
|
||
|
begin
|
||
|
c.Left := c.Left + kx;
|
||
|
c.Width := c.Width - kx;
|
||
|
c.Top := c.Top + ky;
|
||
|
c.Height := c.Height - ky;
|
||
|
end;
|
||
|
|
||
|
ct2, ct10:
|
||
|
begin
|
||
|
c.Width := c.Width + kx;
|
||
|
c.Height := c.Height + ky;
|
||
|
end;
|
||
|
|
||
|
ct3:
|
||
|
begin
|
||
|
c.Top := c.Top + ky;
|
||
|
c.Width := c.Width + kx;
|
||
|
c.Height := c.Height - ky;
|
||
|
end;
|
||
|
|
||
|
ct4:
|
||
|
begin
|
||
|
c.Left := c.Left + kx;
|
||
|
c.Width := c.Width - kx;
|
||
|
c.Height := c.Height + ky;
|
||
|
end;
|
||
|
|
||
|
ct5:
|
||
|
begin
|
||
|
c.Width := c.Width + kx;
|
||
|
end;
|
||
|
|
||
|
ct6:
|
||
|
begin
|
||
|
c.Left := c.Left + kx;
|
||
|
c.Width := c.Width - kx;
|
||
|
end;
|
||
|
|
||
|
ct7:
|
||
|
begin
|
||
|
c.Top := c.Top + ky;
|
||
|
c.Height := c.Height - ky;
|
||
|
end;
|
||
|
|
||
|
ct8:
|
||
|
begin
|
||
|
c.Height := c.Height + ky;
|
||
|
end;
|
||
|
end;
|
||
|
CheckNegative(c);
|
||
|
CTtoCursor;
|
||
|
|
||
|
if c.Left < 0 then
|
||
|
c.Left := 0;
|
||
|
|
||
|
if c.IsAncestor and (c is TfrxView) then
|
||
|
if (c.Top < -1e-4) or (c.Top > c.Parent.Height) then
|
||
|
c.SetBounds(SaveBounds.Left, SaveBounds.Top, SaveBounds.Right, SaveBounds.Bottom);
|
||
|
|
||
|
if c is TfrxBand then
|
||
|
begin
|
||
|
if FCT in [ct1, ct3, ct7] then
|
||
|
for i := 0 to c.Objects.Count - 1 do
|
||
|
with TfrxComponent(c.Objects[i]) do
|
||
|
Top := Top - ky;
|
||
|
AdjustBandHeight(TfrxBand(c));
|
||
|
AdjustBands;
|
||
|
end;
|
||
|
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
Repaint;
|
||
|
NotifyRect := frxRect(c.Left, c.Top, c.Width, c.Height);
|
||
|
end;
|
||
|
|
||
|
// resizing dialogue form
|
||
|
if FMouseDown and (FMode1 = dmSize) and (TObject(FSelectedObjects[0]) is TfrxDialogPage) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
dpage := TObject(FSelectedObjects[0]) as TfrxDialogPage;
|
||
|
case FCT of
|
||
|
ct2:
|
||
|
begin
|
||
|
dpage.ClientWidth := dpage.ClientWidth + kx;
|
||
|
dpage.ClientHeight := dpage.ClientHeight + ky;
|
||
|
end;
|
||
|
|
||
|
ct5:
|
||
|
begin
|
||
|
dpage.ClientWidth := dpage.ClientWidth + kx;
|
||
|
end;
|
||
|
|
||
|
ct8:
|
||
|
begin
|
||
|
dpage.ClientHeight := dpage.ClientHeight + ky;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
SetPageDimensions(Round(dpage.ClientWidth), Round(dpage.ClientHeight), Rect(0, 0, 0, 0));
|
||
|
Repaint;
|
||
|
NotifyRect := frxRect(0, 0, dpage.ClientWidth, dpage.ClientHeight);
|
||
|
end;
|
||
|
|
||
|
// scaling
|
||
|
if FMouseDown and (FMode1 = dmScale) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
with FScaleRect do
|
||
|
if not ((Right + kx < Left) or (Bottom + ky < Top)) then
|
||
|
FScaleRect := frxRect(Left, Top, Right + kx, Bottom + ky);
|
||
|
nx := (FScaleRect.Right - FScaleRect.Left) / (FScaleRect1.Right - FScaleRect1.Left);
|
||
|
ny := (FScaleRect.Bottom - FScaleRect.Top) / (FScaleRect1.Bottom - FScaleRect1.Top);
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.Left := FScaleRect1.Left + (THackComponent(c).FOriginalRect.Left - FScaleRect1.Left) * nx;
|
||
|
c.Top := FScaleRect1.Top + (THackComponent(c).FOriginalRect.Top - FScaleRect1.Top) * ny;
|
||
|
if c.Parent is TfrxBand then
|
||
|
c.Top := c.Top - c.Parent.Top;
|
||
|
c.Width := THackComponent(c).FOriginalRect.Right * nx;
|
||
|
c.Height := THackComponent(c).FOriginalRect.Bottom * ny;
|
||
|
end;
|
||
|
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
Repaint;
|
||
|
with FScaleRect do
|
||
|
NotifyRect := frxRect(Right - Left, Bottom - Top, nx, ny);
|
||
|
end;
|
||
|
|
||
|
// drawing selection rectangle
|
||
|
if FMouseDown and (FMode1 = dmSelectionRect) then
|
||
|
begin
|
||
|
FSelectionRect := frxRect(FSelectionRect.Left, FSelectionRect.Top, X, Y);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
// inserting a line
|
||
|
if not FMouseDown and (FMode1 = dmInsertLine) then
|
||
|
begin
|
||
|
kx := X / FScale - FInsertion.Left;
|
||
|
ky := Y / FScale - FInsertion.Top;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FInsertion.Left := FInsertion.Left + kx;
|
||
|
FInsertion.Top := FInsertion.Top + ky;
|
||
|
with FInsertion do
|
||
|
NotifyRect := frxRect(Left, Top, 0, 0);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
// inserting a line + resizing
|
||
|
if FMouseDown and (FMode1 = dmInsertLine) then
|
||
|
begin
|
||
|
kx := X / FScale - (FInsertion.Left + FInsertion.Width);
|
||
|
ky := Y / FScale - (FInsertion.Top + FInsertion.Height);
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FInsertion.Width := FInsertion.Width + kx;
|
||
|
FInsertion.Height := FInsertion.Height + ky;
|
||
|
with FInsertion do
|
||
|
NotifyRect := frxRect(Left, Top, Width, Height);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
// check containers
|
||
|
if not FMouseDown and (FMode = dmSelect) and not (FMode1 in [dmSize, dmScale]) then
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (csContainer in c.frComponentStyle) and Contain2(c) then
|
||
|
c.ContainerMouseMove(Self, Round(X), Round(Y));
|
||
|
end;
|
||
|
|
||
|
// handle containers
|
||
|
if FMouseDown and (FMode1 = dmContainer) then
|
||
|
begin
|
||
|
kx := X / FScale - FLastMousePointX;
|
||
|
ky := Y / FScale - FLastMousePointY;
|
||
|
if CheckMove then Exit;
|
||
|
|
||
|
FModifyFlag := True;
|
||
|
c := FSelectedObjects[0];
|
||
|
c.ContainerMouseMove(Self, Round(X), Round(Y));
|
||
|
FLastMousePointX := FLastMousePointX + kx;
|
||
|
FLastMousePointY := FLastMousePointY + ky;
|
||
|
Repaint;
|
||
|
end;
|
||
|
//todo
|
||
|
// if FMouseDown and (Cursor <> crHand) then
|
||
|
// if Parent is TScrollingWinControl then
|
||
|
// with TScrollingWinControl(Parent) do
|
||
|
// begin
|
||
|
// x := x + Round(FMargins.Left * FScale);
|
||
|
// y := y + Round(FMargins.Top * FScale);
|
||
|
// if x > (ClientRect.Right + HorzScrollBar.Position) then
|
||
|
// begin
|
||
|
// i := x - (ClientRect.Right + HorzScrollBar.Position);
|
||
|
// HorzScrollBar.Position := HorzScrollBar.Position + i;
|
||
|
// end;
|
||
|
// if x < HorzScrollBar.Position then
|
||
|
// begin
|
||
|
// i := HorzScrollBar.Position - x;
|
||
|
// HorzScrollBar.Position := HorzScrollBar.Position - i;
|
||
|
// end;
|
||
|
// if y > (ClientRect.Bottom + VertScrollBar.Position) then
|
||
|
// begin
|
||
|
// i := y - (ClientRect.Bottom + VertScrollBar.Position);
|
||
|
// VertScrollBar.Position := VertScrollBar.Position + i;
|
||
|
// end;
|
||
|
// if y < VertScrollBar.Position then
|
||
|
// begin
|
||
|
// i := VertScrollBar.Position - y;
|
||
|
// VertScrollBar.Position := VertScrollBar.Position - i;
|
||
|
// end;
|
||
|
// end;
|
||
|
|
||
|
if (SelectedCount = 0) or FMouseDown then
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(NotifyRect);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
c, c1: TfrxComponent;
|
||
|
R: TfrxRect;
|
||
|
l: TList;
|
||
|
NotifyRect: TfrxRect;
|
||
|
|
||
|
function Round8(e: Extended): Extended;
|
||
|
begin
|
||
|
Result := Round(e * 100000000) / 100000000;
|
||
|
end;
|
||
|
|
||
|
function Contain(c: TfrxComponent): Boolean;
|
||
|
var
|
||
|
cLeft, cTop, cRight, cBottom, e: Extended;
|
||
|
Sign: Boolean;
|
||
|
|
||
|
function Dist(x, y: Extended): Boolean;
|
||
|
var
|
||
|
k: Extended;
|
||
|
begin
|
||
|
k := c.Height / c.Width;
|
||
|
k := (k * (x / FScale - c.AbsLeft) - (y / FScale - c.AbsTop)) * cos(arctan(k));
|
||
|
Result := k >= 0;
|
||
|
end;
|
||
|
|
||
|
function RectInRect: Boolean;
|
||
|
begin
|
||
|
with FSelectionRect do
|
||
|
Result := not ((cLeft > Right / FScale) or
|
||
|
(cRight < Left / FScale) or
|
||
|
(cTop > Bottom / FScale) or
|
||
|
(cBottom < Top / FScale));
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
Result := False;
|
||
|
cLeft := c.AbsLeft;
|
||
|
cRight := c.AbsLeft + c.Width;
|
||
|
cTop := c.AbsTop;
|
||
|
cBottom := c.AbsTop + c.Height;
|
||
|
|
||
|
if cRight < cLeft then
|
||
|
begin
|
||
|
e := cRight;
|
||
|
cRight := cLeft;
|
||
|
cLeft := e;
|
||
|
end;
|
||
|
if cBottom < cTop then
|
||
|
begin
|
||
|
e := cBottom;
|
||
|
cBottom := cTop;
|
||
|
cTop := e;
|
||
|
end;
|
||
|
|
||
|
if (c is TfrxLineView) and TfrxLineView(c).Diagonal and
|
||
|
(c.Width <> 0) and (c.Height <> 0) then
|
||
|
with FSelectionRect do
|
||
|
begin
|
||
|
Sign := Dist(Left, Top);
|
||
|
if Dist(Right, Top) <> Sign then
|
||
|
Result := True;
|
||
|
if Dist(Left, Bottom) <> Sign then
|
||
|
Result := True;
|
||
|
if Dist(Right, Bottom) <> Sign then
|
||
|
Result := True;
|
||
|
|
||
|
if Result then
|
||
|
Result := RectInRect;
|
||
|
end
|
||
|
else
|
||
|
Result := RectInRect;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
inherited;
|
||
|
if FDisableUpdate then Exit;
|
||
|
if Button <> TMouseButton.mbLeft then Exit;
|
||
|
{$IFDEF MACOS}
|
||
|
X := X - 2;
|
||
|
Y := Y - 2;
|
||
|
{$ENDIF}
|
||
|
|
||
|
l := TList.Create;
|
||
|
for i := 0 to FSelectedObjects.Count - 1 do
|
||
|
l.Add(FSelectedObjects[i]);
|
||
|
FMouseDown := False;
|
||
|
|
||
|
// insert an object
|
||
|
if FMode = dmInsert then
|
||
|
begin
|
||
|
with FInsertion do
|
||
|
begin
|
||
|
R := frxRect(Left, Top, Left + Width, Top + Height);
|
||
|
if ((ComponentClass.InheritsFrom(TfrxCustomLineView)) and (Flags = 0)) then
|
||
|
begin
|
||
|
if Width < 0 then
|
||
|
R.Right := Left - Width;
|
||
|
if Height < 0 then
|
||
|
R.Bottom := Top - Height;
|
||
|
|
||
|
if (Width < 0) and (Abs(Width) > Abs(Height)) then
|
||
|
begin
|
||
|
R.Left := Left + Width;
|
||
|
R.Right := Left;
|
||
|
end;
|
||
|
if (Height < 0) and (Abs(Height) > Abs(Width)) then
|
||
|
begin
|
||
|
R.Top := Top + Height;
|
||
|
R.Bottom := Top;
|
||
|
end;
|
||
|
end
|
||
|
else if not ((ComponentClass.InheritsFrom(TfrxLineView)) and (Flags <> 0)) then
|
||
|
begin
|
||
|
if ((Width >= 0) and (Width < 4)) or ((Height > 0) and (Height < 4)) then
|
||
|
R := frxRect(Left, Top, Left + OriginalWidth, Top + OriginalHeight);
|
||
|
NormalizeRect(R);
|
||
|
end;
|
||
|
Left := Round8(R.Left);
|
||
|
Top := Round8(R.Top);
|
||
|
Width := Round8(R.Right - R.Left);
|
||
|
Height := Round8(R.Bottom - R.Top);
|
||
|
end;
|
||
|
FDrawInsertion := False;
|
||
|
|
||
|
if Assigned(FOnInsert) then
|
||
|
FOnInsert(Self);
|
||
|
end;
|
||
|
|
||
|
// select objects that inside of selection rect
|
||
|
if FMode1 = dmSelectionRect then
|
||
|
begin
|
||
|
NormalizeRect(FSelectionRect);
|
||
|
FSelectedObjects.Clear;
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
if (c is TfrxReportComponent) and not (c is TfrxBand) and Contain(c) then
|
||
|
if not (csContainer in c.frComponentStyle) then
|
||
|
FSelectedObjects.Add(c)
|
||
|
else
|
||
|
begin
|
||
|
for j := 0 to c.ContainerObjects.Count - 1 do
|
||
|
begin
|
||
|
c1 := c.ContainerObjects[j];
|
||
|
if c1.Visible and Contain(c1) then
|
||
|
FSelectedObjects.Add(c1);
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
FDrawSelection := False;
|
||
|
if FSelectedObjects.Count = 0 then
|
||
|
FSelectedObjects.Add(FPage);
|
||
|
Repaint;
|
||
|
end;
|
||
|
|
||
|
// round coordinates
|
||
|
if FMode1 in [dmMove, dmSize] then
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
if (c is TfrxView) and (FMode1 = dmMove) then
|
||
|
if FSavedAlign.Count > 0 then
|
||
|
begin
|
||
|
TfrxView(c).Align := TfrxAlign(FSavedAlign[0]);
|
||
|
FSavedAlign.Delete(0);
|
||
|
end;
|
||
|
c.Left := Round8(c.Left);
|
||
|
c.Top := Round8(c.Top);
|
||
|
c.Width := Round8(c.Width);
|
||
|
c.Height := Round8(c.Height);
|
||
|
end;
|
||
|
if FMode1 = dmSizeBand then
|
||
|
FSizedBand.Height := Round8(FSizedBand.Height);
|
||
|
|
||
|
// container
|
||
|
if FMode1 = dmContainer then
|
||
|
begin
|
||
|
c := SelectedObjects[0];
|
||
|
c.ContainerMouseUp(Self, Round(X), Round(Y));
|
||
|
end;
|
||
|
|
||
|
AdjustBands;
|
||
|
if not ListsEqual(l, FSelectedObjects) then
|
||
|
SelectionChanged else
|
||
|
Repaint;
|
||
|
DoModify;
|
||
|
l.Free;
|
||
|
FCT := ct0;
|
||
|
if not ((FMode = dmInsert) and (FInsertion.ComponentClass <> nil)) then
|
||
|
FMode1 := dmNone;
|
||
|
|
||
|
if SelectedCount = 0 then
|
||
|
NotifyRect := frxRect(X / FScale, Y / FScale, 0, 0) else
|
||
|
NotifyRect := GetSelectionBounds;
|
||
|
if Assigned(FOnNotifyPosition) then
|
||
|
FOnNotifyPosition(NotifyRect);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.DblClick;
|
||
|
begin
|
||
|
inherited;
|
||
|
EditObject;
|
||
|
FDblClicked := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.MouseLeave;
|
||
|
begin
|
||
|
if not FMouseDown and (FMode1 = dmInsertObject) then
|
||
|
begin
|
||
|
FInsertion.Left := -FGridX * 1000;
|
||
|
FInsertion.Top := -FGridY * 1000;
|
||
|
FDrawInsertion := False;
|
||
|
Repaint;
|
||
|
end;
|
||
|
if not FMouseDown and (FMode1 = dmInsertLine) then
|
||
|
begin
|
||
|
if FGridType = gtChar then
|
||
|
begin
|
||
|
FInsertion.Left := - FGridX / 2;
|
||
|
FInsertion.Top := - FGridY / 2;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
FInsertion.Left := - FGridX;
|
||
|
FInsertion.Top := - FGridY;
|
||
|
end;
|
||
|
Repaint;
|
||
|
end;
|
||
|
if FMode = dmDrag then
|
||
|
SetInsertion(nil, 0, 0, 0);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.CheckGuides(var kx, ky: Extended;
|
||
|
var Result: Boolean);
|
||
|
begin
|
||
|
//
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.GroupObjects;
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
c: TfrxComponent;
|
||
|
sl: TStringList;
|
||
|
begin
|
||
|
sl := TfrxStringList.Create;
|
||
|
sl.Sorted := True;
|
||
|
sl.Duplicates := dupIgnore;
|
||
|
|
||
|
{ reset group index }
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.GroupIndex := 0;
|
||
|
end;
|
||
|
|
||
|
{ collect available indexes }
|
||
|
for i := 0 to FObjects.Count - 1 do
|
||
|
begin
|
||
|
c := FObjects[i];
|
||
|
sl.Add(IntToStr(c.GroupIndex));
|
||
|
end;
|
||
|
|
||
|
{ find an unique index }
|
||
|
j := 0;
|
||
|
repeat
|
||
|
Inc(j);
|
||
|
until sl.IndexOf(IntToStr(j)) = -1;
|
||
|
|
||
|
{ set group index }
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.GroupIndex := j;
|
||
|
end;
|
||
|
|
||
|
sl.Free;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxDesignerWorkspace.UngroupObjects;
|
||
|
var
|
||
|
i: Integer;
|
||
|
c: TfrxComponent;
|
||
|
begin
|
||
|
for i := 0 to SelectedCount - 1 do
|
||
|
begin
|
||
|
c := FSelectedObjects[i];
|
||
|
c.GroupIndex := 0;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
end.
|