{***************************************************}
{                                                   }
{             FastReport v5.0                       }
{              Tool controls                        }
{                                                   }
{         Copyright (c) 1998-2014                   }
{         by Alexander Tzyganenko,                  }
{            Fast Reports Inc.                      }
{                                                   }
{                                                   }
{  Flat ComboBox, FontComboBox v1.2                 }
{  For Delphi 2,3,4,5. Freeware.                    }
{                                                   }
{  Copyright (c) 1999 by:                           }
{    Dmitry Statilko (dima_misc@hotbox.ru)          }
{    - Main idea and realisation of Flat ComboBox   }
{      inherited from TCustomComboBox               }
{                                                   }
{    Vladislav Necheporenko (vlad_n@ua.fm)          }
{    - Help in bug fixes                            }
{    - Adaptation to work on Delphi 2               }
{    - MRU list in FontComboBox that stored values  }
{      in regitry                                   }
{    - Font preview box in FontComboBox             }
{    - New look style, like in Office XP            }
{                                                   }
{***************************************************}

unit frxCtrls;

interface

{$I frx.inc}

uses
  {$IFNDEF NONWINFPC}Windows, CommCtrl, Registry, ActiveX,{$ENDIF}
  {$IFDEF FPC}LCLType, LMessages, LCLIntf, LazHelper, LazarusPackageIntf,{$ENDIF}
  Messages, Types, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Buttons, IniFiles, frxDPIAwareInt, frxDPIAwareBaseControls, frxClass
  {$IFDEF Delphi6}
  , Variants
  {$ENDIF};

type
{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxCustomFilterEdit = class(TfrxDPIAwareBasePanel)
  private
    FFrameIsActive: Boolean;
    FClearBtnActive: Boolean;
    FEdit: TEdit;
    FBitmapActive: TBitmap;
    FBitmapUnactive: TBitmap;
    FOnFilterChanged: TNotifyEvent;
    FFilterColor: TColor;
    procedure DoFocus(Sender: TObject);
    procedure DoLostFocus(Sender: TObject);
    procedure DoTextChange(Sender: TObject);
    procedure UpdateSize;
    procedure SetFilterColor(const Value: TColor);
  protected
{$IFNDEF Linux}
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
{$ENDIF}
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure PaintBorder;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
  public
    procedure Paint; override;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property FilterColor: TColor read FFilterColor write SetFilterColor;
    property BitmapActive: TBitmap read FBitmapActive;
    property BitmapUnactive: TBitmap read FBitmapUnactive;
    property EditControl: TEdit read FEdit;
    property OnFilterChanged: TNotifyEvent read FOnFilterChanged write FOnFilterChanged;
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxFilterEdit = class(TfrxCustomFilterEdit)
  published
    property Align;
    property Alignment;
    property Anchors;
    property AutoSize;
    property BitmapActive;
    property BitmapUnactive;
    property Constraints;
    property UseDockManager default True;
    property DockSite;
    property DoubleBuffered;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property EditControl;
    property FullRepaint;
    property ParentBiDiMode;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnClick;
    property OnConstrainedResize;
    property OnContextPopup;
    property OnDockDrop;
    property OnDockOver;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnGetSiteInfo;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnStartDock;
    property OnStartDrag;
    property OnUnDock;
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxCustomComboBox = class(TCustomComboBox)
  private
    FButtonWidth: Integer;
    msMouseInControl: Boolean;
    FListInstance: Pointer;
    FDefListProc: Pointer;
    FSolidBorder: Boolean;
    FReadOnly: Boolean;
    FEditOffset: Integer;
    FListWidth: Integer;
    FCurrentPPI: Integer;
    {$IFDEF FPC}
    procedure SelectAllWhenClicked(Sender: TObject);
  protected
    procedure DoPPIChanged(aNewPPI: Integer); virtual;
    {$ELSE}
    FChildHandle: HWND;
    FListHandle: HWND;
    FUpDropdown: Boolean;
    procedure ListWndProc(var Message: TMessage);
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
    procedure WMDpiChanged(var Message: TMessage); message FRX_WM_DPICHANGED_AFTERPARENT;
    procedure PaintButton(ButtonStyle: Integer);
    procedure PaintBorder(DC: HDC; const SolidBorder: Boolean);
    procedure PaintDisabled;
    function GetSolidBorder: Boolean;
    function GetListHeight: Integer;
   protected
    procedure ComboWndProc(var Message: TMessage; ComboWnd: HWnd; ComboProc: Pointer); override;
    procedure WndProc(var Message: TMessage); override;
    procedure CreateWnd; override;
    procedure DrawImage(DC: HDC; Index: Integer; R: TRect); dynamic;
    procedure DoPPIChanged(aNewPPI: Integer); virtual;
   private
    {$ENDIF}
    procedure CMEnabledChanged(var Msg: TMessage); message CM_ENABLEDCHANGED;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure SetReadOnly(Value: Boolean);
    procedure SetListWidth(const Value: Integer);
  protected
    {$IFDEF FPC}
    OnlyMask: Boolean;
    {$ENDIF}
    procedure CreateParams(var Params: TCreateParams); override;
    procedure KeyPress(var Key: Char); override;
    function GetScale: Single;
    property ListWidth: Integer read FListWidth write SetListWidth;
    property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
    property SolidBorder: Boolean read FSolidBorder;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    {$IFNDEF FPC}
    procedure Resize; override;
    {$ENDIF}
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxComboBox = class(TfrxCustomComboBox)
  published
    property Color;
    property DragMode;
    property DragCursor;
    property DropDownCount;
    property Enabled;
    property Font;
    property ItemHeight;
    property Items;
    property ListWidth;
    property MaxLength;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Sorted;
    property TabOrder;
    property TabStop;
    property Text;
    property ReadOnly;
    property Visible;
    property ItemIndex;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnDrawItem;
    property OnDropDown;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnStartDrag;
{$IFDEF Delphi4}
    property Anchors;
    property BiDiMode;
    property Constraints;
    property DragKind;
    property ParentBiDiMode;
    property OnEndDock;
    property OnStartDock;
{$ENDIF}
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxFontPreview = class(TWinControl)
  private
    FPanel: TPanel;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetDefaultFontSize(aNewPPI: Integer);
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxFontComboBox = class(TfrxCustomComboBox)
  private
    {$IFNDEF FPC}
    frFontViewForm: TfrxFontPreview;
    {$ENDIF}
    FRegKey: String;
    FTrueTypeBMP: TBitmap;
    FDeviceBMP: TBitmap;
    FOnClick: TNotifyEvent;
    FUpdate: Boolean;
    FShowMRU: Boolean;
    Numused: Integer;
    FIni: TCustomIniFile;
    {$IFNDEF FPC}
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
    {$ENDIF}
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMFontChange(var Message: TMessage); message CM_FONTCHANGE;
    procedure SetRegKey(Value: String);
  protected
    procedure Loaded; override;
    procedure Init;
    procedure Reset;
    procedure Click; override;
    procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
    procedure DrawImage(DC: HDC; Index: Integer; R: TRect); {$IFNDEF FPC}  override; {$ENDIF}
    procedure DoPPIChanged(aNewPPI: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure PopulateList; virtual;
    property IniFile: TCustomIniFile read FIni write FIni;
  published
    property ShowMRU: Boolean read FShowMRU write FShowMRU default True;
    property MRURegKey: String read FRegKey write SetRegKey;
    property Text;
    property Color;
    property DragMode;
    property DragCursor;
    property DropDownCount;
    property Enabled;
    property Font;
{$IFDEF Delphi4}
    property Anchors;
    property BiDiMode;
    property Constraints;
    property DragKind;
    property ParentBiDiMode;
{$ENDIF}
    property ItemHeight;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnChange;
    property OnClick: TNotifyEvent read FOnClick write FOnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnDropDown;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnStartDrag;
{$IFDEF Delphi4}
    property OnEndDock;
    property OnStartDock;
{$ENDIF}
  end;

{$IFDEF DELPHI16}
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
{$ENDIF}
  TfrxComboEdit = class(TComboBox)
  private
    FPanel: TWinControl;
    FButton: TSpeedButton;
    FButtonEnabled: Boolean;
    FOnButtonClick: TNotifyEvent;
    {$IFDEF FPC}
    {$IFNDEF NONWINFPC}
    function GetEditHandle: HWND;
    {$ENDIF}
    {$ENDIF}
    function GetGlyph: TBitmap;
    procedure SetGlyph(Value: TBitmap);
    function GetButtonHint: String;
    procedure SetButtonHint(Value: String);
    procedure SetButtonEnabled(Value: Boolean);
    procedure ButtonClick(Sender: TObject);
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
    procedure SetPos;
  public
    constructor Create(AOwner: TComponent); override;
    procedure CreateWnd; override;
    procedure KeyPress(var Key: Char); override;
    {$IFDEF FPC}
    {$IFNDEF NONWINFPC}
    property EditHandle: HWND read GetEditHandle;
    {$ENDIF}
    {$ENDIF}
  published
    property Glyph: TBitmap read GetGlyph write SetGlyph;
    property ButtonEnabled: Boolean read FButtonEnabled write SetButtonEnabled default True;
    property ButtonHint: String read GetButtonHint write SetButtonHint;
    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
  end;

  TfrxScrollMaxChangeEvent = procedure(Sender: TObject; Orientation: TfrxScrollerOrientation; Value: Integer) of Object;
  TfrxScrollPosChangeEvent = procedure(Sender: TObject; Orientation: TfrxScrollerOrientation; var Value: Integer) of Object;

  TfrxScrollWin = class(TCustomControl)
  private
    FBorderStyle: TBorderStyle;
    FHorzPage: Integer;
    FHorzPosition: Integer;
    FHorzRange: Integer;
    FLargeChange: Integer;
    FSmallChange: Integer;
    FVertPage: Integer;
    FVertPosition: Integer;
    FVertRange: Integer;
    FHideScrolls: Boolean;
    FOnScrollMaxChange: TfrxScrollMaxChangeEvent;
    FOnScrollPosChange: TfrxScrollPosChangeEvent;
    procedure SetHideScrolls(b: Boolean);
    function GetLongPosition(DefValue: Integer; Code: Word): Integer;
    procedure SetHorzPosition(Value: Integer);
    procedure SetHorzRange(Value: Integer);
    procedure SetPosition(Value: Integer; Code: Word);
    procedure SetVertPosition(Value: Integer);
    procedure SetVertRange(Value: Integer);
    procedure UpdateScrollBar(Max, Page, Pos: Integer; Code: Word);
    procedure WMEraseBackground(var Message: TMessage); message WM_ERASEBKGND;
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure SetHorzPage(const Value: Integer);
    procedure SetVertPage(const Value: Integer);
    procedure SetBorderStyle(const Value: TBorderStyle);
  protected
    FCurrentPPI: Integer;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure OnHScrollChange(Sender: TObject); virtual;
    procedure OnVScrollChange(Sender: TObject); virtual;
    procedure WMDpiChanged(var Message: TMessage); message FRX_WM_DPICHANGED_AFTERPARENT;
    procedure DoPPIChanged(aNewPPI: Integer); virtual;
    function GetScale: Single;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Paint; override;
    function GetScaledFontSize: Integer;
    procedure SetScaledFontSize(Value: Integer);
    {$IFNDEF FPC}
    property BevelKind;
    {$ENDIF}
    property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle;
    property HorzPage: Integer read FHorzPage write SetHorzPage;
    property HorzPosition: Integer read FHorzPosition write SetHorzPosition;
    property HorzRange: Integer read FHorzRange write SetHorzRange;
    property LargeChange: Integer read FLargeChange write FLargeChange;
    property SmallChange: Integer read FSmallChange write FSmallChange;
    property VertPage: Integer read FVertPage write SetVertPage;
    property VertPosition: Integer read FVertPosition write SetVertPosition;
    property VertRange: Integer read FVertRange write SetVertRange;
    property HideScrolls: Boolean read FHideScrolls write SetHideScrolls;
    property OnScrollMaxChange: TfrxScrollMaxChangeEvent read FOnScrollMaxChange write FOnScrollMaxChange;
    property OnScrollPosChange: TfrxScrollPosChangeEvent read FOnScrollPosChange write FOnScrollPosChange;
  end;

   function frxBlend(C1, C2: TColor; W1: Integer): TColor;
{$IFDEF FPC}
//  procedure Register;
{$ENDIF}

implementation

{$R *.res}
{$IFDEF Delphi6}
{$WARN SYMBOL_DEPRECATED OFF}
{$ENDIF}

uses frxPrinter, frxUtils;

const
  fr01cm = 3.77953;
  fr01in = 96 / 10;

type
  THackScrollBar = class(TScrollBar);


{ Additional functions }

function Min(val1, val2: Word): Word;
begin
  Result := val1;
  if val1 > val2 then
    Result := val2;
end;

function GetFontMetrics(Font: TFont): TTextMetric;
var
  DC: HDC;
  SaveFont: HFont;
begin
  DC := GetDC(0);
  SaveFont := SelectObject(DC, Font.Handle);
  GetTextMetrics(DC, Result);
  SelectObject(DC, SaveFont);
  ReleaseDC(0, DC);
end;

function GetFontHeight(Font: TFont): Integer;
begin
  Result := GetFontMetrics(Font).tmHeight;
end;

function frxBlend(C1, C2: TColor; W1: Integer): TColor;
var
  W2, A1, A2, D, F, G: Integer;
begin
  if C1 < 0 then C1 := GetSysColor(C1 and $FF);
  if C2 < 0 then C2 := GetSysColor(C2 and $FF);

  if W1 >= 100 then D := 1000
  else D := 100;

  W2 := D - W1;
  F := D div 2;

  A2 := C2 shr 16 * W2;
  A1 := C1 shr 16 * W1;
  G := (A1 + A2 + F) div D and $FF;
  Result := G shl 16;

  A2 := (C2 shr 8 and $FF) * W2;
  A1 := (C1 shr 8 and $FF) * W1;
  G := (A1 + A2 + F) div D and $FF;
  Result := Result or G shl 8;

  A2 := (C2 and $FF) * W2;
  A1 := (C1 and $FF) * W1;
  G := (A1 + A2 + F) div D and $FF;
  Result := Result or G;
end;

{ TfrxCustomFilterEdit }

procedure TfrxCustomFilterEdit.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  FFrameIsActive := True;
  {$IFDEF FPC}
  {$note FIXME TfrxCustomComboBox.CMMouseEnter}
  {$ELSE}
  if Enabled then
  begin
    PaintBorder;
    Invalidate;
  end;
  {$ENDIF}
end;

procedure TfrxCustomFilterEdit.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  FFrameIsActive := False;
  {$IFDEF FPC}
  {$note FIXME TfrxCustomComboBox.CMMouseLeave}
  {$ELSE}
  if Enabled and not FEdit.Focused then
  begin
    PaintBorder;
    Invalidate;
  end;
  {$ENDIF}
end;

constructor TfrxCustomFilterEdit.Create(AOwner: TComponent);
begin
  inherited;
{$IFNDEF FPC}
  BevelKind := bkNone;
{$ENDIF}
  BevelInner := bvNone;
  BevelOuter := bvNone;
  BorderStyle := bsSingle;
  BorderWidth := 1;
  FEdit := TEdit.Create(nil);
  FEdit.Parent := Self;
  FEdit.BorderStyle := bsNone;
  FEdit.OnEnter := DoFocus;
  FEdit.OnExit := DoLostFocus;
  FEdit.OnChange := DoTextChange;
  Color := clWindow;
  FilterColor := clWindow;
  FBitmapActive := TBitmap.Create;
  FBitmapUnactive := TBitmap.Create;
end;

destructor TfrxCustomFilterEdit.Destroy;
begin
  FreeAndNil(FBitmapActive);
  FreeAndNil(FBitmapUnactive);
  FreeAndNil(FEdit);
  inherited;
end;

procedure TfrxCustomFilterEdit.DoFocus(Sender: TObject);
begin
  FFrameIsActive := True;
  PaintBorder;
  Invalidate;
end;

procedure TfrxCustomFilterEdit.DoLostFocus(Sender: TObject);
begin
  FFrameIsActive := False;
  PaintBorder;
  Invalidate;
end;

procedure TfrxCustomFilterEdit.DoTextChange(Sender: TObject);
var
  bTextIsEmpty: Boolean;
begin
  bTextIsEmpty := FEdit.Text <> '';
  if bTextIsEmpty <> FClearBtnActive then
  begin
    FClearBtnActive := bTextIsEmpty;
    UpdateSize;
    Invalidate;
  end;
  if Assigned(FOnFilterChanged) then
    FOnFilterChanged(Sender);
end;

procedure TfrxCustomFilterEdit.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited;
  if (X > 1) and (X < Height) then
    FEdit.Clear;
end;

procedure TfrxCustomFilterEdit.Paint;
var
  aRect: TRect;
  btnWidth, Offset: Integer;
  LG: {$IFDEF FPC}TLogBrush{$ELSE}LOGBRUSH{$ENDIF};
  hP: HPEN;
  OldPen: HGDIOBJ;
  SerchIcon: TBitmap;
begin
  inherited;
  aRect := GetClientRect;
  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := FFilterColor;
  Offset := Round(4 * GetScale);
  Canvas.FillRect(aRect);
  btnWidth := ((aRect.Bottom - aRect.Top) - Offset * 2) div 2 * 2;

  LG.lbStyle := BS_SOLID;
  LG.lbColor := 0;// black;
  LG.lbHatch := 0;

  hP := ExtCreatePen(PS_GEOMETRIC or PS_ENDCAP_ROUND, Round(GetScale),
    LG, 0, nil);
  try
    OldPen := SelectObject(Canvas.Handle, hP);
    Canvas.MoveTo(Offset, Offset);
    Canvas.LineTo(btnWidth + Offset, btnWidth + Offset);
    Canvas.MoveTo(Offset, btnWidth + Offset);
    Canvas.LineTo(btnWidth + Offset, Offset);
    Canvas.Brush.Color := clBlack;
    SelectObject(Canvas.Handle, OldPen);
  finally
    DeleteObject(hP);
  end;
  Offset := 0;
  btnWidth := ((aRect.Bottom - aRect.Top) - Offset * 2) div 2 * 2;
  if FFrameIsActive then
    SerchIcon := FBitmapActive
  else
    SerchIcon := FBitmapUnactive;
  Canvas.StretchDraw(Rect((aRect.Right - aRect.Left - btnWidth + 1), 1, (aRect.Right - aRect.Left - btnWidth + 1) + btnWidth, btnWidth), SerchIcon);
end;

procedure TfrxCustomFilterEdit.PaintBorder;
var
  R: TRect;
  DC: HDC;
begin
  DC := GetWindowDC(Handle);
  try
    GetWindowRect(Handle, R);
    OffsetRect(R, -R.Left, -R.Top);
    InflateRect(R, 0, 0);
    if FFrameIsActive then
      FrameRect(DC, R, GetSysColorBrush(COLOR_HIGHLIGHT))
    else
      FrameRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
  finally
    ReleaseDC(Handle, DC);
  end;
end;

procedure TfrxCustomFilterEdit.SetFilterColor(const Value: TColor);
begin
  FFilterColor := Value;
  Color := Value;
  EditControl.Color := Color;
end;

procedure TfrxCustomFilterEdit.UpdateSize;
var
  nOffset: Integer;
begin
  nOffset := Round(2 * GetScale);
  FClearBtnActive := FEdit.Text <> '';
  if FClearBtnActive then
    FEdit.SetBounds(Height, nOffset, Width - Height * 2, Height - 1)
  else
    FEdit.SetBounds(1, nOffset, Width - Height, Height - 1);
end;

{$IFNDEF Linux}
procedure TfrxCustomFilterEdit.WMNCPaint(var Message: TWMNCPaint);
var
  R: TRect;
  DC: HDC;
begin
  DC := GetWindowDC(Handle);
  try
    GetWindowRect(Handle, R);
    OffsetRect(R, -R.Left, -R.Top);
    InflateRect(R, 0, 0);
    FillRect(DC, R, GetSysColorBrush(Color))
  finally
    ReleaseDC(Handle, DC);
  end;
  PaintBorder;
end;
{$ENDIF}

procedure TfrxCustomFilterEdit.WMSize(var Message: TWMSize);
begin
  inherited;
  UpdateSize;
end;

{ TfrxCustomComboBox }

constructor TfrxCustomComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  {$IFDEF FPC}
  FListInstance := nil;
  OnClick := SelectAllWhenClicked;
  {$IFDEF FPC}
  OnlyMask := False;
  {$ENDIF}
  {$ELSE}
  FListInstance := MakeObjectInstance(ListWndProc);
  {$ENDIF}
  FDefListProc := nil;
  ItemHeight := GetFontHeight(Font);
  Width := 100;
  FEditOffset := 0;
  FCurrentPPI := Screen.PixelsPerInch;
  FButtonWidth := Round(11 * FCurrentPPI / frx_DefaultPPI);
end;

destructor TfrxCustomComboBox.Destroy;
begin
  inherited Destroy;
  {$IFNDEF FPC}
  FreeObjectInstance(FListInstance);
  {$ENDIF}
end;


procedure TfrxCustomComboBox.DoPPIChanged(aNewPPI: Integer);
begin
  FButtonWidth := MulDiv(11, aNewPPI, FCurrentPPI);
  FListWidth := MulDiv(FListWidth, aNewPPI, FCurrentPPI);
end;


procedure TfrxCustomComboBox.SetListWidth(const Value: Integer);
begin
  FListWidth := MulDiv(Value, FCurrentPPI, frx_DefaultPPI);
end;

procedure TfrxCustomComboBox.SetReadOnly(Value: Boolean);
begin
  if FReadOnly <> Value then
  begin
    FReadOnly := Value;
    {$IFDEF FPC}
    inherited ReadOnly := Value;
    {$ELSE}
    if HandleAllocated then
      SendMessage(EditHandle, EM_SETREADONLY, Ord(Value), 0);
    {$ENDIF}
  end;
end;

procedure TfrxCustomComboBox.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  {$IFNDEF FPC}
  with Params do
    Style := (Style and not CBS_DROPDOWNLIST) or CBS_OWNERDRAWFIXED or CBS_DROPDOWN;
  {$ENDIF}
end;

function TfrxCustomComboBox.GetScale: Single;
begin
  Result := FCurrentPPI / frx_DefaultPPI;
end;

{$IFNDEF FPC}
procedure TfrxCustomComboBox.CreateWnd;
begin
  inherited;
  SendMessage(EditHandle, EM_SETREADONLY, Ord(FReadOnly), 0);
  // Desiding, which of the handles is DropDown list handle...
  if FChildHandle <> EditHandle then
    FListHandle := FChildHandle;
  //.. and superclassing it
  FDefListProc := Pointer(GetWindowLong(FListHandle, GWL_WNDPROC));
  SetWindowLong(FListHandle, GWL_WNDPROC, frxInteger(FListInstance));
end;

procedure TfrxCustomComboBox.ListWndProc(var Message: TMessage);
var
  p: TPoint;

  procedure CallDefaultProc;
  begin
    with Message do
      Result := CallWindowProc(FDefListProc, FListHandle, Msg, WParam, LParam);
  end;

begin
  case Message.Msg of
    LB_SETTOPINDEX:
      begin
        if ItemIndex > DropDownCount then
          CallDefaultProc;
      end;
    WM_WINDOWPOSCHANGING:
      with TWMWindowPosMsg(Message).WindowPos^ do
      begin
        // calculating the size of the drop down list
        if FListWidth <> 0 then
          cx := FListWidth else
          cx := Width;
        cy := GetListHeight;
        p.x := cx;
        p.y := cy + GetFontHeight(Font) + 6;
        p := ClientToScreen(p);
        FUpDropdown := False;
        if p.y > Screen.Height then //if DropDownList showing below
          begin
            FUpDropdown := True;
          end;
      end;
    else
      CallDefaultProc;
  end;
end;

procedure TfrxCustomComboBox.WndProc(var Message: TMessage);
begin
  case Message.Msg of
    WM_SETTEXT:
      Invalidate;
     WM_PARENTNOTIFY:
       if LoWord(Message.wParam)=WM_CREATE then begin
         if FDefListProc <> nil then
           begin
             // This check is necessary to be sure that combo is created, not
             // RECREATED (somehow CM_RECREATEWND does not work)
             SetWindowLong(FListHandle, GWL_WNDPROC, frxInteger(FDefListProc));
             FDefListProc := nil;
             FChildHandle := Message.lParam;
           end
          else
           begin
             // WM_Create is the only event I found where I can get the ListBox handle.
             // The fact that combo box usually creates more then 1 handle complicates the
             // things, so I have to have the FChildHandle to resolve it later (in CreateWnd).
             if FChildHandle = 0 then
               FChildHandle := Message.lParam
             else
               FListHandle := Message.lParam;
           end;
       end;
    WM_WINDOWPOSCHANGING:
      {$IFDEF FPC}
      {$warning MoveWindow can't be used here - we have resize loop and crash.}
      {$ELSE}
      MoveWindow(EditHandle, 3+FEditOffset, 3, Width-FButtonWidth-8-FEditOffset,
        Height-6, True);
      {$ENDIF}
  end;
  inherited;
end;

procedure TfrxCustomComboBox.WMDpiChanged(var Message: TMessage);
var
  NewPPI: Integer;
begin
  Inherited;
  NewPPI := frxGetDpiForWindow(Handle);
  if NewPPI = FCurrentPPI then Exit;
  DoPPIChanged(NewPPI);
  FCurrentPPI := NewPPI;
end;

procedure TfrxCustomComboBox.WMPaint(var Message: TWMPaint);
var
  PS, PSE: TPaintStruct;
begin
  BeginPaint(Handle,PS);
  try
    if Enabled then
    begin
      DrawImage(PS.HDC, ItemIndex ,Rect(3, 3, FEditOffset + 3, Height - 3));
      if GetSolidBorder then
      begin
        PaintBorder(PS.HDC, True);
        if DroppedDown then
          PaintButton(2)
        else
          PaintButton(1);
      end else
      begin
        PaintBorder(PS.HDC, False);
        PaintButton(0);
      end;
    end else
    begin
      {$IFNDEF FPC}
      BeginPaint(EditHandle, PSE);
      try
        PaintDisabled;
      finally
        EndPaint(EditHandle, PSE);
      end;
      {$ENDIF}
    end;
  finally
    EndPaint(Handle,PS);
  end;
  Message.Result := 0;
end;

procedure TfrxCustomComboBox.DrawImage(DC: HDC; Index: Integer; R: TRect);
begin
  if FEditOffset > 0 then
   FillRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
end;

procedure TfrxCustomComboBox.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  ComboProc: Pointer);
var
  DC: HDC;
begin
  inherited;
  if (ComboWnd = EditHandle) then
    case Message.Msg of
      WM_SETFOCUS:
        begin
          DC:=GetWindowDC(Handle);
          PaintBorder(DC,True);
          PaintButton(1);
          ReleaseDC(Handle,DC);
        end;
      WM_KILLFOCUS:
        begin
          DC:=GetWindowDC(Handle);
          PaintBorder(DC,False);
          PaintButton(0);
          ReleaseDC(Handle,DC);
        end;
    end;
end;

procedure TfrxCustomComboBox.CNCommand(var Message: TWMCommand);
begin
  inherited;
  if (Message.NotifyCode in [CBN_CLOSEUP]) then
    PaintButton(1);
end;

procedure TfrxCustomComboBox.PaintBorder(DC: HDC; const SolidBorder: Boolean);
var
  R: TRect;
begin
  GetWindowRect(Handle, R);
  OffsetRect(R, -R.Left, -R.Top);
  if SolidBorder then
    FrameRect(DC, R, GetSysColorBrush(COLOR_HIGHLIGHT))
  else
    FrameRect(DC, R, GetSysColorBrush(COLOR_BTNFACE));
  InflateRect(R, -1, -1);
  FrameRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
  InflateRect(R, -1, -1);
  R.Right:=R.Right - FButtonWidth - 2;
  FrameRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
end;

procedure TfrxCustomComboBox.PaintButton(ButtonStyle: Integer);
var
  R: TRect;
  DC: HDC;

  procedure FillButton(DC: HDC; R: TRect; Color: TColor);
  var
    Brush, SaveBrush: HBRUSH;
  begin
    Brush := CreateSolidBrush(ColorToRGB(Color));
    SaveBrush := SelectObject(DC, Brush);
    FillRect(DC, R, Brush);
    SelectObject(DC, SaveBrush);
    DeleteObject(Brush);
  end;

  procedure PaintButtonLine(DC: HDC; Color: TColor);
  var
    Pen, SavePen: HPEN;
    R: TRect;
  begin
    GetWindowRect(Handle, R);
    OffsetRect (R, -R.Left, -R.Top);
    InflateRect(R, -FButtonWidth - 4, -1);
    Pen := CreatePen(PS_SOLID, 1, ColorToRGB(Color));
    SavePen := SelectObject(DC, Pen);
    MoveToEx(DC, R.Right, R.Top, nil);
    LineTo(DC, R.Right, R.Bottom);
    SelectObject(DC, SavePen);
    DeleteObject(Pen);
  end;

begin
  DC := GetWindowDC(Handle);
  //X := Trunc(FButtonWidth / 2) + Width - FButtonWidth - 4;
  //Y := Trunc((Height - 4) / 2) + 1;

  SetRect(R, Width - FButtonWidth - 3, 1, Width - 1, Height - 1);
  if ButtonStyle = 0 then //No 3D border
  begin
    FillButton(DC, R, clBtnFace);
    FrameRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
    PaintButtonLine(DC, clWindow);
    frxDrawArrow(Canvas, R, clBtnText);
  end;
  if ButtonStyle = 1 then //3D up border
  begin
    FillButton(DC, R, frxBlend(clHighlight, clWindow, 30));
    PaintButtonLine(DC, clHighlight);
    frxDrawArrow(Canvas, R, clBtnText);
  end;
  if ButtonStyle = 2 then //3D down border
  begin
    FillButton(DC, R, frxBlend(clHighlight, clWindow, 50));
    PaintButtonLine(DC, clHighlight);
    frxDrawArrow(Canvas, R, clCaptionText);
  end;
  ReleaseDC(Handle, DC);
end;

procedure TfrxCustomComboBox.PaintDisabled;
var
  R: TRect;
  Brush, SaveBrush: HBRUSH;
  DC: HDC;
  BtnShadowBrush: HBRUSH;
begin
  BtnShadowBrush := GetSysColorBrush(COLOR_BTNSHADOW);
  DC := GetWindowDC(Handle);
  Brush := CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  SaveBrush := SelectObject(DC, Brush);
  FillRect(DC, ClientRect, Brush);
  SelectObject(DC, SaveBrush);
  DeleteObject(Brush);
  GetWindowRect(Handle, R);
  OffsetRect(R, -R.Left, -R.Top);
  FrameRect(DC, R, BtnShadowBrush);
  SetRect(R, Width - FButtonWidth - 3, 1, Width - 1, Height - 1);
  frxDrawArrow(Canvas, R, clGrayText);
  ReleaseDC(Handle,DC);
end;

procedure TfrxCustomComboBox.Resize;
var
  m: TMessage;
begin
  inherited;
  m.Msg := FRX_WM_DPICHANGED_AFTERPARENT;
  WMDpiChanged(m);
end;

function TfrxCustomComboBox.GetSolidBorder: Boolean;
begin
  Result := ((csDesigning in ComponentState)) or
    (DroppedDown or (GetFocus = {$IFDEF FPC}Handle{$ELSE}EditHandle{$ENDIF}) or msMouseInControl);
end;

function TfrxCustomComboBox.GetListHeight: Integer;
begin
  Result := ItemHeight * Min(DropDownCount, Items.Count) + 2;
  if (DropDownCount <= 0) or (Items.Count = 0) then
    Result := ItemHeight + 2;
end;
{$ELSE}
procedure TfrxCustomComboBox.SelectAllWhenClicked(Sender: TObject);
begin
  SelectAll;
end;
{$ENDIF}
procedure TfrxCustomComboBox.CMEnabledChanged(var Msg: TMessage);
begin
  inherited;
  Invalidate;
end;

procedure TfrxCustomComboBox.CMMouseEnter(var Message: TMessage);
var
  DC: HDC;
begin
  inherited;
  msMouseInControl := True;
  {$IFDEF FPC}
  {$note FIXME TfrxCustomComboBox.CMMouseEnter}
  {$ELSE}
  if Enabled and not (GetFocus = EditHandle) and not DroppedDown then
  begin
    DC:=GetWindowDC(Handle);
    PaintBorder(DC, True);
    PaintButton(1);
    ReleaseDC(Handle, DC);
  end;
  {$ENDIF}
end;

procedure TfrxCustomComboBox.CMMouseLeave(var Message: TMessage);
var
  DC: HDC;
begin
  inherited;
  msMouseInControl := False;
  {$IFDEF FPC}
  {$note FIXME TfrxCustomComboBox.CMMouseLeave}
  {$ELSE}
  if Enabled  and not (GetFocus = EditHandle) and not DroppedDown then
  begin
    DC:=GetWindowDC(Handle);
    PaintBorder(DC, False);
    PaintButton(0);
    ReleaseDC(Handle, DC);
  end;
  {$ENDIF}
end;

procedure TfrxCustomComboBox.KeyPress(var Key: Char);
var
 sPos: Integer;
 {$IFDEF FPC}
 Mask: boolean;
 i: Integer;
 Bufstr: String;
 {$ELSE}
 sLen: Integer;
 {$ENDIF}
begin
  inherited KeyPress(Key);
  {$IFDEF FPC}
  if(Key=#8) then exit;
  Bufstr := AnsiUpperCase(Text);
  Delete(Bufstr, SelStart+1, SelLength);
  Bufstr := Bufstr + AnsiUpperCase(Key);
  Mask := false;
  for i:= 0 to Items.Count-1 do
    if(Pos(Bufstr, AnsiUpperCase(Items[i]))=1) then
    begin
      sPos := Bufstr.Length;
      ItemIndex:=i;
      Click();
      SelStart := sPos;
      SelLength := Length(Text)-sPos;
      Mask := True;
      break;
    end;
  if (Mask) or (OnlyMask) then
    Key := #0;
  {$ELSE}
  if (ItemIndex >= 0) and (ItemIndex < Items.Count) then
  begin
    sPos := SelStart;
    sLen := SelLength;
    Text := Items[ItemIndex];
    SelStart := sPos;
    SelLength := sLen;
  end;
  {$ENDIF}
end;

procedure TfrxCustomComboBox.CMFontChanged(var Message: TMessage);
begin
  inherited;
  ItemHeight := GetFontHeight(Font);
  {$IFNDEF FPC}
  RecreateWnd;
  {$ENDIF}
end;

{ TfrxFontComboBox }

function CreateBitmap(ResName: PChar): TBitmap;
begin
   Result := TBitmap.Create;
   Result.Handle := LoadBitmap(HInstance, ResName);
   if Result.Handle = 0 then
   begin
     Result.Free;
     Result := nil;
   end;
end;

function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
  FontType: Integer; Data: Pointer): Integer; stdcall;
begin
  if (TStrings(Data).IndexOf(LogFont.lfFaceName) < 0) then
    TStrings(Data).AddObject(LogFont.lfFaceName, TObject(FontType));
  Result := 1;
end;

constructor TfrxFontComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  {$IFNDEF FPC}
  if not (csDesigning in ComponentState) then
    frFontViewForm := TfrxFontPreview.Create(Self);
  {$ENDIF}
  Width := 150;
  DoPPIChanged(Screen.PixelsPerInch);
  FShowMRU := True;
  Numused := -1;
  MRURegKey := '';
  FIni := nil;
end;

destructor TfrxFontComboBox.Destroy;
begin
  FTrueTypeBMP.Free;
  FDeviceBMP.Free;
  if FIni <> nil then
    Fini.Free;
  {$IFNDEF FPC}
  if not (csDesigning in ComponentState) then
    frFontViewForm.Destroy;
  {$ENDIF}
  inherited Destroy;
end;

procedure TfrxFontComboBox.DoPPIChanged(aNewPPI: Integer);
begin
  inherited;
  FreeAndNil(FTrueTypeBMP);
  FreeAndNil(FDeviceBMP);
  FTrueTypeBMP := CreateBitmap('FRXTRUETYPE_FNT');
  FDeviceBMP := CreateBitmap('FRXDEVICE_FNT');
  ScaleBitmap(FTrueTypeBMP, aNewPPI);
  ScaleBitmap(FDeviceBMP, aNewPPI);
  DropDownCount := 12;
  {$IFNDEF FPC}
  FEditOffset := FTrueTypeBMP.Width;
  FReadOnly := True;
  {$ELSE}
  OnlyMask := True;
  {$ENDIF}
end;

procedure TfrxFontComboBox.Loaded;
begin
  inherited Loaded;
  if csDesigning in ComponentState then exit;
  FUpdate := True;
  try
    PopulateList;
    if Items.IndexOf(Text) = -1 then
      ItemIndex:=0;
  finally
    FUpdate := False;
  end;
end;

procedure TfrxFontComboBox.SetRegKey(Value: String);
begin
  if Value = '' then
    FRegKey := '\Software\Fast Reports\MRUFont' else
    FRegKey := Value;
end;

procedure TfrxFontComboBox.PopulateList;
var
  LFont: TLogFont;
  DC: HDC;
//  {$IFNDEF NONWINFPC}
 // Reg: TRegistry;
//  {$ENDIF}
  s: String;
  i: Integer;
  str: TStringList;
begin
  Sorted:=True;
  Items.BeginUpdate;
  str := TStringList.Create;
  str.Sorted := True;
  try
    Clear;
    DC := GetDC(0);
    try
      FillChar(LFont, sizeof(LFont), 0);
      LFont.lfCharset := DEFAULT_CHARSET;
      {$IFDEF FPC}
      EnumFontFamiliesEx(DC, @LFont, FontEnumExProc(@EnumFontsProc), PtrUInt(str), 0);
      {$ELSE}
      EnumFontFamiliesEx(DC, LFont, @EnumFontsProc, frxInteger(str), 0);
      {$ENDIF}
    finally
      ReleaseDC(0, DC);
    end;
    if frxPrinters.HasPhysicalPrinters then
    try
      FillChar(LFont, sizeof(LFont), 0);
      LFont.lfCharset := DEFAULT_CHARSET;
      if frxPrinters.Printer <> nil then
      begin

        {$IFDEF NONWINFPC}
        DC := GetDC(0);
        try
          EnumFontFamiliesEx(DC, @LFont, FontEnumExProc(@EnumFontsProc), PtrUInt(str), 0);
        finally
          ReleaseDC(0, DC);
        end;
        {$ELSE}
        EnumFontFamiliesEx(frxPrinters.Printer.Canvas.Handle,
          {$IFDEF FPC}@LFont{$ELSE}LFont{$ENDIF}, @EnumFontsProc, frxInteger(str), 0);
        {$ENDIF}
      end;
    except;
    end;
  finally
    Items.Assign(str);
    Items.EndUpdate;
  end;
  str.Free;
  Sorted := False;
 // {$IFNDEF NONWINFPC}
  if (FShowMRU) and (FIni <> nil) then
  begin
    NumUsed := -1;
    Items.BeginUpdate;
    //Reg:=TRegistry.Create;
    try
      //Reg.OpenKey(FRegKey, True);
      for i := 4 downto 0 do
      begin
        s := Fini.ReadString('MRUFont', 'Font' + IntToStr(i), '');
        if (s <> '') and (Items.IndexOf(s) <> -1) then
        begin
          Items.InsertObject(0, s, TObject(Fini.ReadInteger('MRUFont', 'FontType' + IntToStr(i), 0)));
          Inc(Numused);
        end else
        begin
          Fini.WriteString('MRUFont', 'Font' + IntToStr(i), '');
          Fini.WriteInteger('MRUFont', 'FontType' + IntToStr(i), 0);
        end;
      end;
    finally
      Items.EndUpdate;
    end;
  end;
  //{$ENDIF}
end;

procedure TfrxFontComboBox.DrawImage(DC: HDC; Index: Integer; R: TRect);
var
  C: TCanvas;
  Bitmap: TBitmap;
begin
  inherited;
  Index := Items.IndexOf(Text);
  if Index = -1 then exit;
  C := TCanvas.Create;
  C.Handle := DC;
  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
    C.Brush.Color := clWindow;
    C.BrushCopy(Bounds(R.Left, (R.Top + R.Bottom - Bitmap.Height)
     div 2, Bitmap.Width, Bitmap.Height), Bitmap, Bounds(0, 0, Bitmap.Width,
     Bitmap.Height), Bitmap.TransparentColor);
  end;
  C.Free;
end;


procedure TfrxFontComboBox.DrawItem(Index: Integer; Rect: TRect;
  State: TOwnerDrawState);
var
  Bitmap: TBitmap;
  BmpWidth: Integer;
  Text: array[0..255] of Char;
{$IFNDEF FPC}
  tWidth: Integer;
{$ENDIF}
begin
 {$IFNDEF FPC}
 if odSelected in State then
 begin
   frFontViewForm.SetDefaultFontSize(FCurrentPPI);
   frFontViewForm.FPanel.Caption := Self.Items[index];
   frFontViewForm.FPanel.Font.Name := Self.Items[index];
   { use one of the Icon's bitmaps to calculate size of text }
   { we do not use it to output any text, so it shouldn't impact draw }
   FTrueTypeBMP.Canvas.Font.Assign(frFontViewForm.FPanel.Font);
   tWidth := FTrueTypeBMP.Canvas.TextWidth(frFontViewForm.FPanel.Caption);
   if tWidth > frFontViewForm.Width then
     frFontViewForm.FPanel.Font.Height := Round(frFontViewForm.FPanel.Font.Height / (tWidth / frFontViewForm.Width));
 end;
 {$ENDIF}
 with Canvas do
 begin
   BmpWidth  := 15;
   FillRect(Rect);
   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+1 , (Rect.Top + Rect.Bottom - Bitmap.Height)
       div 2, Bitmap.Width, Bitmap.Height), Bitmap, Bounds(0, 0, Bitmap.Width,
       Bitmap.Height), Bitmap.TransparentColor);
   end;
   StrPCopy(Text, Items[Index]);
   Rect.Left := Rect.Left + BmpWidth + 2;
   DrawText(Canvas.Handle, Text, StrLen(Text), Rect,
{$IFDEF Delphi4}
   DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX));
{$ELSE}
   DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX);
{$ENDIF}
   if (Index = Numused) then
   begin
     Pen.Color := clBtnShadow;
     MoveTo(0,Rect.Bottom - 2);
     LineTo(width, Rect.Bottom - 2);
   end;
   if (Index = Numused + 1) and (Numused <> -1) then
   begin
     Pen.Color := clBtnShadow;
     MoveTo(0, Rect.Top);
     LineTo(width, Rect.Top);
   end;
 end;
end;

procedure TfrxFontComboBox.CMFontChanged(var Message: TMessage);
begin
  inherited;
  Init;
end;

procedure TfrxFontComboBox.CMFontChange(var Message: TMessage);
begin
  inherited;
  Reset;
end;

procedure TfrxFontComboBox.Init;
begin
  if GetFontHeight(Font) > FTrueTypeBMP.Height then
    ItemHeight := GetFontHeight(Font)
  else
    ItemHeight := FTrueTypeBMP.Height + 1;
  {$IFNDEF NONWINFPC}
  {$IFDEF FPC}
  // if HandleAllocated then
  //  RecreateWnd(Self);
  {$ELSE}
  RecreateWnd;
  {$ENDIF}
  {$ENDIF}
end;

procedure TfrxFontComboBox.Click;
begin
 inherited Click;
 if not (csReading in ComponentState) then
   if not FUpdate and Assigned(FOnClick) then FOnClick(Self);
end;

procedure TfrxFontComboBox.Reset;
begin
  if csDesigning in ComponentState then exit;
  FUpdate := True;
  try
    PopulateList;
    if Items.IndexOf(Text) = -1 then
      ItemIndex := 0;
  finally
    FUpdate := False;
  end;
end;
{$IFNDEF FPC}
procedure TfrxFontComboBox.CNCommand(var Message: TWMCommand);
var
  pnt:TPoint;
  ind, i, sWidth:integer;
  m: TMonitor;
  //{$IFNDEF NONWINFPC}
  //Reg: TRegistry;
  //{$ENDIF}
begin
  inherited;
  if (Message.NotifyCode in [CBN_CLOSEUP]) then
  begin
    frFontViewForm.Visible := False;
    ind := itemindex;
    if (ItemIndex = -1) or (ItemIndex = 0) then exit;
    if FShowMRU then
    begin
      Items.BeginUpdate;
      if Items.IndexOf(Items[ind]) <= Numused then
      begin
        Items.Move(Items.IndexOf(Items[ind]), 0);
        ItemIndex := 0;
      end else
      begin
        Items.InsertObject(0, Items[ItemIndex], Items.Objects[ItemIndex]);
        Itemindex := 0;
        if Numused < 4 then
          Inc(Numused)
        else
          Items.Delete(5);
      end;
      Items.EndUpdate;
     // {$IFNDEF NONWINFPC}
      //Reg := TRegistry.Create;
      if (FIni <> nil) then
      begin
        //Reg.OpenKey(FRegKey,True);
        for i := 0 to 4 do
          if i <= Numused then
          begin
           FIni.WriteString('MRUFont', 'Font' + IntToStr(i), Items[i]);
           FIni.WriteInteger('MRUFont', 'FontType' + IntToStr(i), Integer(Items.Objects[i]));
         end else
         begin
           FIni.WriteString('MRUFont', 'Font' + IntToStr(i), '');
           Fini.WriteInteger('MRUFont', 'FontType' + IntToStr(i), 0);
         end;
      end;
    end;
  end;
  if (Message.NotifyCode in [CBN_DROPDOWN]) then
  begin
    {$IFDEF NONWINFPC}
    {$note TfrxFontComboBox.CNCommand fix LB_SETCURSEL}
    {$ELSE}
    if ItemIndex < 5 then
      PostMessage(FListHandle, LB_SETCURSEL, 0, 0);
    {$ENDIF}
    pnt.x := Self.Left + Self.Width;
    pnt.y := Self.Top + Self.Height;
    pnt := Parent.ClientToScreen(pnt);
    frFontViewForm.Top := pnt.y;
    frFontViewForm.Left := pnt.x + 1;
    m := Screen.MonitorFromWindow(Self.Handle, mdNearest);
    if Assigned(m) then
      sWidth := m.WorkareaRect.Right
    else
      sWidth := Screen.Width;

    if frFontViewForm.Left + frFontViewForm.Width > sWidth then
    begin
      pnt.x := Self.Left;
      pnt := Parent.ClientToScreen(pnt);
      frFontViewForm.Left := pnt.x - frFontViewForm.Width - 1;
    end;
    if FUpDropdown then
    begin
      pnt.y := Self.Top;
      pnt := Parent.ClientToScreen(pnt);
      frFontViewForm.Top := pnt.y - frFontViewForm.Height;
    end;
    frFontViewForm.Visible := True;
  end;
end;
{$ENDIF}


{ TfrxFontPreview }

constructor TfrxFontPreview.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Width := 200;
  Height := 50;
  Visible := False;
  Parent := AOwner as TWinControl;

  FPanel := TPanel.Create(Self);
  with FPanel do
  begin
    Parent := Self;
    Color := clWindow;
    {$IFNDEF FPC}
    Ctl3D := False;
    ParentCtl3D := False;
    {$ENDIF}
    BorderStyle := bsSingle;
    BevelInner := bvNone;
    BevelOuter := bvNone;
    Font.Color := clWindowText;
    Font.Size := 18;
    Align := alClient;
  end;
end;

destructor TfrxFontPreview.Destroy;
begin
  FPanel.Free;
  FPanel := nil;
  inherited Destroy;
end;

procedure TfrxFontPreview.SetDefaultFontSize(aNewPPI: Integer);
begin
  FPanel.Font.Size := 18;
  FPanel.Font.Height := MulDiv(FPanel.Font.Height, aNewPPI, frx_DefaultPPI);
end;

procedure TfrxFontPreview.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams( Params);
    with Params do begin
      Style := WS_POPUP or WS_CLIPCHILDREN;
      ExStyle := WS_EX_TOOLWINDOW;
      {$IFNDEF NONWINFPC}
      WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
      {$ENDIF}
    end;
end;


{ TfrxComboEdit }

constructor TfrxComboEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Style := csSimple;
  Height := 21;
  FPanel := TPanel.Create(Self);
  FPanel.Parent := Self;
  FPanel.SetBounds(Width - Height + 2, 2, Height - 4, Height - 4);
  FButton := TSpeedButton.Create(Self);
  FButton.Parent := FPanel;
  FButton.SetBounds(0, 0, FPanel.Width, FPanel.Height);
  FButton.OnClick := ButtonClick;
  FButtonEnabled := True;
end;

procedure TfrxComboEdit.SetPos;
begin
  {$IFDEF NONWINFPC}
  {$note FIXME TfrxComboEdit.SetPos}
  {$ELSE}
  SetWindowPos(EditHandle, 0, 0, 0, Width - Height - 4, ItemHeight,
    SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE)
  {$ENDIF}
end;

procedure TfrxComboEdit.CreateWnd;
begin
  inherited CreateWnd;
  SetPos;
end;

procedure TfrxComboEdit.WMSize(var Message: TWMSize);
begin
  inherited;
  FPanel.SetBounds(Width - Height + 2, 2, Height - 4, Height - 4);
end;

procedure TfrxComboEdit.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  FButton.Enabled := Enabled;
end;

procedure TfrxComboEdit.KeyPress(var Key: Char);
begin
  if (Key = Char(vk_Return)) or (Key = Char(vk_Escape)) then
    GetParentForm(Self).Perform(CM_DIALOGKEY, Byte(Key), 0);
  inherited KeyPress(Key);
end;

function TfrxComboEdit.GetGlyph: TBitmap;
begin
  Result := FButton.Glyph;
end;

{$IFDEF FPC}
{$IFNDEF NONWINFPC}
function TfrxComboEdit.GetEditHandle: HWND;
begin
  Result := LazHelper.GetComboEditHandle(Handle);
end;
{$ENDIF}
{$ENDIF}

procedure TfrxComboEdit.SetGlyph(Value: TBitmap);
begin
  FButton.Glyph := Value;
end;

function TfrxComboEdit.GetButtonHint: String;
begin
  Result := FButton.Hint;
end;

procedure TfrxComboEdit.SetButtonHint(Value: String);
begin
  FButton.Hint := Value;
end;

procedure TfrxComboEdit.SetButtonEnabled(Value: Boolean);
begin
  FButtonEnabled := Value;
  FButton.Enabled := Value;
end;

procedure TfrxComboEdit.ButtonClick(Sender: TObject);
begin
  SetFocus;
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Self);
end;


{ TfrxScrollWin }

constructor TfrxScrollWin.Create(AOwner: TComponent);
begin
  inherited;
  FSmallChange := 1;
  FLargeChange := 10;
  FHorzPage := 0;
  FVertPage := 0;
  FHideScrolls := False;
{$IFDEF Delphi7}
  ControlStyle := ControlStyle + [csNeedsBorderPaint];
{$ENDIF}
  FCurrentPPI := Screen.PixelsPerInch;
end;

procedure TfrxScrollWin.CreateParams(var Params: TCreateParams);
const
  BorderStyles: array[TBorderStyle] of DWORD = (0, WS_BORDER);
begin
  inherited;
  with Params do
  begin
    Style := Style or WS_CLIPCHILDREN or BorderStyles[FBorderStyle];
    if (not HideScrolls) then
      Style := Style or WS_HSCROLL or WS_VSCROLL;
    if {$IFNDEF FPC}Ctl3D and {$ENDIF} NewStyleControls and (FBorderStyle = bsSingle) then
    begin
      Style := Style and not WS_BORDER;
      ExStyle := ExStyle or WS_EX_CLIENTEDGE;
    end;
  end;
end;

procedure TfrxScrollWin.DoPPIChanged(aNewPPI: Integer);
begin

end;

procedure TfrxScrollWin.SetBorderStyle(const Value: TBorderStyle);
begin
  FBorderStyle := Value;
  {$IFNDEF NONWINFPC}
  {$IFDEF FPC}
  // if HandleAllocated then
  //  RecreateWnd(Self);
  {$ELSE}
  RecreateWnd;
  {$ENDIF}
  {$ENDIF}
end;

procedure TfrxScrollWin.WMDpiChanged(var Message: TMessage);
var
  NewPPI: Integer;
begin
  Inherited;
  NewPPI := frxGetDpiForWindow(Handle);
  if NewPPI = FCurrentPPI then Exit;
  DoPPIChanged(NewPPI);
  FCurrentPPI := NewPPI;
end;

procedure TfrxScrollWin.WMEraseBackground(var Message: TMessage);
begin
end;

procedure TfrxScrollWin.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  Message.Result := DLGC_WANTARROWS or DLGC_WANTTAB or DLGC_WANTALLKEYS;
end;

procedure TfrxScrollWin.SetHideScrolls(b: Boolean);
begin
  if (FHideScrolls <> b) then
  begin
    ShowScrollBar(Self.Handle, SB_BOTH, not b);
    ShowScrollBar(Self.Handle, SB_HORZ, not b);
    ShowScrollBar(Self.Handle, SB_VERT, not b);
    FHideScrolls := b;
  end;
end;

function TfrxScrollWin.GetLongPosition(DefValue: Integer; Code: Word): Integer;
var
  {$IFNDEF NONWINFPC}
  ScrollInfo: Windows.TScrollInfo;
  {$ELSE}
  ScrollInfo: TScrollInfo;
  {$ENDIF}
begin
  {$IFDEF FPC}
  FillChar(ScrollInfo, SizeOf(ScrollInfo), #0);
  {$ENDIF}
  ScrollInfo.cbSize := SizeOf(TScrollInfo);
  ScrollInfo.fMask := SIF_TRACKPOS;
  Result := DefValue;
  {$IFDEF NONWINFPC}
  if LCLIntf.GetScrollInfo(Handle, Code, ScrollInfo) then
  {$ELSE}
  if FlatSB_GetScrollInfo(Handle, Code, Windows.TScrollInfo(ScrollInfo)) then
  {$ENDIF}
    Result := ScrollInfo.nTrackPos;
end;

function TfrxScrollWin.GetScale: Single;
begin
  Result := FCurrentPPI / frx_DefaultPPI;
end;

function TfrxScrollWin.GetScaledFontSize: Integer;
var
  f: TFont;
begin
  { used to scale back font before saving }
  f := TFont.Create;
  try
    f.Assign(Font);
    f.Height := MulDiv(f.Height, Font.PixelsPerInch, FCurrentPPI);
    Result := f.Size;
  finally
    f.Free;
  end;
end;

procedure TfrxScrollWin.SetHorzPage(const Value: Integer);
begin
  FHorzPage := Value;
  HorzRange := HorzRange;
end;

procedure TfrxScrollWin.SetHorzPosition(Value: Integer);
begin
  if Assigned(FOnScrollPosChange) then
    FOnScrollPosChange(Self, frsHorizontal, Value);
  if Value > FHorzRange - FHorzPage then
    Value := FHorzRange - FHorzPage;
  if Value < 0 then
    Value := 0;
  if Value <> FHorzPosition then
  begin
    FHorzPosition := Value;
    SetPosition(Value, SB_HORZ);
    OnHScrollChange(Self);
  end;
end;

procedure TfrxScrollWin.SetHorzRange(Value: Integer);
begin
  if Assigned(FOnScrollMaxChange) and (Value - FHorzPage >= 0) then
    FOnScrollMaxChange(Self, frsHorizontal, Value - FHorzPage);
  FHorzRange := Value;
  UpdateScrollBar(Value, HorzPage, HorzPosition, SB_HORZ);
end;

procedure TfrxScrollWin.SetVertPage(const Value: Integer);
begin
  FVertPage := Value;
  VertRange := VertRange;
end;

procedure TfrxScrollWin.SetVertPosition(Value: Integer);
begin
  if Assigned(FOnScrollPosChange) then
    FOnScrollPosChange(Self, frsVertical, Value);
  if Value > FVertRange - FVertPage then
    Value := FVertRange - FVertPage;
  if Value < 0 then
    Value := 0;
  if Value <> FVertPosition then
  begin
    FVertPosition := Value;
    SetPosition(Value, SB_VERT);
    OnVScrollChange(Self);
  end;
end;

procedure TfrxScrollWin.SetVertRange(Value: Integer);
begin
  if Assigned(FOnScrollMaxChange) and (Value - FVertPage>=0) then
    FOnScrollMaxChange(Self, frsVertical, Value - FVertPage);
  FVertRange := Value;
  UpdateScrollBar(Value, VertPage, VertPosition, SB_VERT);
end;

procedure TfrxScrollWin.SetPosition(Value: Integer; Code: Word);
begin
  {$IFDEF NONWINFPC}
  LCLIntf.SetScrollPos(Handle, Code, Value, True);
  {$ELSE}
  FlatSB_SetScrollPos(Handle, Code, Value, True);
  {$ENDIF}
end;

procedure TfrxScrollWin.SetScaledFontSize(Value: Integer);
var
  f: TFont;
begin
  { used to scale back font before saving }
  f := TFont.Create;
  try
    f.Assign(Font);
    f.Size := Value;
    Font.Height := MulDiv(f.Height, FCurrentPPI, Font.PixelsPerInch);
  finally
    f.Free;
  end;
end;

procedure TfrxScrollWin.UpdateScrollBar(Max, Page, Pos: Integer; Code: Word);
var
  ScrollInfo:{$IFNDEF NONWINFPC}Windows.{$ENDIF}TScrollInfo;
begin
  if HideScrolls then
    Exit;
  {$IFDEF FPC}
  FillChar(ScrollInfo, SizeOf(ScrollInfo), #0);
  {$ENDIF}
  ScrollInfo.cbSize := SizeOf(ScrollInfo);
  ScrollInfo.fMask := SIF_ALL;
  ScrollInfo.nMin := 0;
  if Max < Page then
    Max := 0;
  ScrollInfo.nMax := Max;
  ScrollInfo.nPage := Page;
  ScrollInfo.nPos := Pos;
  ScrollInfo.nTrackPos := Pos;
  {$IFDEF NONWINFPC}
  LCLIntf.setScrollInfo(Handle, Code, ScrollInfo, True);
  {$ELSE}
  FlatSB_SetScrollInfo(Handle, Code, Windows.TScrollInfo(ScrollInfo), True);
  {$ENDIF}
end;

procedure TfrxScrollWin.Paint;
begin
  with Canvas do
  begin
    Brush.Color := Color;
    FillRect(Rect(0, 0, ClientWidth, ClientHeight));
  end;
end;

procedure TfrxScrollWin.WMHScroll(var Message: TWMHScroll);
begin
  case Message.ScrollCode of
    SB_LINEUP: HorzPosition := HorzPosition - FSmallChange;
    SB_LINEDOWN: HorzPosition := HorzPosition + FSmallChange;
    SB_PAGEUP: HorzPosition := HorzPosition - FLargeChange;
    SB_PAGEDOWN: HorzPosition := HorzPosition + FLargeChange;
    SB_THUMBPOSITION, SB_THUMBTRACK:
      HorzPosition := GetLongPosition(Message.Pos, SB_HORZ);
    SB_TOP: HorzPosition := 0;
    SB_BOTTOM: HorzPosition := HorzRange;
  end;
end;

procedure TfrxScrollWin.WMVScroll(var Message: TWMVScroll);
begin
  case Message.ScrollCode of
    SB_LINEUP: VertPosition := VertPosition - FSmallChange;
    SB_LINEDOWN: VertPosition := VertPosition + FSmallChange;
    SB_PAGEUP: VertPosition := VertPosition - FLargeChange;
    SB_PAGEDOWN: VertPosition := VertPosition + FLargeChange;
    SB_THUMBPOSITION, SB_THUMBTRACK:
      VertPosition := GetLongPosition(Message.Pos, SB_VERT);
    SB_TOP: VertPosition := 0;
    SB_BOTTOM: VertPosition := VertRange;
  end;
end;

procedure TfrxScrollWin.OnHScrollChange(Sender: TObject);
begin
end;

procedure TfrxScrollWin.OnVScrollChange(Sender: TObject);
begin
end;


{$IFDEF FPC}
{procedure RegisterUnitfrxCtrls;
begin
  RegisterComponents('Fast Report 6',[TfrxComboBox,
    TfrxFontComboBox, TfrxComboEdit,
    TfrxScrollWin
   ]);
end;

procedure Register;
begin
  RegisterUnit('frxCtrls',@RegisterUnitfrxCtrls);
end;}
{$ENDIF}

end.
