www.pudn.com > mmtd1.1.rar > SUIFontComboBox.pas
////////////////////////////////////////////////////////////////////////////////
//
//
// FileName : SUIFontComboBox.pas
// Creator : Steve McDonald
// Merger : Shen Min
// Date : 2003-04-01 V1-V3
// 2003-06-24 V4
// Comment :
//
// Copyright (c) 2002-2003 Sunisoft
// http://www.sunisoft.com
// Email: support@sunisoft.com
//
////////////////////////////////////////////////////////////////////////////////
unit SUIFontComboBox;
{$B-} {- Complete Boolean Evaluation }
{$R-} {- Range-Checking }
{$V-} {- Var-String Checking }
{$T-} {- Typed @ operator }
{$X+} {- Extended syntax }
{$P+} {- Open string params }
{$J+} {- Writeable structured consts }
{$H+} {- Use long strings by default }
{$W-,T-}
interface
{$I SUIPack.inc}
uses
Windows, Messages, Classes, Controls, Graphics, StdCtrls, Forms, SUIThemes,
SUIComboBox;
resourcestring
SResNotFound = 'Resource %s not found';
type
{ TsuiFontDrawComboBox }
TFontDrawComboStyle = csDropDown..csDropDownList;
TsuiFontDrawComboBox = class(TsuiCustomComboBox)
private
FStyle: TFontDrawComboStyle;
FItemHeightChanging: Boolean;
procedure SetComboStyle(Value: TFontDrawComboStyle);
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMRecreateWnd(var Message: TMessage); message CM_RECREATEWND;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure ResetItemHeight;
function MinItemHeight: Integer; virtual;
property Style: TFontDrawComboStyle read FStyle write SetComboStyle default csDropDownList;
public
constructor Create(AOwner: TComponent); override;
end;
{ TsuiFontComboBox }
TFontDevice = (fdScreen, fdPrinter, fdBoth);
TFontListOption = (foAnsiOnly, foTrueTypeOnly, foFixedPitchOnly, foNoOEMFonts, foOEMFontsOnly, foScalableOnly, foNoSymbolFonts);
TFontListOptions = set of TFontListOption;
TsuiFontComboBox = class(TsuiFontDrawComboBox)
private
FTrueTypeBMP: TBitmap;
FDeviceBMP: TBitmap;
FOnChange: TNotifyEvent;
FDevice: TFontDevice;
FUpdate: Boolean;
FUseFonts: Boolean;
FOptions: TFontListOptions;
procedure SetFontName(const NewFontName: TFontName);
function GetFontName: TFontName;
procedure SetDevice(Value: TFontDevice);
procedure SetOptions(Value: TFontListOptions);
procedure SetUseFonts(Value: Boolean);
procedure Reset;
procedure WMFontChange(var Message: TMessage); message WM_FONTCHANGE;
protected
procedure PopulateList; virtual;
procedure Change; override;
procedure Click; override;
procedure DoChange; dynamic;
procedure CreateWnd; override;
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
function MinItemHeight: Integer; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Text;
published
property Device: TFontDevice read FDevice write SetDevice default fdScreen;
property FontName: TFontName read GetFontName write SetFontName;
property Options: TFontListOptions read FOptions write SetOptions default [];
property UseFonts: Boolean read FUseFonts write SetUseFonts default False;
property ItemHeight;
property Color;
property Ctl3D;
property DragMode;
property DragCursor;
property Enabled;
property Font;
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
property ImeMode;
property ImeName;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Style;
property TabOrder;
property TabStop;
property Visible;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDrag;
property OnContextPopup;
property OnEndDock;
property OnStartDock;
end;
TsuiFontSizeComboBox = class(TsuiCustomComboBox)
private
PixelsPerInch : Integer;
FFontName : TFontName;
procedure SetFontName( const Value : TFontName );
procedure Build;
function GetFontSize: Integer;
procedure SetFontSize(const Value: Integer);
public
constructor Create(AOwner: TComponent); override;
published
property FontName : TFontName read FFontName write SetFontName;
property FontSize : Integer read GetFontSize write SetFontSize;
property Color;
property Ctl3D;
property DragMode;
property DragCursor;
property Enabled;
property Font;
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
property ImeMode;
property ImeName;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Style;
property TabOrder;
property TabStop;
property Text;
property Visible;
property OnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDrag;
property OnContextPopup;
property OnEndDock;
property OnStartDock;
end;
implementation
uses
SysUtils,
Consts,
Printers,
Dialogs,
SUIPublic,
SUIResDef;
{ Utility routines }
procedure ResourceNotFound(ResID: PChar);
var
S: string;
begin
if LongRec(ResID).Hi = 0 then
S := IntToStr(LongRec(ResID).Lo)
else
S := StrPas(ResID);
raise EResNotFound.CreateFmt(SResNotFound, [S]);
end;
function MakeModuleBitmap(Module: THandle; ResID: PChar): TBitmap;
begin
Result := TBitmap.Create;
try
if Module <> 0 then begin
if LongRec(ResID).Hi = 0 then
Result.LoadFromResourceID(Module, LongRec(ResID).Lo)
else
Result.LoadFromResourceName(Module, StrPas(ResID));
end
else begin
Result.Handle := LoadBitmap(Module, ResID);
if Result.Handle = 0 then
ResourceNotFound(ResID);
end;
except
Result.Free;
Result := nil;
end;
end;
function CreateBitmap(ResName: PChar): TBitmap;
begin
Result := MakeModuleBitmap(HInstance, ResName);
if Result = nil then
ResourceNotFound(ResName);
end;
function GetItemHeight(Font: TFont): Integer;
var
DC: HDC;
SaveFont: HFont;
Metrics: TTextMetric;
begin
DC := GetDC(0);
try
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Metrics);
SelectObject(DC, SaveFont);
finally
ReleaseDC(0, DC);
end;
Result := Metrics.tmHeight + 1;
if Result = 14 then
Result := 15;
end;
{ TsuiFontDrawComboBox }
constructor TsuiFontDrawComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
inherited Style := csDropDownList;
FStyle := csDropDownList;
end;
procedure TsuiFontDrawComboBox.SetComboStyle(Value: TFontDrawComboStyle);
begin
if FStyle <> Value then begin
FStyle := Value;
inherited Style := Value;
end;
end;
function TsuiFontDrawComboBox.MinItemHeight: Integer;
begin
Result := GetItemHeight(Font);
if Result < 9 then
Result := 9;
end;
procedure TsuiFontDrawComboBox.ResetItemHeight;
var
H: Integer;
begin
H := MinItemHeight;
FItemHeightChanging := True;
try
inherited ItemHeight := H;
finally
FItemHeightChanging := False;
end;
if HandleAllocated then
SendMessage(Handle, CB_SETITEMHEIGHT, 0, H);
end;
procedure TsuiFontDrawComboBox.CreateParams(var Params: TCreateParams);
const
ComboBoxStyles: array[TFontDrawComboStyle] of DWORD =
(CBS_DROPDOWN, CBS_SIMPLE, CBS_DROPDOWNLIST);
begin
inherited CreateParams(Params);
with Params do
Style := (Style and not CBS_DROPDOWNLIST) or CBS_OWNERDRAWFIXED or
ComboBoxStyles[FStyle];
end;
procedure TsuiFontDrawComboBox.CreateWnd;
begin
inherited CreateWnd;
ResetItemHeight;
end;
procedure TsuiFontDrawComboBox.CMFontChanged(var Message: TMessage);
begin
inherited;
ResetItemHeight;
RecreateWnd;
end;
procedure TsuiFontDrawComboBox.CMRecreateWnd(var Message: TMessage);
begin
if not FItemHeightChanging then
inherited;
end;
{ TsuiFontComboBox }
const
WRITABLE_FONTTYPE = 256;
function IsValidFont(Box: TsuiFontComboBox; LogFont: TLogFont; FontType: Integer): Boolean;
begin
Result := True;
if (foAnsiOnly in Box.Options) then
Result := Result and (LogFont.lfCharSet = ANSI_CHARSET);
if (foTrueTypeOnly in Box.Options) then
Result := Result and (FontType and TRUETYPE_FONTTYPE = TRUETYPE_FONTTYPE);
if (foFixedPitchOnly in Box.Options) then
Result := Result and (LogFont.lfPitchAndFamily and FIXED_PITCH = FIXED_PITCH);
if (foOEMFontsOnly in Box.Options) then
Result := Result and (LogFont.lfCharSet = OEM_CHARSET);
if (foNoOEMFonts in Box.Options) then
Result := Result and (LogFont.lfCharSet <> OEM_CHARSET);
if (foNoSymbolFonts in Box.Options) then
Result := Result and (LogFont.lfCharSet <> SYMBOL_CHARSET);
if (foScalableOnly in Box.Options) then
Result := Result and (FontType and RASTER_FONTTYPE = 0);
end;
function EnumFontsProc(var EnumLogFont: TEnumLogFont;
var TextMetric: TNewTextMetric; FontType: Integer; Data: LPARAM): Integer;
export; stdcall;
var
FaceName: string;
begin
FaceName := StrPas(EnumLogFont.elfLogFont.lfFaceName);
with TsuiFontComboBox(Data) do
if (Items.IndexOf(FaceName) < 0) and
IsValidFont(TsuiFontComboBox(Data), EnumLogFont.elfLogFont, FontType) then begin
if EnumLogFont.elfLogFont.lfCharSet <> SYMBOL_CHARSET then
FontType := FontType or WRITABLE_FONTTYPE;
Items.AddObject(FaceName, TObject(FontType));
end;
Result := 1;
end;
constructor TsuiFontComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ItemHeight := 15;
FTrueTypeBMP := CreateBitmap('FONTCOMBO_TRUETYPE_FNT');
FDeviceBMP := CreateBitmap('FONTCOMBO_DEVICE_FNT');
FDevice := fdScreen;
Sorted := True;
inherited ItemHeight := MinItemHeight;
end;
destructor TsuiFontComboBox.Destroy;
begin
FTrueTypeBMP.Free;
FDeviceBMP.Free;
inherited Destroy;
end;
procedure TsuiFontComboBox.CreateWnd;
var
OldFont: TFontName;
begin
OldFont := FontName;
inherited CreateWnd;
FUpdate := True;
try
PopulateList;
inherited Text := '';
SetFontName(OldFont);
finally
FUpdate := False;
end;
if AnsiCompareText(FontName, OldFont) <> 0 then
DoChange;
end;
procedure TsuiFontComboBox.PopulateList;
var
DC: HDC;
begin
if not HandleAllocated then Exit;
Items.BeginUpdate;
try
Clear;
DC := GetDC(0);
try
if (FDevice = fdScreen) or (FDevice = fdBoth) then
EnumFontFamilies(DC, nil, @EnumFontsProc, Longint(Self));
if (FDevice = fdPrinter) or (FDevice = fdBoth) then
try
EnumFontFamilies(Printer.Handle, nil, @EnumFontsProc, Longint(Self));
except
{ skip any errors }
end;
finally
ReleaseDC(0, DC);
end;
finally
Items.EndUpdate;
end;
end;
procedure TsuiFontComboBox.SetFontName(const NewFontName: TFontName);
var
Item: Integer;
begin
if FontName <> NewFontName then begin
if not (csLoading in ComponentState) then begin
HandleNeeded;
{ change selected item }
for Item := 0 to Items.Count - 1 do
if AnsiCompareText(Items[Item], NewFontName) = 0 then begin
ItemIndex := Item;
DoChange;
Exit;
end;
if Style = csDropDownList then
ItemIndex := -1
else
inherited Text := NewFontName;
end
else
inherited Text := NewFontName;
DoChange;
end;
end;
function TsuiFontComboBox.GetFontName: TFontName;
begin
Result := inherited Text;
end;
procedure TsuiFontComboBox.SetOptions(Value: TFontListOptions);
begin
if Value <> Options then begin
FOptions := Value;
Reset;
end;
end;
procedure TsuiFontComboBox.SetDevice(Value: TFontDevice);
begin
if Value <> FDevice then begin
FDevice := Value;
Reset;
end;
end;
procedure TsuiFontComboBox.SetUseFonts(Value: Boolean);
begin
if Value <> FUseFonts then begin
FUseFonts := Value;
Invalidate;
end;
end;
procedure TsuiFontComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
Bitmap: TBitmap;
BmpWidth: Integer;
Text: array[0..255] of Char;
begin
with Canvas do begin
FillRect(Rect);
BmpWidth := 20;
if (Integer(Items.Objects[Index]) and TRUETYPE_FONTTYPE) <> 0 then
Bitmap := FTrueTypeBMP
else
if (Integer(Items.Objects[Index]) and DEVICE_FONTTYPE) <> 0 then
Bitmap := FDeviceBMP
else
Bitmap := nil;
if Bitmap <> nil then begin
BmpWidth := Bitmap.Width;
BrushCopy(Bounds(Rect.Left + 2, (Rect.Top + Rect.Bottom - Bitmap.Height)
div 2, Bitmap.Width, Bitmap.Height), Bitmap, Bounds(0, 0, Bitmap.Width,
Bitmap.Height), Bitmap.TransparentColor);
end;
{ uses DrawText instead of TextOut in order to get clipping against
the combo box button }
{TextOut(Rect.Left + bmpWidth + 6, Rect.Top, Items[Index])}
StrPCopy(Text, Items[Index]);
Rect.Left := Rect.Left + BmpWidth + 6;
if FUseFonts and (Integer(Items.Objects[Index]) and WRITABLE_FONTTYPE <> 0) then
Font.Name := Items[Index];
DrawText(Handle, Text, StrLen(Text), Rect,
DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX));
end;
end;
procedure TsuiFontComboBox.WMFontChange(var Message: TMessage);
begin
inherited;
Reset;
end;
function TsuiFontComboBox.MinItemHeight: Integer;
begin
Result := inherited MinItemHeight;
if Result < FTrueTypeBMP.Height - 1 then
Result := FTrueTypeBMP.Height - 1;
end;
procedure TsuiFontComboBox.Change;
var
I: Integer;
begin
inherited Change;
if Style <> csDropDownList then begin
I := Items.IndexOf(inherited Text);
if (I >= 0) and (I <> ItemIndex) then begin
ItemIndex := I;
DoChange;
end;
end;
end;
procedure TsuiFontComboBox.Click;
begin
inherited Click;
DoChange;
end;
procedure TsuiFontComboBox.DoChange;
begin
if not (csReading in ComponentState) then
if not FUpdate and Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TsuiFontComboBox.Reset;
var
SaveName: TFontName;
begin
if HandleAllocated then begin
FUpdate := True;
try
SaveName := FontName;
PopulateList;
FontName := SaveName;
finally
FUpdate := False;
if FontName <> SaveName then
DoChange;
end;
end;
end;
function EnumFontSizes( var EnumLogFont : TEnumLogFont; PTextMetric : PNewTextMetric; FontType : Integer; Data : LPARAM ) : Integer; export; stdcall;
var
s : String;
i : Integer;
v : Integer;
v2 : Integer;
begin
if (FontType and TRUETYPE_FONTTYPE)<>0 then begin
TsuiFontSizeComboBox(Data).Items.Add('8');
TsuiFontSizeComboBox(Data).Items.Add('9');
TsuiFontSizeComboBox(Data).Items.Add('10');
TsuiFontSizeComboBox(Data).Items.Add('11');
TsuiFontSizeComboBox(Data).Items.Add('12');
TsuiFontSizeComboBox(Data).Items.Add('14');
TsuiFontSizeComboBox(Data).Items.Add('16');
TsuiFontSizeComboBox(Data).Items.Add('18');
TsuiFontSizeComboBox(Data).Items.Add('20');
TsuiFontSizeComboBox(Data).Items.Add('22');
TsuiFontSizeComboBox(Data).Items.Add('24');
TsuiFontSizeComboBox(Data).Items.Add('26');
TsuiFontSizeComboBox(Data).Items.Add('28');
TsuiFontSizeComboBox(Data).Items.Add('36');
TsuiFontSizeComboBox(Data).Items.Add('48');
TsuiFontSizeComboBox(Data).Items.Add('72');
Result := 0;
end
else begin
v := Round( ( EnumLogFont.elfLogFont.lfHeight - PTextMetric.tmInternalLeading ) * 72 / TsuiFontSizeComboBox( Data ).PixelsPerInch );
s := IntToStr( v );
Result := 1;
for i := 0 to Pred( TsuiFontSizeComboBox( Data ).Items.Count ) do begin
v2 := StrToInt( TsuiFontSizeComboBox( Data ).Items[ i ] );
if v2 = v then
exit;
if v2 > v then begin
TsuiFontSizeComboBox( Data ).Items.Insert( i, s );
exit;
end;
end;
TsuiFontSizeComboBox( Data ).Items.Add( s );
end;
end;
procedure TsuiFontSizeComboBox.Build;
var
DC : HDC;
OC : TNotifyEvent;
begin
DC := GetDC( 0 );
Items.BeginUpdate;
try
Items.Clear;
if FontName <> '' then begin
PixelsPerInch := GetDeviceCaps( DC, LOGPIXELSY );
EnumFontFamilies( DC, PChar( FontName ), @EnumFontSizes, Longint( Self ) );
OC := OnClick;
OnClick := nil;
ItemIndex := Items.IndexOf( Text );
OnClick := OC;
if Assigned( OnClick ) then
OnClick( Self );
end;
finally
Items.EndUpdate;
ReleaseDC( 0, DC );
end;
end;
procedure TsuiFontSizeComboBox.SetFontName( const Value : TFontName );
begin
FFontName := Value;
Build;
end;
constructor TsuiFontSizeComboBox.Create(AOwner: TComponent);
begin
inherited;
self.Style := csDropDownList;
end;
function TsuiFontSizeComboBox.GetFontSize: Integer;
begin
try
Result := StrToInt(Items[ItemIndex]);
except
Result := 0;
end;
end;
procedure TsuiFontSizeComboBox.SetFontSize(const Value: Integer);
begin
ItemIndex := Items.IndexOf(IntToStr(Value));
end;
end.