From da061aef2408bf4b9e061627549c65938b8445e8 Mon Sep 17 00:00:00 2001 From: sysrpl Date: Fri, 13 Mar 2015 22:58:24 -0400 Subject: [PATCH] Added TSizingPanel --- palette/TBanner.bmp | Bin 0 -> 566 bytes ...{TBorderContainer.bmp => TSizingPanel.bmp} | Bin palette/TThinButton.bmp | Bin 0 -> 566 bytes palette/make.bat | 4 +- resources/Help.png | Bin 3941 -> 5948 bytes resources/progress_status.png | Bin 6981 -> 5948 bytes resources/progress_status_alt.png | Bin 0 -> 6981 bytes source/codebot.controls.buttons.pas | 76 ++- source/codebot.controls.containers.pas | 565 ++++++++++++++++++ source/codebot.controls.extras.pas | 112 +++- source/codebot.controls.pas | 220 ++++--- source/codebot.controls.scrolling.pas | 8 +- source/codebot.controls.sliders.pas | 2 +- source/codebot.design.editors.pas | 42 +- source/codebot.design.registration.pas | 4 +- source/codebot.design.surfacebitmapeditor.lfm | 2 +- source/codebot.design.surfacebitmapeditor.pas | 3 +- source/codebot.graphics.markup.pas | 121 +++- source/codebot.graphics.pas | 176 +++++- source/codebot.graphics.types.pas | 40 +- .../codebot.graphics.windows.surfaced2d.pas | 14 +- source/codebot.lpk | 8 +- source/codebot.pas | 3 +- source/codebot.system.pas | 19 +- source/palette_icons.lrs | 215 ------- source/palette_icons.res | Bin 6728 -> 7920 bytes source/progress_icons.res | Bin 17729 -> 16696 bytes 27 files changed, 1233 insertions(+), 401 deletions(-) create mode 100644 palette/TBanner.bmp rename palette/{TBorderContainer.bmp => TSizingPanel.bmp} (100%) create mode 100644 palette/TThinButton.bmp create mode 100644 resources/progress_status_alt.png create mode 100644 source/codebot.controls.containers.pas delete mode 100644 source/palette_icons.lrs diff --git a/palette/TBanner.bmp b/palette/TBanner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0da336088903a73c1ac852ace6191a0c0722d7c5 GIT binary patch literal 566 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 eEcY}rf&T@;sMx(%$xl9< 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 diff --git a/resources/progress_status.png b/resources/progress_status.png index 1f82a4503c05fff8ede668bdb1d3818eeb59a052..62fa850772f97615c5e022fcb583ae695a2eb1f0 100644 GIT binary patch literal 5948 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 diff --git a/resources/progress_status_alt.png b/resources/progress_status_alt.png new file mode 100644 index 0000000000000000000000000000000000000000..1f82a4503c05fff8ede668bdb1d3818eeb59a052 GIT binary patch literal 6981 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 literal 0 HcmV?d00001 diff --git a/source/codebot.controls.buttons.pas b/source/codebot.controls.buttons.pas index bd2187a..777f93f 100644 --- a/source/codebot.controls.buttons.pas +++ b/source/codebot.controls.buttons.pas @@ -22,17 +22,22 @@ interface { TCustomThinButton } +type + TButtonKind = (bkButton, skDropDown, bkSplitter); + type TCustomThinButton = class(TRenderGraphicControl) private + FKind: TButtonKind; FImages: TImageStrip; FImageIndex: Integer; FDown: Boolean; FOnDrawButton: TDrawStateEvent; + procedure SetKind(Value: TButtonKind); + procedure SetDown(Value: Boolean); procedure SetImages(Value: TImageStrip); procedure SetImageIndex(Value: Integer); procedure ImagesChanged(Sender: TObject); - procedure SetDown(Value: Boolean); protected function ThemeAware: Boolean; override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; @@ -46,10 +51,12 @@ TCustomThinButton = class(TRenderGraphicControl) procedure MouseLeave; override; procedure Render; override; property Down: Boolean read FDown write SetDown; + property Kind: TButtonKind read FKind write SetKind default bkButton; property OnDrawButton: TDrawStateEvent read FOnDrawButton write FOnDrawButton; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; + procedure Click; end; { TThinButton } @@ -69,6 +76,7 @@ TThinButton = class(TCustomThinButton) property Enabled; property Images; property ImageIndex; + property Kind; property Visible; property OnClick; property OnDblClick; @@ -109,6 +117,12 @@ destructor TCustomThinButton.Destroy; inherited Destroy; end; +procedure TCustomThinButton.Click; +begin + if Assigned(OnClick) then + OnClick(Self); +end; + procedure TCustomThinButton.ImagesChanged(Sender: TObject); begin Invalidate; @@ -148,6 +162,31 @@ procedure TCustomThinButton.SetImages(Value: TImageStrip); end; end; +procedure TCustomThinButton.SetKind(Value: TButtonKind); +begin + if FKind = Value then Exit; + FKind := Value; + FDown := False; + if FKind = bkSplitter then + Width := 16 + else + Width := 32; + DrawState := []; + Invalidate; +end; + +procedure TCustomThinButton.SetDown(Value: Boolean); +begin + if FKind <> bkButton then + Value := False; + if FDown = Value then Exit; + FDown := Value; + if FDown then + DrawState := [dsHot, dsPressed] + else + DrawState := []; +end; + function TCustomThinButton.ThemeAware: Boolean; begin Result := True; @@ -157,6 +196,8 @@ procedure TCustomThinButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseDown(Button, Shift, X, Y); + if FKind = bkSplitter then + Exit; if not FDown then if Button = mbLeft then DrawState := DrawState + [dsPressed]; @@ -169,6 +210,8 @@ procedure TCustomThinButton.MouseMove(Shift: TShiftState; X, Y: Integer); inherited MouseMove(Shift, X, Y); if FDown then Exit; + if FKind = bkSplitter then + Exit; R := ClientRect; if R.Contains(X, Y) then DrawState := DrawState + [dsHot] @@ -180,6 +223,8 @@ procedure TCustomThinButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseUp(Button, Shift, X, Y); + if FKind = bkSplitter then + Exit; if not FDown then if Button = mbLeft then DrawState := DrawState - [dsPressed]; @@ -188,6 +233,8 @@ procedure TCustomThinButton.MouseUp(Button: TMouseButton; Shift: TShiftState; procedure TCustomThinButton.MouseEnter; begin inherited MouseEnter; + if FKind = bkSplitter then + Exit; if not FDown then DrawState := DrawState + [dsHot]; end; @@ -195,6 +242,8 @@ procedure TCustomThinButton.MouseEnter; procedure TCustomThinButton.MouseLeave; begin inherited MouseLeave; + if FKind = bkSplitter then + Exit; if not FDown then DrawState := DrawState - [dsHot]; end; @@ -202,6 +251,7 @@ procedure TCustomThinButton.MouseLeave; procedure TCustomThinButton.Render; var D: TDrawState; + R: TRectI; begin inherited Render; if csDesigning in ComponentState then @@ -212,10 +262,18 @@ procedure TCustomThinButton.Render; D := [dsHot]; Theme.Select(D); end; - if Assigned(FOnDrawButton) then - FOnDrawButton(Self, Surface, ClientRect, DrawState) + R := ClientRect; + if FKind = bkSplitter then + begin + if csDesigning in ComponentState then + Surface.StrokeRoundRect(NewPen(CurrentColor.Darken(0.05)), R, 3); + R.Inflate(0, -2); + Theme.DrawSplit(R, toVertical); + end + else if Assigned(FOnDrawButton) then + FOnDrawButton(Self, Surface, R, DrawState) else - Theme.DrawButtonThin(ClientRect); + Theme.DrawButtonThin(R); if FImages <> nil then begin FImages.Draw(Surface, FImageIndex, @@ -224,15 +282,5 @@ procedure TCustomThinButton.Render; end; end; -procedure TCustomThinButton.SetDown(Value: Boolean); -begin - if FDown = Value then Exit; - FDown := Value; - if FDown then - DrawState := [dsHot, dsPressed] - else - DrawState := []; -end; - end. diff --git a/source/codebot.controls.containers.pas b/source/codebot.controls.containers.pas new file mode 100644 index 0000000..0ee4f4c --- /dev/null +++ b/source/codebot.controls.containers.pas @@ -0,0 +1,565 @@ +(********************************************************) +(* *) +(* Codebot Pascal Library *) +(* http://cross.codebot.org *) +(* Modified March 2015 *) +(* *) +(********************************************************) + +{ } +unit Codebot.Controls.Containers; + +{$i codebot.inc} + +interface + +uses + Classes, SysUtils, Graphics, Controls, Forms, LCLType, + Codebot.System, + Codebot.Controls, + Codebot.Graphics, + Codebot.Graphics.Types; + +{ TSplitter allows containers to be drag resized + See also + } + +type + TSplitter = class(TChangeNotifier) + private + FEnabled: Boolean; + FMinSize: Integer; + FMinRemain: Integer; + FVisible: Boolean; + FMargin: Integer; + procedure SetEnabled(Value: Boolean); + procedure SetMinSize(Value: Integer); + procedure SetMinRemain(Value: Integer); + procedure SetVisible(Value: Boolean); + procedure SetMargin(Value: Integer); + public + { Create a new spliter } + constructor Create; + { Assign the object from a source } + procedure Assign(Source: TPersistent); override; + published + { The control can be resized with the mouse } + property Enabled: Boolean read FEnabled write SetEnabled default False; + { The minumum control can be resized with the mouse } + property MinSize: Integer read FMinSize write SetMinSize default 10; + { The minumum remaining in the parent control } + property MinRemain: Integer read FMinRemain write SetMinRemain default 10; + { When visible is true child controls are arrannged to not occupy the splitter area } + property Visible: Boolean read FVisible write SetVisible default True; + { The splitter area when visiible } + property Margin: Integer read FMargin write SetMargin default 4; + end; + +{ TPanelBackgroundKind determiens the kind of background } + + TPanelBackground = ( + { Solid color } + pbColor, + { Gradient header } + pbToolbar, + { Brush pattern } + pbPattern, + { Image with clamped edges } + pbImage); + +{ TSizingPanel holds controls, pads edges, allows mouse resizing, and paints backgrounds + See also + } + + TSizingPanel = class(TRenderCustomControl) + private + FBackground: TPanelBackground; + FImage: TSurfaceBitmap; + FBorders: TEdges; + FPadding: TEdgeOffset; + FShadows: TEdges; + FSplitter: TSplitter; + FPriorCursor: TCursor; + FDragging: Boolean; + procedure ImageChanged(Sender: TObject); + procedure PaddingChanged(Sender: TObject); + procedure SetBackground(Value: TPanelBackground); + procedure SetBorders(Value: TEdges); + procedure SetImage(Value: TSurfaceBitmap); + procedure SetPadding(Value: TEdgeOffset); + procedure SetShadows(Value: TEdges); + procedure SplitterChanged(Sender: TObject); + function SplitterArea: TRectI; + procedure SetSplitter(Value: TSplitter); + procedure SplitterSized(Size: Integer); + protected + procedure Render; override; + procedure Resize; override; + function GetLogicalClientRect: TRect; override; + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); override; + procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure ArrangeControls; + published + { Background controls the background styling of a panel } + property Background: TPanelBackground read FBackground write SetBackground default pbColor; + { When background is set to pbImage this value is painted in the background and its + edges are clamped } + property Image: TSurfaceBitmap read FImage write SetImage; + { Borders apply single a pixel border to an edge } + property Borders: TEdges read FBorders write SetBorders; + { Shadows apply drop shadow to and edge } + property Shadows: TEdges read FShadows write SetShadows; + { Padding indents the placement of aligned child controls } + property Padding: TEdgeOffset read FPadding write SetPadding; + { Splitter alows the panel to be resized using the mouse } + property Splitter: TSplitter read FSplitter write SetSplitter; + property Align; + property Anchors; + property AutoSize; + property BorderSpacing; + property BidiMode; + property BorderWidth; + property BorderStyle; + property Caption; + property ChildSizing; + property ClientHeight; + property ClientWidth; + property Color; + property Constraints; + property DockSite; + property DragCursor; + property DragKind; + property DragMode; + property Enabled; + property Font; + property ParentBidiMode; + property ParentColor; + property ParentFont; + property ParentShowHint; + property PopupMenu; + property ShowHint; + property TabOrder; + property TabStop; + property UseDockManager default True; + property Visible; + property OnClick; + property OnContextPopup; + property OnDockDrop; + property OnDockOver; + property OnDblClick; + property OnDragDrop; + property OnDragOver; + property OnEndDock; + property OnEndDrag; + property OnEnter; + property OnExit; + property OnGetSiteInfo; + property OnGetDockCaption; + property OnMouseDown; + property OnMouseEnter; + property OnMouseLeave; + property OnMouseMove; + property OnMouseUp; + property OnMouseWheel; + property OnMouseWheelDown; + property OnMouseWheelUp; + property OnResize; + property OnRender; + property OnStartDock; + property OnStartDrag; + property OnUnDock; + end; + +implementation + +{ TSplitter } + +constructor TSplitter.Create; +begin + inherited Create; + FVisible := True; + FMinSize := 10; + FMinRemain := 10; + FMargin:= 4; +end; + +procedure TSplitter.Assign(Source: TPersistent); +var + S: TSplitter; +begin + if Source is TSplitter then + begin + S := Source as TSplitter; + FEnabled := S.Enabled; + FMinSize := S.MinSize; + FMinRemain := S.MinRemain; + FVisible := S.Visible; + FMargin := S.Margin; + Change; + end + else + inherited Assign(Source); +end; + +procedure TSplitter.SetEnabled(Value: Boolean); +begin + if FEnabled = Value then Exit; + FEnabled := Value; + Change; +end; + +procedure TSplitter.SetMinRemain(Value: Integer); +begin + if Value < 10 then + Value := 10; + if FMinRemain = Value then Exit; + FMinRemain := Value; + Change; +end; + +procedure TSplitter.SetMinSize(Value: Integer); +begin + if Value < 10 then + Value := 10; + if FMinSize = Value then Exit; + FMinSize := Value; + Change; +end; + +procedure TSplitter.SetVisible(Value: Boolean); +begin + if FVisible = Value then Exit; + FVisible := Value; + Change; +end; + +procedure TSplitter.SetMargin(Value: Integer); +begin + if Value < 0 then + Value := 0; + if FMargin = Value then Exit; + FMargin := Value; + Change; +end; + +{ TSizingPanel } + +constructor TSizingPanel.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FImage := TSurfaceBitmap.Create; + FImage.OnChange := ImageChanged; + FPadding := TEdgeOffset.Create; + FPadding.OnChange.Add(PaddingChanged); + FSplitter := TSplitter.Create; + FSplitter.OnChange.Add(SplitterChanged); + ControlStyle := ControlStyle + [csAcceptsControls]; + Color := clBtnFace; + Width := 160; + Height := 160; +end; + +destructor TSizingPanel.Destroy; +begin + FSplitter.Free; + FPadding.Free; + FImage.Free; + inherited Destroy; +end; + +procedure TSizingPanel.ArrangeControls; +begin + Codebot.Controls.ArrangeControls(Self, ClientRect, Padding.Left); +end; + +procedure TSizingPanel.SplitterSized(Size: Integer); +begin + if Parent = nil then + Exit; + if FSplitter.Enabled then + case Align of + alTop, alBottom: + begin + if Parent.ClientHeight - Size < FSplitter.MinRemain then + Size := Parent.ClientHeight - FSplitter.MinRemain; + if Size < FSplitter.MinSize then + Size := FSplitter.MinSize; + Height := Size; + end; + alLeft, alRight: + begin + if Parent.ClientWidth - Size < FSplitter.MinRemain then + Size := Parent.ClientWidth - FSplitter.MinRemain; + if Size < FSplitter.MinSize then + Size := FSplitter.MinSize; + Width := Size; + end; + end; +end; + +procedure TSizingPanel.SplitterChanged(Sender: TObject); +begin + if FSplitter.Enabled then + case Align of + alTop, alBottom: SplitterSized(Height); + alLeft, alRight: SplitterSized(Width); + end; +end; + +procedure TSizingPanel.PaddingChanged(Sender: TObject); +begin + ReAlign; + Invalidate; +end; + +procedure TSizingPanel.ImageChanged(Sender: TObject); +begin + if FBackground = pbImage then + Invalidate; +end; + +procedure TSizingPanel.SetBackground(Value: TPanelBackground); +begin + if FBackground = Value then Exit; + FBackground := Value; + Invalidate; +end; + +procedure TSizingPanel.SetBorders(Value: TEdges); +begin + if FBorders = Value then Exit; + FBorders := Value; + ReAlign; + Invalidate; +end; + +procedure TSizingPanel.SetImage(Value: TSurfaceBitmap); +begin + if FImage = Value then Exit; + FImage.Assign(Value); +end; + +procedure TSizingPanel.SetPadding(Value: TEdgeOffset); +begin + if FPadding = Value then Exit; + FPadding.Assign(Value); +end; + +procedure TSizingPanel.SetShadows(Value: TEdges); +begin + if FShadows = Value then Exit; + FShadows := Value; + Invalidate; +end; + +procedure TSizingPanel.Resize; +begin + inherited Resize; + if FSplitter.Enabled then + case Align of + alTop, alBottom: SplitterSized(Height); + alLeft, alRight: SplitterSized(Width); + end; +end; + +procedure TSizingPanel.Render; +const + Pad = 1; +var + R: TRectI; + A, B: TRectI; +begin + R := ClientRect; + if (FBackground = pbImage) and (not FImage.Empty) then + begin + Surface.FillRect(NewBrush(CurrentColor), R); + FImage.Draw(Surface, 0, 0); + if FImage.Width < R.Width then + begin + A := FImage.ClientRect; + A.X := A.Width - 1; + A.Width := 1; + B := R; + B.X := FImage.Width; + B.Height := FImage.Height; + FImage.Draw(Surface, A, B); + end; + if FImage.Height < R.Height then + begin + A := FImage.ClientRect; + A.Y := A.Height - 1; + A.Height := 1; + B := R; + B.Y := FImage.Height; + B.Width := FImage.Width; + FImage.Draw(Surface, A, B); + end; + if (FImage.Width < R.Width) or (FImage.Height < R.Height) then + begin + A := FImage.ClientRect; + A.X := A.Width - 1; + A.Y := A.Height - 1; + A.Width := 1; + A.Height := 1; + B := R; + B.Left := FImage.Width; + B.Top := FImage.Height; + FImage.Draw(Surface, A, B); + end; + end + else if FBackground = pbToolbar then + begin + Surface.FillRect(NewBrush(CurrentColor), R); + Theme.DrawHeader(Height); + end + else if FBackground = pbPattern then + Surface.FillRect(Brushes.Checker, R) + else + Surface.FillRect(NewBrush(CurrentColor), R); + inherited Render; + R.Inflate(Pad, Pad); + if BorderStyle = bsNone then + begin + if edLeft in FBorders then + R.Left := R.Left + Pad; + if edTop in FBorders then + R.Top := R.Top + Pad; + if edRight in FBorders then + R.Right := R.Right - Pad; + if edBottom in FBorders then + R.Bottom := R.Bottom - Pad; + Surface.StrokeRect(NewPen(clBtnShadow), R); + end; + R.Inflate(-Pad, -Pad); + if edLeft in FShadows then + DrawShadow(Surface, R, drLeft); + if edTop in FShadows then + DrawShadow(Surface, R, drUp); + if edRight in FShadows then + DrawShadow(Surface, R, drRight); + if edBottom in FShadows then + DrawShadow(Surface, R, drDown); +end; + +procedure TSizingPanel.SetSplitter(Value: TSplitter); +begin + if FSplitter = Value then Exit; + FSplitter.Assign(Value); +end; + +function TSizingPanel.SplitterArea: TRectI; +var + R: TRectI; +begin + R := ClientRect; + if FSplitter.Enabled then + case Align of + alTop: R.Top := R.Bottom - FSplitter.Margin; + alBottom: R.Bottom := R.Top + FSplitter.Margin; + alLeft: R.Left := R.Right - FSplitter.Margin; + alRight: R.Right := R.Left + FSplitter.Margin; + end + else + begin + R.Width := 0; + R.Height := 0; + end; + Result := R; +end; + +function TSizingPanel.GetLogicalClientRect: TRect; +var + R: TRectI; + M: Integer; +begin + R := ClientRect; + M := FSplitter.Margin; + if not FSplitter.Visible then + M := 0; + if FSplitter.Enabled then + case Align of + alTop: R.Bottom := R.Bottom - M; + alBottom: R.Top := R.Top + M; + alLeft: R.Right := R.Right - M; + alRight: R.Left := R.Left + M; + end; + if FPadding.Left > R.X then + R.X := FPadding.Left; + if FPadding.Top > R.Y then + R.Y := FPadding.Top; + if R.Right > ClientWidth - FPadding.Right then + R.Right := ClientWidth - FPadding.Right; + if R.Bottom > ClientHeight - FPadding.Bottom then + R.Bottom := ClientHeight - FPadding.Bottom; + if BorderStyle = bsNone then + begin + if (R.Left = 0) and (edLeft in FBorders) then + R.Left := 1; + if (R.Top = 0) and (edTop in FBorders) then + R.Top := 1; + if (R.Right = Width) and (edRight in FBorders) then + R.Right := R.Right - 1; + if (R.Bottom = Height) and (edBottom in FBorders) then + R.Bottom := R.Bottom - 1; + end; + Result := R; +end; + +procedure TSizingPanel.MouseDown(Button: TMouseButton; Shift: TShiftState; + X, Y: Integer); +var + R: TRectI; +begin + inherited MouseDown(Button, Shift, X, Y); + if Button = mbLeft then + begin + R := SplitterArea; + FDragging := R.Contains(X, Y); + end; +end; + +procedure TSizingPanel.MouseMove(Shift: TShiftState; X, Y: Integer); +var + R: TRectI; +begin + inherited MouseMove(Shift, X, Y); + R := SplitterArea; + if (Cursor <> crHSplit) and (Cursor <> crVSplit) then + FPriorCursor := Cursor; + if R.Contains(X, Y) then + if Align in [alLeft, alRight] then + Cursor := crHSplit + else + Cursor := crVSplit + else + Cursor := FPriorCursor; + if FDragging and FSplitter.Enabled then + begin + case Align of + alRight: X := ClientWidth - X; + alBottom: Y := ClientHeight - Y; + end; + case Align of + alTop, alBottom: SplitterSized(Y); + alLeft, alRight: SplitterSized(X); + end; + end; +end; + +procedure TSizingPanel.MouseUp(Button: TMouseButton; Shift: TShiftState; X, + Y: Integer); +begin + inherited MouseUp(Button, Shift, X, Y); + if Button = mbLeft then + FDragging := False; +end; + + +end. + diff --git a/source/codebot.controls.extras.pas b/source/codebot.controls.extras.pas index 7674979..7a63559 100644 --- a/source/codebot.controls.extras.pas +++ b/source/codebot.controls.extras.pas @@ -45,6 +45,9 @@ TRenderImage = class(TRenderGraphicControl) FColorized: Boolean; FMode: TImageMode; FSaturation: Float; + FSharedImage: TSurfaceBitmap; + function GetComputeImage: TSurfaceBitmap; + function GetRenderArea: TRectI; procedure ImageChange(Sender: TObject); procedure SetAngle(Value: Float); procedure SetColorized(Value: Boolean); @@ -53,14 +56,19 @@ TRenderImage = class(TRenderGraphicControl) function GetOpacity: Byte; procedure SetOpacity(Value: Byte); procedure SetSaturation(Value: Float); + procedure SetSharedImage(Value: TSurfaceBitmap); protected procedure SetColor(Value: TColor); override; procedure GetPreferredSize(var PreferredWidth, PreferredHeight: integer; Raw: Boolean = False; WithThemeSpace: Boolean = True); override; procedure Render; override; + property ComputeImage: TSurfaceBitmap read GetComputeImage; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; + procedure UpdateImage; + property RenderArea: TRectI read GetRenderArea; + property SharedImage: TSurfaceBitmap read FSharedImage write SetSharedImage; published property Image: TSurfaceBitmap read FImage write SetImage; property Angle: Float read FAngle write SetAngle; @@ -143,12 +151,14 @@ TRenderBox = class(TRenderGraphicControl) TIndeterminateProgress = class(TRenderGraphicControl) private + FHelp: string; FTimer: TTimer; FStatus: TProgressStatus; FBusyImages: TImageStrip; FBusyIndex: Integer; FStatusImages: TImageStrip; FIconPosition: TIconPosition; + procedure SetHelp(Value: string); procedure TimerExpired(Sender: TObject); procedure SetStatus(Value: TProgressStatus); procedure SetBusyImages(Value: TImageStrip); @@ -170,6 +180,7 @@ TIndeterminateProgress = class(TRenderGraphicControl) property StatusImages: TImageStrip read FStatusImages write SetStatusImages; property BusyDelay: Cardinal read GetBusyDelay write SetBusyDelay default 30; property IconPosition: TIconPosition read FIconPosition write SetIconPosition default icNear; + property Help: string read FHelp write SetHelp; property Align; property Anchors; property BidiMode; @@ -230,6 +241,66 @@ destructor TRenderImage.Destroy; FCopy.Free; end; +procedure TRenderImage.UpdateImage; +begin + FCopy.Free; + FCopy := nil; + Invalidate; +end; + +function TRenderImage.GetComputeImage: TSurfaceBitmap; +begin + if FSharedImage <> nil then + Result := FSharedImage + else + Result := FImage; +end; + +function TRenderImage.GetRenderArea: TRectI; +var + B: TSurfaceBitmap; + M: TImageMode; +begin + B := ComputeImage; + M := FMode; + if M = imFit then + if (B.Width > Width) or (B.Height > Height) then + M := imFill + else + M := imCenter; + case M of + imCenter: + begin + Result := B.ClientRect; + Result.Offset((Width - B.Width) div 2, (Height - B.Height) div 2); + end; + imFill: + if B.Empty then + begin + Result := B.ClientRect; + Result.Offset(Width div 2, Height div 2); + end + else if Width / Height > B.Width / B.Height then + begin + Result.Top := 0; + Result.Left := 0; + Result.Height := Height; + Result.Width := Round(Height * (B.Width / B.Height)); + Result.X := (Width - Result.Width) div 2; + end + else + begin + Result.Top := 0; + Result.Left := 0; + Result.Width := Width; + Result.Height := Round(Width * (B.Height / B.Width)); + Result.Y := (Height - Result.Height) div 2; + end; + else + Result := ClientRect; + end; +end; + procedure TRenderImage.Render; var NeedsFit: Boolean; @@ -246,7 +317,7 @@ procedure TRenderImage.Render; Pen := NewPen(clBlack); Pen.LinePattern := pnDash; end; - if FImage.Empty then + if ComputeImage.Empty then begin if csDesigning in ComponentState then Surface.StrokeRect(Pen, ClientRect); @@ -257,7 +328,7 @@ procedure TRenderImage.Render; if FCopy = nil then begin FCopy := TSurfaceBitmap.Create; - FCopy.Assign(FImage); + FCopy.Assign(ComputeImage); if FColorized then FCopy.Colorize(Color) else @@ -266,7 +337,7 @@ procedure TRenderImage.Render; Bitmap := FCopy; end else - Bitmap := FImage; + Bitmap := ComputeImage; NeedsFit := FMode = imFit; if NeedsFit then if (Bitmap.Width > Width) or (Bitmap.Height > Height) then @@ -281,7 +352,7 @@ procedure TRenderImage.Render; imCenter: begin Surface.Matrix := M; - Bitmap.Draw(Surface, (Width - FImage.Width) div 2, + Bitmap.Draw(Surface, (Width - ComputeImage.Width) div 2, (Height - Bitmap.Height) div 2); end; imFill: @@ -371,12 +442,12 @@ procedure TRenderImage.SetMode(Value: TImageMode); function TRenderImage.GetOpacity: Byte; begin - Result := FImage.Opacity; + Result := ComputeImage.Opacity; end; procedure TRenderImage.SetOpacity(Value: Byte); begin - FImage.Opacity := Value; + ComputeImage.Opacity := Value; if FCopy <> nil then FCopy.Opacity := Value; Invalidate; @@ -392,6 +463,12 @@ procedure TRenderImage.SetSaturation(Value: Float); Invalidate; end; +procedure TRenderImage.SetSharedImage(Value: TSurfaceBitmap); +begin + FSharedImage := Value; + UpdateImage; +end; + procedure TRenderImage.SetColor(Value: TColor); begin if Value = Color then Exit; @@ -406,8 +483,8 @@ procedure TRenderImage.GetPreferredSize(var PreferredWidth, begin if (not FImage.Empty) and (FMode = imCenter) then begin - PreferredWidth := FImage.Width; - PreferredHeight := FImage.Height; + PreferredWidth := ComputeImage.Width; + PreferredHeight := ComputeImage.Height; end; end; @@ -481,6 +558,7 @@ procedure TIndeterminateProgress.Render; (drLeft, drCenter, drRight, drCenter); Margin = 4; var + ComputedStatus: TProgressStatus; Images: TImageStrip; Index: Integer; R: TRectI; @@ -489,7 +567,10 @@ procedure TIndeterminateProgress.Render; begin inherited Render; Images := nil; - if Status = psBusy then + ComputedStatus := Status; + if FHelp <> '' then + ComputedStatus := psHelp; + if ComputedStatus = psBusy then begin Images := FBusyImages; if (Images = nil) or (Images.Count = 0) then @@ -497,15 +578,17 @@ procedure TIndeterminateProgress.Render; FBusyIndex := FBusyIndex mod Images.Count; Index := FBusyIndex; end - else if Status > psBusy then + else if ComputedStatus > psBusy then begin Images := FStatusImages; if (Images = nil) or (Images.Count = 0) then Images := GlobalStatusImages; - Index := Ord(Status) - Ord(psReady); + Index := Ord(ComputedStatus) - Ord(psReady); end; R := ClientRect; S := Caption; + if FHelp <> '' then + S := FHelp; F := NewFont(Font); if Images = nil then Surface.TextOut(F, S, R, Dir[FIconPosition]) @@ -550,6 +633,13 @@ procedure TIndeterminateProgress.TimerExpired(Sender: TObject); Invalidate; end; +procedure TIndeterminateProgress.SetHelp(Value: string); +begin + if FHelp = Value then Exit; + FHelp := Value; + Invalidate; +end; + procedure TIndeterminateProgress.SetStatus(Value: TProgressStatus); begin if FStatus = Value then Exit; diff --git a/source/codebot.controls.pas b/source/codebot.controls.pas index b99a750..ac262e2 100644 --- a/source/codebot.controls.pas +++ b/source/codebot.controls.pas @@ -19,9 +19,44 @@ interface Codebot.Graphics, Codebot.Graphics.Types; -{ ESurfaceAccessError } +{ TEdgeOffset represents a padding or margin on a control + See also + } type + TEdgeOffset = class(TChangeNotifier) + private + FBottom: Integer; + FLeft: Integer; + FRight: Integer; + FTop: Integer; + procedure SetBottom(Value: Integer); + procedure SetLeft(Value: Integer); + procedure SetRight(Value: Integer); + procedure SetTop(Value: Integer); + public + { Copy padding } + procedure Assign(Source: TPersistent); override; + { Space on the left } + property Left: Integer read FLeft write SetLeft default 0; + { Space on the top } + property Top: Integer read FTop write SetTop default 0; + { Space on the right } + property Right: Integer read FRight write SetRight default 0; + { Space on the bottom } + property Bottom: Integer read FBottom write SetBottom default 0; + end; + +{ TEdge represents information about the border of a control } + + TEdge = (edLeft, edTop, edRight, edBottom); + +{ TEdges represents information about multiple borders on a control } + + TEdges = set of TEdge; + +{ ESurfaceAccessError } + {doc off} ESurfaceAccessError = class(Exception); {doc on} @@ -142,76 +177,63 @@ TRenderForm = class(TForm) property ThemeName: string read FThemeName write SetThemeName; end; -{ TBorderContainer } - - TBorderContainer = class(TRenderCustomControl) - protected - procedure Render; override; - public - constructor Create(AOwner: TComponent); override; - published - property Align; - property Anchors; - property AutoSize; - property BorderSpacing; - property BidiMode; - property BorderWidth; - property BorderStyle; - property Caption; - property ChildSizing; - property ClientHeight; - property ClientWidth; - property Color; - property Constraints; - property DockSite; - property DragCursor; - property DragKind; - property DragMode; - property Enabled; - property Font; - property ParentBidiMode; - property ParentColor; - property ParentFont; - property ParentShowHint; - property PopupMenu; - property ShowHint; - property TabOrder; - property TabStop; - property UseDockManager default True; - property Visible; - property OnClick; - property OnContextPopup; - property OnDockDrop; - property OnDockOver; - property OnDblClick; - property OnDragDrop; - property OnDragOver; - property OnEndDock; - property OnEndDrag; - property OnEnter; - property OnExit; - property OnGetSiteInfo; - property OnGetDockCaption; - property OnMouseDown; - property OnMouseEnter; - property OnMouseLeave; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnMouseWheelDown; - property OnMouseWheelUp; - property OnResize; - property OnRender; - property OnStartDock; - property OnStartDrag; - property OnUnDock; - end; +procedure ArrangeControls(Container: TWinControl; Bounds: TRectI; Offset: Integer = 0); implementation uses Codebot.Constants; +{ TEdgeOffset } + +procedure TEdgeOffset.Assign(Source: TPersistent); +var + E: TEdgeOffset; +begin + if Source is TEdgeOffset then + begin + E := Source as TEdgeOffset; + FLeft := E.Left; + FTop := E.Top; + FRight := E.Right; + FBottom := E.Bottom; + Change; + end + else + inherited Assign(Source); +end; + +procedure TEdgeOffset.SetLeft(Value: Integer); +begin + if Value < 0 then Value := 0; + if FLeft = Value then Exit; + FLeft := Value; +end; + +procedure TEdgeOffset.SetTop(Value: Integer); +begin + if Value < 0 then Value := 0; + if FTop = Value then Exit; + FTop := Value; + Change; +end; + +procedure TEdgeOffset.SetRight(Value: Integer); +begin + if Value < 0 then Value := 0; + if FRight = Value then Exit; + FRight := Value; + Change; +end; + +procedure TEdgeOffset.SetBottom(Value: Integer); +begin + if Value < 0 then Value := 0; + if FBottom = Value then Exit; + FBottom := Value; + Change; +end; + { TRenderGraphicControl } constructor TRenderGraphicControl.Create(AOwner: TComponent); @@ -476,22 +498,66 @@ procedure TRenderForm.ThemeChanged; Invalidate; end; -{ TBorderContainer } - -constructor TBorderContainer.Create(AOwner: TComponent); +function CompareControls(constref A: TControl; constref B: TControl): Integer; begin - inherited Create(AOwner); - ControlStyle := ControlStyle + [csAcceptsControls]; - Color := clWindow; - Width := 160; - Height := 160; + Result := A.Left - B.Left; end; -procedure TBorderContainer.Render; +procedure ArrangeControls(Container: TWinControl; Bounds: TRectI; Offset: Integer = 0); + + function IsLabel(C: TControl): Boolean; + var + S: string; + begin + S := C.ClassName; + Result := S.EndsWith('Label'); + end; + + function IsSlider(C: TControl): Boolean; + var + S: string; + begin + S := C.ClassName; + Result := S.EndsWith('SlideBar'); + end; + +var + Controls: TArrayList; + Control: TControl; + X, Y: Integer; + I: Integer; begin - inherited Render; - if csDesigning in ComponentState then - Surface.FillRect(Brushes.Checker, ClientRect); + for I := 0 to Container.ControlCount - 1 do + begin + Control := Container.Controls[I]; + if Bounds.Contains(Control.Left, Control.Top) then + Controls.Push(Control); + end; + Controls.Sort(CompareControls); + X := Bounds.Left + Offset; + Y := Bounds.Height; + for Control in Controls do + begin + if IsLabel(Control) then + begin + X := X + 8; + Control.Left := X; + Control.Top := (Y - Control.Height) div 2 + Bounds.Top; + X := X + Control.Width + 8; + end + else if IsSlider(Control) then + begin + Control.Left := X; + Control.Top := (Y - Control.Height) div 2 + Bounds.Top; + X := X + Control.Width; + end + else + begin + Control.Left := X; + Control.Top := (Y - Control.Height) div 2 + Bounds.Top; + X := X + Control.Width; + end; + end; end; end. diff --git a/source/codebot.controls.scrolling.pas b/source/codebot.controls.scrolling.pas index 8e6546b..d407549 100644 --- a/source/codebot.controls.scrolling.pas +++ b/source/codebot.controls.scrolling.pas @@ -1113,16 +1113,16 @@ constructor TDrawTextList.Create(AOwner: TComponent); S: TStringList; begin inherited Create(AOwner); + FAutoScroll := False; + FAutoHeight := True; S := TStringList.Create; S.Add('item one'); S.Add('item two'); S.Add('item three'); S.OnChange := ItemsChange; - ItemsChange(Self); - FAutoScroll := False; - FAutoHeight := True; - ItemHeight := TextHeight + 2; FItems := S; + ItemHeight := TextHeight + 2; + ItemsChange(S); end; destructor TDrawTextList.Destroy; diff --git a/source/codebot.controls.sliders.pas b/source/codebot.controls.sliders.pas index 5127490..6bec857 100644 --- a/source/codebot.controls.sliders.pas +++ b/source/codebot.controls.sliders.pas @@ -175,7 +175,7 @@ function TCustomSlideBar.GetGripRect: TRectI; if FMin = FMax then I := 0 else - I := Round(FPosition / (FMax - FMin) * (Width - P.X)); + I := Round((FPosition - FMin) / (FMax - FMin) * (Width - P.X)); Result.Offset(I, Height div 2 - P.Y div 2); end; end; diff --git a/source/codebot.design.editors.pas b/source/codebot.design.editors.pas index 469ae13..2a228f5 100644 --- a/source/codebot.design.editors.pas +++ b/source/codebot.design.editors.pas @@ -15,9 +15,10 @@ interface uses SysUtils, Classes, Graphics, PropEdits, ComponentEditors, ProjectIntf, - NewItemIntf, TypInfo, + TypInfo, Codebot.Graphics, Codebot.Graphics.Types, + Codebot.Controls.Containers, Codebot.Controls.Extras, Codebot.Design.SurfaceBitmapEditor, Codebot.Design.ImageListEditor; @@ -58,6 +59,16 @@ TSurfaceBitmapPropertyEditor = class(TPropertyEditor) function GetValue: AnsiString; override; end; +{ TSizingPanelEditor } + + TSizingPanelEditor = class(TComponentEditor) + public + procedure Edit; override; + procedure ExecuteVerb(Index: Integer); override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + end; + { TRenderImageEditor } TRenderImageEditor = class(TComponentEditor) @@ -220,6 +231,35 @@ procedure TSurfaceBitmapPropertyEditor.Edit; end; end; +{ TSizingPanelEditor } + +function TSizingPanelEditor.GetVerb(Index: Integer): string; +begin + Result := 'Arrange controls'; +end; + +function TSizingPanelEditor.GetVerbCount: Integer; +begin + Result := 1; +end; + +procedure TSizingPanelEditor.Edit; +var + Panel: TSizingPanel; +begin + if Component is TSizingPanel then + begin + Panel := Component as TSizingPanel; + Panel.ArrangeControls; + Designer.Modified; + end; +end; + +procedure TSizingPanelEditor.ExecuteVerb(Index: Integer); +begin + Edit; +end; + { TRenderImageEditor } function TRenderImageEditor.GetVerb(Index: Integer): string; diff --git a/source/codebot.design.registration.pas b/source/codebot.design.registration.pas index 83d996e..7b51cd7 100644 --- a/source/codebot.design.registration.pas +++ b/source/codebot.design.registration.pas @@ -22,6 +22,7 @@ interface Codebot.Controls.Grids, Codebot.Controls.Banner, Codebot.Controls.Buttons, + Codebot.Controls.Containers, Codebot.Controls.Colors, Codebot.Controls.Extras, Codebot.Controls.Scrolling, @@ -36,7 +37,7 @@ implementation procedure Register; begin { Components } - RegisterComponents('Codebot', [TIndeterminateProgress, TBorderContainer, TBanner, + RegisterComponents('Codebot', [TIndeterminateProgress, TSizingPanel, TBanner, TRenderBox, TRenderImage, TImageStrip, TThinButton, TContentGrid, TDrawList, TDrawTextList, THuePicker, TSaturationPicker, TSlideBar]); { Property editors } @@ -47,6 +48,7 @@ procedure Register; RegisterPropertyEditor(TSurfaceBitmap.ClassInfo, nil, '', TSurfaceBitmapPropertyEditor); { Component editors } + RegisterComponentEditor(TSizingPanel, TSizingPanelEditor); RegisterComponentEditor(TRenderImage, TRenderImageEditor); RegisterComponentEditor(TImageStrip, TImageStripEditor); { Custom forms } diff --git a/source/codebot.design.surfacebitmapeditor.lfm b/source/codebot.design.surfacebitmapeditor.lfm index 0e6faad..e59a689 100644 --- a/source/codebot.design.surfacebitmapeditor.lfm +++ b/source/codebot.design.surfacebitmapeditor.lfm @@ -299,7 +299,7 @@ object SurfaceBitmapEditor: TSurfaceBitmapEditor TitleSub.Text = 'A surface bitmap can load and save all popular image formats' TitleSub.X = 0 TitleSub.Y = 0 - object BorderContainer: TBorderContainer + object BorderContainer: TSizingPanel Left = 8 Height = 240 Top = 88 diff --git a/source/codebot.design.surfacebitmapeditor.pas b/source/codebot.design.surfacebitmapeditor.pas index 065f0b9..73f00bc 100644 --- a/source/codebot.design.surfacebitmapeditor.pas +++ b/source/codebot.design.surfacebitmapeditor.pas @@ -21,13 +21,14 @@ interface Codebot.Graphics, Codebot.Graphics.Types, Codebot.Controls.Banner, + Codebot.Controls.Containers, Codebot.Controls.Extras; { TSurfaceBitmapEditor } type TSurfaceBitmapEditor = class(TBannerForm) - BorderContainer: TBorderContainer; + BorderContainer: TSizingPanel; RenderImage: TRenderImage; OKButton: TButton; CancelButton: TButton; diff --git a/source/codebot.graphics.markup.pas b/source/codebot.graphics.markup.pas index 22778cd..f43bcb5 100644 --- a/source/codebot.graphics.markup.pas +++ b/source/codebot.graphics.markup.pas @@ -128,20 +128,41 @@ TExpression = record TExpressionArray = TArrayList; +{ TSurfaceHeader } + + TSurfaceHeader = record + public + procedure Reset; + procedure Normalize; + public + Title: string; + Width: Integer; + Height: Integer; + Opacity: Byte; + Scale: Float; + Display: string; + end; + { TSurfaceData } TSurfaceData = record private - Brushes: TArrayList; - Pens: TArrayList; - Fonts: TArrayList; - Commands: TArrayList; + function GetScale: Float; + private function FindBrush(const Name: string): IBrush; function FindPen(const Name: string): IPen; function FindFont(const Name: string): IFont; + property Scale: Float read GetScale; public + Doc: IDocument; + Valid: Boolean; + Header: TSurfaceHeader; Expressions: TExpressionArray; - procedure Parse(const Markup: string); + Brushes: TArrayList; + Pens: TArrayList; + Fonts: TArrayList; + Commands: TArrayList; + procedure Process(Document: IDocument; constref Defaults: TSurfaceHeader); procedure Render(Surface: ISurface); end; @@ -223,9 +244,38 @@ procedure TExpression.Resolve(var Data: TCommandData); end; end; + +procedure TSurfaceHeader.Reset; +begin + Title := '(untitled)'; + Width := 256; + Height := 256; + Opacity := 255; + Scale := 1; + Display := 'fit'; +end; + +procedure TSurfaceHeader.Normalize; +begin + if Scale > 5 then + Scale := 5 + else if Scale < 0.25 then + Scale := 0.25; + if Width < 32 then + Width := 32 + else if Width > 512 then + Width := 512; + if Height < 32 then + Height := 32 + else if Height > 512 then + Height := 512; + if Display.ArrayIndex(['fit', 'tile', 'overlay']) < 0 then + Display := 'fit'; +end; + { TSurfaceData } -procedure TSurfaceData.Parse(const Markup: string); +procedure TSurfaceData.Process(Document: IDocument; constref Defaults: TSurfaceHeader); var Added: TExpressionArray; @@ -323,9 +373,9 @@ procedure TSurfaceData.Parse(const Markup: string); else Brush := nil; if Brush <> nil then - Result.Pen := NewPen(Brush, W) + Result.Pen := NewPen(Brush, W * Scale) else - Result.Pen := NewPen(C, W); + Result.Pen := NewPen(C, W * Scale); end; function ParseFont(F: IFiler): TFontData; @@ -362,7 +412,7 @@ procedure TSurfaceData.Parse(const Markup: string); if S <> '' then begin I := StrToIntDef(S, 0); - if I > 10 then + if I > 0 then Font.Height := I; end; Style := []; @@ -514,21 +564,31 @@ procedure TSurfaceData.Parse(const Markup: string); end; var - D: IDocument; R: INode; N: INode; L: INodeList; F: IFiler; S: string; begin + Doc := Document; + Header := Defaults; Brushes.Length := 0; Pens.Length := 0; Fonts.Length := 0; Commands.Length := 0; - D := DocumentCreate; - D.Xml := Markup; - R := D.Force('surface'); - L := R.SelectList('brush'); + R := Doc.Root; + Valid := (R <> nil) and (R.Name = 'surface'); + if not Valid then + Exit; + F := R.Filer; + Header.Title := F.ReadStr('@title', Defaults.Title, True).Trim; + Header.Width := F.ReadInt('@width', Defaults.Width, True); + Header.Height := F.ReadInt('@height', Defaults.Height, True); + Header.Opacity := F.ReadInt('@opacity', Defaults.Opacity, True); + Header.Scale := F.ReadFloat('@scale', Defaults.Scale, True); + Header.Display := F.ReadStr('@display', Defaults.Display, True); + Header.Normalize; + L := R.SelectList('resources/brush'); if L <> nil then for N in L do begin @@ -538,7 +598,7 @@ procedure TSurfaceData.Parse(const Markup: string); else Brushes.Push(ParseBrush(F)); end; - L := R.SelectList('pen'); + L := R.SelectList('resources/pen'); if L <> nil then for N in L do begin @@ -548,7 +608,7 @@ procedure TSurfaceData.Parse(const Markup: string); else Pens.Push(ParsePen(F, Self)); end; - L := R.SelectList('font'); + L := R.SelectList('resources/font'); if L <> nil then for N in L do begin @@ -558,7 +618,11 @@ procedure TSurfaceData.Parse(const Markup: string); else Fonts.Push(ParseFont(F)); end; - L := R.Nodes; + N := R.SelectNode('commands'); + if N <> nil then + L := N.Nodes + else + L := nil; if L <> nil then for N in L do begin @@ -610,6 +674,11 @@ procedure TSurfaceData.Parse(const Markup: string); Expressions := Added; end; +function TSurfaceData.GetScale: Float; +begin + Result := Header.Scale; +end; + function TSurfaceData.FindBrush(const Name: string): IBrush; var I: Integer; @@ -666,13 +735,13 @@ procedure TSurfaceData.Render(Surface: ISurface); Data := Commands[I]; Resolve(Data); case Data.Kind of - ckMoveTo: Surface.MoveTo(Data.X, Data.Y); - ckLineTo: Surface.LineTo(Data.X, Data.Y); - ckArcTo: Surface.ArcTo(Data.Area, Data.BeginAngle, Data.EndAngle); - ckCurveTo: Surface.CurveTo(Data.P.X, Data.P.Y, Data.C1, Data.C2); - ckEllipse: Surface.Ellipse(Data.Rect); - ckRectangle: Surface.Rectangle(Data.Rect); - ckRoundRectangle: Surface.RoundRectangle(Data.RoundRect, Data.Radius); + ckMoveTo: Surface.MoveTo(Data.X * Scale, Data.Y * Scale); + ckLineTo: Surface.LineTo(Data.X * Scale, Data.Y * Scale); + ckArcTo: Surface.ArcTo(Data.Area * Scale, Data.BeginAngle, Data.EndAngle); + ckCurveTo: Surface.CurveTo(Data.P.X * Scale, Data.P.Y * Scale, Data.C1 * Scale, Data.C2 * Scale); + ckEllipse: Surface.Ellipse(Data.Rect * Scale); + ckRectangle: Surface.Rectangle(Data.Rect * Scale); + ckRoundRectangle: Surface.RoundRectangle(Data.RoundRect * Scale, Data.Radius * Scale); ckText: begin F := FindFont(Data.Font); @@ -690,8 +759,8 @@ procedure TSurfaceData.Render(Surface: ISurface); ckStatePop: Surface.Restore; ckIdentity: Surface.Matrix.Identity; ckRotate: Surface.Matrix.Rotate(Data.Angle); - ckScale: Surface.Matrix.Scale(Data.X, Data.Y); - ckTranslate: Surface.Matrix.Translate(Data.X, Data.Y); + ckScale: Surface.Matrix.Scale(Data.X * Scale, Data.Y * Scale); + ckTranslate: Surface.Matrix.Translate(Data.X * Scale, Data.Y * Scale); ckStroke: begin P := FindPen(Data.Resource); diff --git a/source/codebot.graphics.pas b/source/codebot.graphics.pas index 9da7353..77b91a6 100644 --- a/source/codebot.graphics.pas +++ b/source/codebot.graphics.pas @@ -90,6 +90,8 @@ TSurfaceBitmap = class(TGraphic) procedure Assign(Source: TPersistent); override; procedure Clear; override; {doc on} + { Set the underlying bitmpa referenc directly } + procedure CopyReference(Bitmap: IBitmap); { Draw the image on a canvas at x and y, optionaly picking a frame as the source } procedure Draw(Surface: ISurface; X, Y: Integer; FrameIndex: Integer = -1); overload; { Draw the image on a canvas stretching it from the source to dest rectangles } @@ -208,11 +210,13 @@ TImageStrip = class(TComponent) procedure FillRectColor(Surface: ISurface; const Rect: TRectI; Color: TColorB; Radius: Float = 0); procedure StrokeRectColor(Surface: ISurface; const Rect: TRectI; Color: TColorB; Radius: Float = 0); +procedure FillRectState(Surface: ISurface; const Rect: TRectI; State: TDrawState); function DrawDummyBitmap(Width, Height: Integer): IBitmap; function DrawHueLinear(Width, Height: Integer): IBitmap; function DrawHueRadial(Width, Height: Integer): IBitmap; function DrawSaturationBox(Width, Height: Integer; Hue: Float): IBitmap; function DrawDesaturationBox(Width, Height: Integer; Hue: Float): IBitmap; +procedure DrawShadow(Surface: ISurface; const Rect: TRectI; Direction: TDirection); { Brushes creates a series of bitmap batterns } @@ -529,6 +533,13 @@ constructor TSurfaceBitmap.Create; FOpacity := High(Byte); end; +procedure TSurfaceBitmap.CopyReference(Bitmap: IBitmap); +begin + UpdateBitmap(Bitmap); + FWidth := Bitmap.Width; + FHeight := Bitmap.Height; +end; + procedure TSurfaceBitmap.UpdateBitmap(B: IBitmap); var F: TImageFormat; @@ -583,15 +594,15 @@ function TSurfaceBitmap.GetFrames(Index: Integer): TRectI; if Empty then Exit; Result := TRectI.Create(FWidth, FHeight); - if FWidth > FHeight then + if Width > Height then begin - Result.Width := FHeight; - Result.Offset(Index * FHeight, 0); + Result.Width := Height; + Result.Offset(Index * Height, 0); end else begin - Result.Height := FWidth; - Result.Offset(0, Index * FWidth); + Result.Height := Width; + Result.Offset(0, Index * Width); end; end; @@ -600,10 +611,10 @@ function TSurfaceBitmap.GetFrameCount: Integer; Result := 0; if Empty then Exit; - if FWidth > FHeight then - Result := FWidth div FHeight + if Width > Height then + Result := Width div Height else - Result := FHeight div FWidth; + Result := Height div Width; end; procedure TSurfaceBitmap.SetFormat(Value: TImageFormat); @@ -619,7 +630,7 @@ function TSurfaceBitmap.GetPixels: PPixel; function TSurfaceBitmap.GetEmpty: Boolean; begin - Result := (FWidth < 1) or (FHeight < 1); + Result := (Width < 1) or (Height < 1); end; function TSurfaceBitmap.GetMimeType: string; @@ -657,14 +668,17 @@ procedure TSurfaceBitmap.SetTransparent(Value: Boolean); function TSurfaceBitmap.GetWidth: Integer; begin - Result := FWidth; + if FBitmap.Empty then + Result := FWidth + else + Result := Bitmap.Width; end; procedure TSurfaceBitmap.SetWidth(Value: Integer); begin if Value < 1 then Value := 0; - if Value <> FWidth then + if Value <> Width then begin FWidth := Value; HandleRelease; @@ -673,14 +687,17 @@ procedure TSurfaceBitmap.SetWidth(Value: Integer); function TSurfaceBitmap.GetHeight: Integer; begin - Result := FHeight; + if FBitmap.Empty then + Result := FHeight + else + Result := Bitmap.Height; end; procedure TSurfaceBitmap.SetHeight(Value: Integer); begin if Value < 1 then Value := 0; - if Value <> FHeight then + if Value <> Height then begin FHeight := Value; HandleRelease; @@ -828,7 +845,12 @@ procedure TSurfaceBitmap.Colorize(Color: TColorB); Exit; HandleNeeded; for I := Low(Shades) to High(Shades) do - Shades[I] := Color.Lighten(I / High(Byte)); + begin + if I > $7F then + Shades[I] := Color.Lighten((I - $7F) / $7F) + else + Shades[I] := Color.Darken(1 - I / $7F); + end; P := FBitmap.Pixels; for I := 1 to FBitmap.Width * FBitmap.Height do begin @@ -938,7 +960,7 @@ procedure TSurfaceBitmap.Resample(Width, Height: Integer; SetSize(Width, Height); Exit; end; - if (Width = FWidth) or (Height = FHeight) then + if (Width = Self.Width) or (Height = Self.Height) then Exit; HandleNeeded; UpdateBitmap(FBitmap.Resample(Width, Height, Quality)); @@ -953,7 +975,7 @@ procedure TSurfaceBitmap.SetSize(Width, Height: Integer); Width := 0; if Height < 0 then Height := 0; - if (Width <> FWidth) or (Height <> FHeight) then + if (Width <> Self.Width) or (Height <> Self.Height) then begin FWidth := Width; FHeight := Height; @@ -1273,8 +1295,8 @@ procedure TImageStrip.Draw(Surface: ISurface; Index: Integer; X, B := TSurfaceBitmap.Create; B.SetSize(Size, Size); FBitmap.Draw(B.Surface, 0, 0, Index); - B.Desaturate(0.75); - B.Opacity := $A0; + B.Desaturate(1); + B.Opacity := $70; B.Draw(Surface, X, Y); B.Free; end @@ -1345,6 +1367,20 @@ procedure StrokeRectColor(Surface: ISurface; const Rect: TRectI; Color: TColorB; Surface.StrokeRoundRect(NewPen(Color), Rect, Radius); end; +procedure FillRectState(Surface: ISurface; const Rect: TRectI; State: TDrawState); +var + C: TColorB; +begin + if dsSelected in State then + begin + C := clHighlight; + Surface.FillRect(NewBrush(C.Blend(clWindow, 0.75)), Rect); + Surface.StrokeRect(NewPen(C.Blend(clWindow, 0.25)), Rect); + end + else + Surface.FillRect(NewBrush(clWindow), Rect); +end; + function DrawDummyBitmap(Width, Height: Integer): IBitmap; var S: ISurface; @@ -1470,6 +1506,57 @@ function DrawDesaturationBox(Width, Height: Integer; Hue: Float): IBitmap; end; end; +procedure DrawShadow(Surface: ISurface; const Rect: TRectI; Direction: TDirection); +const + Margin = 8; +var + R: TRectI; + C: TColorB; + B: IBrush; +begin + R := Rect; + C := clBlack; + C.Alpha := 5; + B := NewBrush(C); + case Direction of + drLeft: + begin + R.Right := R.Left + Margin; + while R.Width > 1 do + begin + Surface.FillRect(B, R); + Dec(R.Width); + end; + end; + drUp: + begin + R.Bottom := R.Top + Margin; + while R.Height > 1 do + begin + Surface.FillRect(B, R); + Dec(R.Height); + end; + end; + drRight: + begin + R.Left := R.Right - Margin; + while R.Width > 1 do + begin + Surface.FillRect(B, R); + R.Left := R.Left + 1; + end; + end; + drDown: + begin + R.Top := R.Bottom - Margin; + while R.Height > 1 do + begin + Surface.FillRect(B, R); + R.Top := R.Top + 1; + end; + end; + end; +end; { Brushes } @@ -1858,6 +1945,8 @@ class procedure TDefaultTheme.DrawButton(const Rect: TRectI); end; class procedure TDefaultTheme.DrawButtonThin(const Rect: TRectI); +const + Radius = 3; var R: TRectI; C: TColorB; @@ -1873,18 +1962,19 @@ class procedure TDefaultTheme.DrawButtonThin(const Rect: TRectI); G.AddStop(C.Fade(0.6).Darken(0.5), 0); G.AddStop(C.Fade(0).Darken(0.5), 1); Surface.FillRoundRect(G, Rect, 3); - Surface.StrokeRoundRect(NewPen(C.Fade(0.6).Darken(0.6)), Rect, 3); + Surface.StrokeRoundRect(NewPen(C.Fade(0.6).Darken(0.6)), Rect, Radius); end else begin - R.Inflate(R.Width, R.Height); - G := NewBrush(R); - G.AddStop(C.Fade(0), 0); - G.AddStop(C.Fade(0), 0.25); - G.AddStop(C.Fade(0.5).Darken(0.25), 0.3); - G.AddStop(C.Fade(1).Darken(0.8), 1); - Surface.FillRoundRect(G, Rect, 3); - Surface.StrokeRoundRect(NewPen(C.Fade(0.5).Darken(0.5)), Rect, 3); + G := NewBrush(R.Left, R.Top, R.Left, R.Bottom); + C := Control.CurrentColor; + G.AddStop(C.Lighten(0.5), 0); + G.AddStop(C.Darken(0.2), 1); + R.Inflate(-1, -1); + Surface.FillRect(G, R); + Surface.StrokeRect(NewPen(clWhite), R); + R.Inflate(1, 1); + Surface.StrokeRoundRect(NewPen(clBtnShadow), Rect, Radius); end; end; @@ -1915,22 +2005,42 @@ class function TDefaultTheme.MeasureThumbThin(Orientation: TThemeOrientation): T end; class procedure TDefaultTheme.DrawThumbThin(const Rect: TRectI; Orientation: TThemeOrientation); +const + Radius = 3; var + G: IGradientBrush; + C: TColorB; R: TRectI; begin R := Rect; + if Orientation = toVertical then + G := NewBrush(R.Left, R.Top, R.Right, R.Top) + else + G := NewBrush(R.Left, R.Top, R.Left, R.Bottom); + C := Control.CurrentColor; + G.AddStop(C.Lighten(0.5), 0); + G.AddStop(C.Darken(0.2), 1); if [dsHot, dsPressed] * State <> [] then begin - Surface.FillRoundRect(NewBrush(clHighlight), R, 4); + C := clWhite; + C := C.Blend(clHighlight, 0.75); + R.Inflate(-1, -1); + Surface.FillRoundRect(NewBrush(C), R, Radius); if Orientation = toVertical then - R.Inflate(-4, 0) + R.Inflate(-3, 0) else - R.Inflate(0, -4); - Surface.FillRect(NewBrush(clBtnFace), R); + R.Inflate(0, -3); + Surface.FillRect(G, R); + Surface.StrokeRect(NewPen(clWhite), R); end else - Surface.FillRoundRect(NewBrush(clBtnFace), Rect, 4); - Surface.StrokeRoundRect(NewPen(clBtnShadow), Rect, 4); + begin + Surface.FillRoundRect(G, Rect, Radius); + R := Rect; + R.Inflate(-1, -1); + Surface.StrokeRoundRect(NewPen(clWhite), R, Radius); + end; + Surface.StrokeRoundRect(NewPen(clBtnShadow), Rect, Radius); end; class function TDefaultTheme.MeasureBorder: TPointI; diff --git a/source/codebot.graphics.types.pas b/source/codebot.graphics.types.pas index 8d75207..d9163e1 100644 --- a/source/codebot.graphics.types.pas +++ b/source/codebot.graphics.types.pas @@ -76,7 +76,9 @@ TRectI = record procedure SetBottom(Value: Integer); function GetSize: TPointI; function GetTopLeft: TPointI; + function GetBottomLeft: TPointI; function GetBottomRight: TPointI; + function GetTopRight: TPointI; function GetMidPoint: TPointI; public X, Y, Width, Height: Integer; @@ -104,7 +106,9 @@ TRectI = record property Bottom: Integer read GetBottom write SetBottom; property Size: TPointI read GetSize; property TopLeft: TPointI read GetTopLeft; + property BottomLeft: TPointI read GetBottomLeft; property BottomRight: TPointI read GetBottomRight; + property TopRight: TPointI read GetTopRight; property MidPoint: TPointI read GetMidPoint; end; PRectI = ^TRectI; @@ -123,6 +127,7 @@ TPointF = record class operator NotEqual(const A, B: TPointF): Boolean; class operator Add(const A, B: TPointF): TPointF; class operator Subtract(const A, B: TPointF): TPointF; + class operator Multiply(const A: TPointF; B: Float): TPointF; function Equals(const Value: TPointF): Boolean; class function Create: TPointF; overload; static; class function Create(X, Y: Float): TPointF; overload; static; @@ -167,6 +172,7 @@ TRectF = record class operator Explicit(const Value: TRectF): TRect; class operator Equal(const A, B: TRectF): Boolean; class operator NotEqual(const A, B: TRectF): Boolean; + class operator Multiply(const A: TRectF; B: Float): TRectF; class function Create: TRectF; overload; static; class function Create(Size: TPointF): TRectF; overload; static; class function Create(W, H: Float): TRectF; overload; static; @@ -1019,11 +1025,21 @@ function TRectI.GetTopLeft: TPointI; Result := TPointI.Create(X, Y); end; +function TRectI.GetBottomLeft: TPointI; +begin + Result := TPointI.Create(X, Y + Height); +end; + function TRectI.GetBottomRight: TPointI; begin Result := TPointI.Create(X + Width, Y + Height); end; +function TRectI.GetTopRight: TPointI; +begin + Result := TPointI.Create(X + Width, Y); +end; + function TRectI.GetMidPoint: TPointI; begin Result := TPointI.Create(X + Width div 2, Y + Height div 2); @@ -1083,6 +1099,12 @@ function TRectI.GetMidPoint: TPointI; Result.Y := A.Y - B.Y; end; +class operator TPointF.Multiply(const A: TPointF; B: Float): TPointF; +begin + Result.X := A.X * B; + Result.Y := A.Y * B; +end; + class function TPointF.Create: TPointF; begin Result.X := 0; @@ -1225,6 +1247,14 @@ function TPointF.Rotate(const P: TPointF; Angle: Float): TPointF; Result := not A.Equals(B); end; +class operator TRectF.Multiply(const A: TRectF; B: Float): TRectF; +begin + Result.X := A.X * B; + Result.Y := A.Y * B; + Result.Width := A.Width * B; + Result.Height := A.Height * B; +end; + class function TRectF.Create: TRectF; begin Result.X := 0; @@ -1862,10 +1892,10 @@ function TColorB.Darken(Percent: Float): TColorB; var Compliment: Float; begin - if Percent = 0 then + if Percent <= 0.005 then Exit(Self); Result.Alpha := Alpha; - if Percent = 1 then + if Percent >= 0.995 then begin Result.Blue := 0; Result.Green := 0; @@ -1884,16 +1914,16 @@ function TColorB.Lighten(Percent: Float): TColorB; var Compliment: Float; begin - if Percent = 0 then + if Percent <= 0.005 then Exit(Self); Result.Alpha := Alpha; - if (Alpha = 0) or (Percent = 0) then + if Alpha = 0 then begin Result.Blue := 0; Result.Green := 0; Result.Red := 0; end - else if (Alpha = $FF) and (Percent = 1) then + else if (Alpha = $FF) and (Percent >= 0.995) then begin Result.Blue := HiByte; Result.Green := HiByte; diff --git a/source/codebot.graphics.windows.surfaced2d.pas b/source/codebot.graphics.windows.surfaced2d.pas index 49cd41a..23cece4 100644 --- a/source/codebot.graphics.windows.surfaced2d.pas +++ b/source/codebot.graphics.windows.surfaced2d.pas @@ -799,8 +799,7 @@ function CreateLayerParameters(G: ID2D1Geometry): TD2D1LayerParameters; function CreateTextFormat(Font: IFont): IDWriteTextFormat; const - PointsPerInch = 72; - DeviceIndependentPixels = 96; + Factor = 72 / 96; Eng = 'en-us'; Weight: array[Boolean] of DWRITE_FONT_WEIGHT = (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_BOLD); @@ -810,7 +809,7 @@ function CreateTextFormat(Font: IFont): IDWriteTextFormat; Size: Float; Name: WideString; begin - Size := Font.Size / PointsPerInch * DeviceIndependentPixels; + Size := Font.Size * Factor; Name := Font.Name; if WriteFactory.CreateTextFormat(PWideChar(Name), nil, Weight[fsBold in Font.Style], Style[fsItalic in Font.Style], DWRITE_FONT_STRETCH_NORMAL, Size, @@ -1267,9 +1266,12 @@ constructor TFontD2D.Create(F: TFont); FStyle := F.Style; GetObject(F.Handle, SizeOf(LogFont), @LogFont); if LogFont.lfHeight < 0 then - FSize := MulDiv(-LogFont.lfHeight, Points, Dpi) + begin + FSize := -LogFont.lfHeight / Points; + FSize := FSize * Dpi; + end else - FSize := LogFont.lfHeight * (Points / Dpi); + FSize := LogFont.lfHeight; end; function TFontD2D.Format: IDWriteTextFormat; @@ -2195,7 +2197,7 @@ procedure TSurfaceD2D.TextOut(Font: IFont; const Text: string; const Rect: TRect WriteFactory.CreateRenderingParams(Params1); WriteFactory.CreateCustomRenderingParams(Params1.GetGamma, Params1.GetEnhancedContrast, 1, Params1.GetPixelGeometry, - DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL, + DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, Params2); FTarget.SetTextRenderingParams(Params2); FTarget.SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE); diff --git a/source/codebot.lpk b/source/codebot.lpk index 856e5c6..6a2850d 100644 --- a/source/codebot.lpk +++ b/source/codebot.lpk @@ -34,7 +34,7 @@ - + @@ -201,8 +201,12 @@ - + + + + + diff --git a/source/codebot.pas b/source/codebot.pas index 5fd33b5..4f1e82e 100644 --- a/source/codebot.pas +++ b/source/codebot.pas @@ -22,7 +22,8 @@ interface Codebot.Controls, Codebot.Controls.Colors, Codebot.Controls.Edits, Codebot.Controls.Banner, Codebot.Controls.Grids, Codebot.Design.ImageListEditor, Codebot.Design.SurfaceBitmapEditor, - Codebot.Controls.Buttons, Codebot.Graphics.Markup, LazarusPackageIntf; + Codebot.Controls.Buttons, Codebot.Graphics.Markup, + Codebot.Controls.Containers, LazarusPackageIntf; implementation diff --git a/source/codebot.system.pas b/source/codebot.system.pas index 0d2658b..1458249 100644 --- a/source/codebot.system.pas +++ b/source/codebot.system.pas @@ -155,10 +155,13 @@ type TArrayListEnumerator = class(TArrayEnumerator) end; class var DefaultConvertString: TConvertString; { The array acting as a list } var Items: TArray; + class function Convert: TArrayList; static; { Convert a list to an array } class operator Implicit(const Value: TArrayList): TArray; { Convert an array to a list } class operator Implicit(const Value: TArray): TArrayList; + { Convert an open array to a list } + class operator Implicit(const Value: array of T): TArrayList; { Returns the lower bounds of the list } function Lo: Integer; { Returns the upper bounds of the list } @@ -735,7 +738,7 @@ TChangeNotifier = class(TPersistent) property OnChange: INotifyDelegate read GetOnChange; end; -{ Comapre two block of memory returning true if they are the same } +{ Compare two block of memory returning true if they are the same } function MemCompare(const A, B; Size: LongWord): Boolean; {$endregion} @@ -2560,6 +2563,14 @@ function TArrayList.GetEnumerator: IEnumerator; Result.Items := Value; end; +class operator TArrayList.Implicit(const Value: array of T): TArrayList; +var + I: T; +begin + for I in Value do + Result.Push(I); +end; + procedure TArrayList.Reverse; var Swap: T; @@ -2799,6 +2810,11 @@ procedure TArrayList.SetItem(Index: Integer; const Value: T); Items[Index] := Value; end; +class function TArrayList.Convert: TArrayList; +begin + Result.Length := 0; +end; + { TNamedValues } function TNamedValues.GetEnumerator: IEnumerator; @@ -3018,6 +3034,7 @@ procedure TChangeNotifier.Change; for Event in FOnChange do Event(Self); end; + {$endregion} {$region classes} diff --git a/source/palette_icons.lrs b/source/palette_icons.lrs deleted file mode 100644 index cb7384f..0000000 --- a/source/palette_icons.lrs +++ /dev/null @@ -1,215 +0,0 @@ -LazarusResources.Add('TAlphaImage','BMP',[ - 'BM6'#2#0#0#0#0#0#0'v'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#4#0#0#0#0#0#192#1 - +#0#0#19#11#0#0#19#11#0#0#16#0#0#0#16#0#0#0#0#0#0#0#0#0#128#0#0#128#0#0#0#128 - +#128#0#128#0#0#0#128#0#128#0#128#128#0#0#192#192#192#0#128#128#128#0#0#0#255 - +#0#0#255#0#0#0#255#255#0#255#0#0#0#255#0#255#0#255#255#0#0#255#255#255#0'www' - +'wwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0 - +'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0'wx'#0#0#0#0#0#0#0#0#0#0'ww'#0#0'wx' - +#204#204#204#204#204#204#204#204#204#192'ww'#0#0'wx'#204#204#204#204#204#204 - +#204#204#194' ww'#0#0'wx'#204#204#204#204#204#204#204#194'" ww'#0#0'wx'#204 - +#204#204#204#204#204#194'"" ww'#0#0'wx'#254#254#254#254#254#242'""" ww'#0#0 - +'wx'#255#239#239#239#239#239#226'"" ww'#0#0'wx'#254#254#254#254#254#254#254 - +#242'" ww'#0#0'wx'#255#239#239#239#239#239#239#239#226' ww'#0#0'wx'#254#254 - +#255#254#254#254#254#254#254' ww'#0#0'wx'#255#239#251#255#239#239#239#239#239 - +#224'ww'#0#0'wx'#254#255#191#254#254#254#254#254#254#240'ww'#0#0'wx'#255#239 - +#255#239#239#239#239#239#239#224'ww'#0#0'wx'#254#254#254#254#254#254#254#254 - +#254#240'ww'#0#0'wx'#255#239#239#239#239#239#239#239#239#224'ww'#0#0'wx'#255 - +#255#255#255#255#255#255#255#255#240'ww'#0#0'wx'#136#136#136#136#136#136#136 - +#136#136#136'ww'#0#0'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww' - +#0#0'wwwwwwwwwwwwww'#0#0'wwwwwwwwwwwwww'#0#0 -]); -LazarusResources.Add('TDrawList','BMP',[ - 'BM6'#2#0#0#0#0#0#0'v'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#4#0#0#0#0#0#192#1 - +#0#0#19#11#0#0#19#11#0#0#16#0#0#0#16#0#0#0#0#0#0#0#255#0#0#0#0#128#0#0#255 - +#255#0#0#0#255#255#0#128#128#128#0#192#192#192#0#223#223#223#0#255#255#255#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'ffffffffffffff'#0#0 - +'ffffffffffffff'#0#0'ffffffffffffff'#0#0'ffffffffffffff'#0#0'fewwwwwwwwwwff' - +#0#0'fe'#6'ffffffffgff'#0#0'fe'#8'UUUUUUUXgff'#0#0'fe'#8'Q'#17#17#17#17#17#17 - +'Xgff'#0#0'fe'#8'Q'#17#17#17#17#17'"Xgff'#0#0'fe'#8'Q'#17#17#17#17'""Xgff'#0 - +#0'fe'#8'X'#136#131#131#131#131'"Xgff'#0#0'fe'#8'XH88888Xgff'#0#0'fe'#8'T' - +#136#131#131#131#131#131'Xgff'#0#0'fe'#8'UUUUUUUXgff'#0#0'fe'#8#136#136#136 - +#136#136#136#136#136'gff'#0#0'fe'#8'UUUUUUUXgff'#0#0'fe'#8'Q'#17#17#17#17#17 - +#17'Xgff'#0#0'fe'#8'Q'#17#17#17#17#17'"Xgff'#0#0'fe'#8'Q'#17#17#17#17'""Xgff' - +#0#0'fe'#8'X'#136#131#131#131#131'"Xgff'#0#0'fe'#8'XH88888Xgff'#0#0'fe'#8'T' - +#136#131#131#131#131#131'Xgff'#0#0'fe'#8'UUUUUUUXgff'#0#0'fe'#0#0#0#0#0#0#0#0 - +#0#7'ff'#0#0'feUUUUUUUUUUff'#0#0'ffffffffffffff'#0#0'ffffffffffffff'#0#0'fff' - +'fffffffffff'#0#0 -]); -LazarusResources.Add('TDrawTextList','BMP',[ - 'BM6'#2#0#0#0#0#0#0'v'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#4#0#0#0#0#0#192#1 - +#0#0#19#11#0#0#19#11#0#0#16#0#0#0#16#0#0#0#0#0#0#0#128#0#0#0#192#192#192#0#0 - +#0#255#0#0#255#255#0#128#128#128#0#153#168#172#0#192#192#192#0#223#223#223#0 - +#255#255#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'"""""""""""""' - +'"'#0#0'""""""""""""""'#0#0'""""""""""""""'#0#0'""""""""""""""'#0#0'"%'#136 - +#136#136#136#136#136#136#136#136#136'""'#0#0'"%'#7'wwwwwwwwx""'#0#0'"%'#9#153 - +#153#153#153#153#153#153#153'x""'#0#0'"%'#9#153#153#153#153#153#153#153#153 - +'x""'#0#0'"%'#9#147#153#17#17#17#17#17#25'x""'#0#0'"%'#9'1'#153#153#153#153 - +#153#153#153'x""'#0#0'"%'#9#153#153#153#153#153#153#153#153'x""'#0#0'"%'#9'a' - +#153#17#17#17#17#17#153'x""'#0#0'"%'#9'4'#153#153#153#153#153#153#153'x""'#0 - +#0'"%'#9#153#153#153#153#153#153#153#153'x""'#0#0'"%'#9'A'#153#17#17#17#17#17 - +#25'x""'#0#0'"%'#9#22#153#153#153#153#153#153#153'x""'#0#0'"%'#9#153#153#153 - +#153#153#153#153#153'x""'#0#0'"%'#9'd'#153#17#17#17#17#17#153'x""'#0#0'"%'#9 - +'C'#153#153#153#153#153#153#153'x""'#0#0'"%'#9#153#153#153#153#153#153#153 - +#153'x""'#0#0'"%'#9#147#153#17#17#17#17#17#25'x""'#0#0'"%'#9'1'#153#153#153 - +#153#153#153#153'x""'#0#0'"%'#9#153#153#153#153#153#153#153#153'x""'#0#0'"%' - +#0#0#0#0#0#0#0#0#0#8'""'#0#0'"%UUUUUUUUUU""'#0#0'""""""""""""""'#0#0'"""""""' - +'"""""""'#0#0'""""""""""""""'#0#0 -]); -LazarusResources.Add('THuePicker','BMP',[ - 'BMf'#9#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#24#0#0#0#0#0'0'#9 - +#0#0#19#11#0#0#19#11#0#0#0#0#0#0#0#0#0#0#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0 - +#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255 - +#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0 - +#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255 - +#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255 - +#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255 - +#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255 - +#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0 - +#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0 - +#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0 - +#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0 - +#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0 - +#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0 - +#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0 - +#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0 - +#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255 - +#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128 - +#128#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255 - +#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255 - +#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128 - +#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255 - +#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0 - +#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255 - +#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255 - +#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128 - +#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0 - +#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0 - +#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128 - ,#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0 - +#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255 - +#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255 - +#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0 - +#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0 - +#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0 - +#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0 - +#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0 - +#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0 - +#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0 - +#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255 - +#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0 - +#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255 - +#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255 - +#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255 - +#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#128#128#128#0#0#255 - +#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0 - +#255#0#0#255#128#128#128#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#128#128#128#0#0#255#0#0#255#0#255#255#0#255 - +#255#0#255#255#0#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#255#0#255#0#0 - +#255#0#0#255#0#0#255#0#255#255#0#255#255#0#255#0#0#255#0#0#255#128#128#128 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 - +#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192#192 -]); -LazarusResources.Add('TSaturationPicker','BMP',[ - 'BM6'#2#0#0#0#0#0#0'v'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#4#0#0#0#0#0#192#1 - +#0#0#19#11#0#0#19#11#0#0#16#0#0#0#16#0#0#0#6#6#14#0#13#13'-'#0'))7'#0#29#29 - +'\'#0'SSi'#0#29#29#156#0'``'#159#0#29#29#223#0'``'#225#0#128#128#128#0#147 - +#147#176#0#172#172#182#0#161#161#226#0#192#192#192#0#207#207#239#0#241#241 - +#250#0#221#221#221#221#221#221#221#221#221#221#221#221#221#221#0#0#221#221 - +#221#221#221#221#221#221#221#221#221#221#221#221#0#0#221#221#221#221#221#221 - +#221#221#221#221#221#221#221#221#0#0#221#221#221#221#221#221#221#221#221#221 - +#221#221#221#221#0#0#221#217#153#153#153#153#153#153#153#153#153#153#221#221 - +#0#0#221#217#255#255#255#255#255#255#255#255#255#249#221#221#0#0#221#217#255 - +#255#255#255#255#255#255#255#255#233#221#221#0#0#221#217#239#238#238#238#238 - +#238#238#238#238#233#221#221#0#0#221#217#222#222#222#238#236#236#236#204#204 - +#201#221#221#0#0#221#217#221#221#220#220#204#204#204#204#204#201#221#221#0#0 - +#221#217#219#220#188#204#204#204#140#140#136#137#221#221#0#0#221#217#187#170 - +#170#170#138#136#136#136#136#137#221#221#0#0#221#217#170#170#168#168#168#136 - +#136#136'xy'#221#221#0#0#221#217#153#166'jhh'#136'xwwy'#221#221#0#0#221#217 - +#153'fffvuwwwy'#221#221#0#0#221#217#148'ffVUgWwwy'#221#221#0#0#221#217'DDDVU' - +'UUWWy'#221#221#0#0#221#217'DDECEUUUUY'#221#221#0#0#221#217'BB4333SUUY'#221 - +#221#0#0#221#217'""2333333Y'#221#221#0#0#221#217'""""313339'#221#221#0#0#221 - +#217'!!!'#17#17#17#17#17#17#25#221#221#0#0#221#217#0#0#0#16#16#16#17#17#17#25 - +#221#221#0#0#221#217#0#0#0#0#0#0#0#0#0#9#221#221#0#0#221#217#153#153#153#153 - +#153#153#153#153#153#153#221#221#0#0#221#221#221#221#221#221#221#221#221#221 - +#221#221#221#221#0#0#221#221#221#221#221#221#221#221#221#221#221#221#221#221 - +#0#0#221#221#221#221#221#221#221#221#221#221#221#221#221#221#0#0 -]); -LazarusResources.Add('TSlideBar','BMP',[ - 'BM6'#2#0#0#0#0#0#0'v'#0#0#0'('#0#0#0#28#0#0#0#28#0#0#0#1#0#4#0#0#0#0#0#192#1 - +#0#0#19#11#0#0#19#11#0#0#0#0#0#0#0#0#0#0#0#0#0#0#192#192#192#0#128#128#128#0 - +#192#192#192#0#223#223#223#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 - +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#17#17#17#17#17#17#17#17#17#17#17#17 - +#17#17#0#0#17#17#17#17#17#17#17#17#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18 - +'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17 - +#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17 - +#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18 - +'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17 - +#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#16#0#0#0#0#0#0#1#17#17#17#0 - +#0#17#17#17'$"""""" '#17#17#17#0#0#17#17#17'$333333 '#17#17#17#0#0#17#17#17 - +'$333333 '#17#17#17#0#0#17#17#17'$333333 '#17#17#17#0#0#17#17#17'$333333 '#17 - +#17#17#0#0#17#17#17'$DDDDDD@'#17#17#17#0#0#17#17#17#18'""""""!'#17#17#17#0#0 - +#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17 - +#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17 - +#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0 - +#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17 - +#17#17#17#17#0#0#17#17#17#17#17#17#18'A'#17#17#17#17#17#17#0#0#17#17#17#17#17 - +#17#17#17#17#17#17#17#17#17#0#0#17#17#17#17#17#17#17#17#17#17#17#17#17#17#0#0 -]); diff --git a/source/palette_icons.res b/source/palette_icons.res index 5f27151f21ac8252c444df865345d16f1826fd61..901c418773c1d21fea2cc041aa18ad8b73661cbb 100644 GIT binary patch delta 680 zcmb`D!AiqG5Qc{|p_kA$Eyc5y-V|y#C4z{tHK-slHCZFxa!?Foda>=)|J2U*B=3;05q_hG!gd=ca2owVRPQYce+IHQxZAbyR z14vU~U$u?dTxAbhG^LcEb146%)VmdE!ecBT;op61813TyvC-_7yxEbC^MlJcwEErn z#>oc;*P%a|#NnBAUbhCtdbUrY9&-xsL(Z~(B@q4Sz5u%byVoM-Rn_ECc~w`pForZ$ zFgYJ{yvVXV01x&sQwNR#*muKD-l|r^SYKWpW@VQ>w|A>Ho?_T}z&d-;qbV`vyb&P) zgqTF|U;ev)N09ZO60&IsTKNL~k)IK)33mn=rt}f?DivIG>6IQSJCs~5An(fsxU+Zt Nlzr&+WU+Ft`~Xv^qK*In delta 62 zcmexhd%|SHBBss%ST?b!J1{UX{Qu9y5W?WZ;Li}m;KJYvB%Oh5KcJW+gC~#%iflg5 MSt+o2j!Xy>08*C_+5i9m diff --git a/source/progress_icons.res b/source/progress_icons.res index 6b7fab1441724fa0cca92140e077c634c0229eb3..6e098b8eed2a1cce6e325f648f64a2e4e1428614 100644 GIT binary patch delta 5966 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 delta 7007 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