mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-31 14:16:11 +02:00
TAChart: Fix drawing of checkboxes/radiobuttons on Cocoa, part 2.
git-svn-id: trunk@62633 -
This commit is contained in:
parent
d66d8ecf94
commit
6483f57d33
@ -20,14 +20,19 @@
|
|||||||
|
|
||||||
unit TAChartListbox;
|
unit TAChartListbox;
|
||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$MODE objfpc}{$H+}
|
||||||
|
|
||||||
|
{$IFDEF DARWIN}
|
||||||
|
{$DEFINE USE_BITMAPS}
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, Controls, StdCtrls,
|
Classes, Controls, StdCtrls, Types,
|
||||||
TAChartUtils, TACustomSeries, TALegend, TAGraph;
|
TAChartUtils, TACustomSeries, TALegend, TAGraph;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TChartListbox = class;
|
TChartListbox = class;
|
||||||
|
|
||||||
@ -51,7 +56,10 @@ type
|
|||||||
TChartListbox = class(TCustomListbox)
|
TChartListbox = class(TCustomListbox)
|
||||||
private
|
private
|
||||||
FChart: TChart;
|
FChart: TChart;
|
||||||
|
FCheckBoxSize: TSize;
|
||||||
FCheckStyle: TCheckBoxesStyle;
|
FCheckStyle: TCheckBoxesStyle;
|
||||||
|
FDown: Boolean;
|
||||||
|
FHot: Boolean;
|
||||||
FLegendItems: TChartLegendItems;
|
FLegendItems: TChartLegendItems;
|
||||||
FListener: TListener;
|
FListener: TListener;
|
||||||
FOnAddSeries: TChartListboxAddSeriesEvent;
|
FOnAddSeries: TChartListboxAddSeriesEvent;
|
||||||
@ -77,8 +85,10 @@ type
|
|||||||
procedure DrawItem(
|
procedure DrawItem(
|
||||||
AIndex: Integer; ARect: TRect; AState: TOwnerDrawState); override;
|
AIndex: Integer; ARect: TRect; AState: TOwnerDrawState); override;
|
||||||
procedure KeyDown(var AKey: Word; AShift: TShiftState); override;
|
procedure KeyDown(var AKey: Word; AShift: TShiftState); override;
|
||||||
procedure MouseDown(
|
procedure MouseDown(AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
|
||||||
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
|
procedure MouseEnter; override;
|
||||||
|
procedure MouseLeave; override;
|
||||||
|
procedure MouseUp(AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
|
||||||
protected
|
protected
|
||||||
procedure CalcRects(
|
procedure CalcRects(
|
||||||
const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
|
const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
|
||||||
@ -185,11 +195,49 @@ uses
|
|||||||
Graphics, Math, LCLIntf, LCLType, SysUtils, Themes,
|
Graphics, Math, LCLIntf, LCLType, SysUtils, Themes,
|
||||||
TACustomSource, TADrawerCanvas, TADrawUtils, TAEnumerators, TAGeometry;
|
TACustomSource, TADrawerCanvas, TADrawUtils, TAEnumerators, TAGeometry;
|
||||||
|
|
||||||
procedure Register;
|
type
|
||||||
|
TThemedStatesUsed = {%H-}tbRadioButtonUnCheckedNormal..tbCheckboxCheckedDisabled;
|
||||||
|
|
||||||
|
{$IFDEF USE_BITMAPS}
|
||||||
|
var
|
||||||
|
ThemedBitmaps: Array[TThemedStatesUsed] of TBitmap;
|
||||||
|
|
||||||
|
function CreateBitmap(AThemedButton: TThemedButton; ABkColor: TColor): TBitmap;
|
||||||
|
var
|
||||||
|
s: TSize;
|
||||||
|
details: TThemedElementDetails;
|
||||||
begin
|
begin
|
||||||
RegisterComponents(CHART_COMPONENT_IDE_PAGE, [TChartListbox]);
|
Result := ThemedBitmaps[AThemedButton];
|
||||||
|
if Assigned(Result) and (Result.Canvas.Pixels[0, 0] = ABkColor) then
|
||||||
|
exit;
|
||||||
|
FreeAndNil(Result);
|
||||||
|
Result := TBitmap.Create;
|
||||||
|
details := ThemeServices.GetElementDetails(AThemedButton);
|
||||||
|
s := ThemeServices.GetDetailSize(details);
|
||||||
|
Result.SetSize(s.CX, s.CY);
|
||||||
|
Result.Canvas.Brush.Color := ABkColor;
|
||||||
|
Result.Canvas.FillRect(0, 0, Result.Width, Result.Height);
|
||||||
|
ThemeServices.DrawElement(Result.Canvas.Handle, details, Rect(0, 0, Result.Width, Result.Height));
|
||||||
|
ThemedBitmaps[AThemedButton] := Result;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure InitBitmaps;
|
||||||
|
var
|
||||||
|
tb: TThemedButton;
|
||||||
|
begin
|
||||||
|
for tb in TThemedStatesUsed do
|
||||||
|
ThemedBitmaps[tb] := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure FreeBitmaps;
|
||||||
|
var
|
||||||
|
tb: TThemedButton;
|
||||||
|
begin
|
||||||
|
for tb in TThemedStatesUsed do
|
||||||
|
FreeAndNil(ThemedBitmaps[tb]);
|
||||||
|
end;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
{ TChartListbox }
|
{ TChartListbox }
|
||||||
|
|
||||||
constructor TChartListbox.Create(AOwner: TComponent);
|
constructor TChartListbox.Create(AOwner: TComponent);
|
||||||
@ -211,17 +259,18 @@ procedure TChartListbox.CalcRects(
|
|||||||
const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
|
const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
|
||||||
{ based on the rect of a listbox item, calculates the locations of the
|
{ based on the rect of a listbox item, calculates the locations of the
|
||||||
checkbox and of the series icon }
|
checkbox and of the series icon }
|
||||||
|
const
|
||||||
|
MARGIN = 4;
|
||||||
var
|
var
|
||||||
w, x: Integer;
|
x: Integer;
|
||||||
begin
|
begin
|
||||||
ACheckBoxRect := ZeroRect;
|
ACheckBoxRect := ZeroRect;
|
||||||
ASeriesIconRect := ZeroRect;
|
ASeriesIconRect := ZeroRect;
|
||||||
|
|
||||||
w := Canvas.TextHeight('Tg');
|
x := AItemRect.Left + MARGIN;
|
||||||
x := 4;
|
|
||||||
if cloShowCheckboxes in Options then begin
|
if cloShowCheckboxes in Options then begin
|
||||||
with AItemRect do
|
ACheckBoxRect := Rect(0, 0, FCheckboxSize.CX, FCheckboxSize.CY);
|
||||||
ACheckboxRect := Bounds(Left + 4, (Top + Bottom - w) div 2, w, w);
|
OffsetRect(ACheckboxRect, x, (AItemRect.Top + AItemRect.Bottom - FCheckboxSize.CY) div 2);
|
||||||
if cloShowIcons in Options then
|
if cloShowIcons in Options then
|
||||||
x += ACheckboxRect.Right;
|
x += ACheckboxRect.Right;
|
||||||
end
|
end
|
||||||
@ -285,35 +334,67 @@ begin
|
|||||||
ClickedSeriesIcon(FSeriesIconClicked);
|
ClickedSeriesIcon(FSeriesIconClicked);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetThemedButtonOffset(Hot, Pressed, Disabled: Boolean): Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if Disabled then
|
||||||
|
Result := 3
|
||||||
|
else if Hot then
|
||||||
|
Result := 1
|
||||||
|
else if Pressed then
|
||||||
|
Result := 2;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartListbox.DrawItem(
|
procedure TChartListbox.DrawItem(
|
||||||
AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
|
AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
|
||||||
{ draws the listbox item }
|
{ draws the listbox item }
|
||||||
const
|
const
|
||||||
THEMED_FLAGS: array [TCheckboxesStyle, Boolean] of TThemedButton = (
|
THEMED_BASE: array [TCheckboxesStyle, Boolean] of TThemedButton = (
|
||||||
(tbCheckBoxUncheckedNormal, tbCheckBoxCheckedNormal),
|
(tbCheckBoxUncheckedNormal, tbCheckBoxCheckedNormal),
|
||||||
(tbRadioButtonUnCheckedNormal, tbRadioButtonCheckedNormal)
|
(tbRadioButtonUnCheckedNormal, tbRadioButtonCheckedNormal)
|
||||||
);
|
);
|
||||||
var
|
var
|
||||||
id: IChartDrawer;
|
id: IChartDrawer;
|
||||||
rcb, ricon: TRect;
|
rcb, ricon: TRect;
|
||||||
te: TThemedElementDetails;
|
|
||||||
x: Integer;
|
x: Integer;
|
||||||
ch: Boolean;
|
tb: TThemedButton;
|
||||||
|
tbBase, tbOffs: Integer;
|
||||||
|
{$IFDEF USE_BITMAPS}
|
||||||
|
bmp: TBitmap;
|
||||||
|
{$ELSE}
|
||||||
|
ted: TThemedElementDetails;
|
||||||
|
{$ENDIF}
|
||||||
begin
|
begin
|
||||||
if Assigned(OnDrawItem) then begin
|
if Assigned(OnDrawItem) then begin
|
||||||
OnDrawItem(Self, AIndex, ARect, AState);
|
OnDrawItem(Self, AIndex, ARect, AState);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (FChart = nil) or not InRange(AIndex, 0, Count - 1) then
|
if (FChart = nil) or not InRange(AIndex, 0, Count - 1) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
Canvas.FillRect(ARect);
|
Canvas.FillRect(ARect);
|
||||||
|
if cloShowCheckboxes in Options then begin
|
||||||
|
tbBase := ord(THEMED_BASE[FCheckStyle, Checked[AIndex]]);
|
||||||
|
tbOffs := GetThemedButtonOffset(FHot, FDown, false);
|
||||||
|
tb := TThemedButton(ord(tbBase) + tbOffs);
|
||||||
|
{$IFDEF USE_BITMAPS}
|
||||||
|
bmp := CreateBitmap(tb, Canvas.Brush.Color);
|
||||||
|
FCheckboxSize := Size(bmp.Width, bmp.Height);
|
||||||
|
{$ELSE}
|
||||||
|
ted := ThemeServices.GetElementDetails(tb);
|
||||||
|
FCheckboxSize := ThemeServices.GetDetailSize(ted);
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
CalcRects(ARect, rcb, ricon);
|
CalcRects(ARect, rcb, ricon);
|
||||||
|
|
||||||
if cloShowCheckboxes in Options then begin
|
if cloShowCheckboxes in Options then begin
|
||||||
ch := Checked[AIndex];
|
{$IFDEF USE_BITMAPS}
|
||||||
te := ThemeServices.GetElementDetails(THEMED_FLAGS[FCheckStyle, ch]);
|
Canvas.Draw(rcb.Left, rcb.Top, bmp);
|
||||||
ThemeServices.DrawElement(Canvas.Handle, te, rcb);
|
{$ELSE}
|
||||||
|
ThemeServices.DrawElement(Canvas.Handle, ted, rcb);
|
||||||
|
{$ENDIF}
|
||||||
x := rcb.Right;
|
x := rcb.Right;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -417,8 +498,6 @@ begin
|
|||||||
AHeight := Max(AHeight, GetSystemMetrics(SM_CYMENUCHECK) + 2);
|
AHeight := Max(AHeight, GetSystemMetrics(SM_CYMENUCHECK) + 2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TChartListbox.MouseDown(
|
|
||||||
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
|
|
||||||
{ standard MouseDown handler: checks if the click occured on the checkbox,
|
{ standard MouseDown handler: checks if the click occured on the checkbox,
|
||||||
on the series icon, or on the text.
|
on the series icon, or on the text.
|
||||||
The visibility state of the item's series is changed when clicking on the
|
The visibility state of the item's series is changed when clicking on the
|
||||||
@ -428,11 +507,14 @@ procedure TChartListbox.MouseDown(
|
|||||||
An event OnItemClick is generated when the click occured neither on the
|
An event OnItemClick is generated when the click occured neither on the
|
||||||
checkbox nor the series icon.
|
checkbox nor the series icon.
|
||||||
}
|
}
|
||||||
|
procedure TChartListbox.MouseDown(
|
||||||
|
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
|
||||||
var
|
var
|
||||||
rcb, ricon: TRect;
|
rcb, ricon: TRect;
|
||||||
index: Integer;
|
index: Integer;
|
||||||
p: TPoint;
|
p: TPoint;
|
||||||
begin
|
begin
|
||||||
|
FDown := true;
|
||||||
FSeriesIconClicked := -1;
|
FSeriesIconClicked := -1;
|
||||||
try
|
try
|
||||||
if AButton <> mbLeft then exit;
|
if AButton <> mbLeft then exit;
|
||||||
@ -452,6 +534,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChartListbox.MouseEnter;
|
||||||
|
begin
|
||||||
|
FHot := true;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartListbox.MouseLeave;
|
||||||
|
begin
|
||||||
|
FHot := false;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TChartListBox.MouseUp(
|
||||||
|
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
|
||||||
|
begin
|
||||||
|
FDown := false;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
procedure TChartListbox.Notification(AComponent: TComponent; AOperation: TOperation);
|
procedure TChartListbox.Notification(AComponent: TComponent; AOperation: TOperation);
|
||||||
begin
|
begin
|
||||||
if (AOperation = opRemove) and (AComponent = FChart) then
|
if (AOperation = opRemove) and (AComponent = FChart) then
|
||||||
@ -601,5 +701,18 @@ begin
|
|||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure Register;
|
||||||
|
begin
|
||||||
|
RegisterComponents(CHART_COMPONENT_IDE_PAGE, [TChartListbox]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$IFDEF USE_BITMAPS}
|
||||||
|
initialization
|
||||||
|
InitBitmaps;
|
||||||
|
|
||||||
|
finalization
|
||||||
|
FreeBitmaps;
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user