unit ListViewEx;

interface

uses
  Windows, Messages, SysUtils, Types, UITypes, Classes, Controls, Graphics,
  StdCtrls, ComCtrls, CommCtrl;

type
  TListViewEx = class(TListView)
  protected
    procedure KeyPress(var Key: Char); override;
  public
    constructor Create(AOwner: TComponent); override;
    function AdjustColumns: Boolean;
  published
    property Action;
    property Align;
    property AllocBy;
    property Anchors;
    property BevelEdges;
    property BevelInner;
    property BevelOuter;
    property BevelKind;
    property BevelWidth;
    property BiDiMode;
    property BorderStyle;
    property BorderWidth;
    property Checkboxes;
    property Color;
    property Columns;
    property ColumnClick;
    property Constraints;
    property Ctl3D;
    property DoubleBuffered;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Font;
    property FlatScrollBars;
    property FullDrag;
    property GridLines;
    property Groups;
    property HideSelection;
    property HotTrack;
    property HotTrackStyles;
    property HoverTime;
    property IconOptions;
    property Items;
    property LargeImages;
    property MultiSelect;
    property StyleElements;
    property OwnerData;
    property OwnerDraw;
    property GroupHeaderImages;
    property GroupView;
    property ReadOnly;
    property RowSelect;
    property ParentBiDiMode;
    property ParentColor;
    property ParentDoubleBuffered;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowColumnHeaders;
    property ShowWorkAreas;
    property ShowHint;
    property SmallImages;
    property SortType;
    property StateImages;
    property TabOrder;
    property TabStop;
    property Touch;
    property ViewStyle;
    property Visible;
    property OnAdvancedCustomDraw;
    property OnAdvancedCustomDrawItem;
    property OnAdvancedCustomDrawSubItem;
    property OnChange;
    property OnChanging;
    property OnClick;
    property OnColumnClick;
    property OnColumnDragged;
    property OnColumnRightClick;
    property OnCompare;
    property OnContextPopup;
    property OnCustomDraw;
    property OnCustomDrawItem;
    property OnCustomDrawSubItem;
    property OnCreateItemClass;
    property OnData;
    property OnDataFind;
    property OnDataHint;
    property OnDataStateChange;
    property OnDblClick;
    property OnDeletion;
    property OnDrawItem;
    property OnEdited;
    property OnEditing;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnGesture;
    property OnGetImageIndex;
    property OnGetSubItemImage;
    property OnDragDrop;
    property OnDragOver;
    property OnInfoTip;
    property OnInsert;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseActivate;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnSelectItem;
    property OnItemChecked;
    property OnStartDock;
    property OnStartDrag;
  end;

procedure Register;

implementation

uses Math;

procedure Register;
begin
  RegisterComponents('Rejbrand 2020', [TListViewEx]);
end;

{ TListViewEx }

function TListViewEx.AdjustColumns: Boolean;
var
  AutoSizeWidths: TArray<Integer>;
  TotalAutoSizeWidth: Integer;
  NumAutoSizeCols: Integer;
  i: Integer;
  FixedWidth: Integer;
  FreeWidth: Integer;
  VScrollLikely: Boolean;
  hdr: HWND;
  hdrRect: TRect;
  hdrHeight: Integer;
begin

  Result := False;

  if ViewStyle <> vsReport then
    Exit;

  SetLength(AutoSizeWidths, Columns.Count);
  FixedWidth := 0;
  TotalAutoSizeWidth := 0;
  NumAutoSizeCols := 0;
  for i := 0 to Columns.Count - 1 do
    if Columns[i].AutoSize then
    begin
      AutoSizeWidths[i] := Columns[i].Width;
      Inc(TotalAutoSizeWidth, AutoSizeWidths[i]);
      Inc(NumAutoSizeCols);
    end
    else
      Inc(FixedWidth, Columns[i].Width);

  if TotalAutoSizeWidth = 0 then
    Exit;

  hdr := ListView_GetHeader(Handle);
  if (hdr <> 0) and GetWindowRect(hdr, hdrRect) then
    hdrHeight := hdrRect.Height
  else
    hdrHeight := 24;

  if Items.Count > 0 then
    VScrollLikely := Items.Count * Items[0].DisplayRect(drBounds).Height >=
      Height - 2 * GetSystemMetrics(SM_CYEDGE) - hdrHeight
  else
    VScrollLikely := False;

  FreeWidth := Width - 2 * GetSystemMetrics(SM_CXEDGE) - FixedWidth;
  if VScrollLikely then
    Dec(FreeWidth, GetSystemMetrics(SM_CXVSCROLL));

  if FreeWidth < 6 * NumAutoSizeCols then
    Exit;

  for i := 0 to Columns.Count - 1 do
    if Columns[i].AutoSize then
      Columns[i].Width := Floor(FreeWidth * AutoSizeWidths[i] / TotalAutoSizeWidth);

  Result := True;

end;

constructor TListViewEx.Create(AOwner: TComponent);
begin
  inherited;
  DoubleBuffered := True;
end;

procedure TListViewEx.KeyPress(var Key: Char);
begin
  inherited;
  case Key of
    ^A:
      ListView_SetItemState(Handle, -1, LVIS_SELECTED, LVIS_SELECTED);
  end;
end;

end.
