| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- // SPDX-License-Identifier: LGPL-3.0-linking-exception
- {******************************* CONTRIBUTOR(S) ******************************
- - Edivando S. Santos Brasil | [email protected]
- (Compatibility with delphi VCL 11/2018)
- ***************************** END CONTRIBUTOR(S) *****************************}
- unit ColorSpeedButton;
- {$I bgracontrols.inc}
- {$ifdef windows}
- {$define overridepaint}
- {$endif}
- interface
- uses
- Classes, SysUtils, Types, {$IFDEF FPC}LCLType, LCLProc, LResources,{$ENDIF}
- {$IFNDEF FPC}BGRAGraphics, GraphType, FPImage, {$ENDIF}
- Forms, Controls, Graphics, Dialogs, Buttons, BGRASpeedButton, Themes
- {$ifdef overridepaint}, Math{$ENDIF};
- type
- { TColorState }
- TColorState = class(TPersistent)
- private
- FOwner: TControl;
- FBorderColor: TColor;
- FBorderWidth: integer;
- FColor: TColor;
- procedure SetFBorderColor(AValue: TColor);
- procedure SetFBorderWidth(AValue: integer);
- procedure SetFColor(AValue: TColor);
- public
- constructor Create(AOwner: TControl);
- published
- property Color: TColor read FColor write SetFColor;
- property BorderColor: TColor read FBorderColor write SetFBorderColor;
- property BorderWidth: integer read FBorderWidth write SetFBorderWidth;
- end;
- { TColorSpeedButton }
- TColorSpeedButton = class(TBGRASpeedButton)
- private
- {$ifdef overridepaint}
- FLastDrawDetails: TThemedElementDetails;
- {$endif}
- FPopupMode: boolean;
- FPressed: boolean;
- FStateActive: TColorState;
- FStateDisabled: TColorState;
- FStateHover: TColorState;
- FStateNormal: TColorState;
- FTextAutoSize: boolean;
- FToggle: boolean;
- procedure SetFPopupMode(AValue: boolean);
- procedure SetFPressed(AValue: boolean);
- procedure SetFStateActive(AValue: TColorState);
- procedure SetFStateDisabled(AValue: TColorState);
- procedure SetFStateHover(AValue: TColorState);
- procedure SetFStateNormal(AValue: TColorState);
- procedure SetFTextAutoSize(AValue: boolean);
- procedure SetFToggle(AValue: boolean);
- protected
- {$ifdef overridepaint}
- procedure DrawText({%H-}ACanvas: TPersistent; {%H-}Details: TThemedElementDetails;
- const S: string; R: TRect; Flags, {%H-}Flags2: cardinal);
- procedure MeasureDraw(Draw: boolean; PaintRect: TRect;
- out PreferredWidth, PreferredHeight: integer);
- procedure Paint; override;
- procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
- {%H-}WithThemeSpace: boolean); override;
- {$endif}
- procedure PaintBackground(var PaintRect: TRect); {$IFDEF FPC}override;{$ENDIF}
- public
- constructor Create(TheOwner: TComponent); override;
- destructor Destroy; override;
- procedure Click; override;
- published
- property TextAutoSize: boolean read FTextAutoSize write SetFTextAutoSize;
- property Toggle: boolean read FToggle write SetFToggle;
- property Pressed: boolean read FPressed write SetFPressed;
- property PopupMode: boolean read FPopupMode write SetFPopupMode;
- property StateNormal: TColorState read FStateNormal write SetFStateNormal;
- property StateHover: TColorState read FStateHover write SetFStateHover;
- property StateActive: TColorState read FStateActive write SetFStateActive;
- property StateDisabled: TColorState read FStateDisabled write SetFStateDisabled;
- end;
- {$IFDEF FPC}procedure Register;{$ENDIF}
- implementation
- {$IFDEF FPC}
- procedure Register;
- begin
- RegisterComponents('BGRA Button Controls', [TColorSpeedButton]);
- end;
- {$ENDIF}
- { TColorSpeedButton }
- procedure TColorSpeedButton.SetFStateActive(AValue: TColorState);
- begin
- if FStateActive = AValue then
- Exit;
- FStateActive := AValue;
- Invalidate;
- end;
- procedure TColorSpeedButton.SetFPopupMode(AValue: boolean);
- begin
- if FPopupMode = AValue then
- Exit;
- FPopupMode := AValue;
- end;
- procedure TColorSpeedButton.SetFPressed(AValue: boolean);
- begin
- if FPressed = AValue then
- Exit;
- FPressed := AValue;
- Invalidate;
- end;
- procedure TColorSpeedButton.SetFStateDisabled(AValue: TColorState);
- begin
- if FStateDisabled = AValue then
- Exit;
- FStateDisabled := AValue;
- Invalidate;
- end;
- procedure TColorSpeedButton.SetFStateHover(AValue: TColorState);
- begin
- if FStateHover = AValue then
- Exit;
- FStateHover := AValue;
- Invalidate;
- end;
- procedure TColorSpeedButton.SetFStateNormal(AValue: TColorState);
- begin
- if FStateNormal = AValue then
- Exit;
- FStateNormal := AValue;
- Invalidate;
- end;
- procedure TColorSpeedButton.SetFTextAutoSize(AValue: boolean);
- begin
- if FTextAutoSize = AValue then
- Exit;
- FTextAutoSize := AValue;
- end;
- procedure TColorSpeedButton.SetFToggle(AValue: boolean);
- begin
- if FToggle = AValue then
- Exit;
- FToggle := AValue;
- Invalidate;
- end;
- {$ifdef overridepaint}
- procedure TColorSpeedButton.DrawText(ACanvas: TPersistent;
- Details: TThemedElementDetails; const S: string; R: TRect; Flags, Flags2: cardinal);
- var
- TXTStyle: TTextStyle;
- begin
- TXTStyle := Canvas.TextStyle;
- TXTStyle.Opaque := False;
- TXTStyle.Clipping := (Flags and DT_NOCLIP) = 0;
- TXTStyle.ShowPrefix := (Flags and DT_NOPREFIX) = 0;
- TXTStyle.SingleLine := (Flags and DT_SINGLELINE) <> 0;
- if (Flags and DT_CENTER) <> 0 then
- TXTStyle.Alignment := taCenter
- else
- if (Flags and DT_RIGHT) <> 0 then
- TXTStyle.Alignment := taRightJustify
- else
- TXTStyle.Alignment := taLeftJustify;
- if (Flags and DT_VCENTER) <> 0 then
- TXTStyle.Layout := tlCenter
- else
- if (Flags and DT_BOTTOM) <> 0 then
- TXTStyle.Layout := tlBottom
- else
- TXTStyle.Layout := tlTop;
- TXTStyle.RightToLeft := (Flags and DT_RTLREADING) <> 0;
- // set color here, otherwise SystemFont is wrong if the button was disabled before
- TXTStyle.SystemFont := Canvas.Font.IsDefault;//Match System Default Style
- TXTStyle.Wordbreak := (Flags and DT_WORDBREAK) <> 0;
- if not TXTStyle.Wordbreak then
- TXTStyle.EndEllipsis := (Flags and DT_END_ELLIPSIS) <> 0
- else
- TXTStyle.EndEllipsis := False;
- Canvas.TextRect(R, R.Left, R.Top, S, TXTStyle);
- end;
- procedure TColorSpeedButton.MeasureDraw(Draw: boolean; PaintRect: TRect;
- out PreferredWidth, PreferredHeight: integer);
- var
- GlyphWidth, GlyphHeight: integer;
- Offset, OffsetCap: TPoint;
- ClientSize, TotalSize, TextSize, GlyphSize: TSize;
- M, S: integer;
- SIndex: longint;
- TMP: string;
- TextFlags: integer;
- DrawDetails: TThemedElementDetails;
- FixedWidth: boolean;
- FixedHeight: boolean;
- TextRect: TRect;
- HasGlyph: boolean;
- HasText: boolean;
- CurLayout: TButtonLayout;
- begin
- if Glyph = nil then
- exit;
- DrawDetails := GetDrawDetails;
- PreferredWidth := 0;
- PreferredHeight := 0;
- if Draw then
- begin
- FLastDrawDetails := DrawDetails;
- PaintBackground(PaintRect);
- FixedWidth := True;
- FixedHeight := True;
- end
- else
- begin
- FixedWidth := WidthIsAnchored;
- FixedHeight := HeightIsAnchored;
- end;
- ClientSize.cx := PaintRect.Right - PaintRect.Left;
- ClientSize.cy := PaintRect.Bottom - PaintRect.Top;
- //debugln(['TCustomSpeedButton.MeasureDraw Step1 ',DbgSName(Self),' PaintRect=',dbgs(PaintRect)]);
- // compute size of glyph
- GlyphSize := GetGlyphSize(Draw, PaintRect);
- GlyphWidth := GlyphSize.CX;
- if NumGlyphs > 1 then
- GlyphWidth := GlyphWidth div NumGlyphs;
- GlyphHeight := GlyphSize.CY;
- HasGlyph := (GlyphWidth <> 0) and (GlyphHeight <> 0);
- //debugln(['TCustomSpeedButton.MeasureDraw Step2 ',DbgSName(Self),' PaintRect=',dbgs(PaintRect),' GlyphSize=',GlyphWidth,'x',GlyphHeight]);
- // compute size of text
- CurLayout := BidiAdjustButtonLayout(UseRightToLeftReading, Layout);
- if ShowCaption and (Caption <> '') then
- begin
- TextRect := PaintRect;
- // for wordbreak compute the maximum size for the text
- if Margin > 0 then
- InflateRect(TextRect, -Margin, -Margin);
- if HasGlyph then
- begin
- if (Spacing >= 0) then
- if CurLayout in [blGlyphLeft, blGlyphRight] then
- Dec(TextRect.Right, Spacing)
- else
- Dec(TextRect.Bottom, Spacing);
- if CurLayout in [blGlyphLeft, blGlyphRight] then
- Dec(TextRect.Right, GlyphWidth)
- else
- Dec(TextRect.Bottom, GlyphHeight);
- end;
- if not FixedWidth then
- begin
- TextRect.Left := 0;
- TextRect.Right := High(TextRect.Right) div 2;
- end;
- if not FixedHeight then
- begin
- TextRect.Top := 0;
- TextRect.Bottom := High(TextRect.Bottom) div 2;
- end;
- TextSize := GetTextSize(Draw, TextRect);
- end
- else
- begin
- TextSize.cx := 0;
- TextSize.cy := 0;
- end;
- HasText := (TextSize.cx <> 0) or (TextSize.cy <> 0);
- if Caption <> '' then
- begin
- TMP := Caption;
- SIndex := DeleteAmpersands(TMP);
- if SIndex > 0 then
- if SIndex <= Length(TMP) then
- begin
- //FShortcut := Ord(TMP[SIndex]);
- end;
- end;
- if HasGlyph and HasText then
- S := Spacing
- else
- S := 0;
- M := Margin;
- if not Draw then
- begin
- if M < 0 then
- M := 2;
- if S < 0 then
- S := M;
- end;
- // Calculate caption and glyph layout
- if M = -1 then
- begin
- // auto compute margin to center content
- if S = -1 then
- begin
- // use the same value for Spacing and Margin
- TotalSize.cx := TextSize.cx + GlyphWidth;
- TotalSize.cy := TextSize.cy + GlyphHeight;
- if Layout in [blGlyphLeft, blGlyphRight] then
- M := (ClientSize.cx - TotalSize.cx) div 3
- else
- M := (ClientSize.cy - TotalSize.cy) div 3;
- S := M;
- end
- else
- begin
- // fixed Spacing and center content
- TotalSize.cx := GlyphWidth + S + TextSize.cx;
- TotalSize.cy := GlyphHeight + S + TextSize.cy;
- if Layout in [blGlyphLeft, blGlyphRight] then
- M := (ClientSize.cx - TotalSize.cx) div 2
- else
- M := (ClientSize.cy - TotalSize.cy) div 2;
- end;
- end
- else
- begin
- // fixed Margin
- if S = -1 then
- begin
- // use the rest for Spacing between Glyph and Caption
- TotalSize.cx := ClientSize.cx - (Margin + GlyphWidth);
- TotalSize.cy := ClientSize.cy - (Margin + GlyphHeight);
- if Layout in [blGlyphLeft, blGlyphRight] then
- S := (TotalSize.cx - TextSize.cx) div 2
- else
- S := (TotalSize.cy - TextSize.cy) div 2;
- end;
- end;
- //debugln(['TCustomSpeedButton.MeasureDraw Step3 ',DbgSName(Self),' PaintRect=',dbgs(PaintRect),' GlyphSize=',GlyphWidth,'x',GlyphHeight,' TextSize=',TextSize.cx,'x',TextSize.cy,' S=',S,' M=',M]);
- if Draw then
- begin
- case CurLayout of
- blGlyphLeft:
- begin
- Offset.X := M;
- Offset.Y := (ClientSize.cy - GlyphHeight) div 2;
- OffsetCap.X := Offset.X + GlyphWidth + S;
- OffsetCap.Y := (ClientSize.cy - TextSize.cy) div 2;
- end;
- blGlyphRight:
- begin
- Offset.X := ClientSize.cx - M - GlyphWidth;
- Offset.Y := (ClientSize.cy - GlyphHeight) div 2;
- OffsetCap.X := Offset.X - S - TextSize.cx;
- OffsetCap.Y := (ClientSize.cy - TextSize.cy) div 2;
- end;
- blGlyphTop:
- begin
- Offset.X := (ClientSize.cx - GlyphWidth) div 2;
- Offset.Y := M;
- OffsetCap.X := (ClientSize.cx - TextSize.cx) div 2;
- OffsetCap.Y := Offset.Y + GlyphHeight + S;
- end;
- blGlyphBottom:
- begin
- Offset.X := (ClientSize.cx - GlyphWidth) div 2;
- Offset.Y := ClientSize.cy - M - GlyphHeight;
- OffsetCap.X := (ClientSize.cx - TextSize.cx) div 2;
- OffsetCap.Y := Offset.Y - S - TextSize.cy;
- end;
- end;
- DrawGlyph(Canvas, PaintRect, Offset, FState, Transparent, 0);
- if ShowCaption and (Caption <> '') then
- begin
- with PaintRect, OffsetCap do
- begin
- Left := Left + X;
- Top := Top + Y;
- end;
- TextFlags := DT_LEFT or DT_TOP;
- if UseRightToLeftReading then
- TextFlags := TextFlags or DT_RTLREADING;
- if Draw then
- DrawText(Canvas, DrawDetails, Caption, PaintRect,
- TextFlags, 0);
- end;
- end
- else
- begin
- // measuring, not drawing
- case CurLayout of
- blGlyphLeft, blGlyphRight:
- begin
- // use text size for autosize
- if FTextAutoSize then
- begin
- PreferredWidth := 2 * M + S + GlyphWidth + TextSize.cx;
- PreferredHeight := 2 * M + Max(GlyphHeight, TextSize.cy);
- end
- else
- begin
- // ignore text size width and height
- PreferredWidth := 2 * M + S + GlyphWidth;
- PreferredHeight := 2 * M + {Max(}GlyphHeight{, TextSize.cy)};
- end;
- end;
- blGlyphTop, blGlyphBottom:
- begin
- if FTextAutoSize then
- begin
- PreferredWidth := 2 * M + Max(GlyphWidth, TextSize.cx);
- PreferredHeight := 2 * M + S + GlyphHeight + TextSize.cy;
- end
- else
- begin
- // ignore text size width and height
- PreferredWidth := 2 * M + S + GlyphWidth;
- PreferredHeight := 2 * M + S + GlyphHeight{ + TextSize.cy};
- end;
- end;
- end;
- end;
- end;
- procedure TColorSpeedButton.Paint;
- var
- PaintRect: TRect;
- PreferredWidth: integer;
- PreferredHeight: integer;
- begin
- UpdateState(False);
- if Glyph = nil then
- exit;
- PaintRect := ClientRect;
- MeasureDraw(True, PaintRect, PreferredWidth, PreferredHeight);
- if Assigned(OnPaint) then
- OnPaint(Self);
- end;
- procedure TColorSpeedButton.CalculatePreferredSize(
- var PreferredWidth, PreferredHeight: integer; WithThemeSpace: boolean);
- var
- r: TRect;
- begin
- r := Rect(0, 0, 0, 0);
- MeasureDraw(False, r, PreferredWidth, PreferredHeight);
- end;
- {$endif}
- procedure TColorSpeedButton.PaintBackground(var PaintRect: TRect);
- var
- TempState: TButtonState;
- begin
- TempState := FState;
- if Toggle and Pressed then
- TempState := bsDown;
- Canvas.Pen.JoinStyle := pjsMiter; // remove rounded borders
- Canvas.Pen.Style := psInsideframe; // draws border width inside equally
- case TempState of
- bsUp:
- begin
- Canvas.Pen.Color := FStateNormal.BorderColor;
- Canvas.Pen.Width := FStateNormal.BorderWidth;
- Canvas.Brush.Color := FStateNormal.Color;
- end;
- bsDisabled:
- begin
- Canvas.Pen.Color := FStateDisabled.BorderColor;
- Canvas.Pen.Width := FStateDisabled.BorderWidth;
- Canvas.Brush.Color := FStateDisabled.Color;
- end;
- bsDown, bsExclusive:
- begin
- Canvas.Pen.Color := FStateActive.BorderColor;
- Canvas.Pen.Width := FStateActive.BorderWidth;
- Canvas.Brush.Color := FStateActive.Color;
- end;
- {$IFDEF FPC}//#
- bsHot:
- begin
- Canvas.Pen.Color := FStateHover.BorderColor;
- Canvas.Pen.Width := FStateHover.BorderWidth;
- Canvas.Brush.Color := FStateHover.Color;
- end;
- {$ENDIF}
- end;
- if Canvas.Pen.Width = 0 then
- Canvas.Pen.Color := Canvas.Brush.Color;
- Canvas.Rectangle(PaintRect);
- end;
- constructor TColorSpeedButton.Create(TheOwner: TComponent);
- begin
- inherited Create(TheOwner);
- FStateNormal := TColorState.Create(Self);
- FStateHover := TColorState.Create(Self);
- FStateActive := TColorState.Create(Self);
- FStateDisabled := TColorState.Create(Self);
- { Windows Style }
- FStateNormal.Color := RGBToColor(225, 225, 225);
- FStateNormal.BorderColor := RGBToColor(173, 173, 173);
- FStateHover.Color := RGBToColor(229, 241, 251);
- FStateHover.BorderColor := RGBToColor(0, 120, 215);
- FStateActive.Color := RGBToColor(204, 228, 247);
- FStateActive.BorderColor := RGBToColor(0, 84, 153);
- FStateDisabled.Color := RGBToColor(204, 204, 204);
- FStateDisabled.BorderColor := RGBToColor(191, 191, 191);
- Font.Color := clBlack;
- FTextAutoSize := True;
- end;
- destructor TColorSpeedButton.Destroy;
- begin
- FStateNormal.Free;
- FStateHover.Free;
- FStateActive.Free;
- FStateDisabled.Free;
- inherited Destroy;
- end;
- procedure TColorSpeedButton.Click;
- var
- p: TPoint;
- begin
- if Toggle then
- Pressed := not Pressed;
- if PopupMode and Assigned(PopupMenu) then
- begin
- p := Parent.ClientToScreen(Point(Left, Top));
- PopupMenu.PopUp(p.x, p.y + Height);
- end;
- inherited Click;
- end;
- { TColorState }
- procedure TColorState.SetFBorderColor(AValue: TColor);
- begin
- if FBorderColor = AValue then
- Exit;
- FBorderColor := AValue;
- FOwner.Perform(CM_CHANGED, 0, 0);
- FOwner.Invalidate;
- end;
- procedure TColorState.SetFBorderWidth(AValue: integer);
- begin
- if FBorderWidth = AValue then
- Exit;
- FBorderWidth := AValue;
- FOwner.Perform(CM_CHANGED, 0, 0);
- FOwner.Invalidate;
- end;
- procedure TColorState.SetFColor(AValue: TColor);
- begin
- if FColor = AValue then
- Exit;
- FColor := AValue;
- FOwner.Perform(CM_CHANGED, 0, 0);
- FOwner.Invalidate;
- end;
- constructor TColorState.Create(AOwner: TControl);
- begin
- inherited Create;
- FOwner := AOwner;
- BorderWidth := 1;
- BorderColor := clBlack;
- Color := clWhite;
- end;
- end.
|