
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2457 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1062 lines
33 KiB
ObjectPascal
1062 lines
33 KiB
ObjectPascal
unit spkt_Pane;
|
|
|
|
{$mode delphi}
|
|
{.$Define EnhancedRecordSupport}
|
|
|
|
(*******************************************************************************
|
|
* *
|
|
* Plik: spkt_Pane.pas *
|
|
* Opis: Komponent tafli toolbara *
|
|
* Copyright: (c) 2009 by Spook. Jakiekolwiek u¿ycie komponentu bez *
|
|
* uprzedniego uzyskania licencji od autora stanowi z³amanie *
|
|
* prawa autorskiego! *
|
|
* *
|
|
*******************************************************************************)
|
|
|
|
interface
|
|
|
|
uses Graphics, Controls, Classes, SysUtils, Math, Dialogs,
|
|
SpkGraphTools, SpkGUITools, SpkMath,
|
|
spkt_Appearance, spkt_Const, spkt_Dispatch, spkt_Exceptions,
|
|
spkt_BaseItem, spkt_Items, spkt_Types;
|
|
|
|
type TSpkPaneState = (psIdle, psHover);
|
|
|
|
type TSpkMousePaneElementType = (peNone, pePaneArea, peItem);
|
|
|
|
TSpkMousePaneElement = record
|
|
ElementType : TSpkMousePaneElementType;
|
|
ElementIndex : integer;
|
|
end;
|
|
|
|
T2DIntRectArray = array of T2DIntRect;
|
|
TSpkPaneItemsLayout = record
|
|
Rects : T2DIntRectArray;
|
|
Width : integer;
|
|
end;
|
|
|
|
type TSpkPane = class;
|
|
|
|
TSpkPane = class(TSpkComponent)
|
|
private
|
|
FPaneState : TSpkPaneState;
|
|
|
|
FMouseHoverElement : TSpkMousePaneElement;
|
|
FMouseActiveElement : TSpkMousePaneElement;
|
|
protected
|
|
FCaption : string;
|
|
FRect : T2DIntRect;
|
|
FToolbarDispatch : TSpkBaseToolbarDispatch;
|
|
FAppearance : TSpkToolbarAppearance;
|
|
FImages : TImageList;
|
|
FDisabledImages : TImageList;
|
|
FLargeImages : TImageList;
|
|
FDisabledLargeImages : TImageList;
|
|
FVisible : boolean;
|
|
FItems : TSpkItems;
|
|
|
|
// *** Generowanie layoutu elementów ***
|
|
function GenerateLayout: TSpkPaneItemsLayout;
|
|
|
|
// *** Obs³uga designtime i DFM ***
|
|
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
|
|
procedure DefineProperties(Filer : TFiler); override;
|
|
procedure Loaded; override;
|
|
|
|
// *** Gettery i settery ***
|
|
procedure SetCaption(const Value: string);
|
|
procedure SetVisible(const Value: boolean);
|
|
procedure SetAppearance(const Value: TSpkToolbarAppearance);
|
|
procedure SetImages(const Value: TImageList);
|
|
procedure SetDisabledImages(const Value : TImageList);
|
|
procedure SetLargeImages(const Value: TImageList);
|
|
procedure SetDisabledLargeImages(const Value : TImageList);
|
|
procedure SetRect(ARect : T2DIntRect);
|
|
procedure SetToolbarDispatch(const Value: TSpkBaseToolbarDispatch);
|
|
public
|
|
// *** Konstruktor, destruktor ***
|
|
constructor Create(AOwner : TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
// *** Obs³uga gryzonia ***
|
|
procedure MouseLeave;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
|
|
// *** Geometria i rysowanie ***
|
|
function GetWidth : integer;
|
|
procedure Draw(ABuffer : TBitmap; ClipRect : T2DIntRect);
|
|
function FindItemAt(x, y: integer): integer;
|
|
|
|
// *** Obs³uga elementów ***
|
|
procedure FreeingItem(AItem : TSpkBaseItem);
|
|
|
|
property ToolbarDispatch : TSpkBaseToolbarDispatch read FToolbarDispatch write SetToolbarDispatch;
|
|
property Appearance : TSpkToolbarAppearance read FAppearance write SetAppearance;
|
|
property Rect : T2DIntRect read FRect write SetRect;
|
|
property Images : TImageList read FImages write SetImages;
|
|
property DisabledImages : TImageList read FDisabledImages write SetDisabledImages;
|
|
property LargeImages : TImageList read FLargeImages write SetLargeImages;
|
|
property DisabledLargeImages : TImageList read FDisabledLargeImages write SetDisabledLargeImages;
|
|
property Items : TSpkItems read FItems;
|
|
published
|
|
property Caption : string read FCaption write SetCaption;
|
|
property Visible : boolean read FVisible write SetVisible;
|
|
end;
|
|
|
|
type TSpkPanes = class(TSpkCollection)
|
|
private
|
|
protected
|
|
FToolbarDispatch : TSpkBaseToolbarDispatch;
|
|
FAppearance : TSpkToolbarAppearance;
|
|
FImages : TImageList;
|
|
FDisabledImages : TImageList;
|
|
FLargeImages : TImageList;
|
|
FDisabledLargeImages : TImageList;
|
|
|
|
// *** Gettery i settery ***
|
|
procedure SetToolbarDispatch(const Value: TSpkBaseToolbarDispatch);
|
|
function GetItems(index: integer): TSpkPane; reintroduce;
|
|
procedure SetAppearance(const Value: TSpkToolbarAppearance);
|
|
procedure SetImages(const Value: TImageList);
|
|
procedure SetDisabledImages(const Value : TImageList);
|
|
procedure SetLargeImages(const Value: TImageList);
|
|
procedure SetDisabledLargeImages(const Value : TImageList);
|
|
public
|
|
// *** Dodawanie i wstawianie elementów ***
|
|
function Add : TSpkPane;
|
|
function Insert(index : integer) : TSpkPane;
|
|
|
|
// *** Reakcja na zmiany listy ***
|
|
procedure Notify(Item: TComponent; Operation : TOperation); override;
|
|
procedure Update; override;
|
|
|
|
property Items[index : integer] : TSpkPane read GetItems; default;
|
|
property ToolbarDispatch : TSpkBaseToolbarDispatch read FToolbarDispatch write SetToolbarDispatch;
|
|
property Appearance : TSpkToolbarAppearance read FAppearance write SetAppearance;
|
|
property Images : TImageList read FImages write SetImages;
|
|
property DisabledImages : TImageList read FDisabledImages write SetDisabledImages;
|
|
property LargeImages : TImageList read FLargeImages write SetLargeImages;
|
|
property DisabledLargeImages : TImageList read FDisabledLargeImages write SetDisabledLargeImages;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TSpkPane }
|
|
|
|
procedure TSpkPane.SetRect(ARect: T2DIntRect);
|
|
|
|
var Pt : T2DIntPoint;
|
|
i : integer;
|
|
Layout : TSpkPaneItemsLayout;
|
|
|
|
begin
|
|
FRect:=ARect;
|
|
|
|
// Obliczamy layout
|
|
Layout:=GenerateLayout;
|
|
|
|
{$IFDEF EnhancedRecordSupport}
|
|
Pt:=T2DIntPoint.create(ARect.left + PANE_BORDER_SIZE + PANE_LEFT_PADDING, ARect.top + PANE_BORDER_SIZE);
|
|
{$ELSE}
|
|
Pt.create(ARect.left + PANE_BORDER_SIZE + PANE_LEFT_PADDING, ARect.top + PANE_BORDER_SIZE);
|
|
{$ENDIF}
|
|
|
|
if length(Layout.Rects)>0 then
|
|
begin
|
|
for i := 0 to high(Layout.Rects) do
|
|
FItems[i].Rect:=Layout.Rects[i] + Pt;
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPane.SetToolbarDispatch(const Value: TSpkBaseToolbarDispatch);
|
|
|
|
begin
|
|
FToolbarDispatch := Value;
|
|
FItems.ToolbarDispatch:=FToolbarDispatch;
|
|
end;
|
|
|
|
constructor TSpkPane.Create(AOwner : TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
FPaneState:=psIdle;
|
|
FMouseHoverElement.ElementType:=peNone;
|
|
FMouseHoverElement.ElementIndex:=-1;
|
|
FMouseActiveElement.ElementType:=peNone;
|
|
FMouseActiveElement.ElementIndex:=-1;
|
|
|
|
FCaption:='Pane';
|
|
{$IFDEF EnhancedRecordSupport}
|
|
FRect:=T2DIntRect.create(0,0,0,0);
|
|
{$ELSE}
|
|
FRect.create(0,0,0,0);
|
|
{$ENDIF}
|
|
FToolbarDispatch:=nil;
|
|
FAppearance:=nil;
|
|
FImages:=nil;
|
|
FDisabledImages:=nil;
|
|
FLargeImages:=nil;
|
|
FDisabledLargeImages:=nil;
|
|
|
|
FVisible:=true;
|
|
|
|
FItems:=TSpkItems.Create(self);
|
|
FItems.ToolbarDispatch:=FToolbarDispatch;
|
|
FItems.Appearance:=FAppearance;
|
|
end;
|
|
|
|
procedure TSpkPane.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited DefineProperties(Filer);
|
|
|
|
Filer.DefineProperty('Items',FItems.ReadNames,FItems.WriteNames,true);
|
|
end;
|
|
|
|
destructor TSpkPane.Destroy;
|
|
begin
|
|
FItems.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSpkPane.Draw(ABuffer: TBitmap; ClipRect: T2DIntRect);
|
|
|
|
var x: Integer;
|
|
y: Integer;
|
|
BgFromColor, BgToColor, CaptionColor, FontColor, BorderLightColor,
|
|
BorderDarkColor : TColor;
|
|
i: Integer;
|
|
|
|
begin
|
|
// W niektórych warunkach nie jesteœmy w stanie rysowaæ:
|
|
// * Brak dyspozytora
|
|
if FToolbarDispatch=nil then
|
|
exit;
|
|
// * Brak appearance
|
|
if FAppearance=nil then
|
|
exit;
|
|
|
|
if FPaneState = psIdle then
|
|
begin
|
|
// psIdle
|
|
BgFromColor:=FAppearance.Pane.GradientFromColor;
|
|
BgToColor:=FAppearance.Pane.GradientToColor;
|
|
CaptionColor:=FAppearance.Pane.CaptionBgColor;
|
|
FontColor:=FAppearance.Pane.CaptionFont.Color;
|
|
BorderLightColor:=FAppearance.Pane.BorderLightColor;
|
|
BorderDarkColor:=FAppearance.Pane.BorderDarkColor;
|
|
end else
|
|
begin
|
|
// psHover
|
|
BgFromColor:=TColorTools.Brighten(FAppearance.Pane.GradientFromColor,20);
|
|
BgToColor:=TColorTools.Brighten(FAppearance.Pane.GradientToColor,20);
|
|
CaptionColor:=TColorTools.Brighten(FAppearance.Pane.CaptionBgColor,20);
|
|
FontColor:=TColorTools.Brighten(FAppearance.Pane.CaptionFont.Color,20);
|
|
BorderLightColor:=TColorTools.Brighten(FAppearance.Pane.BorderLightColor,20);
|
|
BorderDarkColor:=TColorTools.Brighten(FAppearance.Pane.BorderDarkColor,20);
|
|
end;
|
|
|
|
// T³o
|
|
TGuiTools.DrawRoundRect(ABuffer.Canvas,
|
|
{$IFDEF EnhancedRecordSupport}
|
|
T2DIntRect.Create(FRect.left,
|
|
FRect.top,
|
|
FRect.right - PANE_BORDER_HALF_SIZE,
|
|
FRect.Bottom - PANE_BORDER_HALF_SIZE),
|
|
{$ELSE}
|
|
Create2DIntRect(FRect.left,
|
|
FRect.top,
|
|
FRect.right - PANE_BORDER_HALF_SIZE,
|
|
FRect.Bottom - PANE_BORDER_HALF_SIZE),
|
|
{$ENDIF}
|
|
PANE_CORNER_RADIUS,
|
|
BgFromColor,
|
|
BgToColor,
|
|
FAppearance.Pane.GradientType,
|
|
ClipRect);
|
|
|
|
// T³o etykiety tafli
|
|
TGuiTools.DrawRoundRect(ABuffer.Canvas,
|
|
{$IFDEF EnhancedRecordSupport}
|
|
T2DIntRect.Create(FRect.Left,
|
|
FRect.Bottom - PANE_CAPTION_HEIGHT - PANE_BORDER_HALF_SIZE,
|
|
FRect.right - PANE_BORDER_HALF_SIZE,
|
|
FRect.bottom - PANE_BORDER_HALF_SIZE),
|
|
{$ELSE}
|
|
Create2DIntRect(FRect.Left,
|
|
FRect.Bottom - PANE_CAPTION_HEIGHT - PANE_BORDER_HALF_SIZE,
|
|
FRect.right - PANE_BORDER_HALF_SIZE,
|
|
FRect.bottom - PANE_BORDER_HALF_SIZE),
|
|
{$ENDIF}
|
|
PANE_CORNER_RADIUS,
|
|
CaptionColor,
|
|
clNone,
|
|
bkSolid,
|
|
ClipRect,
|
|
false,
|
|
false,
|
|
true,
|
|
true);
|
|
|
|
// Etykieta tafli
|
|
ABuffer.Canvas.Font.assign(FAppearance.Pane.CaptionFont);
|
|
x:=FRect.left + (FRect.width - ABuffer.Canvas.TextWidth(FCaption)) div 2;
|
|
y:=FRect.Bottom - PANE_BORDER_SIZE - PANE_CAPTION_HEIGHT + 1 +
|
|
(PANE_CAPTION_HEIGHT - ABuffer.Canvas.TextHeight('Wy')) div 2;
|
|
|
|
TGUITools.DrawText(ABuffer.Canvas,
|
|
x,
|
|
y,
|
|
FCaption,
|
|
FontColor,
|
|
ClipRect);
|
|
|
|
// Ramki
|
|
TGUITools.DrawAARoundFrame(ABuffer,
|
|
{$IFDEF EnhancedRecordSupport}
|
|
T2DIntRect.create(FRect.left+1,
|
|
FRect.top+1,
|
|
FRect.Right,
|
|
FRect.bottom),
|
|
{$ELSE}
|
|
Create2DIntRect(FRect.left+1,
|
|
FRect.top+1,
|
|
FRect.Right,
|
|
FRect.bottom),
|
|
{$ENDIF}
|
|
PANE_CORNER_RADIUS,
|
|
BorderLightColor,
|
|
ClipRect);
|
|
TGUITools.DrawAARoundFrame(ABuffer,
|
|
{$IFDEF EnhancedRecordSupport}
|
|
T2DIntRect.create(FRect.left,
|
|
FRect.top,
|
|
FRect.Right-1,
|
|
FRect.bottom-1),
|
|
{$ELSE}
|
|
Create2DIntRect(FRect.left,
|
|
FRect.top,
|
|
FRect.Right-1,
|
|
FRect.bottom-1),
|
|
{$ENDIF}
|
|
PANE_CORNER_RADIUS,
|
|
BorderDarkColor,
|
|
ClipRect);
|
|
|
|
// Elementy
|
|
if FItems.Count>0 then
|
|
for i := 0 to FItems.Count - 1 do
|
|
begin
|
|
if FItems[i].Visible then
|
|
Fitems[i].Draw(ABuffer, ClipRect);
|
|
end;
|
|
end;
|
|
|
|
function TSpkPane.FindItemAt(x, y : integer) : integer;
|
|
|
|
var i : integer;
|
|
|
|
begin
|
|
result:=-1;
|
|
i:=FItems.count-1;
|
|
while (i>=0) and (result=-1) do
|
|
begin
|
|
if FItems[i].Visible then
|
|
begin
|
|
{$IFDEF EnhancedRecordSupport}
|
|
if FItems[i].Rect.Contains(T2DIntVector.create(x,y)) then
|
|
{$ELSE}
|
|
if FItems[i].Rect.Contains(x,y) then
|
|
{$ENDIF}
|
|
result:=i;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPane.FreeingItem(AItem: TSpkBaseItem);
|
|
begin
|
|
FItems.RemoveReference(AItem);
|
|
end;
|
|
|
|
function TSpkPane.GenerateLayout: TSpkPaneItemsLayout;
|
|
|
|
type TLayoutRow = array of integer;
|
|
TLayoutColumn = array of TLayoutRow;
|
|
TLayout = array of TLayoutColumn;
|
|
|
|
var Layout : TLayout;
|
|
CurrentColumn : integer;
|
|
CurrentRow : integer;
|
|
CurrentItem : integer;
|
|
c, r, i: Integer;
|
|
ItemTableBehaviour : TSpkItemTableBehaviour;
|
|
ItemGroupBehaviour : TSpkItemGroupBehaviour;
|
|
ItemSize : TSpkItemSize;
|
|
ForceNewColumn : boolean;
|
|
LastX : integer;
|
|
MaxRowX : integer;
|
|
ColumnX : integer;
|
|
rows: Integer;
|
|
ItemWidth: Integer;
|
|
tmpRect : T2DIntRect;
|
|
|
|
begin
|
|
setlength(result.Rects,FItems.count);
|
|
result.Width:=0;
|
|
|
|
if FItems.count=0 then
|
|
exit;
|
|
|
|
// Notatka: algorytm jest skonstruowany w ten sposób, ¿e trójka: CurrentColumn,
|
|
// CurrentRow oraz CurrentItem wskazuje na element, którego jeszcze nie
|
|
// ma (zaraz za ostatnio dodanym elementem).
|
|
|
|
setlength(Layout,1);
|
|
CurrentColumn:=0;
|
|
|
|
setlength(Layout[CurrentColumn],1);
|
|
CurrentRow:=0;
|
|
|
|
setlength(Layout[CurrentColumn][CurrentRow],0);
|
|
CurrentItem:=0;
|
|
|
|
ForceNewColumn:=false;
|
|
|
|
for i := 0 to FItems.count - 1 do
|
|
begin
|
|
ItemTableBehaviour := FItems[i].GetTableBehaviour;
|
|
ItemSize := FItems[i].GetSize;
|
|
|
|
// Rozpoczêcie nowej kolumny?
|
|
if (i=0) or
|
|
(ItemSize = isLarge) or
|
|
(ItemTableBehaviour = tbBeginsColumn) or
|
|
((ItemTableBehaviour = tbBeginsRow) and (CurrentRow = 2)) or
|
|
(ForceNewColumn) then
|
|
begin
|
|
// Jeœli ju¿ jesteœmy na pocz¹tku nowej kolumny, nie ma nic do roboty.
|
|
if (CurrentRow<>0) or (CurrentItem<>0) then
|
|
begin
|
|
setlength(Layout, length(Layout)+1);
|
|
CurrentColumn:=high(Layout);
|
|
|
|
setlength(Layout[CurrentColumn], 1);
|
|
CurrentRow:=0;
|
|
|
|
setlength(Layout[CurrentColumn][CurrentRow],0);
|
|
CurrentItem:=0;
|
|
end;
|
|
end else
|
|
// Rozpoczêcie nowego wiersza?
|
|
if (ItemTableBehaviour = tbBeginsRow) then
|
|
begin
|
|
// Jeœli ju¿ jesteœmy na pocz¹tku nowego wiersza, nie ma nic do roboty.
|
|
if CurrentItem <> 0 then
|
|
begin
|
|
setlength(Layout[CurrentColumn], length(Layout[CurrentColumn])+1);
|
|
inc(CurrentRow);
|
|
CurrentItem:=0;
|
|
end;
|
|
end;
|
|
|
|
ForceNewColumn:=ItemSize = isLarge;
|
|
|
|
// Jeœli element jest widoczny, dodajemy go w aktualnej kolumnie i aktualnym
|
|
// wierszu.
|
|
if FItems[i].Visible then
|
|
begin
|
|
setlength(Layout[CurrentColumn][CurrentRow], length(Layout[CurrentColumn][CurrentRow])+1);
|
|
Layout[CurrentColumn][CurrentRow][CurrentItem]:=i;
|
|
|
|
inc(CurrentItem);
|
|
end;
|
|
end;
|
|
|
|
// W tym miejscu mamy gotowy layout. Teraz trzeba obliczyæ pozycje i rozmiary
|
|
// Rectów.
|
|
|
|
// Najpierw wype³niamy je pustymi danymi, które zape³ni¹ miejsce elementów
|
|
// niewidocznych.
|
|
{$IFDEF EnhancedRecordSupport}
|
|
for i := 0 to FItems.count - 1 do
|
|
result.Rects[i]:=T2DIntRect.create(-1, -1, -1, -1);
|
|
{$ELSE}
|
|
for i := 0 to FItems.count - 1 do
|
|
result.Rects[i].create(-1, -1, -1, -1);
|
|
{$ENDIF}
|
|
|
|
MaxRowX:=0;
|
|
|
|
// Teraz iterujemy po layoucie, ustalaj¹c recty.
|
|
if length(Layout)>0 then
|
|
for c := 0 to high(Layout) do
|
|
begin
|
|
if c>0 then
|
|
begin
|
|
LastX:=MaxRowX + PANE_COLUMN_SPACER;
|
|
MaxRowX:=LastX;
|
|
end
|
|
else
|
|
begin
|
|
LastX:=MaxRowX;
|
|
end;
|
|
|
|
ColumnX:=LastX;
|
|
|
|
rows:=length(Layout[c]);
|
|
if rows>0 then
|
|
for r := 0 to rows - 1 do
|
|
begin
|
|
LastX:=ColumnX;
|
|
|
|
if length(Layout[c][r])>0 then
|
|
for i := 0 to high(Layout[c][r]) do
|
|
begin
|
|
ItemGroupBehaviour:=FItems[Layout[c][r][i]].GetGroupBehaviour;
|
|
ItemSize:=FItems[Layout[c][r][i]].GetSize;
|
|
ItemWidth:=FItems[Layout[c][r][i]].GetWidth;
|
|
|
|
if ItemSize = isLarge then
|
|
begin
|
|
tmpRect.top:=PANE_FULL_ROW_TOPPADDING;
|
|
tmpRect.bottom:=tmpRect.top + PANE_FULL_ROW_HEIGHT - 1;
|
|
tmpRect.left:=LastX;
|
|
tmpRect.right:=LastX + ItemWidth - 1;
|
|
|
|
LastX:=tmpRect.right + 1;
|
|
if LastX>MaxRowX then
|
|
MaxRowX:=LastX;
|
|
end
|
|
else
|
|
begin
|
|
if ItemGroupBehaviour in [gbContinuesGroup, gbEndsGroup] then
|
|
begin
|
|
tmpRect.Left:=LastX;
|
|
tmpRect.right:=tmpRect.Left + ItemWidth - 1;
|
|
end
|
|
else
|
|
begin
|
|
// Jeœli element nie jest pierwszy, musi zostaæ
|
|
// odsuniêty marginesem od poprzedniego
|
|
if i>0 then
|
|
tmpRect.Left:=LastX + PANE_GROUP_SPACER else
|
|
tmpRect.Left:=LastX;
|
|
tmpRect.right:=tmpRect.Left + ItemWidth - 1;
|
|
end;
|
|
|
|
{$REGION 'Obliczanie tmpRect.top i bottom'}
|
|
case rows of
|
|
1 : begin
|
|
tmpRect.top:=PANE_ONE_ROW_TOPPADDING;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
2 : begin
|
|
case r of
|
|
0 : begin
|
|
tmpRect.top:=PANE_TWO_ROWS_TOPPADDING;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
1 : begin
|
|
tmpRect.top:=PANE_TWO_ROWS_TOPPADDING + PANE_ROW_HEIGHT + PANE_TWO_ROWS_VSPACER;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
end;
|
|
end;
|
|
3 : begin
|
|
case r of
|
|
0 : begin
|
|
tmpRect.top:=PANE_THREE_ROWS_TOPPADDING;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
1 : begin
|
|
tmpRect.top:=PANE_THREE_ROWS_TOPPADDING + PANE_ROW_HEIGHT + PANE_THREE_ROWS_VSPACER;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
2 : begin
|
|
tmpRect.top:=PANE_THREE_ROWS_TOPPADDING + 2 * PANE_ROW_HEIGHT + 2 * PANE_THREE_ROWS_VSPACER;
|
|
tmpRect.bottom:=tmpRect.top + PANE_ROW_HEIGHT - 1;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDREGION}
|
|
|
|
LastX:=tmpRect.right + 1;
|
|
if LastX>MaxRowX then
|
|
MaxRowX:=LastX;
|
|
end;
|
|
|
|
Result.Rects[Layout[c][r][i]]:=tmpRect;
|
|
end;
|
|
end;
|
|
end;
|
|
// W tym miejscu MaxRowX wskazuje na pierwszy piksel za najbardziej wysuniêtym
|
|
// w prawo elementem - ergo jest równy szerokoœci ca³ego layoutu.
|
|
Result.Width:=MaxRowX;
|
|
end;
|
|
|
|
procedure TSpkPane.GetChildren(Proc: TGetChildProc; Root: TComponent);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
inherited;
|
|
|
|
if FItems.Count>0 then
|
|
for i := 0 to FItems.Count - 1 do
|
|
Proc(FItems.Items[i]);
|
|
end;
|
|
|
|
function TSpkPane.GetWidth: integer;
|
|
|
|
var tmpBitmap : TBitmap;
|
|
PaneCaptionWidth, PaneElementsWidth : integer;
|
|
TextW : integer;
|
|
ElementsW : integer;
|
|
Layout : TSpkPaneItemsLayout;
|
|
|
|
begin
|
|
// Przygotowywanie...
|
|
result:=-1;
|
|
if FToolbarDispatch=nil then
|
|
exit;
|
|
if FAppearance=nil then
|
|
exit;
|
|
|
|
tmpBitmap:=FToolbarDispatch.GetTempBitmap;
|
|
if tmpBitmap=nil then
|
|
exit;
|
|
tmpBitmap.Canvas.font.assign(FAppearance.Pane.CaptionFont);
|
|
|
|
// *** Minimalna szerokoϾ tafli (tekstu) ***
|
|
TextW:=tmpBitmap.Canvas.TextWidth(FCaption);
|
|
PaneCaptionWidth:=2*PANE_BORDER_SIZE +
|
|
2*PANE_CAPTION_HMARGIN +
|
|
TextW;
|
|
|
|
// *** Szerokoœæ elementów tafli ***
|
|
Layout:=GenerateLayout;
|
|
ElementsW:=Layout.Width;
|
|
PaneElementsWidth:=PANE_BORDER_SIZE + PANE_LEFT_PADDING + ElementsW + PANE_RIGHT_PADDING + PANE_BORDER_SIZE;
|
|
|
|
// *** Ustawianie szerokoœci tafli ***
|
|
result:=max(PaneCaptionWidth, PaneElementsWidth);
|
|
end;
|
|
|
|
procedure TSpkPane.Loaded;
|
|
begin
|
|
inherited;
|
|
if FItems.ListState = lsNeedsProcessing then
|
|
FItems.ProcessNames(self.Owner);
|
|
end;
|
|
|
|
procedure TSpkPane.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
begin
|
|
if FMouseActiveElement.ElementType = peItem then
|
|
begin
|
|
if FMouseActiveElement.ElementIndex<>-1 then
|
|
FItems[FMouseActiveElement.ElementIndex].MouseDown(Button, Shift, X, Y);
|
|
end else
|
|
if FMouseActiveElement.ElementType = pePaneArea then
|
|
begin
|
|
FPaneState:=psHover;
|
|
end else
|
|
if FMouseActiveElement.ElementType = peNone then
|
|
begin
|
|
if FMouseHoverElement.ElementType = peItem then
|
|
begin
|
|
if FMouseHoverElement.ElementIndex<>-1 then
|
|
begin
|
|
FMouseActiveElement.ElementType:=peItem;
|
|
FMouseActiveElement.ElementIndex:=FMouseHoverElement.ElementIndex;
|
|
|
|
FItems[FMouseHoverElement.ElementIndex].MouseDown(Button, Shift, X, Y);
|
|
end
|
|
else
|
|
begin
|
|
FMouseActiveElement.ElementType:=pePaneArea;
|
|
FMouseActiveElement.ElementIndex:=-1;
|
|
end;
|
|
end else
|
|
if FMouseHoverElement.ElementType = pePaneArea then
|
|
begin
|
|
FMouseActiveElement.ElementType:=pePaneArea;
|
|
FMouseActiveElement.ElementIndex:=-1;
|
|
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia.
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPane.MouseLeave;
|
|
begin
|
|
if FMouseActiveElement.ElementType = peNone then
|
|
begin
|
|
if FMouseHoverElement.ElementType = peItem then
|
|
begin
|
|
if FMouseHoverElement.ElementIndex<>-1 then
|
|
FItems[FMouseHoverElement.ElementIndex].MouseLeave;
|
|
end else
|
|
if FMouseHoverElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia.
|
|
end;
|
|
end;
|
|
|
|
FMouseHoverElement.ElementType:=peNone;
|
|
FMouseHoverElement.ElementIndex:=-1;
|
|
|
|
// Niezale¿nie od tego, który element by³ aktywny / pod mysz¹, trzeba
|
|
// wygasiæ HotTrack.
|
|
if FPaneState<>psIdle then
|
|
begin
|
|
FPaneState:=psIdle;
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyVisualsChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPane.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
|
|
var i : integer;
|
|
NewMouseHoverElement : TSpkMousePaneElement;
|
|
|
|
begin
|
|
// MouseMove jest wywo³ywany tylko, gdy tafla jest aktywna, b¹dŸ gdy
|
|
// mysz rusza siê wewn¹trz jej obszaru. Wobec tego zawsze nale¿y
|
|
// w tej sytuacji zapaliæ HotTrack.
|
|
|
|
if FPaneState = psIdle then
|
|
begin
|
|
FPaneState:=psHover;
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyVisualsChanged;
|
|
end;
|
|
|
|
// Szukamy obiektu pod mysz¹
|
|
i:=FindItemAt(x, y);
|
|
if i<>-1 then
|
|
begin
|
|
NewMouseHoverElement.ElementType:=peItem;
|
|
NewMouseHoverElement.ElementIndex:=i;
|
|
end else
|
|
if (X>=FRect.left) and (Y>=FRect.top) and
|
|
(X<=FRect.right) and (Y<=FRect.bottom) then
|
|
begin
|
|
NewMouseHoverElement.ElementType:=pePaneArea;
|
|
NewMouseHoverElement.ElementIndex:=-1;
|
|
end else
|
|
begin
|
|
NewMouseHoverElement.ElementType:=peNone;
|
|
NewMouseHoverElement.ElementIndex:=-1;
|
|
end;
|
|
|
|
if FMouseActiveElement.ElementType = peItem then
|
|
begin
|
|
if FMouseActiveElement.ElementIndex<>-1 then
|
|
FItems[FMouseActiveElement.ElementIndex].MouseMove(Shift, X, Y);
|
|
end else
|
|
if FMouseActiveElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia
|
|
end else
|
|
if FMouseActiveElement.ElementType = peNone then
|
|
begin
|
|
// Jeœli element pod mysz¹ siê zmienia, informujemy poprzedni element o
|
|
// tym, ¿e mysz opuszcza jego obszar
|
|
if (NewMouseHoverElement.ElementType<>FMouseHoverElement.ELementType) or
|
|
(NewMouseHoverElement.ElementIndex<>FMouseHoverElement.ElementIndex) then
|
|
begin
|
|
if FMouseHoverElement.ElementType = peItem then
|
|
begin
|
|
if FMouseHoverElement.ElementIndex<>-1 then
|
|
FItems[FMouseHoverElement.ElementIndex].MouseLeave;
|
|
end else
|
|
if FMouseHoverElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia
|
|
end;
|
|
end;
|
|
|
|
if NewMouseHoverElement.ElementType = peItem then
|
|
begin
|
|
if NewMouseHoverElement.ElementIndex<>-1 then
|
|
FItems[NewMouseHoverElement.ElementIndex].MouseMove(Shift, X, Y);
|
|
end else
|
|
if NewMouseHoverElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia
|
|
end;
|
|
end;
|
|
|
|
FMouseHoverElement:=NewMouseHoverElement;
|
|
end;
|
|
|
|
procedure TSpkPane.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
|
|
Y: Integer);
|
|
|
|
var ClearActive : boolean;
|
|
|
|
begin
|
|
ClearActive:=not(ssLeft in Shift) and not(ssMiddle in Shift) and not(ssRight in Shift);
|
|
|
|
if FMouseActiveElement.ElementType = peItem then
|
|
begin
|
|
if FMouseActiveElement.ElementIndex<>-1 then
|
|
FItems[FMouseActiveElement.ElementIndex].MouseUp(Button, Shift, X, Y);
|
|
end else
|
|
if FMouseActiveElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia.
|
|
end;
|
|
|
|
if ClearActive and
|
|
(FMouseActiveElement.ElementType<>FMouseHoverElement.ElementType) or
|
|
(FMouseActiveElement.ElementIndex<>FMouseHoverElement.ElementIndex) then
|
|
begin
|
|
if FMouseActiveElement.ElementType = peItem then
|
|
begin
|
|
if FMouseActiveElement.ElementIndex<>-1 then
|
|
FItems[FMouseActiveElement.ElementIndex].MouseLeave;
|
|
end else
|
|
if FMouseActiveElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia.
|
|
end;
|
|
|
|
if FMouseHoverElement.ElementType = peItem then
|
|
begin
|
|
if FMouseActiveElement.ElementIndex<>-1 then
|
|
FItems[FMouseActiveElement.ElementIndex].MouseMove(Shift, X, Y);
|
|
end else
|
|
if FMouseHoverElement.ElementType = pePaneArea then
|
|
begin
|
|
// Placeholder, jeœli zajdzie potrzeba obs³ugi tego zdarzenia.
|
|
end else
|
|
if FMouseHoverElement.ElementType = peNone then
|
|
begin
|
|
if FPaneState<>psIdle then
|
|
begin
|
|
FPaneState:=psIdle;
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyVisualsChanged;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if ClearActive then
|
|
begin
|
|
FMouseActiveElement.ElementType:=peNone;
|
|
FMouseActiveElement.ElementIndex:=-1;
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPane.SetAppearance(const Value: TSpkToolbarAppearance);
|
|
begin
|
|
FAppearance := Value;
|
|
FItems.Appearance := Value;
|
|
end;
|
|
|
|
procedure TSpkPane.SetCaption(const Value: string);
|
|
begin
|
|
FCaption := Value;
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyMetricsChanged;
|
|
end;
|
|
|
|
procedure TSpkPane.SetDisabledImages(const Value: TImageList);
|
|
begin
|
|
FDisabledImages := Value;
|
|
FItems.DisabledImages:=FDisabledImages;
|
|
end;
|
|
|
|
procedure TSpkPane.SetDisabledLargeImages(const Value: TImageList);
|
|
begin
|
|
FDisabledLargeImages := Value;
|
|
FItems.DisabledLargeImages:=FDisabledLargeImages;
|
|
end;
|
|
|
|
procedure TSpkPane.SetImages(const Value: TImageList);
|
|
begin
|
|
FImages := Value;
|
|
FItems.Images:=FImages;
|
|
end;
|
|
|
|
procedure TSpkPane.SetLargeImages(const Value: TImageList);
|
|
begin
|
|
FLargeImages := Value;
|
|
FItems.LargeImages:=FLargeImages;
|
|
end;
|
|
|
|
procedure TSpkPane.SetVisible(const Value: boolean);
|
|
begin
|
|
FVisible := Value;
|
|
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyItemsChanged;
|
|
end;
|
|
|
|
{ TSpkPanes }
|
|
|
|
function TSpkPanes.Add: TSpkPane;
|
|
begin
|
|
Result:=TSpkPane.Create(FRootComponent);
|
|
Result.Parent:=FRootComponent;
|
|
AddItem(Result);
|
|
end;
|
|
|
|
function TSpkPanes.GetItems(index: integer): TSpkPane;
|
|
begin
|
|
result:=TSpkPane(inherited Items[index]);
|
|
end;
|
|
|
|
function TSpkPanes.Insert(index: integer): TSpkPane;
|
|
|
|
var Owner, Parent : TComponent;
|
|
i: Integer;
|
|
|
|
begin
|
|
if (index<0) or (index>self.Count) then
|
|
raise InternalException.create('TSpkPanes.Insert: Nieprawid³owy indeks!');
|
|
|
|
if FRootComponent<>nil then
|
|
begin
|
|
Owner:=FRootComponent.Owner;
|
|
Parent:=FRootComponent;
|
|
end
|
|
else
|
|
begin
|
|
Owner:=nil;
|
|
Parent:=nil;
|
|
end;
|
|
|
|
result:=TSpkPane.Create(Owner);
|
|
result.Parent:=Parent;
|
|
|
|
if FRootComponent<>nil then
|
|
begin
|
|
i:=0;
|
|
while FRootComponent.Owner.FindComponent('SpkPane'+inttostr(i))<>nil do
|
|
inc(i);
|
|
|
|
result.Name:='SpkPane'+inttostr(i);
|
|
end;
|
|
|
|
InsertItem(index,result);
|
|
end;
|
|
|
|
procedure TSpkPanes.Notify(Item: TComponent;
|
|
Operation : TOperation);
|
|
begin
|
|
inherited Notify(Item, Operation);
|
|
|
|
case Operation of
|
|
opInsert: begin
|
|
// Ustawienie dyspozytora na nil spowoduje, ¿e podczas
|
|
// przypisywania w³asnoœci nie bêd¹ wo³ane metody Notify*
|
|
TSpkPane(Item).ToolbarDispatch:=nil;
|
|
|
|
TSpkPane(Item).Appearance:=FAppearance;
|
|
TSpkPane(Item).Images:=FImages;
|
|
TSpkPane(Item).DisabledImages:=FDisabledImages;
|
|
TSpkPane(Item).LargeImages:=FLargeImages;
|
|
TSpkPane(Item).DisabledLargeImages:=FDisabledLargeImages;
|
|
TSpkPane(Item).ToolbarDispatch:=FToolbarDispatch;
|
|
end;
|
|
opRemove: begin
|
|
if not(csDestroying in Item.ComponentState) then
|
|
begin
|
|
TSpkPane(Item).ToolbarDispatch:=nil;
|
|
TSpkPane(Item).Appearance:=nil;
|
|
TSpkPane(Item).Images:=nil;
|
|
TSpkPane(Item).DisabledImages:=nil;
|
|
TSpkPane(Item).LargeImages:=nil;
|
|
TSpkPane(Item).DisabledLargeImages:=nil;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetImages(const Value: TImageList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FImages := Value;
|
|
if self.Count>0 then
|
|
for I := 0 to self.count - 1 do
|
|
Items[i].Images:=Value;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetLargeImages(const Value: TImageList);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FLargeImages := Value;
|
|
if self.Count>0 then
|
|
for I := 0 to self.count - 1 do
|
|
Items[i].LargeImages:=Value;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetToolbarDispatch(const Value: TSpkBaseToolbarDispatch);
|
|
|
|
var i : integer;
|
|
|
|
begin
|
|
FToolbarDispatch := Value;
|
|
if self.Count>0 then
|
|
for i := 0 to self.count - 1 do
|
|
Items[i].ToolbarDispatch:=FToolbarDispatch;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetAppearance(const Value: TSpkToolbarAppearance);
|
|
|
|
var i: Integer;
|
|
|
|
begin
|
|
FAppearance := Value;
|
|
if self.Count>0 then
|
|
for i := 0 to self.count - 1 do
|
|
Items[i].Appearance:=FAppearance;
|
|
|
|
if FToolbarDispatch<>nil then
|
|
FToolbarDispatch.NotifyMetricsChanged;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetDisabledImages(const Value: TImageList);
|
|
|
|
var I: Integer;
|
|
|
|
begin
|
|
FDisabledImages := Value;
|
|
if self.Count>0 then
|
|
for I := 0 to self.count - 1 do
|
|
Items[i].DisabledImages:=Value;
|
|
end;
|
|
|
|
procedure TSpkPanes.SetDisabledLargeImages(const Value: TImageList);
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FDisabledLargeImages := Value;
|
|
if self.Count>0 then
|
|
for I := 0 to self.count - 1 do
|
|
Items[i].DisabledLargeImages:=Value;
|
|
end;
|
|
|
|
procedure TSpkPanes.Update;
|
|
begin
|
|
inherited Update;
|
|
|
|
if assigned(FToolbarDispatch) then
|
|
FToolbarDispatch.NotifyItemsChanged;
|
|
end;
|
|
|
|
|
|
end.
|