{*****************************************************************************} { } { Tnt Delphi Unicode Controls } { http://www.tntware.com/delphicontrols/unicode/ } { Version: 2.3.0 } { } { Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) } { } {*****************************************************************************} unit TntButtons; {$INCLUDE TntCompilers.inc} interface uses Windows, Messages, Classes, Controls, Graphics, StdCtrls, ExtCtrls, CommCtrl, Buttons, TntControls; type ITntGlyphButton = interface ['{15D7E501-1E33-4293-8B45-716FB3B14504}'] function GetButtonGlyph: Pointer; procedure UpdateInternalGlyphList; end; {TNT-WARN TSpeedButton} TTntSpeedButton = class(TSpeedButton {TNT-ALLOW TSpeedButton}, ITntGlyphButton) private FPaintInherited: Boolean; function GetCaption: TWideCaption; procedure SetCaption(const Value: TWideCaption); function GetHint: WideString; procedure SetHint(const Value: WideString); function IsCaptionStored: Boolean; function IsHintStored: Boolean; procedure CMHintShow(var Message: TMessage); message CM_HINTSHOW; procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR; protected function GetButtonGlyph: Pointer; procedure UpdateInternalGlyphList; dynamic; procedure PaintButton; dynamic; procedure Paint; override; procedure DefineProperties(Filer: TFiler); override; function GetActionLinkClass: TControlActionLinkClass; override; procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override; published property Caption: TWideCaption read GetCaption write SetCaption stored IsCaptionStored; property Hint: WideString read GetHint write SetHint stored IsHintStored; end; {TNT-WARN TBitBtn} TTntBitBtn = class(TBitBtn {TNT-ALLOW TBitBtn}, ITntGlyphButton) private FPaintInherited: Boolean; FMouseInControl: Boolean; function IsCaptionStored: Boolean; function GetCaption: TWideCaption; procedure SetCaption(const Value: TWideCaption); function IsHintStored: Boolean; function GetHint: WideString; procedure SetHint(const Value: WideString); procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR; procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER; procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE; protected function GetButtonGlyph: Pointer; procedure UpdateInternalGlyphList; dynamic; procedure DrawItem(const DrawItemStruct: TDrawItemStruct); dynamic; procedure CreateWindowHandle(const Params: TCreateParams); override; procedure DefineProperties(Filer: TFiler); override; function GetActionLinkClass: TControlActionLinkClass; override; procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override; published property Caption: TWideCaption read GetCaption write SetCaption stored IsCaptionStored; property Hint: WideString read GetHint write SetHint stored IsHintStored; end; procedure TButtonGlyph_CalcButtonLayout(Control: TControl; DC: HDC; const Client: TRect; const Offset: TPoint; const Caption: WideString; Layout: TButtonLayout; Margin, Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect; BiDiFlags: Integer {$IFDEF COMPILER_7_UP}; WordWrap: Boolean {$ENDIF}); function TButtonGlyph_Draw(Control: TControl; Canvas: TCanvas; const Client: TRect; const Offset: TPoint; const Caption: WideString; Layout: TButtonLayout; Margin: Integer; Spacing: Integer; State: TButtonState; Transparent: Boolean; BiDiFlags: Longint {$IFDEF COMPILER_7_UP}; WordWrap: Boolean {$ENDIF}): TRect; implementation uses SysUtils, ActnList, TntForms, TntStdCtrls, TypInfo, RTLConsts, TntWindows, {$IFDEF THEME_7_UP} Themes, {$ENDIF} TntClasses, TntActnList, TntSysUtils; type EAbortPaint = class(EAbort); // Many routines in this unit are nearly the same as those found in Buttons.pas. They are // included here because the VCL implementation of TButtonGlyph is completetly inaccessible. type THackButtonGlyph_D6_D7_D9 = class protected FOriginal: TBitmap; FGlyphList: TImageList; FIndexs: array[TButtonState] of Integer; FxxxxTransparentColor: TColor; FNumGlyphs: TNumGlyphs; end; THackBitBtn_D6_D7_D9 = class(TButton{TNT-ALLOW TButton}) protected FCanvas: TCanvas; FGlyph: Pointer; FxxxxStyle: TButtonStyle; FxxxxKind: TBitBtnKind; FxxxxLayout: TButtonLayout; FxxxxSpacing: Integer; FxxxxMargin: Integer; IsFocused: Boolean; end; THackSpeedButton_D6_D7_D9 = class(TGraphicControl) protected FxxxxGroupIndex: Integer; FGlyph: Pointer; FxxxxDown: Boolean; FDragging: Boolean; end; {$IFDEF COMPILER_6} // verified against VCL source in Delphi 6 and BCB 6 THackButtonGlyph = THackButtonGlyph_D6_D7_D9; THackBitBtn = THackBitBtn_D6_D7_D9; THackSpeedButton = THackSpeedButton_D6_D7_D9; {$ENDIF} {$IFDEF DELPHI_7} // verified against VCL source in Delphi 7 THackButtonGlyph = THackButtonGlyph_D6_D7_D9; THackBitBtn = THackBitBtn_D6_D7_D9; THackSpeedButton = THackSpeedButton_D6_D7_D9; {$ENDIF} {$IFDEF DELPHI_9} // verified against VCL source in Delphi 9 THackButtonGlyph = THackButtonGlyph_D6_D7_D9; THackBitBtn = THackBitBtn_D6_D7_D9; THackSpeedButton = THackSpeedButton_D6_D7_D9; {$ENDIF} {$IFDEF DELPHI_10} // verified against VCL source in Delphi 10 THackButtonGlyph = THackButtonGlyph_D6_D7_D9; THackBitBtn = THackBitBtn_D6_D7_D9; THackSpeedButton = THackSpeedButton_D6_D7_D9; {$ENDIF} function GetButtonGlyph(Control: TControl): THackButtonGlyph; var GlyphButton: ITntGlyphButton; begin if Control.GetInterface(ITntGlyphButton, GlyphButton) then Result := GlyphButton.GetButtonGlyph else raise ETntInternalError.Create('Internal Error: Control does not support ITntGlyphButton.'); end; procedure UpdateInternalGlyphList(Control: TControl); var GlyphButton: ITntGlyphButton; begin if Control.GetInterface(ITntGlyphButton, GlyphButton) then GlyphButton.UpdateInternalGlyphList else raise ETntInternalError.Create('Internal Error: Control does not support ITntGlyphButton.'); end; function TButtonGlyph_CreateButtonGlyph(Control: TControl; State: TButtonState): Integer; var ButtonGlyph: THackButtonGlyph; NumGlyphs: Integer; begin ButtonGlyph := GetButtonGlyph(Control); NumGlyphs := ButtonGlyph.FNumGlyphs; if (State = bsDown) and (NumGlyphs < 3) then State := bsUp; Result := ButtonGlyph.FIndexs[State]; if (Result = -1) then begin UpdateInternalGlyphList(Control); Result := ButtonGlyph.FIndexs[State]; end; end; procedure TButtonGlyph_DrawButtonGlyph(Control: TControl; Canvas: TCanvas; const GlyphPos: TPoint; State: TButtonState; Transparent: Boolean); var ButtonGlyph: THackButtonGlyph; Glyph: TBitmap; GlyphList: TImageList; Index: Integer; {$IFDEF THEME_7_UP} Details: TThemedElementDetails; R: TRect; Button: TThemedButton; {$ENDIF} begin ButtonGlyph := GetButtonGlyph(Control); Glyph := ButtonGlyph.FOriginal; GlyphList := ButtonGlyph.FGlyphList; if Glyph = nil then Exit; if (Glyph.Width = 0) or (Glyph.Height = 0) then Exit; Index := TButtonGlyph_CreateButtonGlyph(Control, State); with GlyphPos do {$IFDEF THEME_7_UP} if ThemeServices.ThemesEnabled then begin R.TopLeft := GlyphPos; R.Right := R.Left + Glyph.Width div ButtonGlyph.FNumGlyphs; R.Bottom := R.Top + Glyph.Height; case State of bsDisabled: Button := tbPushButtonDisabled; bsDown, bsExclusive: Button := tbPushButtonPressed; else // bsUp Button := tbPushButtonNormal; end; Details := ThemeServices.GetElementDetails(Button); ThemeServices.DrawIcon(Canvas.Handle, Details, R, GlyphList.Handle, Index); end else {$ENDIF} if Transparent or (State = bsExclusive) then ImageList_DrawEx(GlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0, clNone, clNone, ILD_Transparent) else ImageList_DrawEx(GlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0, ColorToRGB(clBtnFace), clNone, ILD_Normal); end; procedure TButtonGlyph_DrawButtonText(Canvas: TCanvas; const Caption: WideString; TextBounds: TRect; State: TButtonState; BiDiFlags: LongInt {$IFDEF COMPILER_7_UP}; WordWrap: Boolean {$ENDIF}); begin with Canvas do begin Brush.Style := bsClear; if State = bsDisabled then begin OffsetRect(TextBounds, 1, 1); Font.Color := clBtnHighlight; {$IFDEF COMPILER_7_UP} if WordWrap then Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_VCENTER or BiDiFlags or DT_WORDBREAK) else {$ENDIF} Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_VCENTER or BiDiFlags); OffsetRect(TextBounds, -1, -1); Font.Color := clBtnShadow; {$IFDEF COMPILER_7_UP} if WordWrap then Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_WORDBREAK or BiDiFlags) { TODO: Figure out why DT_VCENTER is not used } else {$ENDIF} Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_VCENTER or BiDiFlags); end else begin {$IFDEF COMPILER_7_UP} if WordWrap then Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_WORDBREAK or BiDiFlags) { TODO: Figure out why DT_VCENTER is not used } else {$ENDIF} Tnt_DrawTextW(Handle, PWideChar(Caption), Length(Caption), TextBounds, DT_CENTER or DT_VCENTER or BiDiFlags); end; end; end; procedure TButtonGlyph_CalcButtonLayout(Control: TControl; DC: HDC; const Client: TRect; const Offset: TPoint; const Caption: WideString; Layout: TButtonLayout; Margin, Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect; BiDiFlags: Integer {$IFDEF COMPILER_7_UP}; WordWrap: Boolean {$ENDIF}); var TextPos: TPoint; ClientSize, GlyphSize, TextSize: TPoint; TotalSize: TPoint; Glyph: TBitmap; NumGlyphs: Integer; ButtonGlyph: THackButtonGlyph; begin ButtonGlyph := GetButtonGlyph(Control); Glyph := ButtonGlyph.FOriginal; NumGlyphs := ButtonGlyph.FNumGlyphs; if (BiDiFlags and DT_RIGHT) = DT_RIGHT then if Layout = blGlyphLeft then Layout := blGlyphRight else if Layout = blGlyphRight then Layout := blGlyphLeft; // Calculate the item sizes. ClientSize := Point(Client.Right - Client.Left, Client.Bottom - Client.Top); if Assigned(Glyph) then GlyphSize := Point(Glyph.Width div NumGlyphs, Glyph.Height) else GlyphSize := Point(0, 0); if Length(Caption) > 0 then begin {$IFDEF COMPILER_7_UP} TextBounds := Rect(0, 0, Client.Right - Client.Left - GlyphSize.X - 3, 0); { TODO: Figure out why GlyphSize.X is in here. } {$ELSE} TextBounds := Rect(0, 0, Client.Right - Client.Left, 0); {$ENDIF} {$IFDEF COMPILER_7_UP} if WordWrap then Tnt_DrawTextW(DC, PWideChar(Caption), Length(Caption), TextBounds, DT_WORDBREAK or DT_CALCRECT or BiDiFlags) else {$ENDIF} Tnt_DrawTextW(DC, PWideChar(Caption), Length(Caption), TextBounds, DT_CALCRECT or BiDiFlags); TextSize := Point(TextBounds.Right - TextBounds.Left, TextBounds.Bottom - TextBounds.Top); end else begin TextBounds := Rect(0, 0, 0, 0); TextSize := Point(0, 0); end; // If the layout has the glyph on the right or the left, then both the text and the glyph are centered vertically. // If the glyph is on the top or the bottom, then both the text and the glyph are centered horizontally. if Layout in [blGlyphLeft, blGlyphRight] then begin GlyphPos.Y := (ClientSize.Y - GlyphSize.Y + 1) div 2; TextPos.Y := (ClientSize.Y - TextSize.Y + 1) div 2; end else begin GlyphPos.X := (ClientSize.X - GlyphSize.X + 1) div 2; TextPos.X := (ClientSize.X - TextSize.X + 1) div 2; end; // If there is no text or no bitmap, then Spacing is irrelevant. if (TextSize.X = 0) or (GlyphSize.X = 0) then Spacing := 0; // Adjust Margin and Spacing. if Margin = -1 then begin if Spacing = -1 then begin TotalSize := Point(GlyphSize.X + TextSize.X, GlyphSize.Y + TextSize.Y); if Layout in [blGlyphLeft, blGlyphRight] then Margin := (ClientSize.X - TotalSize.X) div 3 else Margin := (ClientSize.Y - TotalSize.Y) div 3; Spacing := Margin; end else begin TotalSize := Point(GlyphSize.X + Spacing + TextSize.X, GlyphSize.Y + Spacing + TextSize.Y); if Layout in [blGlyphLeft, blGlyphRight] then Margin := (ClientSize.X - TotalSize.X + 1) div 2 else Margin := (ClientSize.Y - TotalSize.Y + 1) div 2; end; end else begin if Spacing = -1 then begin TotalSize := Point(ClientSize.X - (Margin + GlyphSize.X), ClientSize.Y - (Margin + GlyphSize.Y)); if Layout in [blGlyphLeft, blGlyphRight] then Spacing := (TotalSize.X - TextSize.X) div 2 else Spacing := (TotalSize.Y - TextSize.Y) div 2; end; end; case Layout of blGlyphLeft: begin GlyphPos.X := Margin; TextPos.X := GlyphPos.X + GlyphSize.X + Spacing; end; blGlyphRight: begin GlyphPos.X := ClientSize.X - Margin - GlyphSize.X; TextPos.X := GlyphPos.X - Spacing - TextSize.X; end; blGlyphTop: begin GlyphPos.Y := Margin; TextPos.Y := GlyphPos.Y + GlyphSize.Y + Spacing; end; blGlyphBottom: begin GlyphPos.Y := ClientSize.Y - Margin - GlyphSize.Y; TextPos.Y := GlyphPos.Y - Spacing - TextSize.Y; end; end; // Fixup the Result variables. with GlyphPos do begin Inc(X, Client.Left + Offset.X); Inc(Y, Client.Top + Offset.Y); end; {$IFDEF THEME_7_UP} { Themed text is not shifted, but gets a different color. } if ThemeServices.ThemesEnabled then OffsetRect(TextBounds, TextPos.X + Client.Left, TextPos.Y + Client.Top) else {$ENDIF} OffsetRect(TextBounds, TextPos.X + Client.Left + Offset.X, TextPos.Y + Client.Top + Offset.Y); end; function TButtonGlyph_Draw(Control: TControl; Canvas: TCanvas; const Client: TRect; const Offset: TPoint; const Caption: WideString; Layout: TButtonLayout; Margin: Integer; Spacing: Integer; State: TButtonState; Transparent: Boolean; BiDiFlags: Longint {$IFDEF COMPILER_7_UP}; WordWrap: Boolean {$ENDIF}): TRect; var GlyphPos: TPoint; begin TButtonGlyph_CalcButtonLayout(Control, Canvas.Handle, Client, Offset, Caption, Layout, Margin, Spacing, GlyphPos, Result, BiDiFlags {$IFDEF COMPILER_7_UP}, WordWrap {$ENDIF}); TButtonGlyph_DrawButtonGlyph(Control, Canvas, GlyphPos, State, Transparent); TButtonGlyph_DrawButtonText(Canvas, Caption, Result, State, BiDiFlags {$IFDEF COMPILER_7_UP}, WordWrap {$ENDIF}); end; { TTntSpeedButton } procedure TTntSpeedButton.DefineProperties(Filer: TFiler); begin inherited; TntPersistent_AfterInherited_DefineProperties(Filer, Self); end; function TTntSpeedButton.IsCaptionStored: Boolean; begin Result := TntControl_IsCaptionStored(Self) end; function TTntSpeedButton.GetCaption: TWideCaption; begin Result := TntControl_GetText(Self); end; procedure TTntSpeedButton.SetCaption(const Value: TWideCaption); begin TntControl_SetText(Self, Value); end; function TTntSpeedButton.IsHintStored: Boolean; begin Result := TntControl_IsHintStored(Self) end; function TTntSpeedButton.GetHint: WideString; begin Result := TntControl_GetHint(Self) end; procedure TTntSpeedButton.SetHint(const Value: WideString); begin TntControl_SetHint(Self, Value); end; procedure TTntSpeedButton.CMHintShow(var Message: TMessage); begin ProcessCMHintShowMsg(Message); inherited; end; procedure TTntSpeedButton.CMDialogChar(var Message: TCMDialogChar); begin with Message do if IsWideCharAccel(CharCode, Caption) and Enabled and Visible and (Parent <> nil) and Parent.Showing then begin Click; Result := 1; end else inherited; end; function TTntSpeedButton.GetButtonGlyph: Pointer; begin Result := THackSpeedButton(Self).FGlyph; end; procedure TTntSpeedButton.UpdateInternalGlyphList; begin FPaintInherited := True; try Repaint; finally FPaintInherited := False; end; Invalidate; raise EAbortPaint.Create(''); end; procedure TTntSpeedButton.Paint; begin if FPaintInherited then inherited else PaintButton; end; procedure TTntSpeedButton.PaintButton; const DownStyles: array[Boolean] of Integer = (BDR_RAISEDINNER, BDR_SUNKENOUTER); FillStyles: array[Boolean] of Integer = (BF_MIDDLE, 0); var PaintRect: TRect; DrawFlags: Integer; Offset: TPoint; {$IFDEF THEME_7_UP} Button: TThemedButton; ToolButton: TThemedToolBar; Details: TThemedElementDetails; {$ENDIF} begin try if not Enabled then begin FState := bsDisabled; THackSpeedButton(Self).FDragging := False; end else if FState = bsDisabled then if Down and (GroupIndex <> 0) then FState := bsExclusive else FState := bsUp; Canvas.Font := Self.Font; {$IFDEF THEME_7_UP} if ThemeServices.ThemesEnabled then begin {$IFDEF COMPILER_7_UP} PerformEraseBackground(Self, Canvas.Handle); {$ENDIF} SelectObject(Canvas.Handle, Canvas.Font.Handle); { For some reason, PerformEraseBackground sometimes messes the font up. } if not Enabled then Button := tbPushButtonDisabled else if FState in [bsDown, bsExclusive] then Button := tbPushButtonPressed else if MouseInControl then Button := tbPushButtonHot else Button := tbPushButtonNormal; ToolButton := ttbToolbarDontCare; if Flat then begin case Button of tbPushButtonDisabled: Toolbutton := ttbButtonDisabled; tbPushButtonPressed: Toolbutton := ttbButtonPressed; tbPushButtonHot: Toolbutton := ttbButtonHot; tbPushButtonNormal: Toolbutton := ttbButtonNormal; end; end; PaintRect := ClientRect; if ToolButton = ttbToolbarDontCare then begin Details := ThemeServices.GetElementDetails(Button); ThemeServices.DrawElement(Canvas.Handle, Details, PaintRect); PaintRect := ThemeServices.ContentRect(Canvas.Handle, Details, PaintRect); end else begin Details := ThemeServices.GetElementDetails(ToolButton); ThemeServices.DrawElement(Canvas.Handle, Details, PaintRect); PaintRect := ThemeServices.ContentRect(Canvas.Handle, Details, PaintRect); end; if Button = tbPushButtonPressed then begin // A pressed speed button has a white text. This applies however only to flat buttons. if ToolButton <> ttbToolbarDontCare then Canvas.Font.Color := clHighlightText; Offset := Point(1, 0); end else Offset := Point(0, 0); TButtonGlyph_Draw(Self, Canvas, PaintRect, Offset, Caption, Layout, Margin, Spacing, FState, Transparent, DrawTextBiDiModeFlags(0) {$IFDEF COMPILER_7_UP}, False {$ENDIF}); end else {$ENDIF} begin PaintRect := Rect(0, 0, Width, Height); if not Flat then begin DrawFlags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT; if FState in [bsDown, bsExclusive] then DrawFlags := DrawFlags or DFCS_PUSHED; DrawFrameControl(Canvas.Handle, PaintRect, DFC_BUTTON, DrawFlags); end else begin if (FState in [bsDown, bsExclusive]) or (MouseInControl and (FState <> bsDisabled)) or (csDesigning in ComponentState) then DrawEdge(Canvas.Handle, PaintRect, DownStyles[FState in [bsDown, bsExclusive]], FillStyles[Transparent] or BF_RECT) else if not Transparent then begin Canvas.Brush.Color := Color; Canvas.FillRect(PaintRect); end; InflateRect(PaintRect, -1, -1); end; if FState in [bsDown, bsExclusive] then begin if (FState = bsExclusive) and (not Flat or not MouseInControl) then begin Canvas.Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight); Canvas.FillRect(PaintRect); end; Offset.X := 1; Offset.Y := 1; end else begin Offset.X := 0; Offset.Y := 0; end; TButtonGlyph_Draw(Self, Canvas, PaintRect, Offset, Caption, Layout, Margin, Spacing, FState, Transparent, DrawTextBiDiModeFlags(0) {$IFDEF COMPILER_7_UP}, False {$ENDIF}); end; except on E: EAbortPaint do ; else raise; end; end; function TTntSpeedButton.GetActionLinkClass: TControlActionLinkClass; begin Result := TntControl_GetActionLinkClass(Self, inherited GetActionLinkClass); end; {$IFDEF COMPILER_10_UP} type TAccessGraphicControl = class(TGraphicControl); {$ENDIF} procedure TTntSpeedButton.ActionChange(Sender: TObject; CheckDefaults: Boolean); {$IFDEF COMPILER_10_UP} // bug fix for VCL where ImageIndex on Action ALWAYS overrides the Glyph. type CallActionChange = procedure(Sender: TObject; CheckDefaults: Boolean) of object; var M: TMethod; {$ENDIF} begin TntControl_BeforeInherited_ActionChange(Self, Sender, CheckDefaults); {$IFNDEF COMPILER_10_UP} inherited; {$ELSE} // call TGraphicControl.ActionChange (bypass TSpeedButton.ActionChange) M.Code := @TAccessGraphicControl.ActionChange; M.Data := Self; CallActionChange(M)(Sender, CheckDefaults); // call Delphi2005's TSpeedButton.ActionChange if Sender is TCustomAction{TNT-ALLOW TCustomAction} then with TCustomAction{TNT-ALLOW TCustomAction}(Sender) do begin if CheckDefaults or (Self.GroupIndex = 0) then Self.GroupIndex := GroupIndex; { Copy image from action's imagelist } if (Glyph.Empty) and (ActionList <> nil) and (ActionList.Images <> nil) and (ImageIndex >= 0) and (ImageIndex < ActionList.Images.Count) then CopyImage(ActionList.Images, ImageIndex); end; {$ENDIF} end; { TTntBitBtn } procedure TTntBitBtn.CreateWindowHandle(const Params: TCreateParams); begin CreateUnicodeHandle(Self, Params, 'BUTTON'); end; procedure TTntBitBtn.DefineProperties(Filer: TFiler); begin inherited; TntPersistent_AfterInherited_DefineProperties(Filer, Self); end; function TTntBitBtn.IsCaptionStored: Boolean; var BaseClass: TClass; PropInfo: PPropInfo; begin Assert(Self is TButton{TNT-ALLOW TButton}); Assert(Self is TBitBtn{TNT-ALLOW TBitBtn}); if Kind = bkCustom then // don't use TBitBtn, it's broken for Kind <> bkCustom BaseClass := TButton{TNT-ALLOW TButton} else begin //TBitBtn has it's own storage specifier, based upon the button kind BaseClass := TBitBtn{TNT-ALLOW TBitBtn}; end; PropInfo := GetPropInfo(BaseClass, 'Caption'); if PropInfo = nil then raise EPropertyError.CreateResFmt(PResStringRec(@SUnknownProperty), ['Caption']); Result := IsStoredProp(Self, PropInfo); end; function TTntBitBtn.GetCaption: TWideCaption; begin Result := TntControl_GetText(Self) end; procedure TTntBitBtn.SetCaption(const Value: TWideCaption); begin TntControl_SetText(Self, Value); end; function TTntBitBtn.IsHintStored: Boolean; begin Result := TntControl_IsHintStored(Self) end; function TTntBitBtn.GetHint: WideString; begin Result := TntControl_GetHint(Self) end; procedure TTntBitBtn.SetHint(const Value: WideString); begin TntControl_SetHint(Self, Value); end; procedure TTntBitBtn.CMDialogChar(var Message: TCMDialogChar); begin TntButton_CMDialogChar(Self, Message); end; function TTntBitBtn.GetButtonGlyph: Pointer; begin Result := THackBitBtn(Self).FGlyph; end; procedure TTntBitBtn.UpdateInternalGlyphList; begin FPaintInherited := True; try Repaint; finally FPaintInherited := False; end; Invalidate; raise EAbortPaint.Create(''); end; procedure TTntBitBtn.CNDrawItem(var Message: TWMDrawItem); begin if FPaintInherited then inherited else DrawItem(Message.DrawItemStruct^); end; procedure TTntBitBtn.DrawItem(const DrawItemStruct: TDrawItemStruct); var IsDown, IsDefault: Boolean; State: TButtonState; R: TRect; Flags: Longint; FCanvas: TCanvas; IsFocused: Boolean; {$IFDEF THEME_7_UP} Details: TThemedElementDetails; Button: TThemedButton; Offset: TPoint; {$ENDIF} begin try FCanvas := THackBitBtn(Self).FCanvas; IsFocused := THackBitBtn(Self).IsFocused; FCanvas.Handle := DrawItemStruct.hDC; R := ClientRect; with DrawItemStruct do begin FCanvas.Handle := hDC; FCanvas.Font := Self.Font; IsDown := itemState and ODS_SELECTED <> 0; IsDefault := itemState and ODS_FOCUS <> 0; if not Enabled then State := bsDisabled else if IsDown then State := bsDown else State := bsUp; end; {$IFDEF THEME_7_UP} if ThemeServices.ThemesEnabled then begin if not Enabled then Button := tbPushButtonDisabled else if IsDown then Button := tbPushButtonPressed else if FMouseInControl then Button := tbPushButtonHot else if IsFocused or IsDefault then Button := tbPushButtonDefaulted else Button := tbPushButtonNormal; Details := ThemeServices.GetElementDetails(Button); // Parent background. ThemeServices.DrawParentBackground(Handle, DrawItemStruct.hDC, @Details, True); // Button shape. ThemeServices.DrawElement(DrawItemStruct.hDC, Details, DrawItemStruct.rcItem); R := ThemeServices.ContentRect(FCanvas.Handle, Details, DrawItemStruct.rcItem); if Button = tbPushButtonPressed then Offset := Point(1, 0) else Offset := Point(0, 0); TButtonGlyph_Draw(Self, FCanvas, R, Offset, Caption, Layout, Margin, Spacing, State, False, DrawTextBiDiModeFlags(0) {$IFDEF COMPILER_7_UP}, Self.WordWrap {$ENDIF}); if IsFocused and IsDefault then begin FCanvas.Pen.Color := clWindowFrame; FCanvas.Brush.Color := clBtnFace; DrawFocusRect(FCanvas.Handle, R); end; end else {$ENDIF} begin R := ClientRect; Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT; if IsDown then Flags := Flags or DFCS_PUSHED; if DrawItemStruct.itemState and ODS_DISABLED <> 0 then Flags := Flags or DFCS_INACTIVE; { DrawFrameControl doesn't allow for drawing a button as the default button, so it must be done here. } if IsFocused or IsDefault then begin FCanvas.Pen.Color := clWindowFrame; FCanvas.Pen.Width := 1; FCanvas.Brush.Style := bsClear; FCanvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom); { DrawFrameControl must draw within this border } InflateRect(R, -1, -1); end; { DrawFrameControl does not draw a pressed button correctly } if IsDown then begin FCanvas.Pen.Color := clBtnShadow; FCanvas.Pen.Width := 1; FCanvas.Brush.Color := clBtnFace; FCanvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom); InflateRect(R, -1, -1); end else DrawFrameControl(DrawItemStruct.hDC, R, DFC_BUTTON, Flags); if IsFocused then begin R := ClientRect; InflateRect(R, -1, -1); end; FCanvas.Font := Self.Font; if IsDown then OffsetRect(R, 1, 1); TButtonGlyph_Draw(Self, FCanvas, R, Point(0, 0), Caption, Layout, Margin, Spacing, State, False, DrawTextBiDiModeFlags(0) {$IFDEF COMPILER_7_UP}, Self.WordWrap {$ENDIF}); if IsFocused and IsDefault then begin R := ClientRect; InflateRect(R, -4, -4); FCanvas.Pen.Color := clWindowFrame; FCanvas.Brush.Color := clBtnFace; DrawFocusRect(FCanvas.Handle, R); end; end; FCanvas.Handle := 0; except on E: EAbortPaint do ; else raise; end; end; procedure TTntBitBtn.CMMouseEnter(var Message: TMessage); begin FMouseInControl := True; inherited; end; procedure TTntBitBtn.CMMouseLeave(var Message: TMessage); begin FMouseInControl := False; inherited; end; {$IFDEF COMPILER_10_UP} type TAccessButton = class(TButton{TNT-ALLOW TButton}); {$ENDIF} procedure TTntBitBtn.ActionChange(Sender: TObject; CheckDefaults: Boolean); {$IFDEF COMPILER_10_UP} // bug fix for VCL where ImageIndex on Action ALWAYS overrides the Glyph. type CallActionChange = procedure(Sender: TObject; CheckDefaults: Boolean) of object; var M: TMethod; {$ENDIF} begin TntControl_BeforeInherited_ActionChange(Self, Sender, CheckDefaults); {$IFNDEF COMPILER_10_UP} inherited; {$ELSE} // call TButton.ActionChange (bypass TBitBtn.ActionChange) M.Code := @TAccessButton.ActionChange; M.Data := Self; CallActionChange(M)(Sender, CheckDefaults); // call Delphi2005's TBitBtn.ActionChange if Sender is TCustomAction{TNT-ALLOW TCustomAction} then with TCustomAction{TNT-ALLOW TCustomAction}(Sender) do begin { Copy image from action's imagelist } if (Glyph.Empty) and (ActionList <> nil) and (ActionList.Images <> nil) and (ImageIndex >= 0) and (ImageIndex < ActionList.Images.Count) then CopyImage(ActionList.Images, ImageIndex); end; {$ENDIF} end; function TTntBitBtn.GetActionLinkClass: TControlActionLinkClass; begin Result := TntControl_GetActionLinkClass(Self, inherited GetActionLinkClass); end; end.