git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@24 05c56307-c608-d34a-929d-697000501d7a
2678 lines
74 KiB
ObjectPascal
2678 lines
74 KiB
ObjectPascal
|
|
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ Express Cross Platform Library classes }
|
|
{ }
|
|
{ Copyright (c) 2000-2008 Developer Express Inc. }
|
|
{ ALL RIGHTS RESERVED }
|
|
{ }
|
|
{ The entire contents of this file is protected by U.S. and }
|
|
{ International Copyright Laws. Unauthorized reproduction, }
|
|
{ reverse-engineering, and distribution of all or any portion of }
|
|
{ the code contained in this file is strictly prohibited and may }
|
|
{ result in severe civil and criminal penalties and will be }
|
|
{ prosecuted to the maximum extent possible under the law. }
|
|
{ }
|
|
{ RESTRICTIONS }
|
|
{ }
|
|
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
|
|
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
|
|
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
|
|
{ LICENSED TO DISTRIBUTE THE EXPRESSCROSSPLATFORMLIBRARY AND ALL }
|
|
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM }
|
|
{ ONLY. }
|
|
{ }
|
|
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
|
|
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
|
|
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
|
|
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
|
|
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
|
|
{ }
|
|
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
|
|
{ ADDITIONAL RESTRICTIONS. }
|
|
{ }
|
|
{********************************************************************}
|
|
|
|
unit dxSkinsCore;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF DELPHI6}
|
|
Types,
|
|
{$ENDIF}
|
|
Windows, SysUtils, Classes, Graphics, Math, cxGraphics, cxGeometry, cxClasses,
|
|
cxLookAndFeels, dxGDIPlusApi, dxGDIPlusClasses, dxSkinsStrs, ActiveX, Forms;
|
|
|
|
type
|
|
TdxSkinVersion = Double;
|
|
|
|
const
|
|
dxSkinSignature = 'dxSkin';
|
|
dxSkinStreamVersion: TdxSkinVersion = 1.0;
|
|
ImageNameSuffix = '_Image.png';
|
|
GlyphNameSuffix = '_Glyph.png';
|
|
BitmapNameSuffixes: array[Boolean] of string = (GlyphNameSuffix, ImageNameSuffix);
|
|
{$IFNDEF DELPHI6}
|
|
PathDelim = '\';
|
|
{$ENDIF}
|
|
|
|
type
|
|
TdxSkin = class;
|
|
TdxSkinClass = class of TdxSkin;
|
|
TdxSkinCustomPersistentObject = class;
|
|
TdxSkinCustomPersistentObjectClass = class of TdxSkinCustomPersistentObject;
|
|
TdxSkinPersistentClass = class of TdxSkinPersistent;
|
|
TdxSkinControlGroupClass = class of TdxSkinControlGroup;
|
|
TdxSkinElementClass = class of TdxSkinElement;
|
|
TdxSkinColor = class;
|
|
TdxSkinProperty = class;
|
|
TdxSkinPropertyClass = class of TdxSkinProperty;
|
|
TdxSkinControlGroup = class;
|
|
TdxSkinImage = class;
|
|
TdxSkinElement = class;
|
|
|
|
EdxSkin = class(Exception);
|
|
|
|
IdxSkinChangeListener = interface
|
|
['{28681774-0475-43AE-8704-1C904D294742}']
|
|
procedure SkinChanged(Sender: TdxSkin);
|
|
end;
|
|
|
|
{ TdxSkinCustomPersistentObject }
|
|
|
|
TdxSkinCustomPersistentObject = class(TPersistent)
|
|
private
|
|
FName: string;
|
|
FOwner: TPersistent;
|
|
FTag: Integer;
|
|
FOnChange: TNotifyEvent;
|
|
protected
|
|
procedure DoChange; virtual;
|
|
function GetOwner: TPersistent; override;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); virtual;
|
|
function Clone: TdxSkinCustomPersistentObject; virtual;
|
|
|
|
property Tag: Integer read FTag write FTag;
|
|
published
|
|
property Name: string read FName write FName;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
end;
|
|
|
|
{ TdxSkinPersistent }
|
|
|
|
TdxSkinPersistent = class(TdxSkinCustomPersistentObject)
|
|
private
|
|
FLockCount: Integer;
|
|
FModified: Boolean;
|
|
FProperties: TcxObjectList;
|
|
FSorted: Boolean;
|
|
function GetPropertyCount: Integer;
|
|
function GetProperty(Index: Integer): TdxSkinProperty;
|
|
procedure SetSorted(AValue: Boolean);
|
|
protected
|
|
procedure AddSubItem(AInstance: TdxSkinCustomPersistentObject; AList: TcxObjectList);
|
|
procedure Changed; virtual;
|
|
procedure DoSort; virtual;
|
|
procedure SubItemHandler(Sender: TObject); virtual;
|
|
procedure ReadProperties(AStream: TStream);
|
|
procedure WriteProperties(AStream: TStream);
|
|
|
|
property LockCount: Integer read FLockCount write FLockCount;
|
|
property Sorted: Boolean read FSorted write SetSorted;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function AddProperty(const AName: string;
|
|
APropertyClass: TdxSkinPropertyClass): TdxSkinProperty;
|
|
procedure BeginUpdate;
|
|
procedure CancelUpdate;
|
|
procedure DeleteProperty(const AProperty: TdxSkinProperty); virtual;
|
|
procedure EndUpdate;
|
|
function GetPropertyByName(const AName: string): TdxSkinProperty;
|
|
procedure Sort;
|
|
|
|
property Modified: Boolean read FModified write FModified;
|
|
property PropertyCount: Integer read GetPropertyCount;
|
|
property Properties[Index: Integer]: TdxSkinProperty read GetProperty;
|
|
end;
|
|
|
|
{ TdxSkin }
|
|
|
|
TdxSkin = class(TdxSkinPersistent)
|
|
private
|
|
FColors: TcxObjectList;
|
|
FGroups: TcxObjectList;
|
|
FListeners: TInterfaceList;
|
|
FName: string;
|
|
FVersion: TdxSkinVersion;
|
|
FOnChange: TNotifyEvent;
|
|
function GetColor(Index: Integer): TdxSkinColor;
|
|
function GetColorCount: Integer;
|
|
function GetGroup(Index: Integer): TdxSkinControlGroup;
|
|
function GetGroupCount: Integer;
|
|
procedure SetName(const Value: string);
|
|
protected
|
|
procedure DoChange; override;
|
|
procedure DoSort; override;
|
|
procedure NotifyListeners;
|
|
procedure LoadFromResource(hInst: THandle);
|
|
|
|
property Listeners: TInterfaceList read FListeners;
|
|
public
|
|
constructor Create(const AName: string; ALoadOnCreate: Boolean; hInst: THandle); reintroduce; virtual;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function AddColor(const AName: string; const AColor: TColor): TdxSkinColor;
|
|
function AddGroup(const AName: string = ''): TdxSkinControlGroup;
|
|
procedure AddListener(AListener: IdxSkinChangeListener);
|
|
procedure Clear;
|
|
procedure ClearModified;
|
|
function Clone(const AName: string): TdxSkin; reintroduce; virtual;
|
|
procedure DeleteProperty(const AProperty: TdxSkinProperty); override;
|
|
function GetColorByName(const AName: string): TdxSkinColor;
|
|
function GetGroupByName(const AName: string): TdxSkinControlGroup;
|
|
procedure LoadFromStream(AStream: TStream); virtual;
|
|
procedure LoadFromFile(const AFileName: string);
|
|
procedure RemoveListener(AListener: IdxSkinChangeListener);
|
|
procedure SaveToFile(const AFileName: string);
|
|
procedure SaveToStream(AStream: TStream); virtual;
|
|
|
|
property Colors[Index: Integer]: TdxSkinColor read GetColor;
|
|
property ColorCount: Integer read GetColorCount;
|
|
property GroupCount: Integer read GetGroupCount;
|
|
property Groups[Index: Integer]: TdxSkinControlGroup read GetGroup;
|
|
published
|
|
property Name: string read FName write SetName;
|
|
property Version: TdxSkinVersion read FVersion;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
end;
|
|
|
|
{ TdxSkinProperty }
|
|
|
|
TdxSkinProperty = class(TdxSkinCustomPersistentObject)
|
|
protected
|
|
procedure ReadData(Stream: TStream); virtual;
|
|
procedure ReadFromStream(Stream: TStream); virtual;
|
|
procedure WriteData(Stream: TStream); virtual;
|
|
procedure WriteToStream(Stream: TStream); virtual;
|
|
public
|
|
class procedure Register;
|
|
class procedure Unregister;
|
|
class function Description: string; virtual;
|
|
end;
|
|
|
|
{ TdxSkinIntegerProperty }
|
|
|
|
TdxSkinIntegerProperty = class(TdxSkinProperty)
|
|
private
|
|
FValue: Integer;
|
|
procedure SetValue(AValue: Integer);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Value: Integer read FValue write SetValue default 0;
|
|
end;
|
|
|
|
{ TdxSkinBooleanProperty }
|
|
|
|
TdxSkinBooleanProperty = class(TdxSkinProperty)
|
|
private
|
|
FValue: Boolean;
|
|
procedure SetValue(AValue: Boolean);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Value: Boolean read FValue write SetValue default False;
|
|
end;
|
|
|
|
{ TdxSkinColor }
|
|
|
|
TdxSkinColor = class(TdxSkinProperty)
|
|
private
|
|
FValue: TColor;
|
|
procedure SetValue(AValue: TColor);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Value: TColor read FValue write SetValue default clDefault;
|
|
end;
|
|
|
|
{ TdxSkinRectProperty }
|
|
|
|
TdxSkinRectProperty = class(TdxSkinProperty)
|
|
private
|
|
FValue: TcxRect;
|
|
function GetValueByIndex(Index: Integer): Integer;
|
|
procedure SetValue(Value: TcxRect);
|
|
procedure SetValueByIndex(Index, Value: Integer);
|
|
procedure InternalHandler(Sender: TObject);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
|
|
property Value: TcxRect read FValue write SetValue;
|
|
published
|
|
property Left: Integer index 0 read GetValueByIndex write SetValueByIndex default 0;
|
|
property Top: Integer index 1 read GetValueByIndex write SetValueByIndex default 0;
|
|
property Right: Integer index 2 read GetValueByIndex write SetValueByIndex default 0;
|
|
property Bottom: Integer index 3 read GetValueByIndex write SetValueByIndex default 0;
|
|
end;
|
|
|
|
{ TdxSkinSizeProperty }
|
|
|
|
TdxSkinSizeProperty = class(TdxSkinProperty)
|
|
private
|
|
FValue: TSize;
|
|
procedure SetValue(const Value: TSize);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
function GetValueByIndex(Index: Integer): Integer;
|
|
procedure SetValueByIndex(Index, Value: Integer);
|
|
|
|
property Value: TSize read FValue write SetValue;
|
|
published
|
|
property cx: Integer index 0 read GetValueByIndex write SetValueByIndex default 0;
|
|
property cy: Integer index 1 read GetValueByIndex write SetValueByIndex default 0;
|
|
end;
|
|
|
|
{ TdxSkinBorder }
|
|
|
|
TdxSkinBorder = class(TdxSkinProperty)
|
|
private
|
|
FColor: TColor;
|
|
FKind: TcxBorder;
|
|
FThin: Integer;
|
|
FBrush: GpBrush;
|
|
procedure SetColor(AValue: TColor);
|
|
procedure SetThin(AValue: Integer);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
|
|
property Brush: GpBrush read FBrush;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Draw(DC: HDC; const ABounds: TRect); virtual;
|
|
procedure DrawEx(Graphics: GpGraphics; const ABounds: TRect); virtual;
|
|
|
|
property Kind: TcxBorder read FKind;
|
|
published
|
|
property Color: TColor read FColor write SetColor default clNone;
|
|
property Thin: Integer read FThin write SetThin default 1;
|
|
end;
|
|
|
|
{ TdxSkinBorders }
|
|
|
|
TdxSkinBorders = class(TdxSkinProperty)
|
|
private
|
|
FBorders: array[TcxBorder] of TdxSkinBorder;
|
|
function GetBorder(ABorder: TcxBorder): TdxSkinBorder;
|
|
function GetBorderByIndex(Index: Integer): TdxSkinBorder;
|
|
procedure SetBorderByIndex(Index: Integer; AValue: TdxSkinBorder);
|
|
protected
|
|
procedure CreateBorders;
|
|
procedure DeleteBorders;
|
|
procedure SubItemHandler(Sender: TObject); virtual;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(ASource: TPersistent); override;
|
|
|
|
property Items[AKind: TcxBorder]: TdxSkinBorder read GetBorder; default;
|
|
published
|
|
property Left: TdxSkinBorder index 0 read GetBorderByIndex write SetBorderByIndex;
|
|
property Top: TdxSkinBorder index 1 read GetBorderByIndex write SetBorderByIndex;
|
|
property Right: TdxSkinBorder index 2 read GetBorderByIndex write SetBorderByIndex;
|
|
property Bottom: TdxSkinBorder index 3 read GetBorderByIndex write SetBorderByIndex;
|
|
end;
|
|
|
|
{ TdxSkinStringProperty }
|
|
|
|
TdxSkinStringProperty = class(TdxSkinProperty)
|
|
private
|
|
FValue: string;
|
|
procedure SetValue(const AValue: string);
|
|
protected
|
|
procedure ReadData(Stream: TStream); override;
|
|
procedure WriteData(Stream: TStream); override;
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Value: string read FValue write SetValue;
|
|
end;
|
|
|
|
{ TdxSkinControlGroup }
|
|
|
|
TdxSkinControlGroup = class(TdxSkinPersistent)
|
|
private
|
|
FElements: TcxObjectList;
|
|
function GetCount: Integer;
|
|
function GetElement(AIndex: Integer): TdxSkinElement;
|
|
function GetSkin: TdxSkin;
|
|
procedure SetElement(AIndex: Integer; AElement: TdxSkinElement);
|
|
protected
|
|
procedure DoSort; override;
|
|
procedure ReadData(AStream: TStream; const AVersion: TdxSkinVersion); virtual;
|
|
procedure WriteData(AStream: TStream); virtual;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function AddElement(const AName: string): TdxSkinElement;
|
|
function AddElementEx(const AName: string; AElementClass: TdxSkinElementClass): TdxSkinElement;
|
|
procedure Clear;
|
|
procedure ClearModified;
|
|
procedure Delete(AIndex: Integer);
|
|
procedure RemoveElement(AElement: TdxSkinElement);
|
|
function GetElementByName(const AName: string): TdxSkinElement;
|
|
|
|
property Count: Integer read GetCount;
|
|
property Elements[Index: Integer]: TdxSkinElement read GetElement write SetElement;
|
|
property Skin: TdxSkin read GetSkin;
|
|
end;
|
|
|
|
{ TdxSkinImage }
|
|
|
|
TdxSkinElementState = (esNormal, esHot, esPressed, esDisabled, esActive,
|
|
esFocused, esDroppedDown, esChecked, esHotCheck, esActiveDisabled,
|
|
esCheckPressed);
|
|
|
|
TdxSkinElementStates = set of TdxSkinElementState;
|
|
|
|
TdxSkinImageLayout = (ilHorizontal, ilVertical);
|
|
TdxSkinStretchMode = (smStretch, smTile, smNoResize);
|
|
TdxSkinElementPartBounds = array[0..2, 0..2] of TRect;
|
|
TdxSkinElementPartVisibility = array[0..2, 0..2] of Boolean;
|
|
|
|
TdxSkinImage = class(TPersistent)
|
|
private
|
|
FImageLayout: TdxSkinImageLayout;
|
|
FIsDirty: Boolean;
|
|
FMargins: TcxRect;
|
|
FOnChange: TNotifyEvent;
|
|
FOwner: TdxSkinElement;
|
|
FPartSizing: TdxSkinElementPartVisibility;
|
|
FPartsVisibility: TdxSkinElementPartVisibility;
|
|
FSize: TSize;
|
|
FSourceName: string;
|
|
FStateBounds: array[TdxSkinElementState] of TRect;
|
|
FStateCount: Integer;
|
|
FStates: TdxSkinElementStates;
|
|
FStretch: TdxSkinStretchMode;
|
|
FTexture: TdxPNGImage;
|
|
FTransparentColor: TColor;
|
|
function GetEmpty: Boolean;
|
|
function GetImageCount: Integer;
|
|
function GetName: string;
|
|
function GetPartSizing(Col, Row: Integer): Boolean;
|
|
function GetPartVisible(Col, Row: Integer): Boolean;
|
|
function GetSize: TSize;
|
|
function GetSourceName: string;
|
|
function GetStateBounds(AImageIndex: Integer; AState: TdxSkinElementState): TRect;
|
|
function GetStateCount: Integer;
|
|
procedure SetImageLayout(AValue: TdxSkinImageLayout);
|
|
procedure SetMargins(AValue: TcxRect);
|
|
procedure SetName(const AValue: string);
|
|
procedure SetStates(AValue: TdxSkinElementStates);
|
|
procedure SetStretch(AValue: TdxSkinStretchMode);
|
|
procedure SetTransparentColor(AValue: TColor);
|
|
procedure SubItemHandler(Sender: TObject);
|
|
protected
|
|
procedure CheckInfo;
|
|
procedure CheckState(var AState: TdxSkinElementState);
|
|
procedure DoChange; virtual;
|
|
procedure DoInitializeInfo; virtual;
|
|
procedure Draw256(DC: HDC; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal); virtual;
|
|
procedure FillRectTile(Graphics: GpGraphics; const ADest, ASource: TRect); virtual;
|
|
function GetOwner: TPersistent; override;
|
|
procedure InitializePartsInfo(const ABounds: TRect; var AParts;
|
|
var AVisibility; ACheckMargins: Boolean);
|
|
procedure ReadData(AStream: TStream);
|
|
procedure WriteData(AStream: TStream);
|
|
|
|
property TransparentColor: TColor read FTransparentColor write SetTransparentColor;
|
|
property IsDirty: Boolean read FIsDirty write FIsDirty;
|
|
|
|
property PartSizing[Col, Row: Integer]: Boolean read GetPartSizing;
|
|
property PartVisible[Col, Row: Integer]: Boolean read GetPartVisible;
|
|
public
|
|
constructor Create(AOwner: TdxSkinElement); virtual;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Clear;
|
|
procedure Draw(DC: HDC; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal); virtual;
|
|
procedure DrawEx(Graphics: GpGraphics; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal); virtual;
|
|
procedure GetBitmap(AImageIndex: Integer; AState: TdxSkinElementState;
|
|
ABitmap: TBitmap; ABkColor: TColor = clNone);
|
|
procedure LoadFromFile(const AFileName: string);
|
|
procedure SaveToFile(const AFileName: string);
|
|
procedure SetStateMapping(AStateOrder: array of TdxSkinElementState);
|
|
|
|
property Empty: Boolean read GetEmpty;
|
|
property ImageCount: Integer read GetImageCount;
|
|
property Name: string read GetName write SetName;
|
|
property Owner: TdxSkinElement read FOwner;
|
|
property Size: TSize read GetSize;
|
|
property SourceName: string read GetSourceName;
|
|
property StateBounds[ImageIndex: Integer; State: TdxSkinElementState]: TRect read GetStateBounds;
|
|
property StateCount: Integer read GetStateCount;
|
|
property Texture: TdxPNGImage read FTexture;
|
|
published
|
|
property Margins: TcxRect read FMargins write SetMargins;
|
|
property States: TdxSkinElementStates read FStates write SetStates;
|
|
property ImageLayout: TdxSkinImageLayout read FImageLayout write SetImageLayout default ilHorizontal;
|
|
property Stretch: TdxSkinStretchMode read FStretch write SetStretch default smStretch;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
end;
|
|
|
|
{ TdxSkinElement }
|
|
|
|
TdxSkinElement = class(TdxSkinPersistent)
|
|
private
|
|
FAlpha: Byte;
|
|
FBorders: TdxSkinBorders;
|
|
FBrush: GpBrush;
|
|
FColor: TColor;
|
|
FContentOffset: TcxRect;
|
|
FGlyph: TdxSkinImage;
|
|
FImage: TdxSkinImage;
|
|
FImageCount: Integer;
|
|
FMinSize: TcxSize;
|
|
FTextColor: TColor;
|
|
function GetGroup: TdxSkinControlGroup;
|
|
function GetIsAlphaUsed: Boolean;
|
|
function GetPath: string;
|
|
function GetSize: TSize;
|
|
procedure SetAlpha(AValue: Byte);
|
|
procedure SetBorders(AValue: TdxSkinBorders);
|
|
procedure SetColor(AValue: TColor);
|
|
procedure SetContentOffset(AValue: TcxRect);
|
|
procedure SetGlyph(AValue: TdxSkinImage);
|
|
procedure SetImage(AValue: TdxSkinImage);
|
|
procedure SetImageCount(AValue: Integer);
|
|
procedure SetMinSize(AValue: TcxSize);
|
|
procedure SetTextColor(AValue: TColor);
|
|
protected
|
|
function ExpandName(ABitmap: TdxSkinImage): string; virtual;
|
|
procedure FillBackgroundByColor(AGraphics: GpGraphics; const ARect: TRect);
|
|
procedure InternalDraw(AGraphics: GpGraphics; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
procedure ReadData(AStream: TStream; AVersion: TdxSkinVersion); virtual;
|
|
procedure WriteData(AStream: TStream; AVersion: TdxSkinVersion); virtual;
|
|
property Brush: GpBrush read FBrush;
|
|
public
|
|
constructor Create(AOwner: TPersistent; const AName: string); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Draw(DC: HDC; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal); virtual;
|
|
procedure SetStateMapping(AStateOrder: array of TdxSkinElementState);
|
|
|
|
property Group: TdxSkinControlGroup read GetGroup;
|
|
property IsAlphaUsed: Boolean read GetIsAlphaUsed;
|
|
property Path: string read GetPath;
|
|
property Size: TSize read GetSize;
|
|
published
|
|
property Color: TColor read FColor write SetColor default clDefault;
|
|
property Alpha: Byte read FAlpha write SetAlpha default 255;
|
|
property Borders: TdxSkinBorders read FBorders write SetBorders;
|
|
property ContentOffset: TcxRect read FContentOffset write SetContentOffset;
|
|
property Glyph: TdxSkinImage read FGlyph write SetGlyph;
|
|
property MinSize: TcxSize read FMinSize write SetMinSize;
|
|
property TextColor: TColor read FTextColor write SetTextColor default clDefault;
|
|
property Image: TdxSkinImage read FImage write SetImage;
|
|
property ImageCount: Integer read FImageCount write SetImageCount default 1;
|
|
end;
|
|
|
|
{ TdxSkinEmptyElement }
|
|
|
|
TdxSkinEmptyElement = class(TdxSkinElement)
|
|
public
|
|
procedure Draw(DC: HDC; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal); override;
|
|
end;
|
|
|
|
{ TdxSkinPartStream }
|
|
|
|
TdxSkinPartStream = class(TStream)
|
|
private
|
|
FPosEnd: Longint;
|
|
FPosStart: Longint;
|
|
FSource: TStream;
|
|
protected
|
|
{$IFDEF DELPHI7}
|
|
function GetSize: Int64; override;
|
|
{$ENDIF}
|
|
public
|
|
constructor Create(ASource: TStream); virtual;
|
|
procedure Initialize(const APosStart, APosEnd: Longint);
|
|
procedure InitializeEx(ASource: TStream; const APosStart, APosEnd: Longint);
|
|
function Read(var Buffer; Count: Longint): Longint; override;
|
|
function Seek(Offset: Longint; Origin: Word): Longint; override;
|
|
function Write(const Buffer; Count: Longint): Longint; override;
|
|
|
|
property PosEnd: Longint read FPosEnd;
|
|
property PosStart: Longint read FPosStart;
|
|
property Source: TStream read FSource;
|
|
end;
|
|
|
|
function dxSkinRegisteredPropertyTypes: TList;
|
|
|
|
procedure dxSkinInvalidOperation(const AMessage: string);
|
|
procedure dxSkinCheck(ACondition: Boolean; const AMessage: string);
|
|
procedure dxSkinCheckVersion(AVersion: Double);
|
|
function dxSkinCheckSignature(AStream: TStream; out AVersion: TdxSkinVersion): Boolean;
|
|
function dxSkinCheckSkinElement(AElement: TdxSkinElement): TdxSkinElement;
|
|
procedure dxSkinWriteSignature(AStream: TStream);
|
|
|
|
implementation
|
|
|
|
const
|
|
PartSizing: array[0..2, 0..2] of Boolean =
|
|
((False, True, False),
|
|
(True, True, True),
|
|
(False, True, False));
|
|
|
|
var
|
|
dxSkinEmptyElement: TdxSkinElement;
|
|
PartStream: TdxSkinPartStream;
|
|
RegisteredPropertyTypes: TList;
|
|
|
|
type
|
|
TdxSkinARGBQuad = packed record
|
|
rgbRed: Byte;
|
|
rgbGreen: Byte;
|
|
rgbBlue: Byte;
|
|
Alpha: Byte;
|
|
end;
|
|
|
|
TRect2Int = array[TcxBorder] of Integer;
|
|
|
|
function ColorToARGB(AColor: TColor; Alpha: Byte = 255): Integer;
|
|
begin
|
|
with TRGBQUAD(ColorToRgb(AColor)) do
|
|
begin
|
|
TdxSkinARGBQuad(Result).Alpha := Alpha;
|
|
TdxSkinARGBQuad(Result).rgbRed := rgbRed;
|
|
TdxSkinARGBQuad(Result).rgbGreen := rgbGreen;
|
|
TdxSkinARGBQuad(Result).rgbBlue := rgbBlue;
|
|
end;
|
|
end;
|
|
|
|
function ReadStringFromStream(AStream: TStream): string;
|
|
var
|
|
L: Integer;
|
|
begin
|
|
AStream.Read(L, SizeOf(L));
|
|
SetLength(Result, L);
|
|
if L > 0 then
|
|
AStream.ReadBuffer(Result[1], L);
|
|
end;
|
|
|
|
function ReadInteger(AStream: TStream): Integer;
|
|
begin
|
|
AStream.Read(Result, SizeOf(Result));
|
|
end;
|
|
|
|
procedure WriteStringToStream(AStream: TStream; const AValue: string);
|
|
var
|
|
L: Integer;
|
|
begin
|
|
L := Length(AValue);
|
|
AStream.Write(L, SizeOf(L));
|
|
if L > 0 then
|
|
AStream.WriteBuffer(AValue[1], L);
|
|
end;
|
|
|
|
procedure WriteInteger(AStream: TStream; const AValue: Integer);
|
|
begin
|
|
AStream.Write(AValue, SizeOf(AValue));
|
|
end;
|
|
|
|
function dxSkinRegisteredPropertyTypes: TList;
|
|
begin
|
|
Result := RegisteredPropertyTypes;
|
|
end;
|
|
|
|
procedure dxSkinInvalidOperation(const AMessage: string);
|
|
begin
|
|
raise EdxSkin.Create(AMessage);
|
|
end;
|
|
|
|
procedure dxSkinCheck(ACondition: Boolean; const AMessage: string);
|
|
begin
|
|
if not ACondition then
|
|
dxSkinInvalidOperation(AMessage);
|
|
end;
|
|
|
|
procedure dxSkinCheckVersion(AVersion: Double);
|
|
begin
|
|
if AVersion < 1 then
|
|
raise EdxSkin.Create(sdxOldFormat);
|
|
end;
|
|
|
|
function dxSkinCheckSignature(AStream: TStream; out AVersion: TdxSkinVersion): Boolean;
|
|
var
|
|
ASignature: string;
|
|
begin
|
|
ASignature := ReadStringFromStream(AStream);
|
|
Result := SameText(ASignature, dxSkinSignature);
|
|
if Result then
|
|
AStream.ReadBuffer(AVersion, SizeOf(AVersion));
|
|
end;
|
|
|
|
function dxSkinCheckSkinElement(AElement: TdxSkinElement): TdxSkinElement;
|
|
begin
|
|
Result := AElement;
|
|
if Result = nil then
|
|
Result := dxSkinEmptyElement;
|
|
end;
|
|
|
|
procedure dxSkinWriteSignature(AStream: TStream);
|
|
begin
|
|
WriteStringToStream(AStream, dxSkinSignature);
|
|
AStream.Write(dxSkinStreamVersion, SizeOf(dxSkinStreamVersion));
|
|
end;
|
|
|
|
function dxCompareByName(AItem1, AItem2: TdxSkinCustomPersistentObject): Integer;
|
|
begin
|
|
Result := AnsiCompareStr(AItem1.Name, AItem2.Name);
|
|
end;
|
|
|
|
function FindItemByName(AItemsList: TcxObjectList; const AName: string): TObject;
|
|
var
|
|
L, H, AIndex, C: Integer;
|
|
begin
|
|
Result := nil;
|
|
L := 0;
|
|
H := AItemsList.Count - 1;
|
|
while L <= H do
|
|
begin
|
|
AIndex := (L + H) div 2;
|
|
C := AnsiCompareStr(TdxSkinCustomPersistentObject(AItemsList[AIndex]).Name, AName);
|
|
if C < 0 then
|
|
L := AIndex + 1
|
|
else
|
|
begin
|
|
H := AIndex - 1;
|
|
if C = 0 then
|
|
begin
|
|
Result := TdxSkinCustomPersistentObject(AItemsList[AIndex]);
|
|
Break;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinPersistent }
|
|
|
|
constructor TdxSkinPersistent.Create(
|
|
AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FProperties := TcxObjectList.Create;
|
|
end;
|
|
|
|
destructor TdxSkinPersistent.Destroy;
|
|
begin
|
|
FProperties.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.Assign(Source: TPersistent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if Source is TdxSkinPersistent then
|
|
begin
|
|
for I := 0 to TdxSkinPersistent(Source).PropertyCount - 1 do
|
|
AddSubItem(TdxSkinPersistent(Source).Properties[I].Clone, FProperties);
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkinPersistent.AddProperty(
|
|
const AName: string; APropertyClass: TdxSkinPropertyClass): TdxSkinProperty;
|
|
begin
|
|
Result := APropertyClass.Create(Self, AName);
|
|
AddSubItem(Result, FProperties);
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.BeginUpdate;
|
|
begin
|
|
Inc(FLockCount);
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.CancelUpdate;
|
|
begin
|
|
Dec(FLockCount);
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.DeleteProperty(const AProperty: TdxSkinProperty);
|
|
begin
|
|
if FProperties.Remove(AProperty) <> -1 then
|
|
begin
|
|
AProperty.Free;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.EndUpdate;
|
|
begin
|
|
Dec(FLockCount);
|
|
if FLockCount = 0 then
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.Sort;
|
|
begin
|
|
SetSorted(True);
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.AddSubItem(
|
|
AInstance: TdxSkinCustomPersistentObject; AList: TcxObjectList);
|
|
begin
|
|
AInstance.FOwner := Self;
|
|
AInstance.OnChange := SubItemHandler;
|
|
AList.Add(AInstance);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.Changed;
|
|
begin
|
|
Modified := True;
|
|
FSorted := False;
|
|
if LockCount = 0 then
|
|
DoChange;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.DoSort;
|
|
begin
|
|
FProperties.Sort(TListSortCompare(@dxCompareByName));
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.SubItemHandler(Sender: TObject);
|
|
begin
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.ReadProperties(AStream: TStream);
|
|
var
|
|
I: Integer;
|
|
APropClass: TdxSkinPropertyClass;
|
|
begin
|
|
for I := 0 to ReadInteger(AStream) - 1 do
|
|
begin
|
|
APropClass := TdxSkinPropertyClass(FindClass(ReadStringFromStream(AStream)));
|
|
AddProperty(ReadStringFromStream(AStream), APropClass).ReadData(AStream);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.WriteProperties(AStream: TStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
WriteInteger(AStream, PropertyCount);
|
|
for I := 0 to PropertyCount -1 do
|
|
Properties[I].WriteToStream(AStream);
|
|
end;
|
|
|
|
function TdxSkinPersistent.GetPropertyByName(const AName: string): TdxSkinProperty;
|
|
begin
|
|
Sort;
|
|
Result := TdxSkinProperty(FindItemByName(FProperties, AName));
|
|
end;
|
|
|
|
function TdxSkinPersistent.GetPropertyCount: Integer;
|
|
begin
|
|
Result := FProperties.Count;
|
|
end;
|
|
|
|
function TdxSkinPersistent.GetProperty(Index: Integer): TdxSkinProperty;
|
|
begin
|
|
Result := FProperties[Index] as TdxSkinProperty;
|
|
end;
|
|
|
|
procedure TdxSkinPersistent.SetSorted(AValue: Boolean);
|
|
begin
|
|
if AValue <> FSorted then
|
|
begin
|
|
FSorted := AValue;
|
|
if AValue then
|
|
DoSort;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkin }
|
|
|
|
constructor TdxSkin.Create(const AName: string;
|
|
ALoadOnCreate: Boolean; hInst: THandle);
|
|
begin
|
|
inherited Create(nil, AName);
|
|
FListeners := TInterfaceList.Create;
|
|
FColors := TcxObjectList.Create;
|
|
FGroups := TcxObjectList.Create;
|
|
FVersion := dxSkinStreamVersion;
|
|
FName := AName;
|
|
if ALoadOnCreate then
|
|
LoadFromResource(hInst);
|
|
end;
|
|
|
|
destructor TdxSkin.Destroy;
|
|
begin
|
|
FListeners.Free;
|
|
FColors.Free;
|
|
FGroups.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkin.ClearModified;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FModified := False;
|
|
for I := 0 to GroupCount - 1 do
|
|
Groups[I].ClearModified;
|
|
end;
|
|
|
|
function TdxSkin.Clone(const AName: string): TdxSkin;
|
|
var
|
|
AClass: TdxSkinClass;
|
|
begin
|
|
AClass := TdxSkinClass(ClassType);
|
|
Result := AClass.Create(Name, False, 0);
|
|
Result.Assign(Self);
|
|
end;
|
|
|
|
procedure TdxSkin.Assign(Source: TPersistent);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if Source is TdxSkin then
|
|
begin
|
|
// clone colors
|
|
for I := 0 to TdxSkin(Source).ColorCount - 1 do
|
|
AddSubItem(TdxSkin(Source).Colors[I].Clone, FColors);
|
|
for I := 0 to TdxSkin(Source).GroupCount - 1 do
|
|
AddSubItem(TdxSkin(Source).Groups[I].Clone, FGroups);
|
|
end;
|
|
inherited Assign(Source);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkin.AddColor(
|
|
const AName: string; const AColor: TColor): TdxSkinColor;
|
|
begin
|
|
Result := TdxSkinColor.Create(Self, AName);
|
|
BeginUpdate;
|
|
try
|
|
AddSubItem(Result, FColors);
|
|
Result.Value := AColor;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkin.AddGroup(const AName: string): TdxSkinControlGroup;
|
|
begin
|
|
Result := TdxSkinControlGroup.Create(Self, AName);
|
|
AddSubItem(Result, FGroups);
|
|
end;
|
|
|
|
procedure TdxSkin.AddListener(AListener: IdxSkinChangeListener);
|
|
begin
|
|
Listeners.Add(AListener);
|
|
end;
|
|
|
|
procedure TdxSkin.Clear;
|
|
begin
|
|
FGroups.Clear;
|
|
FColors.Clear;
|
|
FProperties.Clear;
|
|
end;
|
|
|
|
function TdxSkin.GetColorByName(const AName: string): TdxSkinColor;
|
|
begin
|
|
Sort;
|
|
Result := TdxSkinColor(FindItemByName(FColors, AName));
|
|
end;
|
|
|
|
procedure TdxSkin.DeleteProperty(const AProperty: TdxSkinProperty);
|
|
begin
|
|
inherited DeleteProperty(AProperty);
|
|
if FColors.Remove(AProperty) <> -1 then
|
|
begin
|
|
AProperty.Free;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkin.GetGroupByName(const AName: string): TdxSkinControlGroup;
|
|
begin
|
|
Sort;
|
|
Result := TdxSkinControlGroup(FindItemByName(FGroups, AName));
|
|
end;
|
|
|
|
procedure TdxSkin.LoadFromStream(AStream: TStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not CheckGdiPlus then Exit;
|
|
if not dxSkinCheckSignature(AStream, FVersion) then
|
|
raise EdxSkin.Create(sdxSkinInvalidStreamFormat);
|
|
FName := ReadStringFromStream(AStream);
|
|
dxSkinCheckVersion(FVersion);
|
|
BeginUpdate;
|
|
try
|
|
Clear;
|
|
for I := 0 to ReadInteger(AStream) - 1 do
|
|
begin
|
|
if FVersion >= 0.92 then
|
|
ReadStringFromStream(AStream);
|
|
AddColor(ReadStringFromStream(AStream), ReadInteger(AStream));
|
|
end;
|
|
ReadProperties(AStream);
|
|
for I := 0 to ReadInteger(AStream) - 1 do
|
|
AddGroup(ReadStringFromStream(AStream)).ReadData(AStream, Version);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkin.LoadFromFile(const AFileName: string);
|
|
var
|
|
AStream: TStream;
|
|
begin
|
|
AStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
|
try
|
|
LoadFromStream(AStream);
|
|
finally
|
|
AStream.Free
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkin.RemoveListener(AListener: IdxSkinChangeListener);
|
|
begin
|
|
Listeners.Remove(AListener);
|
|
end;
|
|
|
|
procedure TdxSkin.SaveToFile(const AFileName: string);
|
|
var
|
|
AStream: TStream;
|
|
begin
|
|
AStream := TFileStream.Create(AFileName, fmCreate);
|
|
try
|
|
SaveToStream(AStream);
|
|
finally
|
|
AStream.Free
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkin.SaveToStream(AStream: TStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
dxSkinWriteSignature(AStream);
|
|
WriteStringToStream(AStream, Name);
|
|
WriteInteger(AStream, ColorCount);
|
|
for I := 0 to ColorCount - 1 do
|
|
Colors[I].WriteToStream(AStream);
|
|
WriteProperties(AStream);
|
|
WriteInteger(AStream, GroupCount);
|
|
for I := 0 to GroupCount - 1 do
|
|
Groups[I].WriteData(AStream);
|
|
end;
|
|
|
|
procedure TdxSkin.DoChange;
|
|
begin
|
|
NotifyListeners;
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
procedure TdxSkin.DoSort;
|
|
begin
|
|
inherited DoSort;
|
|
FGroups.Sort(TListSortCompare(@dxCompareByName));
|
|
FColors.Sort(TListSortCompare(@dxCompareByName));
|
|
end;
|
|
|
|
procedure TdxSkin.NotifyListeners;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Inc(FLockCount);
|
|
try
|
|
for I := 0 to Listeners.Count - 1 do
|
|
IdxSkinChangeListener(Listeners[I]).SkinChanged(Self);
|
|
finally
|
|
Dec(FLockCount);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkin.LoadFromResource(hInst: THandle);
|
|
var
|
|
AStream: TStream;
|
|
begin
|
|
AStream := TResourceStream.Create(hInst, Name, PChar(sdxResourceType));
|
|
try
|
|
LoadFromStream(AStream);
|
|
finally
|
|
AStream.Free;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkin.GetColor(Index: Integer): TdxSkinColor;
|
|
begin
|
|
Result := FColors[Index] as TdxSkinColor;
|
|
end;
|
|
|
|
function TdxSkin.GetColorCount: Integer;
|
|
begin
|
|
Result := FColors.Count;
|
|
end;
|
|
|
|
function TdxSkin.GetGroup(Index: Integer): TdxSkinControlGroup;
|
|
begin
|
|
Result := FGroups[Index] as TdxSkinControlGroup;
|
|
end;
|
|
|
|
function TdxSkin.GetGroupCount: Integer;
|
|
begin
|
|
Result := FGroups.Count;
|
|
end;
|
|
|
|
procedure TdxSkin.SetName(const Value: string);
|
|
begin
|
|
FName := Value;
|
|
end;
|
|
|
|
{ TdxSkinImage }
|
|
|
|
constructor TdxSkinImage.Create(AOwner: TdxSkinElement);
|
|
begin
|
|
FOwner := AOwner;
|
|
FTexture := TdxPNGImage.Create();
|
|
FMargins := TcxRect.Create(Self);
|
|
FMargins.OnChange := SubItemHandler;
|
|
FTransparentColor := clNone;
|
|
end;
|
|
|
|
destructor TdxSkinImage.Destroy;
|
|
begin
|
|
FMargins.Free;
|
|
FTexture.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinImage.Assign(Source: TPersistent);
|
|
begin
|
|
if not (Source is TdxSkinImage) then Exit;
|
|
if TdxSkinImage(Source).Empty then
|
|
Clear
|
|
else
|
|
begin
|
|
Texture.Assign(TdxSkinImage(Source).Texture);
|
|
FSourceName := TdxSkinImage(Source).SourceName;
|
|
FIsDirty := True;
|
|
end;
|
|
ImageLayout := TdxSkinImage(Source).ImageLayout;
|
|
States := TdxSkinImage(Source).States;
|
|
Stretch := TdxSkinImage(Source).Stretch;
|
|
FMargins.Assign(TdxSkinImage(Source).Margins);
|
|
end;
|
|
|
|
procedure TdxSkinImage.Clear;
|
|
begin
|
|
Texture.Handle := nil;
|
|
FSourceName := '';
|
|
DoChange;
|
|
end;
|
|
|
|
procedure TdxSkinImage.GetBitmap(AImageIndex: Integer;
|
|
AState: TdxSkinElementState; ABitmap: TBitmap; ABkColor: TColor = clNone);
|
|
begin
|
|
ABitmap.FreeImage;
|
|
ABitmap.Width := Size.cx;
|
|
ABitmap.Height := Size.cy;
|
|
if ABkColor <> clNone then
|
|
begin
|
|
if ABkColor <> clDefault then
|
|
ABitmap.Canvas.Brush.Color := ABkColor;
|
|
ABitmap.Canvas.FillRect(Rect(0, 0, Size.cx, Size.cy));
|
|
end;
|
|
Draw(ABitmap.Canvas.Handle, Rect(0, 0, Size.cx, Size.cy), AImageIndex, AState);
|
|
end;
|
|
|
|
procedure TdxSkinImage.LoadFromFile(const AFileName: string);
|
|
var
|
|
AFile : TFileStream;
|
|
begin
|
|
FSourceName := AFileName;
|
|
AFile := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
|
|
try
|
|
Texture.LoadFromStream(AFile);
|
|
finally
|
|
AFile.Free;
|
|
end;
|
|
DoChange;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SaveToFile(const AFileName: string);
|
|
begin
|
|
if Empty then Exit;
|
|
Texture.SaveToFile(ChangeFileExt(AFileName, '.png'));
|
|
DoChange;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetStateMapping(AStateOrder: array of TdxSkinElementState);
|
|
var
|
|
ASrc: TRect;
|
|
ASize: TSize;
|
|
ABitmap: TBitmap;
|
|
AIndex, AImageIndex: Integer;
|
|
begin
|
|
if Texture.Empty then Exit;
|
|
ABitmap := Texture.GetAsBitmap;
|
|
try
|
|
ASize := Size;
|
|
ASrc := Rect(0, 0, ASize.cx, ASize.cy);
|
|
if ImageLayout = ilHorizontal then
|
|
ASize.cy := 0
|
|
else
|
|
ASize.cx := 0;
|
|
for AImageIndex := 0 to ImageCount - 1 do
|
|
for AIndex := Low(AStateOrder) to High(AStateOrder) do
|
|
begin
|
|
if not (AStateOrder[AIndex] in States) then Continue;
|
|
Texture.StretchDraw(ABitmap.Canvas.Handle,
|
|
StateBounds[AImageIndex, AStateOrder[AIndex]], ASrc);
|
|
OffsetRect(ASrc, ASize.cx, ASize.cy);
|
|
end;
|
|
Texture.SetBitmap(ABitmap);
|
|
finally
|
|
ABitmap.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.Draw(DC: HDC; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
var
|
|
Graphics: GpGraphics;
|
|
begin
|
|
CheckInfo;
|
|
if (FSize.cx <= 0) or (FSize.cy <= 0) or IsRectEmpty(ARect) or not RectVisible(DC, ARect) then Exit;
|
|
if GetDeviceCaps(DC, BITSPIXEL) <= 8 then
|
|
Draw256(DC, ARect, AImageIndex, AState)
|
|
else
|
|
begin
|
|
GdipCreateFromHDC(DC, Graphics);
|
|
DrawEx(Graphics, ARect, AImageIndex, AState);
|
|
GdipDeleteGraphics(Graphics);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.Draw256(DC: HDC; const ARect: TRect; AImageIndex: Integer = 0;
|
|
AState: TdxSkinElementState = esNormal);
|
|
var
|
|
ACanvas: TCanvas;
|
|
AGraphics: GpGraphics;
|
|
ATempBuffer: TBitmap;
|
|
R: TRect;
|
|
begin
|
|
ATempBuffer := TBitmap.Create;
|
|
try
|
|
ATempBuffer.PixelFormat := pf32bit;
|
|
ATempBuffer.Width := ARect.Right - ARect.Left;
|
|
ATempBuffer.Height := ARect.Bottom - ARect.Top;
|
|
|
|
with ARect do
|
|
BitBlt(ATempBuffer.Canvas.Handle, Left, Top, Right - Left, Bottom - Top,
|
|
DC, Left, Top, SRCCOPY);
|
|
|
|
R := ARect;
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
GdipCreateFromHDC(ATempBuffer.Canvas.Handle, AGraphics);
|
|
DrawEx(AGraphics, R, AImageIndex, AState);
|
|
GdipDeleteGraphics(AGraphics);
|
|
|
|
ACanvas := TCanvas.Create;
|
|
try
|
|
ACanvas.Handle := DC;
|
|
ACanvas.Draw(ARect.Left, ARect.Top, ATempBuffer);
|
|
ACanvas.Handle := 0;
|
|
finally
|
|
ACanvas.Free;
|
|
end;
|
|
finally
|
|
ATempBuffer.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.DrawEx(Graphics: GpGraphics; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
var
|
|
ACol, ARow: Integer;
|
|
AVisibility: TdxSkinElementPartVisibility;
|
|
DestParts, SourceParts: TdxSkinElementPartBounds;
|
|
begin
|
|
CheckInfo;
|
|
CheckState(AState);
|
|
if Stretch = smNoResize then
|
|
Texture.DrawEx(Graphics, cxRectCenter(ARect, Size), StateBounds[AImageIndex, AState])
|
|
else
|
|
begin
|
|
FillChar(AVisibility, SizeOf(AVisibility), 1);
|
|
InitializePartsInfo(StateBounds[AImageIndex, AState], SourceParts, AVisibility, False);
|
|
InitializePartsInfo(ARect, DestParts, AVisibility, Stretch = smStretch);
|
|
for ARow := 0 to 2 do
|
|
for ACol := 0 to 2 do
|
|
begin
|
|
if not AVisibility[ACol, ARow] then Continue;
|
|
if not FPartSizing[ACol, ARow] then
|
|
Texture.DrawEx(Graphics, DestParts[ACol, ARow], SourceParts[ACol, ARow])
|
|
else
|
|
if Stretch = smTile then
|
|
FillRectTile(Graphics, DestParts[ACol, ARow], SourceParts[ACol, ARow])
|
|
else
|
|
Texture.StretchDrawEx(Graphics, DestParts[ACol, ARow], SourceParts[ACol, ARow]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.CheckInfo;
|
|
begin
|
|
if not IsDirty then Exit;
|
|
IsDirty := False;
|
|
DoInitializeInfo;
|
|
end;
|
|
|
|
procedure TdxSkinImage.CheckState(var AState: TdxSkinElementState);
|
|
var
|
|
AFirstState: TdxSkinElementState;
|
|
begin
|
|
if not (AState in FStates) then
|
|
for AFirstState := Low(TdxSKinElementState) to High(TdxSKinElementState) do
|
|
if AFirstState in FStates then
|
|
begin
|
|
AState := AFirstState;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.DoChange;
|
|
begin
|
|
IsDirty := True;
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
procedure TdxSkinImage.DoInitializeInfo;
|
|
var
|
|
AState: TdxSkinElementState;
|
|
AParts: TdxSkinElementPartBounds;
|
|
AStateIndices: array[TdxSkinElementState] of Byte;
|
|
begin
|
|
FStateCount := 0;
|
|
FillChar(AStateIndices, SizeOf(AStateIndices), 0);
|
|
for AState := Low(TdxSkinElementState) to High(TdxSkinElementState) do
|
|
if AState in States then
|
|
begin
|
|
AStateIndices[AState] := FStateCount;
|
|
Inc(FStateCount);
|
|
end;
|
|
FSize := cxSize(Texture.Width, Texture.Height);
|
|
if StateCount > 0 then
|
|
begin
|
|
if ImageLayout = ilHorizontal then
|
|
FSize.cx := FSize.cx div ImageCount div StateCount
|
|
else
|
|
FSize.cy := FSize.cy div ImageCount div StateCount;
|
|
end;
|
|
for AState := Low(TdxSkinElementState) to High(TdxSkinElementState) do
|
|
begin
|
|
if ImageLayout = ilHorizontal then
|
|
FStateBounds[AState] := Rect(AStateIndices[AState] * FSize.cx,
|
|
0, (AStateIndices[AState] + 1) * FSize.cx, FSize.cy)
|
|
else
|
|
FStateBounds[AState] := Rect(0, AStateIndices[AState] * FSize.cy,
|
|
FSize.cx, (AStateIndices[AState] + 1) * FSize.cy)
|
|
end;
|
|
InitializePartsInfo(Rect(0, 0, FSize.cx, FSize.cy), AParts, FPartsVisibility, False);
|
|
end;
|
|
|
|
procedure TdxSkinImage.FillRectTile(
|
|
Graphics: GpGraphics; const ADest, ASource: TRect);
|
|
var
|
|
RDest, RSrc: TRect;
|
|
ALastCol, ALastRow, ACol, ARow: Integer;
|
|
ASize: TSize;
|
|
begin
|
|
ASize := cxSize(cxRectWidth(ASource), cxRectHeight(ASource));
|
|
ALastCol := cxRectWidth(ADest) div ASize.cx -
|
|
Ord(cxRectWidth(ADest) mod ASize.cx = 0);
|
|
ALastRow := cxRectHeight(ADest) div ASize.cy -
|
|
Ord(cxRectHeight(ADest) mod ASize.cy = 0);
|
|
for ARow := 0 to ALastRow do
|
|
begin
|
|
RSrc.Top := ASource.Top;
|
|
RSrc.Bottom := ASource.Bottom;
|
|
RDest.Top := ADest.Top + ASize.cy * ARow;
|
|
RDest.Bottom := RDest.Top + ASize.cy;
|
|
if RDest.Bottom > ADest.Bottom then
|
|
begin
|
|
Dec(RSrc.Bottom, RDest.Bottom - ADest.Bottom);
|
|
RDest.Bottom := ADest.Bottom;
|
|
end;
|
|
for ACol := 0 to ALastCol do
|
|
begin
|
|
RSrc.Left := ASource.Left;
|
|
RSrc.Right := ASource.Right;
|
|
RDest.Left := ADest.Left + ASize.cx * ACol;
|
|
RDest.Right := RDest.Left + ASize.cx;
|
|
if RDest.Right > ADest.Right then
|
|
begin
|
|
Dec(RSrc.Right, RDest.Right - ADest.Right);
|
|
RDest.Right := ADest.Right;
|
|
end;
|
|
Texture.DrawEx(Graphics, RDest, RSrc);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkinImage.GetOwner: TPersistent;
|
|
begin
|
|
Result := FOwner;
|
|
end;
|
|
|
|
procedure TdxSkinImage.InitializePartsInfo(const ABounds: TRect;
|
|
var AParts; var AVisibility; ACheckMargins: Boolean);
|
|
|
|
procedure MakePart(const ALeft, ATop, ARight, ABottom: Integer;
|
|
var ARect: TRect; var AVisible: Boolean);
|
|
begin
|
|
if not AVisible then Exit;
|
|
ARect.Left := ALeft;
|
|
ARect.Top := ATop;
|
|
ARect.Right := ARight;
|
|
ARect.Bottom := ABottom;
|
|
AVisible := (ALeft < ARight) and (ATop < ABottom);
|
|
end;
|
|
|
|
var
|
|
I, ADelta, ASize: Integer;
|
|
AMargins, R: TRect;
|
|
begin
|
|
AMargins := Margins.Rect;
|
|
// stretch margins
|
|
Move(dxSkinsCore.PartSizing, FPartSizing, SizeOf(FPartSizing));
|
|
if ACheckMargins then
|
|
begin
|
|
ASize := AMargins.Left + AMargins.Right;
|
|
ADelta := ASize - cxRectWidth(ABounds);
|
|
if ADelta > 0 then
|
|
begin
|
|
for I := 0 to 2 do
|
|
begin
|
|
FPartSizing[0, I] := True;
|
|
FPartSizing[2, I] := True;
|
|
end;
|
|
Dec(AMargins.Left, MulDiv(AMargins.Left, ADelta, ASize));
|
|
Dec(AMargins.Right, MulDiv(AMargins.Right, ADelta, ASize));
|
|
end;
|
|
ASize := AMargins.Top + AMargins.Bottom;
|
|
ADelta := ASize - cxRectHeight(ABounds);
|
|
if ADelta > 0 then
|
|
begin
|
|
Dec(AMargins.Top, MulDiv(AMargins.Top, ADelta, ASize));
|
|
Dec(AMargins.Bottom, MulDiv(AMargins.Bottom, ADelta, ASize));
|
|
for I := 0 to 2 do
|
|
begin
|
|
FPartSizing[I, 0] := True;
|
|
FPartSizing[I, 2] := True;
|
|
end;
|
|
end;
|
|
end;
|
|
//
|
|
with AMargins do
|
|
begin
|
|
R := cxRect(ABounds.Left + Left, ABounds.Top + Top,
|
|
ABounds.Right - Right, ABounds.Bottom - Bottom);
|
|
// check horizontal bounds
|
|
if R.Left > ABounds.Right then
|
|
R.Left := ABounds.Right;
|
|
if R.Left > R.Right then
|
|
R.Right := R.Left;
|
|
if R.Right > ABounds.Right then
|
|
R.Right := ABounds.Right;
|
|
// check vertical bounds
|
|
if R.Top > ABounds.Bottom then
|
|
R.Top := ABounds.Bottom;
|
|
if R.Top > R.Bottom then
|
|
R.Bottom := R.Top;
|
|
if R.Bottom > ABounds.Bottom then
|
|
R.Bottom := ABounds.Bottom;
|
|
end;
|
|
// top line
|
|
MakePart(ABounds.Left, ABounds.Top, R.Left, R.Top,
|
|
TdxSkinElementPartBounds(AParts)[0, 0],
|
|
TdxSkinElementPartVisibility(AVisibility)[0, 0]);
|
|
MakePart(R.Left, ABounds.Top, R.Right, R.Top,
|
|
TdxSkinElementPartBounds(AParts)[1, 0],
|
|
TdxSkinElementPartVisibility(AVisibility)[1, 0]);
|
|
MakePart(R.Right, ABounds.Top, ABounds.Right, R.
|
|
Top, TdxSkinElementPartBounds(AParts)[2, 0],
|
|
TdxSkinElementPartVisibility(AVisibility)[2, 0]);
|
|
// middle line
|
|
MakePart(ABounds.Left, R.Top, R.Left, R.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[0, 1],
|
|
TdxSkinElementPartVisibility(AVisibility)[0, 1]);
|
|
MakePart(R.Left, R.Top, R.Right, R.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[1, 1],
|
|
TdxSkinElementPartVisibility(AVisibility)[1, 1]);
|
|
MakePart(R.Right, R.Top, ABounds.Right, R.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[2, 1],
|
|
TdxSkinElementPartVisibility(AVisibility)[2, 1]);
|
|
// bottom line
|
|
MakePart(ABounds.Left, R.Bottom, R.Left, ABounds.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[0, 2],
|
|
TdxSkinElementPartVisibility(AVisibility)[0, 2]);
|
|
MakePart(R.Left, R.Bottom, R.Right, ABounds.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[1, 2],
|
|
TdxSkinElementPartVisibility(AVisibility)[1, 2]);
|
|
MakePart(R.Right, R.Bottom, ABounds.Right, ABounds.Bottom,
|
|
TdxSkinElementPartBounds(AParts)[2, 2],
|
|
TdxSkinElementPartVisibility(AVisibility)[2, 2]);
|
|
end;
|
|
|
|
function TdxSkinImage.GetEmpty: Boolean;
|
|
begin
|
|
Result := (FSourceName = '') and Texture.Empty;
|
|
end;
|
|
|
|
function TdxSkinImage.GetImageCount: Integer;
|
|
begin
|
|
Result := Owner.ImageCount;
|
|
end;
|
|
|
|
function TdxSkinImage.GetName: string;
|
|
begin
|
|
if not Empty then
|
|
Result := Owner.ExpandName(Self)
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TdxSkinImage.GetPartSizing(Col, Row: Integer): Boolean;
|
|
begin
|
|
Result := FPartSizing[Col, Row];
|
|
end;
|
|
|
|
function TdxSkinImage.GetPartVisible(Col, Row: Integer): Boolean;
|
|
begin
|
|
Result := FPartsVisibility[Col, Row];
|
|
end;
|
|
|
|
function TdxSkinImage.GetSize: TSize;
|
|
begin
|
|
CheckInfo;
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TdxSkinImage.GetSourceName: string;
|
|
begin
|
|
Result := FSourceName;
|
|
if (Result = '') and not Empty then
|
|
Result := Owner.Path + Name;
|
|
end;
|
|
|
|
function TdxSkinImage.GetStateBounds(
|
|
AImageIndex: Integer; AState: TdxSkinElementState): TRect;
|
|
begin
|
|
CheckInfo;
|
|
Result := FStateBounds[AState];
|
|
if AImageIndex > 0 then
|
|
begin
|
|
if ImageLayout = ilHorizontal then
|
|
OffsetRect(Result, StateCount * AImageIndex * Size.cx, 0)
|
|
else
|
|
OffsetRect(Result, 0, StateCount * AImageIndex * Size.cy)
|
|
end;
|
|
end;
|
|
|
|
function TdxSkinImage.GetStateCount: Integer;
|
|
begin
|
|
CheckInfo;
|
|
Result := FStateCount;
|
|
end;
|
|
|
|
procedure TdxSkinImage.ReadData(AStream: TStream);
|
|
var
|
|
APos, ASize: Integer;
|
|
begin
|
|
AStream.Read(FMargins.Data^, SizeOf(TRect));
|
|
AStream.Read(FImageLayout, SizeOf(TdxSkinImageLayout));
|
|
AStream.Read(FStates, SizeOf(TdxSkinElementStates));
|
|
AStream.Read(FStretch, SizeOf(FStretch));
|
|
AStream.Read(ASize, SizeOf(Integer));
|
|
APos := AStream.Position;
|
|
if ASize > 0 then
|
|
begin
|
|
PartStream.InitializeEx(AStream, AStream.Position, AStream.Position + ASize);
|
|
Texture.LoadFromStream(PartStream);
|
|
end;
|
|
AStream.Position := APos + ASize;
|
|
IsDirty := True;
|
|
end;
|
|
|
|
procedure TdxSkinImage.WriteData(AStream: TStream);
|
|
var
|
|
ASize: Integer;
|
|
APNGStream: TMemoryStream;
|
|
begin
|
|
AStream.Write(Margins.Data^, SizeOf(TRect));
|
|
AStream.Write(FImageLayout, SizeOf(TdxSkinImageLayout));
|
|
AStream.Write(FStates, SizeOf(TdxSkinElementStates));
|
|
AStream.Write(FStretch, SizeOf(FStretch));
|
|
APNGStream := TMemoryStream.Create;
|
|
try
|
|
if not Empty then
|
|
Texture.SaveToStream(APNGStream);
|
|
ASize := APNGStream.Size;
|
|
AStream.Write(ASize, SizeOf(Integer));
|
|
if ASize > 0 then
|
|
begin
|
|
APNGStream.Position := 0;
|
|
AStream.Write(APNGStream.Memory^, APNGStream.Size);
|
|
end;
|
|
finally
|
|
APNGStream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetImageLayout(AValue: TdxSkinImageLayout);
|
|
begin
|
|
if ImageLayout <> AValue then
|
|
begin
|
|
FImageLayout := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetMargins(AValue: TcxRect);
|
|
begin
|
|
FMargins.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetStates(AValue: TdxSkinElementStates);
|
|
begin
|
|
if FStates <> AValue then
|
|
begin
|
|
FStates := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetStretch(AValue: TdxSkinStretchMode);
|
|
begin
|
|
if Stretch <> AValue then
|
|
begin
|
|
FStretch := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetTransparentColor(AValue: TColor);
|
|
begin
|
|
if AValue <> TransparentColor then
|
|
begin
|
|
FTransparentColor := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinImage.SetName(const AValue: string);
|
|
begin
|
|
LoadFromFile(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinImage.SubItemHandler(Sender: TObject);
|
|
begin
|
|
DoChange;
|
|
end;
|
|
|
|
{ TdxSkinCustomPersistentObject }
|
|
|
|
constructor TdxSkinCustomPersistentObject.Create(
|
|
AOwner: TPersistent; const AName: string);
|
|
begin
|
|
FName := AName;
|
|
FOwner := AOwner;
|
|
end;
|
|
|
|
function TdxSkinCustomPersistentObject.Clone: TdxSkinCustomPersistentObject;
|
|
var
|
|
AClass: TdxSkinCustomPersistentObjectClass;
|
|
begin
|
|
AClass := TdxSkinCustomPersistentObjectClass(ClassType);
|
|
Result := AClass.Create(nil, Name);
|
|
Result.Assign(Self);
|
|
end;
|
|
|
|
procedure TdxSkinCustomPersistentObject.DoChange;
|
|
begin
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
function TdxSkinCustomPersistentObject.GetOwner: TPersistent;
|
|
begin
|
|
Result := FOwner;
|
|
end;
|
|
|
|
{ TdxSkinProperty }
|
|
|
|
class procedure TdxSkinProperty.Register;
|
|
begin
|
|
RegisteredPropertyTypes.Add(Self);
|
|
RegisterClass(Self);
|
|
end;
|
|
|
|
class procedure TdxSkinProperty.Unregister;
|
|
begin
|
|
UnRegisterClass(Self);
|
|
RegisteredPropertyTypes.Remove(Self);
|
|
end;
|
|
|
|
class function TdxSkinProperty.Description: string;
|
|
begin
|
|
Result := StringReplace(ClassName,
|
|
'TdxSkin', '', [rfReplaceAll, rfIgnoreCase]);
|
|
Result := StringReplace(Result, 'Property', '', [rfReplaceAll, rfIgnoreCase]);
|
|
end;
|
|
|
|
procedure TdxSkinProperty.ReadData(Stream: TStream);
|
|
begin
|
|
end;
|
|
|
|
procedure TdxSkinProperty.ReadFromStream(Stream: TStream);
|
|
begin
|
|
Name := ReadStringFromStream(Stream);
|
|
ReadData(Stream);
|
|
end;
|
|
|
|
procedure TdxSkinProperty.WriteData(Stream: TStream);
|
|
begin
|
|
end;
|
|
|
|
procedure TdxSkinProperty.WriteToStream(Stream: TStream);
|
|
begin
|
|
WriteStringToStream(Stream, ClassName);
|
|
WriteStringToStream(Stream, Name);
|
|
WriteData(Stream);
|
|
end;
|
|
|
|
{ TdxSkinIntegerProperty }
|
|
|
|
procedure TdxSkinIntegerProperty.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinIntegerProperty then
|
|
Value := TdxSkinIntegerProperty(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinIntegerProperty.ReadData(Stream: TStream);
|
|
begin
|
|
Stream.ReadBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinIntegerProperty.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinIntegerProperty.SetValue(AValue: Integer);
|
|
begin
|
|
if AValue <> FValue then
|
|
begin
|
|
FValue := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinBooleanProperty }
|
|
|
|
procedure TdxSkinBooleanProperty.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinBooleanProperty then
|
|
Value := TdxSkinBooleanProperty(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinBooleanProperty.ReadData(Stream: TStream);
|
|
begin
|
|
Stream.ReadBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinBooleanProperty.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinBooleanProperty.SetValue(AValue: Boolean);
|
|
begin
|
|
if AValue <> FValue then
|
|
begin
|
|
FValue := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinColor }
|
|
|
|
constructor TdxSkinColor.Create(AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FValue := clDefault;
|
|
end;
|
|
|
|
procedure TdxSkinColor.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinColor then
|
|
Value := TdxSkinColor(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinColor.ReadData(Stream: TStream);
|
|
begin
|
|
Stream.ReadBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinColor.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinColor.SetValue(AValue: TColor);
|
|
begin
|
|
if AValue <> FValue then
|
|
begin
|
|
FValue := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinRectProperty }
|
|
|
|
constructor TdxSkinRectProperty.Create(AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FValue := TcxRect.Create(Self);
|
|
FValue.OnChange := InternalHandler;
|
|
end;
|
|
|
|
destructor TdxSkinRectProperty.Destroy;
|
|
begin
|
|
FValue.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinRectProperty then
|
|
Value := TdxSkinRectProperty(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.ReadData(Stream: TStream);
|
|
var
|
|
ARect: TRect;
|
|
begin
|
|
Stream.ReadBuffer(ARect, SizeOf(TRect));
|
|
FValue.Rect := ARect;
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FValue.Rect, SizeOf(TRect));
|
|
end;
|
|
|
|
function TdxSkinRectProperty.GetValueByIndex(Index: Integer): Integer;
|
|
begin
|
|
Result := FValue.GetValue(Index);
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.SetValue(Value: TcxRect);
|
|
begin
|
|
FValue.Assign(Value);
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.SetValueByIndex(Index, Value: Integer);
|
|
begin
|
|
FValue.SetValue(Index, Value);
|
|
end;
|
|
|
|
procedure TdxSkinRectProperty.InternalHandler(Sender: TObject);
|
|
begin
|
|
DoChange;
|
|
end;
|
|
|
|
{ TdxSkinSizeProperty }
|
|
|
|
procedure TdxSkinSizeProperty.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinSizeProperty then
|
|
Value := TdxSkinSizeProperty(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
function TdxSkinSizeProperty.GetValueByIndex(Index: Integer): Integer;
|
|
begin
|
|
if Index = 0 then
|
|
Result := FValue.cx
|
|
else
|
|
Result := FValue.cy
|
|
end;
|
|
|
|
procedure TdxSkinSizeProperty.SetValueByIndex(Index, Value: Integer);
|
|
var
|
|
AValue: TSize;
|
|
begin
|
|
AValue := FValue;
|
|
if Index = 0 then
|
|
AValue.cx := Value
|
|
else
|
|
AValue.cy := Value;
|
|
SetValue(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinSizeProperty.ReadData(Stream: TStream);
|
|
begin
|
|
Stream.ReadBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinSizeProperty.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FValue, SizeOf(FValue));
|
|
end;
|
|
|
|
procedure TdxSkinSizeProperty.SetValue(const Value: TSize);
|
|
begin
|
|
if (Value.cx <> FValue.cx) or (Value.cy <> FValue.cy) then
|
|
begin
|
|
FValue := Value;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinBorder }
|
|
|
|
constructor TdxSkinBorder.Create(AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FColor := clNone;
|
|
FThin := 1;
|
|
end;
|
|
|
|
destructor TdxSkinBorder.Destroy;
|
|
begin
|
|
if FBrush <> nil then
|
|
GdipDeleteBrush(FBrush);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinBorder.Assign(Source: TPersistent);
|
|
var
|
|
ASource: TdxSkinBorder;
|
|
begin
|
|
if not (Source is TdxSkinBorder) then Exit;
|
|
ASource := TdxSkinBorder(Source);
|
|
Color := ASource.Color;
|
|
FKind := ASource.Kind;
|
|
Thin := ASource.Thin;
|
|
end;
|
|
|
|
procedure TdxSkinBorder.Draw(DC: HDC; const ABounds: TRect);
|
|
var
|
|
Graphics: GpGraphics;
|
|
begin
|
|
if Color = clNone then Exit;
|
|
GdipCheck(GdipCreateFromHDC(DC, Graphics));
|
|
DrawEx(Graphics, ABounds);
|
|
GdipCheck(GdipDeleteGraphics(Graphics));
|
|
end;
|
|
|
|
procedure TdxSkinBorder.DrawEx(Graphics: GpGraphics; const ABounds: TRect);
|
|
begin
|
|
if (Color = clNone) or (Brush = nil) then Exit;
|
|
with ABounds do
|
|
begin
|
|
case Kind of
|
|
bLeft:
|
|
GdipFillRectangleI(Graphics, Brush, Left, Top, Thin, Bottom - Top);
|
|
bTop:
|
|
GdipFillRectangleI(Graphics, Brush, Left, Top, Right - Left, Thin);
|
|
bRight:
|
|
GdipFillRectangleI(Graphics, Brush, Right - Thin, Top, Thin, Bottom - Top);
|
|
bBottom:
|
|
GdipFillRectangleI(Graphics, Brush, Left, Bottom - Thin, Right - Left, Thin);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinBorder.ReadData(Stream: TStream);
|
|
var
|
|
AColor: TColor;
|
|
begin
|
|
Stream.Read(AColor, SizeOf(FColor));
|
|
Stream.Read(FThin, SizeOf(FThin));
|
|
Color := AColor;
|
|
end;
|
|
|
|
procedure TdxSkinBorder.WriteData(Stream: TStream);
|
|
begin
|
|
Stream.Write(FColor, SizeOf(FColor));
|
|
Stream.Write(FThin, SizeOf(FThin));
|
|
end;
|
|
|
|
procedure TdxSkinBorder.SetColor(AValue: TColor);
|
|
begin
|
|
if AValue <> FColor then
|
|
begin
|
|
FColor := AValue;
|
|
if Color <> clDefault then
|
|
begin
|
|
if FBrush <> nil then
|
|
GdipSetSolidFillColor(FBrush, ColorToARGB(AValue, 255))
|
|
else
|
|
GdipCreateSolidFill(ColorToARGB(Color, 255), FBrush);
|
|
end;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinBorder.SetThin(AValue: Integer);
|
|
begin
|
|
if AValue <> FThin then
|
|
begin
|
|
FThin := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinBorders }
|
|
|
|
constructor TdxSkinBorders.Create(AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
CreateBorders;
|
|
end;
|
|
|
|
destructor TdxSkinBorders.Destroy;
|
|
begin
|
|
DeleteBorders;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinBorders.Assign(ASource: TPersistent);
|
|
var
|
|
ABorder: TcxBorder;
|
|
begin
|
|
if ASource is TdxSkinBorders then
|
|
begin
|
|
for ABorder := Low(TcxBorder) to High(TcxBorder) do
|
|
FBorders[ABorder].Assign(TdxSkinBorders(ASource).FBorders[ABorder])
|
|
end
|
|
else
|
|
inherited Assign(ASource);
|
|
end;
|
|
|
|
procedure TdxSkinBorders.CreateBorders;
|
|
var
|
|
ASide: TcxBorder;
|
|
const
|
|
BorderNames: array[TcxBorder] of string =
|
|
(sdxLeft, sdxTop, sdxRight, sdxBottom);
|
|
begin
|
|
for ASide := bLeft to bBottom do
|
|
begin
|
|
FBorders[ASide] := TdxSkinBorder.Create(Self, BorderNames[ASide]);
|
|
FBorders[ASide].FKind := ASide;
|
|
FBorders[ASide].OnChange := SubItemHandler;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinBorders.DeleteBorders;
|
|
var
|
|
ASide: TcxBorder;
|
|
begin
|
|
for ASide := bLeft to bBottom do
|
|
FBorders[ASide].Free;
|
|
end;
|
|
|
|
procedure TdxSkinBorders.SubItemHandler(Sender: TObject);
|
|
begin
|
|
DoChange;
|
|
end;
|
|
|
|
function TdxSkinBorders.GetBorder(ABorder: TcxBorder): TdxSkinBorder;
|
|
begin
|
|
Result := FBorders[ABorder];
|
|
end;
|
|
|
|
function TdxSkinBorders.GetBorderByIndex(Index: Integer): TdxSkinBorder;
|
|
begin
|
|
Result := FBorders[TcxBorder(Index)];
|
|
end;
|
|
|
|
procedure TdxSkinBorders.SetBorderByIndex(Index: Integer; AValue: TdxSkinBorder);
|
|
begin
|
|
FBorders[TcxBorder(Index)].Assign(AValue);
|
|
end;
|
|
|
|
{ TdxSkinStringProperty }
|
|
|
|
procedure TdxSkinStringProperty.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxSkinStringProperty then
|
|
Value := TdxSkinStringProperty(Source).Value
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinStringProperty.ReadData(Stream: TStream);
|
|
begin
|
|
Value := ReadStringFromStream(Stream);
|
|
end;
|
|
|
|
procedure TdxSkinStringProperty.WriteData(Stream: TStream);
|
|
begin
|
|
WriteStringToStream(Stream, Value);
|
|
end;
|
|
|
|
procedure TdxSkinStringProperty.SetValue(const AValue: string);
|
|
begin
|
|
if AValue <> FValue then
|
|
begin
|
|
FValue := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
{ TdxSkinControlGroup }
|
|
|
|
constructor TdxSkinControlGroup.Create(
|
|
AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FElements := TcxObjectList.Create;
|
|
end;
|
|
|
|
destructor TdxSkinControlGroup.Destroy;
|
|
begin
|
|
FElements.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.Assign(Source: TPersistent);
|
|
var
|
|
I: Integer;
|
|
ASource: TdxSkinControlGroup;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if Source is TdxSkinControlGroup then
|
|
begin
|
|
ASource := TdxSkinControlGroup(Source);
|
|
for I := 0 to ASource.Count - 1 do
|
|
AddSubItem(ASource.Elements[I].Clone, FElements);
|
|
end;
|
|
inherited Assign(Source);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkinControlGroup.AddElement(const AName: string): TdxSkinElement;
|
|
begin
|
|
Result := AddElementEx(AName, TdxSkinElement);
|
|
end;
|
|
|
|
function TdxSkinControlGroup.AddElementEx(
|
|
const AName: string; AElementClass: TdxSkinElementClass): TdxSkinElement;
|
|
begin
|
|
Result := AElementClass.Create(Self, AName);
|
|
AddSubItem(Result, FElements);
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.Clear;
|
|
begin
|
|
FElements.Clear;
|
|
FProperties.Clear;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.ClearModified;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FModified := False;
|
|
for I := 0 to Count - 1 do
|
|
Elements[I].Modified := False;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.Delete(AIndex: Integer);
|
|
begin
|
|
FElements[AIndex].Free;
|
|
FElements.Delete(AIndex);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.RemoveElement(AElement: TdxSkinElement);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
if AElement = Elements[I] then
|
|
begin
|
|
Delete(I);
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TdxSkinControlGroup.GetElementByName(
|
|
const AName: string): TdxSkinElement;
|
|
begin
|
|
Sort;
|
|
Result := TdxSkinElement(FindItemByName(FElements, AName));
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.DoSort;
|
|
begin
|
|
inherited DoSort;
|
|
FElements.Sort(TListSortCompare(@dxCompareByName));
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.ReadData(
|
|
AStream: TStream; const AVersion: TdxSkinVersion);
|
|
var
|
|
AIndex: Integer;
|
|
begin
|
|
for AIndex := 0 to ReadInteger(AStream) - 1 do
|
|
AddElement(ReadStringFromStream(AStream)).ReadData(AStream, AVersion);
|
|
if AVersion < 0.91 then Exit;
|
|
ReadProperties(AStream);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.WriteData(AStream: TStream);
|
|
var
|
|
AIndex: Integer;
|
|
AElement: TdxSkinElement;
|
|
begin
|
|
WriteStringToStream(AStream, Name);
|
|
WriteInteger(AStream, Count);
|
|
for AIndex := 0 to Count - 1 do
|
|
begin
|
|
AElement := Elements[AIndex];
|
|
WriteStringToStream(AStream, AElement.Name);
|
|
AElement.WriteData(AStream, dxSkinStreamVersion);
|
|
end;
|
|
WriteProperties(AStream);
|
|
end;
|
|
|
|
function TdxSkinControlGroup.GetCount: Integer;
|
|
begin
|
|
Result := FElements.Count;
|
|
end;
|
|
|
|
function TdxSkinControlGroup.GetElement(AIndex: Integer): TdxSkinElement;
|
|
begin
|
|
Result := FElements[AIndex] as TdxSkinElement;
|
|
end;
|
|
|
|
function TdxSkinControlGroup.GetSkin: TdxSkin;
|
|
begin
|
|
Result := GetOwner as TdxSkin;
|
|
end;
|
|
|
|
procedure TdxSkinControlGroup.SetElement(AIndex: Integer; AElement: TdxSkinElement);
|
|
begin
|
|
Elements[AIndex].Assign(AElement);
|
|
end;
|
|
|
|
{ TdxSkinElement }
|
|
|
|
constructor TdxSkinElement.Create(
|
|
AOwner: TPersistent; const AName: string);
|
|
begin
|
|
inherited Create(AOwner, AName);
|
|
FColor := clDefault;
|
|
FImageCount := 1;
|
|
FImage := TdxSkinImage.Create(Self);
|
|
FImage.OnChange := SubItemHandler;
|
|
FContentOffset := TcxRect.Create(Self);
|
|
FContentOffset.OnChange := SubItemHandler;
|
|
FGlyph := TdxSkinImage.Create(Self);
|
|
FGlyph.OnChange := SubItemHandler;
|
|
FAlpha := 255;
|
|
FBorders := TdxSkinBorders.Create(Self, sdxBorders);
|
|
FBorders.OnChange := SubItemHandler;
|
|
FTextColor := clDefault;
|
|
FMinSize := TcxSize.Create(Self);
|
|
FMinSize.OnChange := SubItemHandler;
|
|
end;
|
|
|
|
destructor TdxSkinElement.Destroy;
|
|
begin
|
|
FMinSize.Free;
|
|
FContentOffset.Free;
|
|
FImage.Free;
|
|
FGlyph.Free;
|
|
FBorders.Free;
|
|
if FBrush <> nil then
|
|
GdipDeleteBrush(FBrush);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxSkinElement.Assign(Source: TPersistent);
|
|
var
|
|
ASource: TdxSkinElement;
|
|
begin
|
|
if Source is TdxSkinElement then
|
|
begin
|
|
ASource := TdxSkinElement(Source);
|
|
Image.Assign(ASource.Image);
|
|
Glyph.Assign(ASource.Glyph);
|
|
Color := ASource.Color;
|
|
Alpha := ASource.Alpha;
|
|
ContentOffset.Assign(ASource.ContentOffset);
|
|
ImageCount := ASource.ImageCount;
|
|
Borders := ASource.Borders;
|
|
MinSize.Assign(ASource.MinSize);
|
|
TextColor := ASource.TextColor;
|
|
end;
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxSkinElement.Draw(DC: HDC; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
var
|
|
Graphics: GpGraphics;
|
|
|
|
procedure Draw256;
|
|
var
|
|
ACanvas: TCanvas;
|
|
ASaveIndex: Integer;
|
|
ATemp: TBitmap;
|
|
R: TRect;
|
|
begin
|
|
ATemp := TBitmap.Create;
|
|
ATemp.Width := ARect.Right - ARect.Left;
|
|
ATemp.Height := ARect.Bottom - ARect.Top;
|
|
try
|
|
ATemp.PixelFormat := pf32bit;
|
|
with ARect do
|
|
BitBlt(ATemp.Canvas.Handle, 0, 0, Right - Left, Bottom - Top,
|
|
DC, Left, Top, SRCCOPY);
|
|
|
|
R := ARect;
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
GdipCreateFromHDC(ATemp.Canvas.Handle, Graphics);
|
|
InternalDraw(Graphics, R, AImageIndex, AState);
|
|
GdipDeleteGraphics(Graphics);
|
|
|
|
ACanvas := TCanvas.Create;
|
|
try
|
|
ASaveIndex := SaveDC(DC);
|
|
ACanvas.Handle := DC;
|
|
ACanvas.Draw(ARect.Left, ARect.Top, ATemp);
|
|
ACanvas.Handle := 0;
|
|
RestoreDC(DC, ASaveIndex);
|
|
finally
|
|
ACanvas.Free;
|
|
end;
|
|
finally
|
|
ATemp.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if not RectVisible(DC, ARect) or cxRectIsEmpty(ARect) then Exit;
|
|
|
|
if GetDeviceCaps(DC, BITSPIXEL) <= 8 then
|
|
Draw256
|
|
else
|
|
begin
|
|
GdipCreateFromHDC(DC, Graphics);
|
|
InternalDraw(Graphics, ARect, AImageIndex, AState);
|
|
GdipDeleteGraphics(Graphics);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetStateMapping(AStateOrder: array of TdxSkinElementState);
|
|
begin
|
|
FImage.SetStateMapping(AStateOrder);
|
|
FGlyph.SetStateMapping(AStateOrder);
|
|
end;
|
|
|
|
function TdxSkinElement.ExpandName(ABitmap: TdxSkinImage): string;
|
|
begin
|
|
Result := Name + BitmapNameSuffixes[ABitmap = Image]
|
|
end;
|
|
|
|
procedure TdxSkinElement.FillBackgroundByColor(AGraphics: GpGraphics;
|
|
const ARect: TRect);
|
|
begin
|
|
if (Color <> clDefault) and (Color <> clNone) and not cxRectIsEmpty(ARect) then
|
|
if Image.Empty or (Image.Stretch = smNoResize) or IsAlphaUsed then
|
|
GdipFillRectangleI(AGraphics, Brush, ARect.Left, ARect.Top,
|
|
ARect.Right - ARect.Left, ARect.Bottom - ARect.Top);
|
|
end;
|
|
|
|
procedure TdxSkinElement.InternalDraw(AGraphics: GpGraphics; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
var
|
|
R: TRect;
|
|
ASide: TcxBorder;
|
|
begin
|
|
if not Image.Empty then
|
|
begin
|
|
FillBackgroundByColor(AGraphics, ARect);
|
|
Image.DrawEx(AGraphics, ARect, AImageIndex, AState);
|
|
end
|
|
else
|
|
begin
|
|
R := ARect;
|
|
for ASide := bLeft to bBottom do
|
|
with Borders[ASide] do
|
|
begin
|
|
DrawEx(AGraphics, ARect);
|
|
if Color <> clNone then
|
|
if ASide in [bLeft, bTop] then
|
|
Inc(TRect2Int(R)[ASide], Thin)
|
|
else
|
|
Dec(TRect2Int(R)[ASide], Thin);
|
|
end;
|
|
FillBackgroundByColor(AGraphics, R);
|
|
end;
|
|
if not Glyph.Empty then
|
|
Glyph.DrawEx(AGraphics, cxRectContent(ARect, ContentOffset.Rect), AImageIndex, AState);
|
|
end;
|
|
|
|
procedure TdxSkinElement.ReadData(AStream: TStream; AVersion: TdxSkinVersion);
|
|
var
|
|
ASide: TcxBorder;
|
|
begin
|
|
AStream.Read(FColor, SizeOf(TColor));
|
|
AStream.Read(FAlpha, SizeOf(FAlpha));
|
|
AStream.Read(FImageCount, SizeOf(Integer));
|
|
AStream.Read(ContentOffset.Data^, SizeOf(TRect));
|
|
Glyph.ReadData(AStream);
|
|
Image.ReadData(AStream);
|
|
for ASide := bLeft to bBottom do
|
|
begin
|
|
if Group.Skin.Version >= 0.92 then
|
|
ReadStringFromStream(AStream);
|
|
Borders[ASide].ReadFromStream(AStream);
|
|
end;
|
|
Color := FColor;
|
|
if Group.Skin.Version >= 0.93 then
|
|
AStream.Read(FTextColor, SizeOf(TColor));
|
|
if Group.Skin.Version >= 0.94 then
|
|
AStream.Read(FMinSize.Data^, SizeOf(TSize));
|
|
if Group.Skin.Version >= 0.95 then
|
|
ReadProperties(AStream);
|
|
end;
|
|
|
|
procedure TdxSkinElement.WriteData(AStream: TStream; AVersion: TdxSkinVersion);
|
|
var
|
|
ASide: TcxBorder;
|
|
begin
|
|
AStream.Write(FColor, SizeOf(TColor));
|
|
AStream.Write(FAlpha, SizeOf(Alpha));
|
|
AStream.Write(FImageCount, SizeOf(Integer));
|
|
AStream.Write(ContentOffset.Data^, SizeOf(TRect));
|
|
Glyph.WriteData(AStream);
|
|
Image.WriteData(AStream);
|
|
for ASide := bLeft to bBottom do
|
|
Borders[ASide].WriteToStream(AStream);
|
|
AStream.Write(FTextColor, SizeOf(TColor));
|
|
AStream.Write(FMinSize.Data^, SizeOf(TSize));
|
|
WriteProperties(AStream);
|
|
end;
|
|
|
|
function TdxSkinElement.GetGroup: TdxSkinControlGroup;
|
|
begin
|
|
Result := GetOwner as TdxSkinControlGroup;
|
|
end;
|
|
|
|
function TdxSkinElement.GetIsAlphaUsed: Boolean;
|
|
begin
|
|
if Image.Empty then
|
|
Result := Alpha < 255
|
|
else
|
|
Result := Image.Texture.IsAlphaUsed;
|
|
end;
|
|
|
|
function TdxSkinElement.GetPath: string;
|
|
begin
|
|
Result := Group.Name + PathDelim;
|
|
end;
|
|
|
|
function TdxSkinElement.GetSize: TSize;
|
|
begin
|
|
Result := Image.Size;
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetAlpha(AValue: Byte);
|
|
begin
|
|
if Alpha <> AValue then
|
|
begin
|
|
FAlpha := AValue;
|
|
Color := Color;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetBorders(AValue: TdxSkinBorders);
|
|
begin
|
|
FBorders.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetColor(AValue: TColor);
|
|
begin
|
|
FColor := AValue;
|
|
if AValue <> clDefault then
|
|
begin
|
|
if FBrush <> nil then
|
|
GdipSetSolidFillColor(FBrush, ColorToARGB(AValue, Alpha))
|
|
else
|
|
GdipCreateSolidFill(ColorToARGB(Color, Alpha), FBrush);
|
|
end;
|
|
DoChange;
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetContentOffset(AValue: TcxRect);
|
|
begin
|
|
ContentOffset.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetGlyph(AValue: TdxSkinImage);
|
|
begin
|
|
Glyph.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetImage(AValue: TdxSkinImage);
|
|
begin
|
|
Image.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetImageCount(AValue: Integer);
|
|
begin
|
|
if AValue < 1 then
|
|
AValue := 1;
|
|
if AValue <> FImageCount then
|
|
begin
|
|
FImageCount := AValue;
|
|
Image.IsDirty := True;
|
|
Glyph.IsDirty := True;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetMinSize(AValue: TcxSize);
|
|
begin
|
|
FMinSize.Assign(AValue);
|
|
end;
|
|
|
|
procedure TdxSkinElement.SetTextColor(AValue: TColor);
|
|
begin
|
|
FTextColor := AValue;
|
|
DoChange;
|
|
end;
|
|
|
|
{ TdxSkinEmptyElement }
|
|
|
|
procedure TdxSkinEmptyElement.Draw(DC: HDC; const ARect: TRect;
|
|
AImageIndex: Integer = 0; AState: TdxSkinElementState = esNormal);
|
|
var
|
|
RedBrush: HBRUSH;
|
|
begin
|
|
FillRect(DC, ARect, GetStockObject(WHITE_BRUSH));
|
|
RedBrush := CreateSolidBrush(255);
|
|
FrameRect(DC, ARect, RedBrush);
|
|
DeleteObject(RedBrush);
|
|
end;
|
|
|
|
{ TdxSkinPartStream }
|
|
|
|
constructor TdxSkinPartStream.Create(ASource: TStream);
|
|
begin
|
|
FSource := ASource;
|
|
end;
|
|
|
|
{$IFDEF DELPHI7}
|
|
|
|
function TdxSkinPartStream.GetSize: Int64;
|
|
begin
|
|
Result := FPosEnd - FPosStart;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
procedure TdxSkinPartStream.Initialize(const APosStart, APosEnd: Longint);
|
|
begin
|
|
FPosStart := APosStart;
|
|
FPosEnd := APosEnd;
|
|
end;
|
|
|
|
procedure TdxSkinPartStream.InitializeEx(
|
|
ASource: TStream; const APosStart, APosEnd: Longint);
|
|
begin
|
|
FSource := ASource;
|
|
Initialize(APosStart, APosEnd);
|
|
end;
|
|
|
|
function TdxSkinPartStream.Read(var Buffer; Count: Longint): Longint;
|
|
begin
|
|
Result := Source.Read(Buffer, Count);
|
|
end;
|
|
|
|
function TdxSkinPartStream.Seek(Offset: Longint; Origin: Word): Longint;
|
|
var
|
|
ANewPos: Longint;
|
|
begin
|
|
ANewPos := Source.Position + Offset;
|
|
case Origin of
|
|
soFromBeginning:
|
|
ANewPos := PosStart + Offset;
|
|
soFromEnd:
|
|
ANewPos := PosEnd + Offset;
|
|
end;
|
|
Source.Position := Min(Max(PosStart, ANewPos), PosEnd);
|
|
Result := Source.Position - PosStart;
|
|
end;
|
|
|
|
function TdxSkinPartStream.Write(const Buffer; Count: Longint): Longint;
|
|
begin
|
|
Result := Source.Write(Buffer, Count);
|
|
FPosEnd := Source.Position;
|
|
end;
|
|
|
|
procedure RegisterAssistants;
|
|
begin
|
|
dxSkinEmptyElement := TdxSkinEmptyElement.Create(nil, '');
|
|
RegisteredPropertyTypes := TList.Create;
|
|
PartStream := TdxSkinPartStream.Create(nil);
|
|
RegisterClasses([TdxSkinControlGroup, TdxSkinElement, TdxSkinImage]);
|
|
// register properties
|
|
TdxSkinIntegerProperty.Register;
|
|
TdxSkinColor.Register;
|
|
TdxSkinRectProperty.Register;
|
|
TdxSkinSizeProperty.Register;
|
|
TdxSkinBooleanProperty.Register;
|
|
TdxSkinStringProperty.Register;
|
|
//
|
|
CheckGdiPlus;
|
|
CheckPngCodec;
|
|
end;
|
|
|
|
procedure UnregisterAssistants;
|
|
begin
|
|
RegisteredPropertyTypes.Free;
|
|
UnRegisterClasses([TdxSkinControlGroup, TdxSkinElement, TdxSkinImage]);
|
|
UnRegisterClasses([TdxSkinIntegerProperty, TdxSkinColor, TdxSkinRectProperty,
|
|
TdxSkinSizeProperty, TdxSkinBooleanProperty]);
|
|
PartStream.Free;
|
|
FreeAndNil(dxSkinEmptyElement);
|
|
end;
|
|
|
|
initialization
|
|
dxUnitsLoader.AddUnit(@RegisterAssistants, @UnregisterAssistants);
|
|
finalization
|
|
dxUnitsLoader.RemoveUnit(@UnregisterAssistants);
|
|
|
|
end.
|