cxeditpaintutils.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 337 行

PAS
337
字号

{********************************************************************}
{                                                                    }
{       Developer Express Visual Component Library                   }
{       ExpressEditors                                               }
{                                                                    }
{       Copyright (c) 1998-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 EXPRESSEDITORS 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 cxEditPaintUtils;

{$I cxVer.inc}

interface

uses
  Windows, Classes, Controls, Graphics, SysUtils, cxClasses,
  cxControls, cxGraphics, cxLookAndFeels;

const
  cxSolidBrushCacheDefaultMaxDepth = 128;

type
  { TcxSolidBrushCache }

  TcxSolidBrushCache = class
  private
    FBrushColors: array of TColor;
    FBrushes: array of TBrushHandle;
    FCounts: array of Cardinal;
    FDepth: Integer;
    FMaxDepth: Integer;
    FSystemPaletteChangedNotifier: TcxSystemPaletteChangedNotifier;
  protected
    procedure SystemPaletteChanged; virtual;
  public
    constructor Create; overload;
    constructor Create(AMaxDepth: Integer); overload;
    destructor Destroy; override;
    procedure Clear;
    function GetBrush(ABrushColor: TColor): TBrushHandle;
  end;

function GetSolidBrush(ABrushColor: TColor): TBrushHandle; overload;
function GetSolidBrush(ACanvas: TCanvas; ABrushColor: TColor): TBrushHandle; overload;
function GetSolidBrush(ACanvas: TcxCanvas; ABrushColor: TColor): TBrushHandle; overload;
procedure ResetSolidBrushCache;

implementation

uses
  Forms;

const
  cxSysColorPrefix: Cardinal = {$IFDEF DELPHI7}clSystemColor{$ELSE}$80000000{$ENDIF};

var
  FSolidBrushCache: TcxSolidBrushCache = nil;
  FSystemBrushes: array of TBrushHandle;

function GetSolidBrush(ABrushColor: TColor): TBrushHandle;
begin
  Result := FSolidBrushCache.GetBrush(ABrushColor);
end;

function GetSolidBrush(ACanvas: TCanvas; ABrushColor: TColor): TBrushHandle;
begin
  Result := FSolidBrushCache.GetBrush(ABrushColor);
end;

function GetSolidBrush(ACanvas: TcxCanvas; ABrushColor: TColor): TBrushHandle;
begin
  Result := FSolidBrushCache.GetBrush(ABrushColor);
end;

procedure ResetSolidBrushCache;
begin
  FSolidBrushCache.Clear;
end;

procedure CreateSystemBrushes;
var
  I: Word;
begin
  SetLength(FSystemBrushes, COLOR_ENDCOLORS - COLOR_SCROLLBAR + 1);
  for I := COLOR_SCROLLBAR to COLOR_ENDCOLORS do
    FSystemBrushes[I] := GetSysColorBrush(I);
end;

procedure DestroySystemBrushes;
begin
  FSystemBrushes := nil;
end;

{ TcxSolidBrushCache }

constructor TcxSolidBrushCache.Create;
begin
  Create(cxSolidBrushCacheDefaultMaxDepth);
end;

constructor TcxSolidBrushCache.Create(AMaxDepth: Integer);
begin
  inherited Create;
  FMaxDepth := AMaxDepth;
  SetLength(FBrushColors, FMaxDepth);
  SetLength(FBrushes, FMaxDepth);
  SetLength(FCounts, FMaxDepth);
  FSystemPaletteChangedNotifier := TcxSystemPaletteChangedNotifier.Create(True);
  FSystemPaletteChangedNotifier.OnSystemPaletteChanged := SystemPaletteChanged;
end;

destructor TcxSolidBrushCache.Destroy;
begin
  FreeAndNil(FSystemPaletteChangedNotifier);
  Clear;
  FBrushColors := nil;
  FBrushes := nil;
  FCounts := nil;
  inherited Destroy;
end;

procedure TcxSolidBrushCache.Clear;
var
  I: Integer;
begin
  for I := 0 to FDepth - 1 do
    DeleteObject(FBrushes[I]);
  FDepth := 0;
end;

function TcxSolidBrushCache.GetBrush(ABrushColor: TColor): TBrushHandle;

  function GetColorIndex(AColor: TColor; out AIndex: Integer): Boolean; assembler;
  var
    ADepth: Integer;
    APBrushColors, APIndex: ^Integer;
  begin
    ADepth := FDepth;
    APBrushColors := @FBrushColors[0];
    APIndex := @AIndex;
    asm
          push  ebx
          push  edi
          push  esi

          mov   edi, ADepth
          or    edi, edi
          jne   @@0
          mov   eax, edi
          jmp   @@5
    @@0:
          mov   ebx, APBrushColors
          mov   edx, AColor
          mov   esi, ebx
          dec   edi
          shl   edi, 2
          add   esi, edi
          jmp   @@3
    @@1:
          mov   edi, ebx
          add   edi, esi
          shr   edi, 1
          and   di, $FFFC
          cmp   edx, [edi]
          je    @@4
          ja    @@2
          mov   esi, edi
          sub   edi, ebx
          jmp   @@3
    @@2:
          mov   ebx, edi
          sub   edi, esi
          neg   edi
    @@3:
          cmp   edi, 4
          ja    @@1
          mov   edi, ebx
          cmp   edx, [edi]
          jbe   @@4
          mov   edi, esi
          cmp   edx, [edi]
          jbe   @@4
          add   edi, 4
    @@4:
          mov   eax, edi
          sub   eax, APBrushColors
          shr   eax, 2
    @@5:
          mov   ebx, APIndex
          mov   [ebx], eax
          cmp   eax, ADepth
          jae   @@6
          shl   eax, 2
          add   eax, APBrushColors
          cmp   [eax], edx
          jne   @@6
          xor   al, al
          inc   al
          jmp   @@7
    @@6:
          xor   al, al
    @@7:
          pop   esi
          pop   edi
          pop   ebx
          mov   Result, al
    end;
  end;

  function GetRarestColorIndex: Integer;
  var
    ADepth: Integer;
    APCounts: ^Integer;
  begin
    ADepth := FDepth;
    APCounts := @FCounts[0];
    asm
          push  ebx
          push  esi

          mov   ebx, APCounts
          mov   eax, [ebx]
          mov   ecx, ADepth
          mov   edx, ebx
    @@0:
          dec   ecx
          jz    @@1
          add   ebx, 4
          mov   esi, [ebx]
          cmp   eax, esi
          jbe   @@0
          mov   eax, esi
          mov   edx, ebx
          jmp   @@0
    @@1:
          sub   edx, APCounts
          shr   edx, 2
          mov   Result, edx

          pop   esi
          pop   ebx
    end;
  end;

  function PrepareNewItem(AIndex: Integer): TBrushHandle;
  var
    ACount, ARarestColorIndex: Integer;
  begin
    if FDepth = FMaxDepth then
    begin
      ARarestColorIndex := GetRarestColorIndex;
      DeleteObject(FBrushes[ARarestColorIndex]);
      Dec(FDepth);
      if ARarestColorIndex < FDepth then
      begin
        ACount := (FDepth - ARarestColorIndex) shl 2;
        Move(FBrushColors[ARarestColorIndex + 1], FBrushColors[ARarestColorIndex], ACount);
        Move(FBrushes[ARarestColorIndex + 1], FBrushes[ARarestColorIndex], ACount);
        Move(FCounts[ARarestColorIndex + 1], FCounts[ARarestColorIndex], ACount);
      end;
      if AIndex > ARarestColorIndex then
        Dec(AIndex);
    end;
    if AIndex < FDepth then
    begin
      ACount := (FDepth - AIndex) shl 2;
      Move(FBrushColors[AIndex], FBrushColors[AIndex + 1], ACount);
      Move(FBrushes[AIndex], FBrushes[AIndex + 1], ACount);
      Move(FCounts[AIndex], FCounts[AIndex + 1], ACount);
    end;
    Inc(FDepth);
    Result := CreateSolidBrush(ColorToRGB(ABrushColor));
    FBrushColors[AIndex] := ABrushColor;
    FBrushes[AIndex] := Result;
    FCounts[AIndex] := 0;
  end;

var
  AColorIndex: Integer;
begin
  if FSystemBrushes <> nil then
    if (Cardinal(ABrushColor) >= cxSysColorPrefix) and (Cardinal(ABrushColor) <= cxSysColorPrefix or COLOR_ENDCOLORS) then
    begin
      Result := FSystemBrushes[ABrushColor and not cxSysColorPrefix];
      Exit;
    end;
  if GetColorIndex(ABrushColor, AColorIndex) then
  begin
    Inc(FCounts[AColorIndex]);
    Result := FBrushes[AColorIndex];
  end
  else
    Result := PrepareNewItem(AColorIndex);
end;

procedure TcxSolidBrushCache.SystemPaletteChanged;
begin
  Clear;
end;

initialization
  CreateSystemBrushes;
  FSolidBrushCache := TcxSolidBrushCache.Create;

finalization
  FreeAndNil(FSolidBrushCache);
  DestroySystemBrushes;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?