mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-18 11:39:09 +02:00
lcl: dragging of header control buttons (patch from Benito van der Zander, #0011209)
git-svn-id: trunk@14995 -
This commit is contained in:
parent
9685a5b1c7
commit
3ec6f39282
@ -2547,6 +2547,7 @@ type
|
||||
FState: THeaderSectionState;
|
||||
FText: string;
|
||||
FWidth: Integer;
|
||||
FOriginalIndex: Integer;
|
||||
function GetLeft: Integer;
|
||||
function GetRight: Integer;
|
||||
procedure SetAlignment(const AValue: TAlignment);
|
||||
@ -2570,6 +2571,8 @@ type
|
||||
property MinWidth: Integer read FMinWidth write SetMinWidth default 0;
|
||||
property Text: string read FText write SetText;
|
||||
property Width: Integer read FWidth write SetWidth;
|
||||
//index which doesn't change when the user reorders the sections
|
||||
property OriginalIndex: Integer read FOriginalIndex;
|
||||
end;
|
||||
|
||||
THeaderSectionClass = class of THeaderSection;
|
||||
@ -2590,11 +2593,14 @@ type
|
||||
function Add: THeaderSection;
|
||||
function AddItem(Item: THeaderSection; Index: Integer): THeaderSection;
|
||||
function Insert(Index: Integer): THeaderSection;
|
||||
procedure Delete(Index: Integer);
|
||||
property Items[Index: Integer]: THeaderSection read GetItem write SetItem; default;
|
||||
end;
|
||||
|
||||
TSectionTrackState = (tsTrackBegin, tsTrackMove, tsTrackEnd);
|
||||
TCustomSectionTrackEvent = procedure(HeaderControl: TCustomHeaderControl; Section: THeaderSection; Width: Integer; State: TSectionTrackState) of object;
|
||||
TCustomSectionTrackEvent = procedure(HeaderControl: TCustomHeaderControl; Section: THeaderSection; Width: Integer; State: TSectionTrackState) of object;
|
||||
TSectionDragEvent = procedure (Sender: TObject; FromSection, ToSection: THeaderSection;
|
||||
var AllowDrag: Boolean) of object;
|
||||
TCustomSectionNotifyEvent = procedure(HeaderControl: TCustomHeaderControl;
|
||||
Section: THeaderSection) of object;
|
||||
TCustomHCCreateSectionClassEvent = procedure(Sender: TCustomHeaderControl;
|
||||
@ -2605,18 +2611,23 @@ type
|
||||
|
||||
TCustomHeaderControl = class(TCustomControl)
|
||||
private
|
||||
FDragReorder: boolean;
|
||||
FSections: THeaderSections;
|
||||
FImages: TCustomImageList;
|
||||
FPaintRect: TRect;
|
||||
FDown: Boolean;
|
||||
FDownPoint: TPoint;
|
||||
FTracking: Boolean;
|
||||
FSelectedSelection: longint;
|
||||
FTracking, FDragging: Boolean;
|
||||
FEndDragSectionIndex: longint;
|
||||
FSelectedSection: longint;
|
||||
FMouseInControl: Boolean;
|
||||
|
||||
FOnSectionClick: TCustomSectionNotifyEvent;
|
||||
FOnSectionResize: TCustomSectionNotifyEvent;
|
||||
FOnSectionTrack: TCustomSectionTrackEvent;
|
||||
FOnSectionSeparatorDblClick: TCustomSectionNotifyEvent;
|
||||
FOnSectionDrag: TSectionDragEvent;
|
||||
FOnSectionEndDrag: TNotifyEvent;
|
||||
FOnCreateSectionClass: TCustomHCCreateSectionClassEvent;
|
||||
procedure SetImages(const AValue: TCustomImageList);
|
||||
procedure SetSections(const AValue: THeaderSections);
|
||||
@ -2629,6 +2640,9 @@ type
|
||||
procedure SectionClick(Section: THeaderSection); dynamic;
|
||||
procedure SectionResize(Section: THeaderSection); dynamic;
|
||||
procedure SectionTrack(Section: THeaderSection; State: TSectionTrackState); dynamic;
|
||||
procedure SectionSeparatorDblClick(Section: THeaderSection); dynamic;
|
||||
procedure SectionEndDrag(); dynamic;
|
||||
function SectionDrag(FromSection, ToSection: THeaderSection):boolean; dynamic;
|
||||
procedure MouseEnter; override;
|
||||
procedure MouseLeave; override;
|
||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
||||
@ -2643,19 +2657,26 @@ type
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure Click; override;
|
||||
procedure DblClick; override;
|
||||
function GetSectionAt(P: TPoint): Integer;
|
||||
procedure Paint; override;
|
||||
procedure PaintSection(Index: Integer); virtual;
|
||||
published
|
||||
property DragReorder: boolean read FDragReorder write FDragReorder;
|
||||
property Images: TCustomImageList read FImages write SetImages;
|
||||
property Sections: THeaderSections read FSections write SetSections;
|
||||
|
||||
property OnSectionDrag: TSectionDragEvent read FOnSectionDrag
|
||||
write FOnSectionDrag;
|
||||
property OnSectionEndDrag: TNotifyEvent read FOnSectionEndDrag write FOnSectionEndDrag;
|
||||
property OnSectionClick: TCustomSectionNotifyEvent read FOnSectionClick
|
||||
write FOnSectionClick;
|
||||
property OnSectionResize: TCustomSectionNotifyEvent read FOnSectionResize
|
||||
write FOnSectionResize;
|
||||
property OnSectionTrack: TCustomSectionTrackEvent read FOnSectionTrack
|
||||
write FOnSectionTrack;
|
||||
property OnSectionSeparatorDblClick: TCustomSectionNotifyEvent read FOnSectionSeparatorDblClick
|
||||
write FOnSectionSeparatorDblClick;
|
||||
property OnCreateSectionClass: TCustomHCCreateSectionClassEvent read FOnCreateSectionClass
|
||||
write FOnCreateSectionClass;
|
||||
end;
|
||||
|
@ -21,6 +21,7 @@
|
||||
{ TCustomHeaderControl }
|
||||
|
||||
const HeaderBorderSize = 2;
|
||||
DragStartDistance = 5;
|
||||
|
||||
procedure TCustomHeaderControl.SetImages(const AValue: TCustomImageList);
|
||||
begin
|
||||
@ -82,7 +83,7 @@ procedure TCustomHeaderControl.Click;
|
||||
var
|
||||
Index: Integer;
|
||||
begin
|
||||
if not FTracking then
|
||||
if FDown and not FDragging then
|
||||
begin
|
||||
inherited Click;
|
||||
Index := GetSectionAt(ScreenToClient(Mouse.CursorPos));
|
||||
@ -91,6 +92,15 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.DblClick;
|
||||
begin
|
||||
inherited DblClick;
|
||||
if FTracking then
|
||||
begin
|
||||
SectionSeparatorDblClick(Sections[FSelectedSection]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomHeaderControl.GetSectionAt(P: TPoint): Integer;
|
||||
var
|
||||
i: integer;
|
||||
@ -131,6 +141,27 @@ begin
|
||||
FOnSectionTrack(Self, Section, Section.FWidth, State);
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.SectionSeparatorDblClick(Section: THeaderSection
|
||||
);
|
||||
begin
|
||||
if Assigned(FOnSectionSeparatorDblClick) then
|
||||
FOnSectionSeparatorDblClick(Self, Section);
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.SectionEndDrag();
|
||||
begin
|
||||
if Assigned(FOnSectionEndDrag) then
|
||||
FOnSectionEndDrag(self);
|
||||
end;
|
||||
|
||||
function TCustomHeaderControl.SectionDrag(FromSection,
|
||||
ToSection: THeaderSection): boolean;
|
||||
begin
|
||||
Result:=DragReorder;
|
||||
if Result and Assigned(FOnSectionDrag) then
|
||||
FOnSectionDrag(self,FromSection,ToSection,Result);
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.MouseEnter;
|
||||
begin
|
||||
inherited MouseEnter;
|
||||
@ -161,45 +192,69 @@ begin
|
||||
FDown := True;
|
||||
FDownPoint := Point(X, Y);
|
||||
if Button = mbLeft then
|
||||
if GetSectionAt(Point(X - HeaderBorderSize, Y))<>GetSectionAt(Point(X + HeaderBorderSize, Y)) then
|
||||
if (X > HeaderBorderSize ) and
|
||||
(GetSectionAt(Point(X - HeaderBorderSize, Y))<>GetSectionAt(Point(X + HeaderBorderSize, Y))) then
|
||||
begin
|
||||
FTracking:=true;
|
||||
FSelectedSelection:=GetSectionAt(Point(X - HeaderBorderSize, Y));
|
||||
if FSelectedSelection = -1 then
|
||||
FSelectedSection:=GetSectionAt(Point(X - HeaderBorderSize, Y));
|
||||
if FSelectedSection = -1 then
|
||||
FTracking:=false
|
||||
else
|
||||
Cursor:=crSizeE;
|
||||
if FTracking then
|
||||
begin
|
||||
FDown := False;
|
||||
SectionTrack(Sections[FSelectedSelection], tsTrackBegin);
|
||||
SectionTrack(Sections[FSelectedSection], tsTrackBegin);
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
FSelectedSection:=GetSectionAt(Point(X, Y));
|
||||
UpdateState;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.MouseMove(Shift: TShiftState; X, Y: Integer);
|
||||
var CurrentSectionIndex: Integer;
|
||||
begin
|
||||
inherited MouseMove(Shift, X, Y);
|
||||
if not (csDesigning in ComponentState) then
|
||||
begin
|
||||
if FTracking and (ssLeft in shift) then
|
||||
begin
|
||||
if x>=FSections[FSelectedSelection].Left then
|
||||
if x>=FSections[FSelectedSection].Left then
|
||||
begin
|
||||
FSections[FSelectedSelection].Width := X - FSections[FSelectedSelection].Left;
|
||||
SectionTrack(Sections[FSelectedSelection], tsTrackMove);
|
||||
FSections[FSelectedSection].Width := X - FSections[FSelectedSection].Left;
|
||||
SectionTrack(Sections[FSelectedSection], tsTrackMove);
|
||||
end;
|
||||
end
|
||||
else
|
||||
if FDown then
|
||||
else if FDragging and (ssLeft in shift) then
|
||||
begin
|
||||
if GetSectionAt(Point(X, Y)) <> GetSectionAt(FDownPoint) then
|
||||
FDown := False;
|
||||
CurrentSectionIndex:=GetSectionAt(Point(x,y));
|
||||
if CurrentSectionIndex>-1 then
|
||||
begin
|
||||
if (Sections[CurrentSectionIndex].GetLeft + Sections[CurrentSectionIndex].Width div 2 < X) then
|
||||
FEndDragSectionIndex:=CurrentSectionIndex+1
|
||||
else
|
||||
FEndDragSectionIndex:=CurrentSectionIndex;
|
||||
if FEndDragSectionIndex < Sections.Count - 1 then
|
||||
FDragging:=SectionDrag(Sections[FSelectedSection],Sections[FEndDragSectionIndex])
|
||||
else
|
||||
FDragging:=SectionDrag(Sections[FSelectedSection],Sections[Sections.Count - 1]);
|
||||
RePaint;
|
||||
end;
|
||||
end
|
||||
else if FDown then
|
||||
begin
|
||||
if DragReorder and (abs(X-FDownPoint.X) >= DragStartDistance) then
|
||||
begin
|
||||
FDragging:=true;
|
||||
FEndDragSectionIndex:=FSelectedSection;
|
||||
end else
|
||||
if GetSectionAt(Point(X, Y)) <> GetSectionAt(FDownPoint) then
|
||||
FDown := False;
|
||||
end;
|
||||
if shift = [] then
|
||||
if GetSectionAt(Point(X - HeaderBorderSize, Y))<>GetSectionAt(Point(X + HeaderBorderSize, Y)) then
|
||||
if (X > HeaderBorderSize) and
|
||||
(GetSectionAt(Point(X - HeaderBorderSize, Y))<>GetSectionAt(Point(X + HeaderBorderSize, Y))) then
|
||||
Cursor:=crSizeE
|
||||
else
|
||||
Cursor:=crDefault;
|
||||
@ -213,11 +268,19 @@ begin
|
||||
inherited MouseUp(Button, Shift, X, Y);
|
||||
if FTracking then
|
||||
begin
|
||||
SectionTrack(Sections[FSelectedSelection],tsTrackEnd);
|
||||
SectionResize(Sections[FSelectedSelection]);
|
||||
SectionTrack(Sections[FSelectedSection],tsTrackEnd);
|
||||
SectionResize(Sections[FSelectedSection]);
|
||||
end;
|
||||
if FDragging then begin
|
||||
if FSelectedSection<FEndDragSectionIndex then
|
||||
Sections[FSelectedSection].Index:=FEndDragSectionIndex - 1
|
||||
else if FSelectedSection>FEndDragSectionIndex then
|
||||
Sections[FSelectedSection].Index:=FEndDragSectionIndex;
|
||||
SectionEndDrag();
|
||||
end;
|
||||
FDown := False;
|
||||
FTracking:=false;
|
||||
FDragging:=false;
|
||||
UpdateState;
|
||||
end;
|
||||
|
||||
@ -230,13 +293,16 @@ begin
|
||||
MaxState := hsNormal;
|
||||
if Enabled then
|
||||
if FDown then
|
||||
MaxState := hsPressed
|
||||
else
|
||||
if FMouseInControl then
|
||||
begin
|
||||
MaxState := hsPressed;
|
||||
Index := FSelectedSection;
|
||||
end else if FMouseInControl then
|
||||
begin
|
||||
MaxState := hsHot;
|
||||
P := ScreenToClient(Mouse.CursorPos);
|
||||
Index := GetSectionAt(P);
|
||||
end;
|
||||
|
||||
P := ScreenToClient(Mouse.CursorPos);
|
||||
Index := GetSectionAt(P);
|
||||
for i := 0 to Sections.Count - 1 do
|
||||
if (i <> Index) then
|
||||
Sections[i].State := hsNormal
|
||||
@ -265,6 +331,17 @@ begin
|
||||
FPaintRect.Left := Sections[Sections.Count - 1].Right;
|
||||
Details := ThemeServices.GetElementDetails(thHeaderItemRightNormal);
|
||||
ThemeServices.DrawElement(Canvas.Handle, Details, FPaintRect);
|
||||
|
||||
if FDragging then
|
||||
begin
|
||||
canvas.Pen.Width:=2;
|
||||
canvas.Pen.Color:=clHotLight;
|
||||
if FEndDragSectionIndex < Sections.Count then
|
||||
canvas.MoveTo(Sections[FEndDragSectionIndex].Left,0)
|
||||
else
|
||||
canvas.MoveTo(Sections[Sections.Count - 1].Right,0);
|
||||
canvas.LineTo(canvas.PenPos.x,ClientHeight);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomHeaderControl.PaintSection(Index: Integer);
|
||||
@ -342,18 +419,26 @@ end;
|
||||
|
||||
function THeaderSections.Add: THeaderSection;
|
||||
begin
|
||||
Result := AddItem(nil, -1);
|
||||
Result := AddItem(nil, Count);
|
||||
end;
|
||||
|
||||
function THeaderSections.AddItem(Item: THeaderSection; Index: Integer): THeaderSection;
|
||||
var i:longint;
|
||||
begin
|
||||
if Item = nil then
|
||||
Result := FHeaderControl.CreateSection;
|
||||
|
||||
Result.Collection := Self;
|
||||
if Index < Count then
|
||||
if Index > Count then
|
||||
Index := Count - 1;
|
||||
Result.Index := Index;
|
||||
//updates OriginalIndex so that it has the value Index would have if there
|
||||
//never was a move
|
||||
for i:=0 to Count - 1 do
|
||||
if Items[i].FOriginalIndex>=Index then
|
||||
Items[i].FOriginalIndex:=Items[i].FOriginalIndex + 1;
|
||||
Result.FOriginalIndex := Index;
|
||||
|
||||
end;
|
||||
|
||||
function THeaderSections.Insert(Index: Integer): THeaderSection;
|
||||
@ -361,6 +446,17 @@ begin
|
||||
Result := AddItem(nil, Index);
|
||||
end;
|
||||
|
||||
procedure THeaderSections.Delete(Index: Integer);
|
||||
var i:longint;
|
||||
begin
|
||||
inherited Delete(Index);
|
||||
//updates OriginalIndex so that it has the value Index would have if there
|
||||
//never was a move
|
||||
for i:=0 to Count - 1 do
|
||||
if items[i].FOriginalIndex > Index then
|
||||
items[i].FOriginalIndex := items[i].FOriginalIndex - 1;
|
||||
end;
|
||||
|
||||
{ THeaderSection }
|
||||
|
||||
function THeaderSection.GetLeft: Integer;
|
||||
@ -471,6 +567,7 @@ begin
|
||||
FState := hsNormal;
|
||||
FMinWidth := 0;
|
||||
FMaxWidth := 10000;
|
||||
FOriginalIndex:=ACollection.Count-1;
|
||||
end;
|
||||
|
||||
procedure THeaderSection.Assign(Source: TPersistent);
|
||||
|
Loading…
Reference in New Issue
Block a user