home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kolekce / d456 / DCSLIB25.ZIP / DCGrids.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  75KB  |  2,802 lines

  1. {
  2.  BUSINESS CONSULTING
  3.  s a i n t - p e t e r s b u r g
  4.  
  5.          Components Library for Borland Delphi 4.x - 6.x
  6.          Copyright (c) 1998-2001 Alex'EM
  7.  
  8. }
  9. unit DCGrids;
  10.  
  11. {$R-}
  12. {$G+}
  13.  
  14. interface
  15. {$I DCConst.inc}
  16.  
  17. uses
  18.   Windows, Messages, Graphics, grids, classes, controls, sysutils, stdctrls, DCConst, dialogs;
  19.  
  20. type
  21.   TDragGridState = (dsNone, dsColMoving, dsHeaderMoving);
  22.   TDragMousePos  = (dmNone, dmColumn, dmGroupBox);
  23.  
  24.   TDCCustomGrid = class;
  25.   TDCFooter = class;
  26.  
  27.   PGroupBoxItem_tag = ^TGroupBoxItem;
  28.   TGroupBoxItem = packed record
  29.     LOffset: byte;
  30.     ColIndex: integer;
  31.     Size: TPoint;
  32.     MaxHeight: integer;
  33.   end;
  34.  
  35.   TDCGroupBoxList = class(TList)
  36.   private
  37.     FOwner: TDCCustomGrid;
  38.     FMargin: TPoint;
  39.     FBoxSize: integer;
  40.     FUpdateCount: integer;
  41.     FMovePos: integer;
  42.     FMoveIndex: integer;
  43.     FFixedCols: integer;
  44.     FReadOnly: boolean;
  45.     function GetBoxSize: integer;
  46.     function GetBoxItems(Index: integer): TGroupBoxItem;
  47.     procedure SetBoxItems(Index: integer; const Value: TGroupBoxItem);
  48.     function GetItemOffset(i: integer): integer;
  49.     function GetBoundsRect: TRect;
  50.     procedure SetMoveIndex(const Value: integer);
  51.     procedure SetFixedCols(const Value: integer);
  52.     procedure Changed;
  53.   protected
  54.     procedure Update; virtual;
  55.     procedure ColumnMoved(FromIndex, ToIndex: Longint); virtual;
  56.     procedure BeginUpdate;
  57.     procedure EndUpdate;
  58.     function UpdateSize: integer;
  59.     property MoveIndex: integer read FMoveIndex write SetMoveIndex;
  60.   public
  61.     constructor Create(AOwner: TDCCustomGrid);
  62.     procedure Draw;
  63.     function Add(AColIndex, ALOffset: integer): integer;
  64.     procedure Insert(Index, AColIndex, ALOffset: integer);
  65.     procedure Move(CurIndex, NewIndex: Integer);
  66.     procedure Delete(Index: integer);
  67.     procedure Clear; override;
  68.     function GetItemAtPos(APos: TPoint): integer;
  69.     function GetAreaAtPos(APos: TPoint): integer;
  70.     function GetItemRect(Index: integer): TRect;
  71.     procedure UpdateItemSize(Index: integer);
  72.     function  Find(AColIndex: integer): integer;
  73.     procedure Invalidate;
  74.     function PtConvert(APoint: TPoint): TPoint;
  75.     function MouseInBox(X, Y: integer; Convert: boolean): boolean;
  76.     property BoxSize: integer read GetBoxSize;
  77.     property BoxItems[Index: integer]: TGroupBoxItem read GetBoxItems write SetBoxItems;
  78.     property BoundsRect: TRect read GetBoundsRect;
  79.     property FixedCols: integer read FFixedCols write SetFixedCols;
  80.     property ReadOnly: boolean read FReadOnly write FReadOnly;
  81.   end;
  82.  
  83.   TDCFooterPanel = class(TCollectionItem)
  84.   private
  85.     FColIndex: integer;
  86.     FStyle: TBevelStyle;
  87.     FVisible: boolean;
  88.     procedure SetStyle(const Value: TBevelStyle);
  89.     procedure SetVisible(const Value: boolean);
  90.     function GetFooter: TDCFooter;
  91.     function GetCanvas: TCanvas;
  92.   protected
  93.     function AdjustHeight: integer; dynamic;
  94.     procedure SetInternalColIndex(const Value: integer);
  95.     procedure SetColIndex(const Value: integer); virtual;
  96.     function Draw(const Rect: TRect; DrawInfo: TGridDrawInfo): boolean; dynamic;
  97.     function GetColIndex: integer; virtual;
  98.   public
  99.     constructor Create(Collection: TCollection); override;
  100.     property ColIndex: integer read GetColIndex write SetColIndex;
  101.     property Footer: TDCFooter read GetFooter;
  102.     property Canvas: TCanvas read GetCanvas;
  103.   published
  104.     property Style: TBevelStyle read FStyle write SetStyle;
  105.     property Visible: boolean read FVisible write SetVisible;
  106.   end;
  107.  
  108.   TDCFooterTextPanel = class(TDCFooterPanel)
  109.   private
  110.     FText: string;
  111.     procedure SetText(const Value: string);
  112.   protected
  113.     function AdjustHeight: integer; override;
  114.     procedure DoDrawText(var Rect: TRect; Flags: Longint); dynamic;
  115.     function Draw(const Rect: TRect; DrawInfo: TGridDrawInfo): boolean; override;
  116.   public
  117.     function PaintEdge(Rect: TRect; DrawInfo: TGridDrawInfo): TRect;
  118.   published
  119.     property Text: string read FText write SetText;
  120.   end;
  121.  
  122.   TDCFooterPanels = class(TCollection)
  123.   private
  124.     FOwner: TDCFooter;
  125.     function GetItem(Index: Integer): TDCFooterPanel;
  126.     procedure SetItem(Index: Integer; Value: TDCFooterPanel);
  127.   protected
  128.     function GetOwner: TPersistent; override;
  129.     procedure Update(Item: TCollectionItem); override;
  130.   public
  131.     constructor Create(AOwner: TDCFooter);
  132.     function Add: TDCFooterPanel;
  133.     property Items[Index: Integer]: TDCFooterPanel read GetItem write SetItem; default;
  134.   end;
  135.  
  136.   TDCFooterClass = class of TDCFooter;
  137.   TDCFooters = class;
  138.  
  139.   TDCFooter = class(TPersistent)
  140.   private
  141.     FAutoSize: boolean;
  142.     FCanvas: TCanvas;
  143.     FHeight: integer;
  144.     FOwner: TDCFooters;
  145.     FPanels: TDCFooterPanels;
  146.     FStyle: TBevelStyle;
  147.     FVisible: boolean;
  148.     function GetColor: TColor;
  149.     function GetFont: TFont;
  150.     function GetGrid: TDCCustomGrid;
  151.     function GetVisible: boolean;
  152.     procedure SetHeight(const Value: integer);
  153.     procedure SetVisible(const Value: boolean);
  154.     procedure SetStyle(const Value: TBevelStyle);
  155.     procedure SetPanels(const Value: TDCFooterPanels);
  156.     function GetIndex: integer;
  157.     procedure SetIndex(const Value: integer);
  158.     procedure SetOwner(Value: TDCFooters);
  159.     procedure UpdatePanel(Index: Integer; Repaint: Boolean);
  160.     procedure SetAutoSize(const Value: boolean);
  161.   protected
  162.     procedure AdjustHeight;
  163.     procedure ColumnMoved(FromIndex, ToIndex: Integer); virtual;
  164.     procedure Changed(AllItems: boolean); virtual;
  165.     function GetHeight: integer; virtual;
  166.     property AutoSize: boolean read FAutoSize write SetAutoSize default True;
  167.     property Style: TBevelStyle read FStyle write SetStyle;
  168.     property Index: integer read GetIndex write SetIndex;
  169.     property Height: integer read GetHeight write SetHeight;
  170.     property Visible: boolean read GetVisible write SetVisible;
  171.   public
  172.     constructor Create(AOwner: TDCFooters);
  173.     destructor Destroy; override;
  174.     procedure DrawItem(ACanvas: TCanvas; DrawInfo: TGridDrawInfo;
  175.       const Rect: TRect; Index: integer); virtual;
  176.     property Canvas: TCanvas read FCanvas;
  177.     property Color: TColor read GetColor;
  178.     property Font: TFont read GetFont;
  179.     property Grid: TDCCustomGrid read GetGrid;
  180.     property Owner: TDCFooters read FOwner write SetOwner;
  181.     property Panels: TDCFooterPanels read FPanels write SetPanels;
  182.   end;
  183.  
  184.   TDCFooters = class(TPersistent)
  185.   private
  186.     FOwner: TDCCustomGrid;
  187.     FItems: TList;
  188.     FUpdateCount: integer;
  189.     FHeight: integer;
  190.     FStyle: TBevelStyle;
  191.     function GetCount: Integer;
  192.     function GetItem(Index: Integer): TDCFooter;
  193.     procedure SetItem(Index: Integer; const Value: TDCFooter);
  194.     procedure InsertItem(Item: TDCFooter);
  195.     procedure RemoveItem(Item: TDCFooter);
  196.     function GetHeight: integer;
  197.     function GetBoundsRect: TRect;
  198.     procedure SetStyle(const Value: TBevelStyle);
  199.   protected
  200.     procedure ColumnMoved(FromIndex, ToIndex: Longint); virtual;
  201.     procedure Changed;
  202.     function PaintEdge(ARect: TRect): TRect;
  203.     function GetOwner: TPersistent; override;
  204.     function GetMargins: TRect;
  205.     procedure Update(Item: TDCFooter);
  206.     function UpdateSize: integer;
  207.     procedure RedrawItem(Item: TDCFooter; Index: integer);
  208.     property UpdateCount: Integer read FUpdateCount;
  209.   public
  210.     constructor Create(AOwner: TDCCustomGrid);
  211.     destructor Destroy; override;
  212.     procedure BeginUpdate;
  213.     procedure Clear;
  214.     procedure Delete(Index: Integer);
  215.     procedure Draw;
  216.     procedure Invalidate;
  217.     procedure EndUpdate;
  218.     property BoundsRect: TRect read GetBoundsRect;
  219.     property Count: Integer read GetCount;
  220.     property Grid: TDCCustomGrid read FOwner;
  221.     property Items[Index: Integer]: TDCFooter read GetItem write SetItem;
  222.     property Height: integer read GetHeight;
  223.     property Style: TBevelStyle read FStyle write SetStyle;
  224.   end;
  225.  
  226.   TDataGridDesigner = class(TObject)
  227.   private
  228.     FDataGrid: TDCCustomGrid;
  229.   public
  230.     constructor Create(DataGrid: TDCCustomGrid);
  231.     destructor Destroy; override;
  232.     property DataGrid: TDCCustomGrid read FDataGrid;
  233.   end;
  234.  
  235.   TSelectedArea = class(TObject)
  236.   private
  237.     FGrid: TDCCustomGrid;
  238.   protected
  239.     function GetGrid: TDCCustomGrid;
  240.   public
  241.     constructor Create(AGrid: TDCCustomGrid);
  242.     destructor Destroy; override;
  243.     function IsEmpty: boolean; virtual;
  244.     property Grid: TDCCustomGrid read GetGrid;
  245.   end;
  246.  
  247.   TGridGroupBoxDropEvent = procedure (Sender: TObject; ColIndex,
  248.     Position: integer; var Allow: boolean) of object;
  249.   TGridGroupBoxMoveEvent = procedure (Sender: TObject; OldPosition,
  250.     NewPosition: integer; var Allow: boolean) of object;
  251.  
  252.   TGridOption  = (goAutoSize, goAdvancedSelect);
  253.   TGridOptions = set of TGridOption;
  254.  
  255.   TDCCustomGrid = class(TCustomGrid)
  256.   private
  257.     FArrowsVisible: boolean;
  258.     FClickedCol: integer;
  259.     FDesigner: TDataGridDesigner;
  260.     FDragImages: TImageList;
  261.     FDragState: TDragGridState;
  262.     FDragStartPos: TDragMousePos;
  263.     FDragStopPos: TDragMousePos;
  264.     FFooters: TDCFooters;
  265.     FGridOptions: TGridOptions;
  266.     FGrouping: boolean;
  267.     FGroupBoxList: TDCGroupBoxList;
  268.     FLockUpdate: boolean;
  269.     FLockCount: integer;
  270.     FMoveIndex, FMovePos: integer;
  271.     FMousePos: TPoint;
  272.     FOnGroupBoxInsert: TGridGroupBoxDropEvent;
  273.     FOnGroupBoxRemove: TGridGroupBoxDropEvent;
  274.     FOnGroupBoxMove: TGridGroupBoxMoveEvent;
  275.     FOutRange: boolean;
  276.     FScrollBars: TScrollStyle;
  277.     procedure CreateTitleDragImage(Origin: integer);
  278.     function DoGroupBoxClick(X, Y: integer): boolean;
  279.     procedure DoHeaderDragging(X, Y: Integer);
  280.     procedure DrawDragArrows(Hide: boolean);
  281.     function GetGrouping: boolean;
  282.     procedure HideDragImage;
  283.     procedure SetGrouping(const Value: boolean);
  284.     procedure SetGridOptions(const Value: TGridOptions);
  285.     procedure SetScrollBars(const Value: TScrollStyle);
  286.     procedure ShowDragImage;
  287.     procedure StartDragHeader(Origin: integer; DragStart: TDragMousePos);
  288.     procedure StopDragHeader(ApllyChanges: boolean);
  289.     procedure UpdateDragingIndex(X, Y: Integer);
  290.   protected
  291.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  292.     procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  293.     procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  294.     procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
  295.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  296.     procedure CMCancelMode(var Message: TMessage); message CM_CANCELMODE;
  297.     function BeginColumnDrag(var Origin, Destination: Integer;
  298.       const MousePt: TPoint): Boolean; override;
  299.     procedure BeginLayout; virtual;
  300.     function CanColResize(ACol: integer): boolean; virtual;
  301.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  302.     procedure ConstrainedResize(var MinWidth, MinHeight, MaxWidth, MaxHeight: Integer); override;
  303.     procedure CreateCellDragImage(ACol, ARow: integer; var DragImages: TImageList); virtual;
  304.     procedure DoColumnClick(Shift: TShiftState; ColIndex: integer); virtual;
  305.     procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
  306.     procedure DoGroupBoxInsertItem(ColIndex, Position: integer; var Allow: boolean); virtual;
  307.     procedure DoGroupBoxMoveItem(OldPosition, NewPosition: integer; var Allow: boolean); virtual;
  308.     procedure DoGroupBoxRemoveItem(ColIndex, Position: integer; var Allow: boolean); virtual;
  309.     procedure DoStartDrag(var DragObject: TDragObject); override;
  310.     function DrawTitleCell(ACanvas: TCanvas; ACol, ARow: Integer; ARect: TRect;
  311.       BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint; virtual;
  312.     procedure Endlayout; virtual;
  313.     function FlatButtons: boolean; virtual;
  314.     function GetBorderStyle: TEdgeBorderStyle; virtual;
  315.     function GetClientRect: TRect; override;
  316.     function GetGridBounds: TRect;
  317.     function GetDragImages: TDragImageList; override;
  318.     function GetRealColWidth(ColIndex: integer): integer; virtual;
  319.     function GetGroupingBoxSize: integer; virtual;
  320.     procedure GroupBoxChanged; virtual;
  321.     procedure LockUpdate;
  322.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  323.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  324.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  325.       X, Y: Integer); override;
  326.     function RawToDataColumn(ACol: Integer): Integer; virtual; abstract;
  327.     procedure ResizeColWidth(ACol, AWidth: integer); virtual;
  328.     procedure UpdateColWidths(StartIndex: integer; Direct: boolean);
  329.     procedure UnlockUpdate;
  330.     function UpdateLocked: boolean;
  331.     procedure WndProc(var Message: TMessage); override;
  332.     property Designer: TDataGridDesigner read FDesigner;
  333.     property DragState: TDragGridState read FDragState;
  334.     property ClickedCol: integer read FClickedCol write FClickedCol;
  335.     property GridOptions: TGridOptions read FGridOptions write SetGridOptions;
  336.     property GroupBox: TDCGroupBoxList read FGroupBoxList;
  337.     property Footers: TDCFooters read FFooters;
  338.     property OnGroupBoxInsert: TGridGroupBoxDropEvent read FOnGroupBoxInsert write FOnGroupBoxInsert;
  339.     property OnGroupBoxRemove: TGridGroupBoxDropEvent read FOnGroupBoxRemove write FOnGroupBoxRemove;
  340.     property OnGroupBoxMove: TGridGroupBoxMoveEvent read FOnGroupBoxMove write FOnGroupBoxMove;
  341.     property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars;
  342.   public
  343.     constructor Create(AOwner: TComponent); override;
  344.     destructor Destroy; override;
  345.     function GroupingEnabled: boolean; virtual;
  346.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  347.     procedure Paint; override;
  348.     property Grouping: boolean read GetGrouping write SetGrouping;
  349.   end;
  350.  
  351. const
  352.   nbmArrow      = 0;
  353.   nbmEdit       = 1;
  354.   nbmInsert     = 2;
  355.   nbmMultiDot   = 3;
  356.   nbmMultiArrow = 4;
  357.   nbmCheck      = 5;
  358.   nbmMain       = 6;
  359.   nbmIndexAsc   = 7;
  360.   nbmIndexDesc  = 8;
  361.   nbmIndexNone  = 9;
  362.   nbmCheckHrd   = 10;
  363.  
  364. function DrawTitleRect(ACanvas: TCanvas; ATextRect: TRect; AValue: string;
  365.   AAlignment: TAlignment; DrawRect: boolean; Images: TImageList = nil): TPoint;
  366.  
  367. function GDGetImages: TImageList;
  368.  
  369. implementation
  370.  
  371. uses DCPopupWindow, DCEditTools, Forms, CommCtrl;
  372.  
  373. const
  374.  HSCLT_IDEVENT = $1;
  375.  
  376. const
  377.   bmArrow      = 'DC_DBGARROW';
  378.   bmEdit       = 'DC_DBEDIT';
  379.   bmInsert     = 'DC_DBINSERT';
  380.   bmMultiDot   = 'DC_DBMULTIDOT';
  381.   bmMultiArrow = 'DC_DBMULTIARROW';
  382.   bmCheck      = 'DC_DBCHECK';
  383.   bmMain       = 'DC_DBMAIN';
  384.   bmIndexAsc   = 'DC_DBINDEXASC';
  385.   bmIndexDesc  = 'DC_DBINDEXDESC';
  386.   bmIndexNone  = 'DC_DBINDEXNONE';
  387.   bmCheckHrd   = 'DC_HDCHECK';
  388.  
  389. var
  390.  ArrowsBitmap: TBitmap;
  391.  GridIndicatorImages: TImageList;
  392.  
  393. { TDCCustomGrid }
  394.  
  395. function DrawTitleRect(ACanvas: TCanvas; ATextRect: TRect; AValue: string;
  396.   AAlignment: TAlignment; DrawRect: boolean; Images: TImageList = nil): TPoint;
  397. var
  398.  pText, pTextSub, pLine: PChar;
  399.  l: integer;
  400.  P: TPoint;
  401.  R: TRect;
  402.  
  403.  function aGetMax(aValue: array of integer): integer;
  404.   var
  405.    i, max: integer;
  406.   begin
  407.     max := -1;
  408.     Result := -1;
  409.     for i := Low(aValue) to High(aValue) do
  410.     begin
  411.       if aValue[i] > max then
  412.       begin
  413.         max := aValue[i];
  414.         Result := i;
  415.       end;
  416.     end;
  417.   end;
  418.  function aGetValue(aValue: array of pointer; index: integer): pointer;
  419.  begin
  420.    Result := aValue[index];
  421.  end;
  422.  
  423.  function GetEntry: PChar;
  424.   var
  425.    p1, p2, p3: PChar;
  426.    i1, i2, i3, index: integer;
  427.  begin
  428.    p1 := StrPos(pText, '#/');
  429.    p2 := StrPos(pText, #10);
  430.    p3 := StrPos(pText, #13);
  431.  
  432.    if p1<> nil then i1 := p1 - pText else i1 := -1;
  433.    if p2<> nil then i2 := p2 - pText else i2 := -1;
  434.    if p3<> nil then i3 := p3 - pText else i3 := -1;
  435.  
  436.    index := aGetMax([i1, i2, i3]);
  437.    if index = -1 then
  438.      Result := nil
  439.    else
  440.      Result := aGetValue([p1, p2, p3], index)
  441.  end;
  442.  
  443. begin
  444.   Result := Point(0, 0);
  445.   pText  := PChar(aValue);
  446.   R := ATextRect;
  447.   pLine := AllocMem(1);
  448.  
  449.   while (pText <> nil) and (pText^ <> #0) do
  450.   begin
  451.     pTextSub := GetEntry;
  452.     if pTextSub <> nil then
  453.       l := pTextSub - pText - 1
  454.     else
  455.       l := StrLen(pText);
  456.  
  457.     ReallocMem(pLine, l+1);
  458.     StrLCopy(pLine, pText, l);
  459.  
  460.     P := DrawHighLightText(ACanvas, pLine, ATextRect, 0, DT_NOPREFIX, Images);
  461.  
  462.     Result.X := _intMax(Result.X, P.X);
  463.     Result.Y := Result.Y + P.Y;
  464.  
  465.     case AAlignment  of
  466.       taCenter:
  467.         P.X := ATextRect.Left + (ATextRect.Right - P.X) div 2;
  468.       taRightJustify:
  469.         P.X := ATextRect.Right + ATextRect.Left - P.X;
  470.       taLeftJustify:
  471.         P.X := ATextRect.Right - P.X;
  472.     end;
  473.     if ATextRect.Left < P.X then R.Left := P.X else R.Left := ATextRect.Left;
  474.  
  475.     if DrawRect then DrawHighLightText(ACanvas, pLine, R, 1, DT_NOPREFIX, Images);
  476.     R.Top := R.Top + P.Y;
  477.  
  478.     pText := pTextSub;
  479.     if pText <> nil then
  480.     begin
  481.       if pText^ = '/' then Inc(pText, 2) else
  482.       begin
  483.        Inc(pText, 1);
  484.        if (pText^ = #10) or (pText^ = #13) then Inc(pText, 1);
  485.       end;
  486.     end;
  487.   end;
  488.   ReallocMem(pLine, 0);
  489. end;
  490.  
  491. function TDCCustomGrid.BeginColumnDrag(var Origin, Destination: Integer;
  492.   const MousePt: TPoint): Boolean;
  493. begin
  494.   Result := False;
  495.   StartDragHeader(Origin, dmColumn);
  496. end;
  497.  
  498. procedure TDCCustomGrid.CMCancelMode(var Message: TMessage);
  499. begin
  500.   if FDragState <> dsNone then StopDragHeader(True);
  501.   inherited;
  502. end;
  503.  
  504. function TDCCustomGrid.GroupingEnabled: boolean;
  505. begin
  506.   Result := True;
  507. end;
  508.  
  509. constructor TDCCustomGrid.Create(AOwner: TComponent);
  510. begin
  511.   inherited;
  512.   ControlStyle := ControlStyle + [csDisplayDragImage];
  513.   FClickedCol := -1;
  514.   FArrowsVisible := False;
  515.   FDragStartPos  := dmNone;
  516.   FDragStopPos   := dmNone;
  517.   FGroupBoxList  := TDCGroupBoxList.Create(Self);
  518.   FFooters       := TDCFooters.Create(Self);
  519.   
  520.   FMoveIndex := -1;
  521.   FMovePos   := -1;
  522.   FScrollBars    := ssBoth;
  523.   FLockUpdate    := False;
  524.   FLockCount     := 0;
  525. end;
  526.  
  527. procedure TDCCustomGrid.CreateTitleDragImage(Origin: integer);
  528.  var
  529.   ABitmap: TBitmap;
  530.   ARect: TRect;
  531. begin
  532.   if (Origin >= 0) and (Origin < ColCount) then
  533.   begin
  534.     ProcessPaintMessages;
  535.     ABitmap := TBitmap.Create;
  536.     try
  537.       with ABitmap do
  538.       begin
  539.         Width  := GetRealColWidth(Origin);
  540.         Height := RowHeights[0];
  541.         ARect  := Rect(0, 0, Width, Height);
  542.         DrawTitleCell(Canvas, RawToDataColumn(Origin), 0, ARect, dsUp, True, True);
  543.         DrawGridFrameBorder(Canvas, ARect, GetBorderStyle, dsUp, clBtnShadow);
  544.         if FDragImages = nil then FDragImages := TImageList.CreateSize(Width, Height);
  545.       end;
  546.       FDragImages.AddMasked(ABitmap, clNone);
  547.     finally
  548.       ABitmap.Free;
  549.     end;
  550.   end;
  551. end;
  552.  
  553. procedure TDCCustomGrid.DoHeaderDragging(X, Y: Integer);
  554.  var
  555.   P: TPoint;
  556. begin
  557.   P := Point(X, Y);
  558.   P := ClientToScreen(P);
  559.   FDragImages.DragCursor := Cursor;
  560.   FDragImages.DragMove(P.X, P.Y);
  561.   UpdateDragingIndex(X, Y);
  562. end;
  563.  
  564. procedure TDCCustomGrid.DrawDragArrows(Hide: boolean);
  565.  var
  566.   ACellRect, R, ArrowsRect: TRect;
  567.   P, Pos, HotSpot: TPoint;
  568.   ArrowPos,SizeX, SizeY: Integer;
  569.   ScreenDC: HDC;
  570.   ABrush, PBrush: HBRUSH;
  571.   APen, PPen: HPEN;
  572.   Points: array[0..6] of TPoint;
  573.   AColor: integer;
  574.  
  575.   function IsArrowDrawing: boolean;
  576.   begin
  577.     Result := False;
  578.     case FDragStopPos of
  579.       dmNone: Result := False;
  580.       dmColumn:
  581.         Result := (FMovePos <> FMoveIndex) and (FMovePos > -1);
  582.       dmGroupBox:
  583.         with FGroupBoxList do
  584.           Result := (FMovePos <> FMoveIndex) and (FMovePos > -1);
  585.     end;
  586.   end;
  587. begin
  588.   case FDragStopPos of
  589.     dmColumn:
  590.     begin
  591.       ACellRect := CellRect(FMovePos, 0);
  592.       P := Point(0, 0);
  593.       P := ClientToScreen(P);
  594.       OffsetRect(ACellRect, P.X, P.Y);
  595.       if (FMovePos > FMoveIndex) and (FMoveIndex > 0) or FOutRange then
  596.       begin
  597.         ArrowPos := ACellRect.Right;
  598.       end
  599.       else
  600.         ArrowPos := ACellRect.Left;
  601.     end;
  602.     dmGroupBox:
  603.     with FGroupBoxList do
  604.     begin
  605.       ACellRect := GetItemRect(FMovePos);
  606.       P := Point(0, 0);
  607.       P := ClientToScreen(P);
  608.       OffsetRect(ACellRect, P.X, P.Y);
  609.       if (FMovePos >= FMoveIndex) and ((FMoveIndex > -1) or (FMovePos >= Count)) then
  610.         ArrowPos := ACellRect.Right
  611.       else
  612.         ArrowPos := ACellRect.Left - 3;
  613.     end;
  614.     else
  615.       ArrowPos := 0;
  616.   end;
  617.  
  618.   with ACellRect do ArrowsRect := Rect(ArrowPos - 4, Top - 8, ArrowPos + 4, Bottom + 8);
  619.   InflateRect(ArrowsRect, 1, 1);
  620.   if Hide then
  621.   begin
  622.     if (FDragImages <> nil) and FDragImages.Dragging then
  623.     begin
  624.       ImageList_GetIconSize(ImageList_GetDragImage(@Pos, @HotSpot), SizeX, SizeY);
  625.       with Pos do R := Rect(X, Y, X + SizeX, Y + SizeY);
  626.       OffsetRect(R, -HotSpot.X, -HotSpot.Y);
  627.       if not IntersectRect(R, R, ArrowsRect) then Hide := False;
  628.     end
  629.   end;
  630.   if Hide then HideDragImage;
  631.  
  632.   ScreenDC := GetDCEx(GetDesktopWindow, 0, DCX_LOCKWINDOWUPDATE or DCX_CACHE or DCX_WINDOW);
  633.   try
  634.   if FArrowsVisible then
  635.   begin
  636.     with ArrowsBitmap, ArrowsRect do
  637.       BitBlt(ScreenDC, Left, Top, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
  638.     FArrowsVisible := False;
  639.   end
  640.   else
  641.     if IsArrowDrawing then
  642.     begin
  643.       with ArrowsBitmap, ArrowsRect do
  644.       begin
  645.         Width  := Right - Left;
  646.         Height := Bottom - Top;
  647.       end;
  648.       with ArrowsBitmap, ArrowsRect do
  649.         BitBlt(Canvas.Handle, 0, 0, Width, Height, ScreenDC, Left, Top, SRCCOPY);
  650.  
  651.       AColor := ColorToRGB(GetNearestColor(ScreenDC, clDragArrow));
  652.       APen := CreatePen(PS_SOLID, 1, AColor);
  653.       PPen := SelectObject(ScreenDC, APen);
  654.  
  655.       ABrush := CreateSolidBrush(AColor);
  656.       PBrush := SelectObject(ScreenDC, ABrush);
  657.  
  658.       try
  659.         with ACellRect do
  660.         begin
  661.           {Top arrow}
  662.           Points[0] := Point(ArrowPos - 4, Top - 4);
  663.           Points[1] := Point(ArrowPos - 1, Top - 4);
  664.           Points[2] := Point(ArrowPos - 1, Top - 8);
  665.           Points[3] := Point(ArrowPos + 1, Top - 8);
  666.           Points[4] := Point(ArrowPos + 1, Top - 4);
  667.           Points[5] := Point(ArrowPos + 4, Top - 4);
  668.           Points[6] := Point(ArrowPos, Top);
  669.           Polygon(ScreenDC, Points, 7);
  670.  
  671.           {Bottom arrow}
  672.           Points[0] := Point(ArrowPos - 4, Bottom + 4);
  673.           Points[1] := Point(ArrowPos - 1, Bottom + 4);
  674.           Points[2] := Point(ArrowPos - 1, Bottom + 8);
  675.           Points[3] := Point(ArrowPos + 1, Bottom + 8);
  676.           Points[4] := Point(ArrowPos + 1, Bottom + 4);
  677.           Points[5] := Point(ArrowPos + 4, Bottom + 4);
  678.           Points[6] := Point(ArrowPos, Bottom);
  679.           Polygon(ScreenDC, Points, 7);
  680.         end;
  681.       finally
  682.         SelectObject(ScreenDC, PPen);
  683.         SelectObject(ScreenDC, PBrush);
  684.         DeleteObject(APen);
  685.         DeleteObject(ABrush);
  686.       end;
  687.       FArrowsVisible := True;
  688.     end;
  689.   finally
  690.     ReleaseDC(GetDesktopWindow, ScreenDC);
  691.     if Hide then ShowDragImage;
  692.   end;
  693.  
  694. end;
  695.  
  696. function TDCCustomGrid.DrawTitleCell(ACanvas: TCanvas; ACol,
  697.   ARow: Integer; ARect: TRect; BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint;
  698. begin
  699.   {}
  700. end;
  701.  
  702. function TDCCustomGrid.GetBorderStyle: TEdgeBorderStyle;
  703. begin
  704.   Result := ebsNormal;
  705. end;
  706.  
  707. function TDCCustomGrid.GetGrouping: boolean;
  708. begin
  709.   Result := FGrouping and GroupingEnabled;
  710. end;
  711.  
  712. function TDCCustomGrid.GetGroupingBoxSize: integer;
  713. begin
  714.   if FGrouping then
  715.     Result := FGroupBoxList.GetBoxSize
  716.   else
  717.     Result := 0
  718. end;
  719.  
  720. procedure TDCCustomGrid.HideDragImage;
  721. begin
  722.   if (FDragImages <> nil) and FDragImages.Dragging then FDragImages.HideDragImage;
  723. end;
  724.  
  725. procedure TDCCustomGrid.KeyDown(var Key: Word; Shift: TShiftState);
  726. begin
  727.   if (FDragState <> dsNone) then
  728.   begin
  729.     if Key = VK_ESCAPE then StopDragHeader(False);
  730.     Key := 0;
  731.   end;
  732.   inherited;
  733. end;
  734.  
  735. procedure TDCCustomGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  736. begin
  737.   case FDragState of
  738.     dsHeaderMoving:
  739.       DoHeaderDragging(X, Y);
  740.     dsColMoving:;
  741.     else begin
  742.       if (FDragStartPos = dmGroupBox) and (FGroupBoxList.FMoveIndex <> -1) and
  743.          ((Abs(X - FMousePos.X) > 5) or ((Abs(Y - FMousePos.Y) > 5))) then
  744.       begin
  745.         {Drag Groupbox column}
  746.         if not FGroupBoxList.ReadOnly then
  747.           StartDragHeader(FGroupBoxList.MoveIndex, FDragStartPos);
  748.       end;
  749.     end;
  750.   end;
  751.   inherited;
  752. end;
  753.  
  754. procedure TDCCustomGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
  755.   X, Y: Integer);
  756. begin
  757.   case FDragState of
  758.     dsHeaderMoving:
  759.       StopDragHeader(True);
  760.     dsColMoving:;
  761.     else begin
  762.       if (FDragStartPos = dmGroupBox) and (FGroupBoxList.FMoveIndex <> -1) then
  763.       with FGroupBoxList do
  764.       begin
  765.         {═αµαδΦ φα ²δσ∞σφ≥}
  766.         DoColumnClick(Shift, BoxItems[FMoveIndex].ColIndex);
  767.         MoveIndex := -1;
  768.         FDragStartPos := dmNone;
  769.       end;
  770.     end;
  771.   end;
  772.   FMousePos := Point(0, 0);
  773.   inherited;
  774. end;
  775.  
  776. procedure TDCCustomGrid.SetGrouping(const Value: boolean);
  777. begin
  778.   if GroupingEnabled and (Value <> FGrouping) then
  779.   begin
  780.     FGrouping := Value;
  781.     FGroupBoxList.UpdateSize;
  782.   end;
  783. end;
  784.  
  785. procedure TDCCustomGrid.ShowDragImage;
  786. begin
  787.   if (FDragImages <> nil) and FDragImages.Dragging then FDragImages.ShowDragImage;
  788. end;
  789.  
  790. procedure TDCCustomGrid.StartDragHeader(Origin: integer; DragStart: TDragMousePos);
  791.  var
  792.   P, AP: TPoint;
  793.   R: TRect;
  794. begin
  795.   GetCursorPos(P);
  796.   AP := ScreenToClient(P);
  797.   Application.CancelHint;
  798.   case DragStart of
  799.     dmColumn:
  800.     begin
  801.       CreateTitleDragImage(Origin);
  802.       FMoveIndex := Origin;
  803.       FMovePos   := FMoveIndex;
  804.       with FGroupBoxList do
  805.       begin
  806.         MoveIndex := -1;
  807.         FMovePos   := -1;
  808.       end;
  809.       R := CellRect(Origin, 0);
  810.     end;
  811.     dmGroupBox:
  812.     begin
  813.       with FGroupBoxList do
  814.       begin
  815.         CreateTitleDragImage(BoxItems[Origin].ColIndex);
  816.         MoveIndex := Origin;
  817.         FMovePos  := FMoveIndex;
  818.         R := GetItemRect(Origin);
  819.       end;
  820.       FMoveIndex := -1;
  821.       FMovePos   := -1;
  822.     end
  823.   end;
  824.   FDragImages.SetDragImage(0, AP.X - R.Left, AP.Y - R.Top);
  825.   FDragImages.DragCursor := Cursor;
  826.   FDragImages.BeginDrag(GetDeskTopWindow, P.X, P.Y);
  827.   FDragState := dsHeaderMoving;
  828.   FDragStartPos := DragStart;
  829. end;
  830.  
  831. procedure TDCCustomGrid.StopDragHeader(ApllyChanges: boolean);
  832.  var
  833.   Allow: boolean;
  834. begin
  835.   FDragState := dsNone;
  836.   FDragImages.EndDrag;
  837.   FDragImages.Free;
  838.   FDragImages := nil;
  839.  
  840.   if FArrowsVisible then DrawDragArrows(False);
  841.  
  842.   if ApllyChanges then
  843.   begin
  844.     Allow := True;
  845.     try
  846.       case FDragStartPos of
  847.         dmColumn:
  848.           case FDragStopPos of
  849.             dmColumn:
  850.               if (FMovePos <> -1) and (FMoveIndex <> FMovePos) then  MoveColumn(FMoveIndex, FMovePos);
  851.             dmGroupBox:
  852.               begin
  853.                 {├≡≤∩∩Φ≡εΓΩα}
  854.                 {╧≡εΓσ≡Φ≥ⁿ Γετ∞εµφε δΦ π≡≤∩∩Φ≡εΓα≥ⁿ ∩ε Σαφφε∞≤ ∩εδ■}
  855.                 if FGroupBoxList.Find(FMoveIndex) = -1 then
  856.                 begin
  857.                   DoGroupBoxInsertItem(FMoveIndex, FGroupBoxList.FMovePos, Allow);
  858.                   if Allow then
  859.                   begin
  860.                     FGroupBoxList.BeginUpdate;
  861.                     if FGroupBoxList.FMovePos > FGroupBoxList.Count then
  862.                       FGroupBoxList.Add(FMoveIndex, 1)
  863.                     else
  864.                       FGroupBoxList.Insert(FGroupBoxList.FMovePos, FMoveIndex, 1);
  865.                     FGroupBoxList.EndUpdate;
  866.                   end;
  867.                 end;
  868.               end;
  869.           end;
  870.         dmGroupBox:
  871.           case FDragStopPos of
  872.             dmColumn:
  873.               begin
  874.                 {╤φ ≥Φσ π≡≤∩∩Φ≡εΓΩΦ}
  875.                 DoGroupBoxRemoveItem(FMovePos, FGroupBoxList.FMoveIndex, Allow);
  876.                 if Allow then FGroupBoxList.Delete(FGroupBoxList.FMoveIndex);
  877.               end;
  878.             dmGroupBox:
  879.               begin
  880.                 {╧σ≡σπ≡≤∩∩Φ≡εΓΩα}
  881.                 with FGroupBoxList do
  882.                 begin
  883.                   DoGroupBoxMoveItem(FMoveIndex, FMovePos, Allow);
  884.                   if Allow then
  885.                   begin
  886.                     if FMovePos > Count-1 then
  887.                       Move(FMoveIndex, Count-1)
  888.                     else
  889.                       Move(FMoveIndex, FMovePos);
  890.                   end;
  891.                 end;
  892.               end;
  893.           end;
  894.       end;
  895.     except
  896.       {!!!}
  897.     end;
  898.   end
  899.   else begin
  900.     ClickedCol := -1;
  901.     InvalidateCell(FMoveIndex, 0);
  902.   end;
  903.  
  904.   FMoveIndex := -1;
  905.   FMovePos   := -1;
  906.   with FGroupBoxList do
  907.   begin
  908.     MoveIndex := -1;
  909.     FMovePos   := -1;
  910.   end;
  911.  
  912. end;
  913.  
  914. procedure TDCCustomGrid.UpdateDragingIndex(X, Y: Integer);
  915.  var
  916.   DrawInfo: TGridDrawInfo;
  917.   CellHit: TGridCoord;
  918.   AOutRange: boolean;
  919.   Boundary: integer;
  920. begin
  921.   CalcDrawInfo(DrawInfo);
  922.   Boundary := DrawInfo.Horz.GridBoundary - GetSystemMetrics(SM_CYHSCROLL);
  923.   
  924.   CellHit := MouseCoord(X, Y);
  925.  
  926.   AOutRange := False;
  927.   if (Y > -12) and (Y < DrawInfo.Vert.FixedBoundary) then
  928.   begin
  929.     if (X > Boundary) then
  930.     begin
  931.       CellHit.X := DrawInfo.Horz.LastFullVisibleCell;
  932.       CellHit.Y := 0;
  933.       if FDragStartPos = dmGroupBox then AOutRange := True;
  934.     end
  935.     else begin
  936.       if (X > 0) and (X < DrawInfo.Horz.FixedBoundary) then
  937.       begin
  938.         CellHit.X := FixedCols;
  939.         CellHit.Y := 0;
  940.       end
  941.     end;
  942.   end;
  943.  
  944.   if ((CellHit.X >= FixedCols) or (LeftCol > FixedCols)) and
  945.      (CellHit.Y = 0) and (Y > -12) then
  946.   begin
  947.     if (CellHit.X <> FMovePos) or (FDragStopPos <> dmColumn) or
  948.        (AOutRange <> FOutRange) or
  949.        ((X >= DrawInfo.Horz.FullVisBoundary) and (FMovePos <> DrawInfo.Horz.GridCellCount - 1)) then
  950.     begin
  951.       if FArrowsVisible then DrawDragArrows(True);
  952.       if (X < DrawInfo.Horz.FixedBoundary) then
  953.       begin
  954.         if (FMovePos > DrawInfo.Horz.FixedCellCount) then
  955.         begin
  956.           HideDragImage;
  957.           Perform(WM_HSCROLL, MakeLong(SB_LINEUP, 0), 0);
  958.           Update;
  959.           ShowDragImage;
  960.           CalcDrawInfo(DrawInfo);
  961.         end;
  962.         CellHit.X := DrawInfo.Horz.FirstGridCell;
  963.       end
  964.       else with DrawInfo.Horz do
  965.       begin
  966.          if FMovePos = LastFullVisibleCell then
  967.          begin
  968.            if (X >= DrawInfo.Horz.FullVisBoundary) then
  969.            begin
  970.              if (FMovePos < DrawInfo.Horz.GridCellCount -1) then
  971.              begin
  972.                HideDragImage;
  973.                Perform(WM_HSCROLL, MakeLong(SB_LINEDOWN, 0), 0);
  974.                Update;
  975.                CalcDrawInfo(DrawInfo);
  976.                ShowDragImage;
  977.              end;
  978.              CellHit.X := DrawInfo.Horz.LastFullVisibleCell;
  979.            end;
  980.          end;
  981.          if (FMovePos = LastFullVisibleCell + 1) and AOutRange then
  982.          begin
  983.            if (FMovePos < DrawInfo.Horz.GridCellCount -1) then
  984.            begin
  985.              HideDragImage;
  986.              Perform(WM_HSCROLL, MakeLong(SB_LINEDOWN, 0), 0);
  987.              Update;
  988.              CalcDrawInfo(DrawInfo);
  989.              ShowDragImage;
  990.            end;
  991.          end;
  992.       end;
  993.       FDragStopPos := dmColumn;
  994.       FMovePos  := CellHit.X;
  995.       FOutRange := AOutRange;
  996.       DrawDragArrows(True);
  997.     end
  998.     else with DrawInfo.Horz do
  999.     begin
  1000.       if (X >= Boundary) and (RawToDataColumn(LeftCol) >= 0) and
  1001.          (ColWidths[CellHit.X] + FixedBoundary > GridBoundary) then
  1002.       begin
  1003.         if FArrowsVisible then DrawDragArrows(True);
  1004.         HideDragImage;
  1005.         Perform(WM_HSCROLL, MakeLong(SB_LINEDOWN, 0), 0);
  1006.         Update;
  1007.         ShowDragImage;
  1008.         CalcDrawInfo(DrawInfo);
  1009.         CellHit.X := DrawInfo.Horz.FirstGridCell;
  1010.         FDragStopPos := dmColumn;
  1011.         FMovePos  := CellHit.X;
  1012.         FOutRange := AOutRange;
  1013.         DrawDragArrows(True);
  1014.       end
  1015.     end
  1016.   end
  1017.   else begin
  1018.     if FGroupBoxList.MouseInBox(X, Y, False) then
  1019.     with FGroupBoxList do
  1020.     begin
  1021.       CellHit.X := GetAreaAtPos(Point(X, Y));
  1022.       if (CellHit.X <> FMovePos) or (FDragStopPos <> dmGroupBox) then
  1023.       begin
  1024.         if FArrowsVisible then DrawDragArrows(True);
  1025.         FDragStopPos := dmGroupBox;
  1026.         FMovePos := CellHit.X;
  1027.         DrawDragArrows(True);
  1028.       end;
  1029.     end
  1030.     else  begin
  1031.       if FArrowsVisible then DrawDragArrows(True);
  1032.       FMovePos := -1;
  1033.       FGroupBoxList.FMovePos := -1;
  1034.       FDragStopPos := dmNone;
  1035.     end;
  1036.   end;
  1037. end;
  1038.  
  1039. procedure TDCCustomGrid.WMKillFocus(var Message: TWMKillFocus);
  1040. begin
  1041.   if FDragState <> dsNone then StopDragHeader(True);
  1042.   inherited;
  1043. end;
  1044.  
  1045. procedure TDCCustomGrid.WMNCCalcSize(var Message: TWMNCCalcSize);
  1046. begin
  1047.   inherited;
  1048.   Inc(Message.CalcSize_Params^.rgrc[0].Top, GetGroupingBoxSize);
  1049. end;
  1050.  
  1051. procedure TDCCustomGrid.WMNCPaint(var Message: TMessage);
  1052.  var
  1053.   GroupBoxSize: integer;
  1054. begin
  1055.   inherited;
  1056.   GroupBoxSize := GetGroupingBoxSize;
  1057.   if GroupBoxSize > 0 then FGroupBoxList.Draw;
  1058. end;
  1059.  
  1060. destructor TDCCustomGrid.Destroy;
  1061. begin
  1062.   Destroying;
  1063.   FFooters.Free;
  1064.   if FDesigner <> nil then
  1065.   begin
  1066.     FDesigner.Free;
  1067.     FDesigner := nil;
  1068.   end;
  1069.   FGroupBoxList.Free;
  1070.   inherited;
  1071. end;
  1072.  
  1073. function TDCCustomGrid.FlatButtons: boolean;
  1074. begin
  1075.   Result := False;
  1076. end;
  1077.  
  1078. procedure TDCCustomGrid.WndProc(var Message: TMessage);
  1079. begin
  1080.   inherited;
  1081. end;
  1082.  
  1083. procedure TDCCustomGrid.WMNCHitTest(var Message: TWMNCHitTest);
  1084. begin
  1085.   inherited;
  1086.   with Message do
  1087.   begin
  1088.     if FGroupBoxList.MouseInBox(XPos, YPos, True) then
  1089.     begin
  1090.       Result := HTCLIENT{HTBORDER};
  1091.     end;
  1092.   end;
  1093. end;
  1094.  
  1095. function TDCCustomGrid.DoGroupBoxClick(X, Y: integer): boolean;
  1096.  var
  1097.   Index: integer;
  1098.   P: TPoint;
  1099. begin
  1100.   Result := False;
  1101.   if Grouping then
  1102.   begin
  1103.     FMousePos := Point(X, Y);
  1104.     if PtInRect(FGroupBoxList.BoundsRect, FGroupBoxList.PtConvert(FMousePos)) then
  1105.     begin
  1106.       Result := True;
  1107.       P := FMousePos;
  1108.       Index := FGroupBoxList.GetItemAtPos(P);
  1109.       if Index > -1 then
  1110.       begin
  1111.         FGroupBoxList.MoveIndex := Index;
  1112.         FDragStartPos := dmGroupBox;
  1113.       end;
  1114.     end
  1115.   end;
  1116. end;
  1117.  
  1118. procedure TDCCustomGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1119. begin
  1120.   if not( (Button = mbLeft) and DoGroupBoxClick(X, Y) ) then inherited;
  1121. end;
  1122.  
  1123. procedure TDCCustomGrid.ColumnMoved(FromIndex, ToIndex: Integer);
  1124. begin
  1125.   inherited;
  1126.   if GroupingEnabled then GroupBox.ColumnMoved(FromIndex, ToIndex);
  1127.   Footers.ColumnMoved(FromIndex, ToIndex);
  1128. end;
  1129.  
  1130. procedure TDCCustomGrid.DoColumnClick(Shift: TShiftState;
  1131.   ColIndex: integer);
  1132. begin
  1133.   {}
  1134. end;
  1135.  
  1136. procedure TDCCustomGrid.GroupBoxChanged;
  1137. begin
  1138.   {}
  1139. end;
  1140.  
  1141. function TDCCustomGrid.GetRealColWidth(ColIndex: integer): integer;
  1142. begin
  1143.   Result := ColWidths[ColIndex];
  1144. end;
  1145.  
  1146. procedure TDCCustomGrid.DoGroupBoxInsertItem(ColIndex, Position: integer;
  1147.   var Allow: boolean);
  1148. begin
  1149.   {─εßαΓδσφΦσ ²δσ∞σφ≥α Γ π≡≤∩∩Φ≡εΓΩ≤}
  1150.   if Assigned(FOnGroupBoxInsert) then FOnGroupBoxInsert(Self, ColIndex, Position, Allow);
  1151. end;
  1152.  
  1153. procedure TDCCustomGrid.DoGroupBoxMoveItem(OldPosition, NewPosition: integer;
  1154.   var Allow: boolean);
  1155. begin
  1156.   {╧σ≡σφε± ²δσ∞σφ≥α π≡≤∩∩Φ≡εΓΩΦ}
  1157.   if Assigned(FOnGroupBoxMove) then FOnGroupBoxMove(Self, OldPosition, NewPosition, Allow);
  1158. end;
  1159.  
  1160. procedure TDCCustomGrid.DoGroupBoxRemoveItem(ColIndex, Position: integer;
  1161.   var Allow: boolean);
  1162. begin
  1163.   {╧σ≡σφε± ²δσ∞σφ≥α Φτ π≡≤∩∩εΦ≡εΓΩΦ}
  1164.   if Assigned(FOnGroupBoxRemove) then FOnGroupBoxRemove(Self, ColIndex, Position, Allow);
  1165. end;
  1166.  
  1167. procedure TDCCustomGrid.CreateCellDragImage(ACol, ARow: integer;
  1168.   var DragImages: TImageList);
  1169. begin
  1170.   {}
  1171. end;
  1172.  
  1173. procedure TDCCustomGrid.DoStartDrag(var DragObject: TDragObject);
  1174.  var
  1175.   P, AP: TPoint;
  1176.   Cell: TGridCoord;
  1177. begin
  1178.   GetCursorPos(P);
  1179.   AP := ScreenToClient(P);
  1180.   Cell := MouseCoord(AP.X, AP.Y);
  1181.   Application.CancelHint;
  1182.   inherited;
  1183.   CreateCellDragImage(Cell.X, Cell.Y, FDragImages);
  1184.   if FDragImages <> nil then
  1185.   begin
  1186.     FDragImages.SetDragImage(0, 2, 8);
  1187.     FDragImages.BeginDrag(GetDeskTopWindow, P.X, P.Y);
  1188.     FDragState := dsColMoving;
  1189.   end;  
  1190. end;
  1191.  
  1192. function TDCCustomGrid.GetDragImages: TDragImageList;
  1193. begin
  1194.   if FDragImages <> nil then
  1195.   begin
  1196.     Result := FDragImages
  1197.   end
  1198.   else
  1199.     Result := inherited GetDragImages;
  1200. end;
  1201.  
  1202. procedure TDCCustomGrid.DoEndDrag(Target: TObject; X, Y: Integer);
  1203. begin
  1204.   inherited;
  1205.   if FDragImages <> nil then
  1206.   begin
  1207.     FDragImages.Free;
  1208.     FDragImages := nil;
  1209.     FDragState := dsNone;
  1210.   end;
  1211. end;
  1212.  
  1213. procedure TDCCustomGrid.SetGridOptions(const Value: TGridOptions);
  1214.  var
  1215.   ChangedOptions: TGridOptions;
  1216. begin
  1217.   if FGridOptions <> Value then
  1218.   begin
  1219.     ChangedOptions := (FGridOptions + Value) - (FGridOptions * Value);
  1220.     FGridOptions := Value;
  1221.     if goAutoSize in ChangedOptions then LeftCol := FixedCols;
  1222.   end;
  1223. end;
  1224.  
  1225. procedure TDCCustomGrid.UpdateColWidths(StartIndex: integer;
  1226.   Direct: boolean);
  1227.  type
  1228.    TResizeInfo = packed record
  1229.      Width: integer;
  1230.      Sizing: boolean;
  1231.      Fixed: boolean;
  1232.    end;
  1233.  var
  1234.   ResizeInfo: array of TResizeInfo;
  1235.   SizingArea, GridArea: integer;
  1236.   i, ASizingArea, AGridArea, AWidth: integer;
  1237.   DrawInfo: TGridDrawInfo;
  1238.  
  1239.   procedure UpdateColWidth;
  1240.    var
  1241.     i: integer;
  1242.   begin
  1243.     for i := 0 to ColCount - 1 do
  1244.     begin
  1245.       if ResizeInfo[i].Sizing or not ResizeInfo[i].Fixed then
  1246.         ResizeColWidth(i, ResizeInfo[i].Width);
  1247.     end;
  1248.   end;
  1249.  
  1250. begin
  1251.   if UpdateLocked or not(goAutoSize in GridOptions) or ([csLoading]*ComponentState <> []) then Exit;
  1252.   LockUpdate;
  1253.   SetLength(ResizeInfo, ColCount);
  1254.   CalcDrawInfo(DrawInfo);
  1255.   for i := 0 to ColCount - 1 do ResizeInfo[i].Width := ColWidths[i];
  1256.  
  1257.   for i := 0 to ColCount - 1 do
  1258.   begin
  1259.     if (i > StartIndex) and Direct or (i < StartIndex) and not Direct then
  1260.       ResizeInfo[i].Sizing := CanColResize(i)
  1261.     else
  1262.       ResizeInfo[i].Sizing := False;
  1263.     ResizeInfo[i].Fixed := True;
  1264.   end;
  1265.  
  1266.   SizingArea := 0;
  1267.   repeat
  1268.     GridArea := DrawInfo.Horz.GridExtent;
  1269.     for i := 0 to ColCount - 1 do
  1270.     begin
  1271.        if not ResizeInfo[i].Sizing then
  1272.        begin
  1273.          Dec(GridArea, ResizeInfo[i].Width);
  1274.        end;
  1275.        Dec(GridArea, DrawInfo.Horz.EffectiveLineWidth);
  1276.     end;
  1277.  
  1278.     if (GridArea < 0) and (StartIndex <> -1) then
  1279.     begin
  1280.       {═≤µφε ∩≡εßσµα≥ⁿ±  ∩ε ∩ε±δσΣ≤■∙Φ∞ Φ Γ√±≥αΓΦ≥ⁿ Φ∞ ∞ΦφΦ∞αδⁿφ≤■ °Φ≡Φφ≤}
  1281.       GridArea := DrawInfo.Horz.GridExtent;
  1282.       for i := 0 to ColCount - 1 do
  1283.       begin
  1284.          if (not ResizeInfo[i].Sizing) and (i <> StartIndex) then
  1285.          begin
  1286.            Dec(GridArea, ResizeInfo[i].Width);
  1287.          end
  1288.          else begin
  1289.            if ResizeInfo[i].Sizing then
  1290.            begin
  1291.              {┬√ßε≡ ∞ΦφΦ∞αδⁿφεπε ≡ατ∞σ≡α}
  1292.              ResizeInfo[i].Width := 15;
  1293.              ResizeInfo[i].Fixed := True;
  1294.              Dec(GridArea, ResizeInfo[i].Width)
  1295.            end;
  1296.          end;
  1297.          Dec(GridArea, DrawInfo.Horz.EffectiveLineWidth);
  1298.       end;
  1299.       ResizeInfo[StartIndex].Fixed := False;
  1300.       if SizingArea <> 0 then
  1301.         ResizeInfo[StartIndex].Width := GridArea
  1302.       else
  1303.         ResizeInfo[StartIndex].Width := 0;
  1304.       Break;
  1305.     end;
  1306.  
  1307.     SizingArea := 0;
  1308.     for i := 0 to ColCount - 1 do
  1309.     begin
  1310.       if ResizeInfo[i].Sizing then Inc(SizingArea, ResizeInfo[i].Width);
  1311.     end;
  1312.  
  1313.     AGridArea   := GridArea;
  1314.     ASizingArea := SizingArea;
  1315.  
  1316.     if Abs(SizingArea - GridArea) = 1 then
  1317.     begin
  1318.       for i := 0 to ColCount - 1 do
  1319.       begin
  1320.         if ResizeInfo[i].Sizing then
  1321.         begin
  1322.           ResizeInfo[i].Width := ResizeInfo[i].Width + GridArea - SizingArea;
  1323.           Break;
  1324.         end;
  1325.       end;
  1326.       SizingArea := GridArea;
  1327.     end;
  1328.  
  1329.     if (SizingArea > 0) and (SizingArea <> GridArea) then
  1330.     begin
  1331.         for i := 0 to ColCount - 1 do
  1332.         begin
  1333.           if ResizeInfo[i].Sizing then
  1334.           begin
  1335.             AWidth := ResizeInfo[i].Width;
  1336.             ResizeInfo[i].Width := MulDiv(AWidth, AGridArea, ASizingArea);
  1337.             {╠ΦφΦ∞αδⁿφεσ τφα≈σφΦσ}
  1338.             if ResizeInfo[i].Width < 15 then
  1339.             begin
  1340.               ResizeInfo[i].Width  := 15;
  1341.               ResizeInfo[i].Sizing := False;
  1342.               ResizeInfo[i].Fixed  := False;
  1343.               Break;
  1344.             end;
  1345.             Dec(AGridArea, ResizeInfo[i].Width);
  1346.             Dec(ASizingArea, AWidth);
  1347.           end;
  1348.         end;
  1349.     end;
  1350.   until (SizingArea = 0) or (SizingArea = GridArea);
  1351.  
  1352.   if (SizingArea <> GridArea) and (StartIndex <> -1) then with ResizeInfo[StartIndex] do
  1353.   begin
  1354.     Width := Width + GridArea - SizingArea;
  1355.     Fixed := False;
  1356.   end;
  1357.  
  1358.   UpdateColWidth;
  1359.   UnlockUpdate;
  1360.   ColWidthsChanged;
  1361. end;
  1362.  
  1363. procedure TDCCustomGrid.SetScrollBars(const Value: TScrollStyle);
  1364.  var
  1365.   AValue: TScrollStyle;
  1366. begin
  1367.   FScrollBars := Value;
  1368.   AValue := Value;
  1369.   if goAutoSize in GridOptions then
  1370.   begin
  1371.     case Value of
  1372.       ssBoth:
  1373.         AValue := ssVertical;
  1374.       ssHorizontal:
  1375.         AValue := ssNone;
  1376.     end;
  1377.   end;
  1378.   inherited ScrollBars := AValue;
  1379. end;
  1380.  
  1381. procedure TDCCustomGrid.LockUpdate;
  1382. begin
  1383.   FLockUpdate := True;
  1384.   Inc(FLockCount);
  1385. end;
  1386.  
  1387. procedure TDCCustomGrid.UnlockUpdate;
  1388. begin
  1389.   Dec(FLockCount);
  1390.   if FLockCount = 0 then FLockUpdate := False;
  1391. end;
  1392.  
  1393. function TDCCustomGrid.UpdateLocked: boolean;
  1394. begin
  1395.   Result := FLockUpdate;
  1396. end;
  1397.  
  1398. procedure TDCCustomGrid.ResizeColWidth(ACol, AWidth: integer);
  1399. begin
  1400.   ColWidths[ACol] := AWidth;
  1401. end;
  1402.  
  1403. function TDCCustomGrid.CanColResize(ACol: integer): boolean;
  1404. begin
  1405.   Result := ACol >= FixedCols;
  1406. end;
  1407.  
  1408. procedure TDCCustomGrid.ConstrainedResize(var MinWidth, MinHeight,
  1409.   MaxWidth, MaxHeight: Integer);
  1410.  var
  1411.   i: integer;
  1412. begin
  1413.   inherited;
  1414.   if goAutoSize in GridOptions then
  1415.   begin
  1416.     MinWidth := 0;
  1417.     for i := 0 to ColCount - 1 do
  1418.     begin
  1419.       if CanColResize(i) and (ColWidths[i] <> -1) then
  1420.         Inc(MinWidth, -1)
  1421.       else
  1422.         Inc(MinWidth, ColWidths[i]);
  1423.     end;
  1424.   end;
  1425. end;
  1426.  
  1427. procedure TDCCustomGrid.BeginLayout;
  1428. begin
  1429.   {}
  1430. end;
  1431.  
  1432. procedure TDCCustomGrid.Endlayout;
  1433. begin
  1434.   {}
  1435. end;
  1436.  
  1437. function TDCCustomGrid.GetClientRect: TRect;
  1438.  var
  1439.   aHeight: integer;
  1440. begin
  1441.   Result := inherited GetClientRect;
  1442.   aHeight := FFooters.Height;
  1443.   if aHeight > 0 then Result.Bottom := Result.Bottom - aHeight;
  1444. end;
  1445.  
  1446. procedure TDCCustomGrid.Paint;
  1447.  var
  1448.   SaveIndex: integer;
  1449.   ARect: TRect;
  1450. begin
  1451.   ARect := FFooters.BoundsRect;
  1452.   if not IsRectEmpty(ARect) and RectVisible(Canvas.Handle, ARect) then
  1453.   begin
  1454.     SaveIndex := SaveDC(Canvas.Handle);
  1455.     try
  1456.       ExcludeClipRect(Canvas.Handle, ARect.Left, ARect.Top, ARect.Right,
  1457.         ARect.Bottom);
  1458.       inherited;
  1459.     finally
  1460.       RestoreDC(Canvas.Handle, SaveIndex);
  1461.     end;
  1462.     FFooters.Draw;
  1463.   end
  1464.   else
  1465.     inherited;
  1466. end;
  1467.  
  1468. function TDCCustomGrid.GetGridBounds: TRect;
  1469. begin
  1470.   Result := inherited GetClientRect;
  1471. end;
  1472.  
  1473. procedure TDCCustomGrid.WMPaint(var Message: TWMPaint);
  1474. var
  1475.   DC, MemDC: HDC;
  1476.   MemBitmap, OldBitmap: HBITMAP;
  1477.   PS: TPaintStruct;
  1478.   R: TRect;
  1479. begin
  1480.   if not DoubleBuffered or (Message. DC <> 0) then
  1481.   begin
  1482.     if not (csCustomPaint in ControlState) and (ControlCount = 0) then
  1483.       inherited
  1484.     else
  1485.       PaintHandler(Message);
  1486.   end
  1487.   else
  1488.   begin
  1489.     DC := GetDC(0);
  1490.     R := GetGridBounds;
  1491.     MemBitmap := CreateCompatibleBitmap(DC, R.Right, R.Bottom);
  1492.     ReleaseDC(0, DC);
  1493.     MemDC := CreateCompatibleDC(0);
  1494.     OldBitmap := SelectObject(MemDC, MemBitmap);
  1495.     try
  1496.       DC := BeginPaint(Handle, PS);
  1497.       Perform(WM_ERASEBKGND, MemDC, MemDC);
  1498.       Message.DC := MemDC;
  1499.       WMPaint(Message);
  1500.       Message.DC := 0;
  1501.       BitBlt(DC, 0, 0, R.Right, R.Bottom, MemDC, 0, 0, SRCCOPY);
  1502.       EndPaint(Handle, PS);
  1503.     finally
  1504.       SelectObject(MemDC, OldBitmap);
  1505.       DeleteDC(MemDC);
  1506.       DeleteObject(MemBitmap);
  1507.     end;
  1508.   end;
  1509. end;
  1510.  
  1511. { TDCGroupBoxList }
  1512.  
  1513. function TDCGroupBoxList.Add(AColIndex, ALOffset: integer): integer;
  1514.  var
  1515.   pBoxItem: PGroupBoxItem_tag;
  1516. begin
  1517.   GetMem(pBoxItem, SizeOf(TGroupBoxItem));
  1518.   pBoxItem^.ColIndex := AColIndex;
  1519.   pBoxItem^.LOffset  := ALOffset;
  1520.   Result := inherited Add(pBoxItem);
  1521.   UpdateItemSize(Result);
  1522. end;
  1523.  
  1524. procedure TDCGroupBoxList.BeginUpdate;
  1525. begin
  1526.   Inc(FUpdateCount);
  1527. end;
  1528.  
  1529. procedure TDCGroupBoxList.Changed;
  1530. begin
  1531.   if FUpdateCount = 0 then Update;
  1532. end;
  1533.  
  1534. procedure TDCGroupBoxList.Clear;
  1535.  var
  1536.   i: integer;
  1537. begin
  1538.   for i := 0 to Count -1 do
  1539.   begin
  1540.     FreeMem(Items[i], SizeOf(TGroupBoxItem));
  1541.   end;
  1542.   inherited Clear;
  1543. end;
  1544.  
  1545. procedure TDCGroupBoxList.ColumnMoved(FromIndex, ToIndex: Integer);
  1546.  var
  1547.   i, nCount: integer;
  1548.   pBoxItem: PGroupBoxItem_tag;
  1549. begin
  1550.   nCount := Count;
  1551.   for i := 0 to nCount -1 do
  1552.   begin
  1553.     pBoxItem := Items[i];
  1554.     if pBoxItem^.ColIndex = FromIndex then
  1555.       pBoxItem^.ColIndex := ToIndex
  1556.     else begin
  1557.       if FromIndex > ToIndex then
  1558.         if (pBoxItem^.ColIndex >= ToIndex) and (pBoxItem^.ColIndex < FromIndex) then Inc(pBoxItem^.ColIndex) else
  1559.       else
  1560.         if (pBoxItem^.ColIndex <= ToIndex) and (pBoxItem^.ColIndex > FromIndex) then Dec(pBoxItem^.ColIndex);
  1561.     end;
  1562.   end;
  1563. end;
  1564.  
  1565. constructor TDCGroupBoxList.Create(AOwner: TDCCustomGrid);
  1566. begin
  1567.   inherited Create;
  1568.   FOwner := AOwner;
  1569.   FMargin := Point(5, 5);
  1570.   FUpdateCount := 0;
  1571.   FMoveIndex := -1;
  1572.   FMovePos   := -1;
  1573.   FFixedCols :=  0;
  1574. end;
  1575.  
  1576. procedure TDCGroupBoxList.Delete(Index: integer);
  1577.  var
  1578.   pBoxItem: PGroupBoxItem_tag;
  1579. begin
  1580.   while (Index >=0) and (BoxItems[Index].LOffset = 0) do Dec(Index);
  1581.  
  1582.   repeat
  1583.     pBoxItem := Items[Index];
  1584.     FreeMem(pBoxItem, SizeOf(TGroupBoxItem));
  1585.  
  1586.     inherited Delete(Index);
  1587.     Inc(Index);
  1588.   until (Index > Count - 1) or (BoxItems[Index].LOffset <> 0);
  1589.   Changed;
  1590. end;
  1591.  
  1592. procedure TDCGroupBoxList.Draw;
  1593.  var
  1594.   DrawStr: string;
  1595.   i, Border, c: integer;
  1596.   ClipRect, R, ARect: TRect;
  1597.   Offset, PosA, PosB: TPoint;
  1598.   BoxItem: TGroupBoxItem;
  1599.   DC: HDC;
  1600. begin
  1601.   Offset := Point(FMargin.X, FMargin.Y);
  1602.   with FOwner do
  1603.   begin
  1604.     DC := GetWindowDC(Handle);
  1605.     Canvas.Handle := DC;
  1606.     Canvas.Font   := Font;
  1607.     try
  1608.       Canvas.Brush.Color := clBtnShadow;
  1609.       GetWindowRect(Handle, ARect);  OffsetRect(ARect, -ARect.Left, -ARect.Top);
  1610.       ARect.Bottom  := GetBoxSize;
  1611.       if BorderStyle = bsSingle then
  1612.       begin
  1613.         InflateRect(ARect, -1, 0);
  1614.         OffsetRect(ARect, 0, 1);
  1615.         if not FlatButtons then OffsetRect(ARect, 0, 1);
  1616.       end;
  1617.       if Count = 0 then
  1618.       begin
  1619.         ClipRect := ARect;
  1620.         DrawStr := LoadStr(RES_STRN_MSG_GRPBOX);
  1621.         InflateRect(ClipRect, -Offset.X, -Offset.Y);
  1622.         Canvas.Font.Color := clWindow;
  1623.         DrawText(Canvas.Handle, PChar(DrawStr), Length(DrawStr), ClipRect, DT_CALCRECT);
  1624.         DrawText(Canvas.Handle, PChar(DrawStr), Length(DrawStr), ClipRect, DT_LEFT or DT_END_ELLIPSIS);
  1625.         with ClipRect do
  1626.           ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  1627.       end
  1628.       else begin
  1629.         for i := 0 to Count-1 do
  1630.         begin
  1631.           BoxItem := BoxItems[i];
  1632.           R := Rect(0, 0, BoxItem.Size.X, BoxItem.Size.Y);
  1633.           OffsetRect(R, Offset.X, Offset.Y);
  1634.           ClipRect := R;
  1635.  
  1636.           Border := 1;
  1637.           c := ColorToRGB(clSilver);
  1638.           c := RGB(GetRValue(c) shr 1, GetGValue(c) shr 1, GetBValue(c) shr 1);
  1639.           Canvas.Pen.Color := GetNearestColor(Canvas.Handle, c);
  1640.           if i = Self.FMoveIndex then
  1641.           begin
  1642.             {Down}
  1643.             DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_BOTTOMRIGHT);
  1644.             Canvas.PenPos := Point(R.Left, R.Bottom);
  1645.             Canvas.LineTo(R.Left, R.Top);
  1646.             Canvas.LineTo(R.Right, R.Top);
  1647.             InflateRect(R, -1, -1);
  1648.             try
  1649.               DrawTitleCell(Canvas, RawToDataColumn(BoxItem.ColIndex), 0, R, dsDown, True, True);
  1650.             except
  1651.               {}
  1652.             end;
  1653.           end
  1654.           else begin
  1655.             {Up}
  1656.             DrawEdge(Canvas.Handle, R, BDR_RAISEDINNER, BF_TOPLEFT);
  1657.             Canvas.PenPos := Point(R.Left, R.Bottom-1);
  1658.             Canvas.LineTo(R.Right-1, R.Bottom-1);
  1659.             Canvas.LineTo(R.Right-1, R.Top);
  1660.             InflateRect(R, -1, -1);
  1661.             try
  1662.               DrawTitleCell(Canvas, RawToDataColumn(BoxItem.ColIndex), 0, R, dsUp, True, True);
  1663.             except
  1664.               {}
  1665.             end;
  1666.           end;
  1667.  
  1668.           {Γ√≈Φ±δ ∞ ±∞σ∙σφΦ  Σδ  ±δσΣ≤■∙σπε ²δσ∞σφ≥α}
  1669.           if (i < Count -1) and (BoxItems[i+1].LOffset = 0) then
  1670.             Inc(Offset.X, 2 + BoxItem.Size.X)
  1671.           else begin
  1672.             Inc(Offset.X, 5 + BoxItem.Size.X);
  1673.             if (i <> 0) and (BoxItems[i].LOffset <> 0) then
  1674.             begin
  1675.               {≡Φ±≤σ∞ ±εσΣΦφΦ≥σδⁿφ√σ δΦφφΦΦ}
  1676.               Canvas.Pen.Color := clBlack;
  1677.               Canvas.Pen.Width := 1;
  1678.  
  1679.               PosA := Point(R.Left - 13, R.Bottom - 5);
  1680.               PosB := Point(R.Left - Border, R.Bottom - 5);
  1681.               Canvas.PenPos := PosA;
  1682.               Canvas.LineTo(PosB.X, PosB.Y);
  1683.               ExcludeClipRect(Canvas.Handle, PosA.X, PosA.Y, PosB.X + 1, PosB.Y + 1);
  1684.  
  1685.               PosA := Point(R.Left - 13, R.Top - BoxItems[i-1].Size.Y div 2);
  1686.               PosB := Point(R.Left - 13, R.Bottom - 5);
  1687.               Canvas.PenPos := PosA;
  1688.               Canvas.LineTo(PosB.X, PosB.Y);
  1689.               ExcludeClipRect(Canvas.Handle, PosA.X, PosA.Y, PosB.X+1, PosB.Y+1);
  1690.             end;
  1691.           end;
  1692.  
  1693.           Inc(Offset.Y, GetItemOffset(i));
  1694.  
  1695.           with ClipRect do
  1696.             ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  1697.         end;
  1698.       end;
  1699.       Canvas.FillRect(ARect);
  1700.     finally
  1701.       Canvas.Handle := 0;
  1702.       ReleaseDC(Handle, DC);
  1703.     end;
  1704.   end;
  1705. end;
  1706.  
  1707. procedure TDCGroupBoxList.EndUpdate;
  1708. begin
  1709.   if FUpdateCount > 0 then
  1710.   begin
  1711.     Dec(FUpdateCount);
  1712.     Changed;
  1713.   end;
  1714. end;
  1715.  
  1716. function TDCGroupBoxList.Find(AColIndex: integer): integer;
  1717.  var
  1718.   i: integer;
  1719. begin
  1720.   Result := -1;
  1721.   for i := 0 to Count-1 do
  1722.    if BoxItems[i].ColIndex = AColIndex then
  1723.    begin
  1724.      Result := i;
  1725.      Break;
  1726.    end
  1727. end;
  1728.  
  1729. function TDCGroupBoxList.GetAreaAtPos(APos: TPoint): integer;
  1730.  var
  1731.   i, OffsetX: integer;
  1732. begin
  1733.   OffsetX := FMargin.X;
  1734.   for i := 0 to Count - 1 do
  1735.   begin
  1736.     Inc(OffsetX, BoxItems[i].Size.X);
  1737.     if APos.X < OffsetX then
  1738.     begin
  1739.       Result := i;
  1740.       Exit;;
  1741.     end;
  1742.     Inc(OffsetX, 5);
  1743.   end;
  1744.   Result := Count;
  1745. end;
  1746.  
  1747. function TDCGroupBoxList.GetBoundsRect: TRect;
  1748. begin
  1749.   Result := Rect(0, 0, FOwner.ClientWidth, FBoxSize);
  1750. end;
  1751.  
  1752. function TDCGroupBoxList.GetBoxItems(Index: integer): TGroupBoxItem;
  1753. begin
  1754.   Result := PGroupBoxItem_tag(Items[Index])^;
  1755. end;
  1756.  
  1757. function TDCGroupBoxList.GetBoxSize: integer;
  1758. begin
  1759.   if FOwner.GroupingEnabled and FOwner.Grouping then
  1760.     Result := FBoxSize
  1761.   else
  1762.     Result := 0;
  1763. end;
  1764.  
  1765. function TDCGroupBoxList.GetItemAtPos(APos: TPoint): integer;
  1766.  var
  1767.   i: integer;
  1768.   R: TRect;
  1769.   Offset: TPoint;
  1770.   BoxItem: TGroupBoxItem;
  1771. begin
  1772.   APos.Y := APos.Y + BoxSize + 1;
  1773.   Offset := Point(FMargin.X, FMargin.Y);
  1774.   Result := -1;
  1775.   for i := 0 to Count - 1 do
  1776.   begin
  1777.     BoxItem := BoxItems[i];
  1778.     R := Rect(0, 0, BoxItem.Size.X, BoxItem.Size.Y);
  1779.     OffsetRect(R, Offset.X, Offset.Y);
  1780.     if PtInRect(R, APos) then
  1781.     begin
  1782.       Result := i;
  1783.       Break;
  1784.     end;
  1785.     if (i < Count -1) and (BoxItems[i+1].LOffset = 0) then
  1786.       Inc(Offset.X, 2 + BoxItem.Size.X)
  1787.     else
  1788.       Inc(Offset.X, 5 + BoxItem.Size.X);
  1789.     Inc(Offset.Y, GetItemOffset(i));
  1790.   end;
  1791. end;
  1792.  
  1793. function TDCGroupBoxList.GetItemOffset(i: integer): integer;
  1794. begin
  1795.   if (i <  Count - 1) and (BoxItems[i+1].LOffset > 0)then
  1796.   begin
  1797.     if i = Count - 1 then
  1798.       Result := BoxItems[i].Size.Y div 2
  1799.     else begin
  1800.       if BoxItems[i].Size.Y <= BoxItems[i+1].Size.Y then
  1801.         Result := BoxItems[i].MaxHeight div 2
  1802.       else
  1803.         Result := BoxItems[i].MaxHeight - BoxItems[i+1].Size.Y div 2;
  1804.     end;
  1805.   end
  1806.   else
  1807.     Result := 0;
  1808. end;
  1809.  
  1810. function TDCGroupBoxList.GetItemRect(Index: integer): TRect;
  1811.  var
  1812.   i: integer;
  1813.   Offset: TPoint;
  1814. begin
  1815.   if (Index < 0) then
  1816.   begin
  1817.     SetRectEmpty(Result);
  1818.     Exit;
  1819.   end;
  1820.   i := 0;
  1821.   Offset := Point(FMargin.X, FMargin.Y);
  1822.   if Count = 0 then
  1823.     Result := Rect(0, 0, 1, BoxSize - FMargin.Y - 10)
  1824.   else begin
  1825.     while (i < Index) and (i < Count) do
  1826.     begin
  1827.       Inc(Offset.X, 5 + BoxItems[i].Size.X);
  1828.       Inc(Offset.Y, GetItemOffset(i));
  1829.       Inc(i);
  1830.     end;
  1831.  
  1832.     if Index >= Count then
  1833.     begin
  1834.       Result := Rect(0, 0, BoxItems[Count-1].Size.X, BoxItems[Count-1].Size.Y);
  1835.       Dec(Offset.Y, GetItemOffset(Count-1));
  1836.       Dec(Offset.X, BoxItems[Count-1].Size.X + 5);
  1837.     end
  1838.     else
  1839.       Result := Rect(0, 0, BoxItems[Index].Size.X, BoxItems[Index].Size.Y);
  1840.   end;
  1841.   OffsetRect(Result, Offset.X, Offset.Y - BoxSize);
  1842. end;
  1843.  
  1844. procedure TDCGroupBoxList.Insert(Index, AColIndex, ALOffset: integer);
  1845.  var
  1846.   pBoxItem: PGroupBoxItem_tag;
  1847. begin
  1848.   GetMem(pBoxItem, SizeOf(TGroupBoxItem));
  1849.   pBoxItem^.ColIndex := AColIndex;
  1850.   pBoxItem^.LOffset  := ALOffset;
  1851.   inherited Insert(Index, pBoxItem);
  1852.   UpdateItemSize(Index);
  1853. end;
  1854.  
  1855. procedure TDCGroupBoxList.Invalidate;
  1856. begin
  1857.   if FOwner.HandleAllocated and (BoxSize > 0) then Draw;
  1858. end;
  1859.  
  1860. function TDCGroupBoxList.MouseInBox(X, Y: integer; Convert: boolean): boolean;
  1861.  var
  1862.   P: TPoint;
  1863. begin
  1864.   if BoxSize > 0 then
  1865.   begin
  1866.     if Convert then
  1867.       P := PtConvert(FOwner.ScreenToClient(Point(X, Y)))
  1868.     else
  1869.       P := PtConvert(Point(X, Y));
  1870.     Result := PtInRect(BoundsRect, P);
  1871.   end
  1872.   else
  1873.     Result := False;
  1874. end;
  1875.  
  1876. procedure TDCGroupBoxList.Move(CurIndex, NewIndex: Integer);
  1877. begin
  1878.   while (NewIndex >=0) and (BoxItems[NewIndex].LOffset = 0) do Dec(NewIndex);
  1879.   while (CurIndex >=0) and (BoxItems[CurIndex].LOffset = 0) do Dec(CurIndex);
  1880.   if CurIndex <> NewIndex then
  1881.   begin
  1882.     repeat
  1883.       inherited Move(CurIndex, NewIndex);
  1884.       Inc(CurIndex);
  1885.       Inc(NewIndex);
  1886.     until (CurIndex > Count - 1) or (BoxItems[CurIndex].LOffset <> 0)
  1887.   end;
  1888. end;
  1889.  
  1890. function TDCGroupBoxList.PtConvert(APoint: TPoint): TPoint;
  1891. begin
  1892.   Result := Point(APoint.X + FOwner.BorderWidth, APoint.Y + FOwner.BorderWidth + FBoxSize);
  1893.   if FOwner.FlatButtons then
  1894.   begin
  1895.     Dec(Result.X);
  1896.     Dec(Result.Y);
  1897.   end;
  1898. end;
  1899.  
  1900. procedure TDCGroupBoxList.SetBoxItems(Index: integer;
  1901.   const Value: TGroupBoxItem);
  1902. begin
  1903.   PGroupBoxItem_tag(Items[Index])^ := Value;
  1904. end;
  1905.  
  1906. procedure TDCGroupBoxList.SetFixedCols(const Value: integer);
  1907.  var
  1908.   i: integer;
  1909.   pBoxItem: PGroupBoxItem_tag;
  1910. begin
  1911.   if FFixedCols <> Value then
  1912.   begin
  1913.     for i := 0 to Count-1 do
  1914.     begin
  1915.       pBoxItem := Items[i];
  1916.       pBoxItem^.ColIndex := pBoxItem^.ColIndex + Value - FFixedCols;
  1917.     end;
  1918.     FFixedCols := Value;
  1919.   end;
  1920. end;
  1921.  
  1922. procedure TDCGroupBoxList.SetMoveIndex(const Value: integer);
  1923. begin
  1924.   if FMoveIndex <> Value then
  1925.   begin
  1926.     FMoveIndex := Value;
  1927.     Changed;
  1928.   end;
  1929. end;
  1930.  
  1931. procedure TDCGroupBoxList.Update;
  1932. begin
  1933.   with FOwner do
  1934.   begin
  1935.     BeginLayout;
  1936.     GroupBoxChanged;
  1937.     UpdateSize;
  1938.     EndLayout;
  1939.     Perform(CM_SHOWINGCHANGED, 0, 0);
  1940.   end;  
  1941. end;
  1942.  
  1943. procedure TDCGroupBoxList.UpdateItemSize(Index: integer);
  1944.  var
  1945.   R: TRect;
  1946.   BoxItem: TGroupBoxItem;
  1947.   lChanged: boolean;
  1948. begin
  1949.   if (Index > -1) and (Index < Count) then
  1950.   begin
  1951.     R := Rect(0, 0, FOwner.ClientWidth, FOwner.ClientHeight);
  1952.     BoxItem := BoxItems[Index];
  1953.     with FOwner do
  1954.       BoxItem.Size := DrawTitleCell(Canvas, RawToDataColumn(BoxItem.ColIndex), 0, R, dsUp, False, False);
  1955.  
  1956.     if BoxItem.Size.Y = 0 then Inc(BoxItem.Size.Y, 1);
  1957.     Inc(BoxItem.Size.Y, 5);
  1958.     BoxItem.MaxHeight := BoxItem.Size.Y;
  1959.  
  1960.     lChanged := (BoxItem.Size.Y <> BoxItems[Index].Size.Y) or (BoxItem.Size.X <> BoxItems[Index].Size.X);
  1961.     BoxItems[Index] := BoxItem;
  1962.  
  1963.     if lChanged then Changed
  1964.   end;
  1965. end;
  1966.  
  1967. function TDCGroupBoxList.UpdateSize: integer;
  1968.  var
  1969.   i, ABoxSize: integer;
  1970. begin
  1971.   ABoxSize := FBoxSize;
  1972.   if FOwner.Grouping then
  1973.   begin
  1974.     Result := FMargin.Y;
  1975.     if Count = 0 then
  1976.     begin
  1977.       Inc(Result, GetDCTextHeight(FOwner.Font, 'Wg'));
  1978.       Inc(Result, 10);
  1979.     end
  1980.     else begin
  1981.        for i := 0 to Count - 2 do
  1982.        begin
  1983.          Inc(Result, GetItemOffset(i));
  1984.          if (BoxItems[i].LOffset = 0) and (i >0) then
  1985.            PGroupBoxItem_tag(Items[i])^.MaxHeight :=
  1986.              _intMax(BoxItems[i].MaxHeight, BoxItems[i-1].MaxHeight);
  1987.        end;
  1988.  
  1989.       i := Count -  1;
  1990.       if (BoxItems[i].LOffset = 0) and (i >0) then
  1991.         PGroupBoxItem_tag(Items[i])^.MaxHeight :=
  1992.           _intMax(BoxItems[i].MaxHeight, BoxItems[i-1].MaxHeight);
  1993.       if i >= 0 then Inc(Result, BoxItems[i].MaxHeight);
  1994.  
  1995.       Inc(Result, 4);
  1996.     end;
  1997.   end
  1998.   else
  1999.     Result := 0;
  2000.   FBoxSize := Result;
  2001.   if ABoxSize <> Result then with FOwner do
  2002.   begin
  2003.     SetWindowPos(Handle, HWND_TOP, Left, Top, Width, Height,
  2004.       SWP_FRAMECHANGED or SWP_NOZORDER or SWP_NOREDRAW);
  2005.     RedrawWindow(Handle, nil, 0,
  2006.       RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN or RDW_NOINTERNALPAINT);
  2007.   end;
  2008. end;
  2009.  
  2010. procedure CreateGridIndicators;
  2011.  var
  2012.   Bitmap: TBitmap;
  2013.   i: integer;
  2014.  
  2015.  const
  2016.   GRID_INDICATOR_COUNT  = 11;
  2017.   aGridIndicators: array [0..GRID_INDICATOR_COUNT - 1] of string =
  2018.     ( bmArrow, bmEdit, bmInsert, bmMultiDot, bmMultiArrow, bmCheck, bmMain,
  2019.       bmIndexAsc, bmIndexDesc, bmIndexNone, bmCheckHrd);
  2020.  
  2021. begin
  2022.   Bitmap := TBitmap.Create;
  2023.   try
  2024.     for i := 0 to GRID_INDICATOR_COUNT - 1 do
  2025.     begin
  2026.       Bitmap.LoadFromResourceName(HInstance, aGridIndicators[i]);
  2027.       if i = 0 then GridIndicatorImages := TImageList.CreateSize(Bitmap.Width, Bitmap.Height);
  2028.       GridIndicatorImages.AddMasked(Bitmap, Bitmap.Canvas.Pixels[0,0]);
  2029.     end;
  2030.   finally
  2031.     Bitmap.Free;
  2032.   end;
  2033. end;
  2034.  
  2035. procedure DestroyGridIndicators;
  2036. begin
  2037.   GridIndicatorImages.Clear;
  2038.   GridIndicatorImages.Free;
  2039. end;
  2040.  
  2041. function GDGetImages: TImageList;
  2042. begin
  2043.   Result := GridIndicatorImages;
  2044. end;
  2045.  
  2046. { TDCFooter }
  2047.  
  2048. procedure TDCFooter.Changed(AllItems: boolean);
  2049. begin
  2050.   if (FOwner <> nil) and (FOwner.FUpdateCount = 0) then
  2051.   begin
  2052.     AdjustHeight;
  2053.     if AllItems then
  2054.       FOwner.Update(nil)
  2055.     else
  2056.       FOwner.Update(Self)
  2057.   end;
  2058. end;
  2059.  
  2060. procedure TDCFooter.ColumnMoved(FromIndex, ToIndex: Integer);
  2061.  var
  2062.   i, nCount: integer;
  2063.   Panel: TDCFooterPanel;
  2064. begin
  2065.   nCount := Panels.Count;
  2066.   Owner.BeginUpdate;
  2067.   for i := 0 to nCount -1 do
  2068.   begin
  2069.     Panel := Panels.Items[i];
  2070.     if Panel.ColIndex = FromIndex then
  2071.       Panel.ColIndex := ToIndex
  2072.     else begin
  2073.       if FromIndex > ToIndex then
  2074.         if (Panel.ColIndex >= ToIndex) and (Panel.ColIndex < FromIndex) then
  2075.           Panel.ColIndex := Panel.ColIndex + 1
  2076.         else
  2077.       else
  2078.         if (Panel.ColIndex <= ToIndex) and (Panel.ColIndex > FromIndex) then
  2079.           Panel.ColIndex := Panel.ColIndex - 1;
  2080.     end;
  2081.   end;
  2082.   Owner.EndUpdate;
  2083. end;
  2084.  
  2085. constructor TDCFooter.Create(AOwner: TDCFooters);
  2086. begin
  2087.   inherited Create;
  2088.   FPanels := TDCFooterPanels.Create(Self);
  2089.   FCanvas := TCanvas.Create;
  2090.   FVisible := True;
  2091.   FHeight := -1;
  2092.   FAutoSize := True;
  2093.   SetOwner(AOwner);
  2094. end;
  2095.  
  2096. destructor TDCFooter.Destroy;
  2097. begin
  2098.   SetOwner(nil);
  2099.   FCanvas.Free;
  2100.   FPanels.Free;
  2101.   inherited;
  2102. end;
  2103.  
  2104. procedure TDCFooter.DrawItem(ACanvas: TCanvas; DrawInfo: TGridDrawInfo;
  2105.   const Rect: TRect; Index: integer);
  2106.  var
  2107.   DC: HDC;
  2108.   R: TRect;
  2109.   i, nCount: integer;
  2110.   Panel: TDCFooterPanel;
  2111. begin
  2112.   DC := ACanvas.Handle;
  2113.   FCanvas.Lock;
  2114.   try
  2115.     FCanvas.Handle := DC;
  2116.     FCanvas.Font   := Font;
  2117.     FCanvas.Brush.Color := clBtnFace;
  2118.     FCanvas.Brush.Style := bsSolid;
  2119.  
  2120.     {Draw}
  2121.     if Index = -1 then
  2122.     begin
  2123.       nCount := Panels.Count;
  2124.       for i := 0 to nCount - 1 do with DrawInfo.Horz do
  2125.       begin
  2126.         Panel := Panels.Items[i];
  2127.         if Panel.Visible and (Panel.ColIndex <> -1) then
  2128.         begin
  2129.           R := Grid.BoxRect(Panel.ColIndex, 0, Panel.ColIndex, 0);
  2130.           if (R.Left >= FixedBoundary) and not IsRectEmpty(R)then
  2131.           begin
  2132.             R.Top := Rect.Top;
  2133.             R.Bottom := Rect.Bottom;
  2134.             InflateRect(R, 0, -1);
  2135.             if Panel.Draw(R, DrawInfo) then
  2136.               ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
  2137.           end;
  2138.         end;
  2139.       end
  2140.     end
  2141.     else begin
  2142.       Panel := Panels.Items[Index];
  2143.       R := Grid.BoxRect(Panel.ColIndex, 0, Panel.ColIndex, 0);
  2144.       if not IsRectEmpty(R) then
  2145.       begin
  2146.         R.Left := _intMax(R.Left, DrawInfo.Horz.FixedBoundary);
  2147.         R.Top := Rect.Top;
  2148.         R.Bottom := Rect.Bottom;
  2149.         if not( Panel.Visible and Panel.Draw(R, DrawInfo) ) then Canvas.FillRect(R);
  2150.       end;
  2151.     end;
  2152.  
  2153.   finally
  2154.     FCanvas.Handle := 0;
  2155.     FCanvas.Unlock;
  2156.   end;
  2157. end;
  2158.  
  2159. function TDCFooter.GetColor: TColor;
  2160. begin
  2161.   if Grid <> nil then
  2162.     Result := Grid.FixedColor
  2163.   else
  2164.     Result := clWindow;
  2165. end;
  2166.  
  2167. function TDCFooter.GetFont: TFont;
  2168. begin
  2169.   if Grid <> nil then
  2170.     Result := Grid.Font
  2171.   else
  2172.     Result := nil;
  2173. end;
  2174.  
  2175. function TDCFooter.GetGrid: TDCCustomGrid;
  2176. begin
  2177.   if Assigned(FOwner) then
  2178.     Result := FOwner.Grid
  2179.   else
  2180.     Result := nil;
  2181. end;
  2182.  
  2183. function TDCFooter.GetHeight: integer;
  2184. begin
  2185.   Result := FHeight;
  2186. end;
  2187.  
  2188. function TDCFooter.GetIndex: integer;
  2189. begin
  2190.   if Owner <> nil then
  2191.     Result := Owner.FItems.IndexOf(Self)
  2192.   else
  2193.     Result := -1;
  2194. end;
  2195.  
  2196. function TDCFooter.GetVisible: boolean;
  2197. begin
  2198.   Result := FVisible;
  2199. end;
  2200.  
  2201. procedure TDCFooter.SetStyle(const Value: TBevelStyle);
  2202. begin
  2203.   if FStyle <> Value then
  2204.   begin
  2205.     FStyle := Value;
  2206.     Changed(False);
  2207.   end;
  2208. end;
  2209.  
  2210. procedure TDCFooter.SetHeight(const Value: integer);
  2211. begin
  2212.   if FHeight <> Value then
  2213.   begin
  2214.     FHeight := Value;
  2215.     Changed(True);
  2216.   end;
  2217. end;
  2218.  
  2219. procedure TDCFooter.SetIndex(const Value: integer);
  2220.  var
  2221.   CurIndex: Integer;
  2222. begin
  2223.   CurIndex := GetIndex;
  2224.   if (CurIndex >= 0) and (CurIndex <> Value) then
  2225.   begin
  2226.     FOwner.FItems.Move(CurIndex, Value);
  2227.     Changed(True);
  2228.   end;
  2229. end;
  2230.  
  2231. procedure TDCFooter.SetOwner(Value: TDCFooters);
  2232. begin
  2233.   if FOwner <> Value then
  2234.   begin
  2235.     if FOwner <> nil then FOwner.RemoveItem(Self);
  2236.     if Value  <> nil then Value.InsertItem(Self);
  2237.     AdjustHeight;
  2238.   end;
  2239. end;
  2240.  
  2241. procedure TDCFooter.SetPanels(const Value: TDCFooterPanels);
  2242. begin
  2243.   FPanels.Assign(Value);
  2244.   Changed(True);
  2245. end;
  2246.  
  2247. procedure TDCFooter.SetVisible(const Value: boolean);
  2248. begin
  2249.   if FVisible <> Value then
  2250.   begin
  2251.     FVisible := Value;
  2252.     Changed(True);
  2253.   end;
  2254. end;
  2255.  
  2256. procedure TDCFooter.UpdatePanel(Index: Integer; Repaint: Boolean);
  2257. begin
  2258.   Owner.RedrawItem(Self, Index);
  2259. end;
  2260.  
  2261. procedure TDCFooter.SetAutoSize(const Value: boolean);
  2262. begin
  2263.   if FAutoSize <> Value then
  2264.   begin
  2265.     FAutoSize := Value;
  2266.     Changed(True);
  2267.   end;
  2268. end;
  2269.  
  2270. procedure TDCFooter.AdjustHeight;
  2271.  var
  2272.   i, nCount, h: integer;
  2273.   Panel: TDCFooterPanel;
  2274. begin
  2275.   if AutoSize then
  2276.   begin
  2277.     nCount := Panels.Count;
  2278.     h := 0;
  2279.     for i := 0 to nCount -1 do
  2280.     begin
  2281.       Panel := Panels.Items[i];
  2282.       if Panel.Visible then h := _IntMax(Panel.AdjustHeight, h);
  2283.     end;
  2284.     FHeight := h;
  2285.   end;
  2286. end;
  2287.  
  2288. { TDCFooterPanels }
  2289.  
  2290. function TDCFooterPanels.Add: TDCFooterPanel;
  2291. begin
  2292.   Result := TDCFooterPanel(inherited Add);
  2293. end;
  2294.  
  2295. constructor TDCFooterPanels.Create(AOwner: TDCFooter);
  2296. begin
  2297.   inherited Create(TDCFooterPanel);
  2298.   FOwner := AOwner;
  2299. end;
  2300.  
  2301. function TDCFooterPanels.GetItem(Index: Integer): TDCFooterPanel;
  2302. begin
  2303.   Result := TDCFooterPanel(inherited GetItem(Index));
  2304. end;
  2305.  
  2306. function TDCFooterPanels.GetOwner: TPersistent;
  2307. begin
  2308.   Result := FOwner;
  2309. end;
  2310.  
  2311. procedure TDCFooterPanels.SetItem(Index: Integer; Value: TDCFooterPanel);
  2312. begin
  2313.   inherited SetItem(Index, Value);
  2314. end;
  2315.  
  2316. procedure TDCFooterPanels.Update(Item: TCollectionItem);
  2317. begin
  2318.   inherited;
  2319.   with FOwner do
  2320.   begin
  2321.     if (Item = nil) or AutoSize then
  2322.       Changed(False)
  2323.     else
  2324.       UpdatePanel(Item.Index, False)
  2325.   end;
  2326. end;
  2327.  
  2328. { TDCFooterPanel }
  2329.  
  2330. constructor TDCFooterPanel.Create(Collection: TCollection);
  2331. begin
  2332.   inherited;
  2333.   FStyle := beLowered;
  2334.   FColIndex := -1;
  2335.   FVisible := False;
  2336. end;
  2337.  
  2338. function TDCFooterPanel.Draw(const Rect: TRect; DrawInfo: TGridDrawInfo): boolean;
  2339. begin
  2340.   Result := False;
  2341. end;
  2342.  
  2343. function TDCFooterPanel.GetCanvas: TCanvas;
  2344. begin
  2345.   Result := Footer.Canvas;
  2346. end;
  2347.  
  2348. function TDCFooterPanel.GetColIndex: integer;
  2349. begin
  2350.   Result := FColIndex;
  2351. end;
  2352.  
  2353. function TDCFooterPanel.GetFooter: TDCFooter;
  2354. begin
  2355.   Result := TDCFooterPanels(Collection).FOwner;
  2356. end;
  2357.  
  2358. procedure TDCFooterPanel.SetColIndex(const Value: integer);
  2359. begin
  2360.   if FColIndex <> Value then
  2361.   begin
  2362.     FColIndex := Value;
  2363.     Changed(True);
  2364.   end;
  2365. end;
  2366.  
  2367. procedure TDCFooterPanel.SetInternalColIndex(const Value: integer);
  2368. begin
  2369.   if FColIndex <> Value then
  2370.   begin
  2371.     FColIndex := Value;
  2372.     Changed(True);
  2373.   end;
  2374. end;
  2375.  
  2376. procedure TDCFooterPanel.SetStyle(const Value: TBevelStyle);
  2377. begin
  2378.   if FStyle <> Value then
  2379.   begin
  2380.     FStyle := Value;
  2381.     Changed(False);
  2382.   end;
  2383. end;
  2384.  
  2385. procedure TDCFooterPanel.SetVisible(const Value: boolean);
  2386. begin
  2387.   if FVisible <> Value then
  2388.   begin
  2389.     FVisible := Value;
  2390.     Changed(False);
  2391.   end;
  2392. end;
  2393.  
  2394. function TDCFooterPanel.AdjustHeight: integer;
  2395. begin
  2396.   Result := Footer.Height;
  2397. end;
  2398.  
  2399. { TDCFooters }
  2400.  
  2401. procedure TDCFooters.BeginUpdate;
  2402. begin
  2403.   Inc(FUpdateCount);
  2404. end;
  2405.  
  2406. procedure TDCFooters.Changed;
  2407. begin
  2408.   if FUpdateCount = 0 then Update(nil);
  2409. end;
  2410.  
  2411. procedure TDCFooters.Clear;
  2412.  var
  2413.   i, iCount: integer;
  2414. begin
  2415.   BeginUpdate;
  2416.   iCount := Count;
  2417.   for i := iCount-1 downto 0 do Items[i].Free;
  2418.   EndUpdate;
  2419. end;
  2420.  
  2421. constructor TDCFooters.Create(AOwner: TDCCustomGrid);
  2422. begin
  2423.   inherited Create;
  2424.   FItems := TList.Create;
  2425.   FOwner := AOwner;
  2426.   FHeight := 0;
  2427.   FStyle := beFlat;
  2428. end;
  2429.  
  2430. procedure TDCFooters.Delete(Index: Integer);
  2431. begin
  2432.   TDCFooter(FItems[Index]).Free;
  2433. end;
  2434.  
  2435. destructor TDCFooters.Destroy;
  2436. begin
  2437.   FItems.Free;
  2438.   inherited;
  2439. end;
  2440.  
  2441. procedure TDCFooters.Draw;
  2442.  var
  2443.   ARect, BRect, mRect: TRect;
  2444.   i, nCount, SaveIndex: integer;
  2445.   Footer: TDCFooter;
  2446.   DrawInfo: TGridDrawInfo;
  2447. begin
  2448.   SaveIndex := SaveDC(Grid.Canvas.Handle);
  2449.   try
  2450.     ARect := BoundsRect;
  2451.     BRect := PaintEdge(ARect);
  2452.     mRect := GetMargins;
  2453.  
  2454.     Inc(ARect.Left, mRect.Left);
  2455.     Inc(ARect.Top, mRect.Top);
  2456.     Dec(ARect.Right, mRect.Right);
  2457.  
  2458.     nCount := Count;
  2459.     Grid.CalcDrawInfo(DrawInfo);
  2460.     for i := 0 to nCount -1 do
  2461.     begin
  2462.       Footer := Items[i];
  2463.       if Footer.Visible then
  2464.       begin
  2465.         Footer.DrawItem(Grid.Canvas, DrawInfo,
  2466.           Rect(ARect.Left, ARect.Top, ARect.Right, ARect.Top + Footer.Height), -1);
  2467.         Inc(ARect.Top, Footer.Height);
  2468.       end;
  2469.     end;
  2470.     Grid.Canvas.FillRect(BRect);
  2471.   finally
  2472.     RestoreDC(Grid.Canvas.Handle, SaveIndex);
  2473.   end;
  2474. end;
  2475.  
  2476. function TDCFooters.PaintEdge(ARect: TRect): TRect;
  2477. begin
  2478.   with Grid, Canvas do
  2479.   begin
  2480.     Brush.Color := clBtnFace;
  2481.     case FStyle of
  2482.       beNone:;
  2483.       beLowered:;
  2484.       beRaised:
  2485.         begin
  2486.           DrawEdge(Handle, ARect, BDR_SUNKENOUTER, BF_RECT);
  2487.           InflateRect(ARect, -1, -1);
  2488.           DrawEdge(Handle, ARect, BDR_RAISEDINNER, BF_RECT);
  2489.           InflateRect(ARect, -1, -1);
  2490.         end;
  2491.       beFlat:
  2492.         begin
  2493.           DrawEdge(Handle, ARect, BDR_SUNKENOUTER, BF_TOP);
  2494.           Inc(ARect.Top, 1);
  2495.           DrawEdge(Handle, ARect, BDR_SUNKENINNER, BF_BOTTOMRIGHT);
  2496.           DrawEdge(Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);
  2497.           InflateRect(ARect, -1, -1);
  2498.         end;
  2499.       beSingle:
  2500.         begin
  2501.           DrawEdge(Handle, ARect, BDR_SUNKENOUTER, BF_TOP);
  2502.           Inc(ARect.Top, 1);
  2503.         end;
  2504.     end;
  2505.   end;
  2506.   Result := ARect;
  2507. end;
  2508.  
  2509. procedure TDCFooters.EndUpdate;
  2510. begin
  2511.   Dec(FUpdateCount);
  2512.   if FUpdateCount = 0 then Update(nil);
  2513. end;
  2514.  
  2515. function TDCFooters.GetBoundsRect: TRect;
  2516. begin
  2517.   Result := FOwner.GetGridBounds;
  2518.   Result.Top := Result.Bottom - GetHeight;
  2519. end;
  2520.  
  2521. function TDCFooters.GetCount: Integer;
  2522. begin
  2523.   Result := FItems.Count;
  2524. end;
  2525.  
  2526. function TDCFooters.GetHeight: integer;
  2527. begin
  2528.   Result  := FHeight;
  2529. end;
  2530.  
  2531. function TDCFooters.GetItem(Index: Integer): TDCFooter;
  2532. begin
  2533.   Result := FItems.Items[Index]
  2534. end;
  2535.  
  2536. function TDCFooters.GetMargins: TRect;
  2537.  const
  2538.    aMargins: array[TBevelStyle] of TRect =
  2539.      ( {beNone}    (Left: 1; Top: 1; Right: 1; Bottom: 1),
  2540.        {beLowered} (Left: 3; Top: 3; Right: 3; Bottom: 3),
  2541.        {beRaised}  (Left: 3; Top: 3; Right: 3; Bottom: 3),
  2542.        {beFlat}    (Left: 2; Top: 3; Right: 2; Bottom: 2),
  2543.        {beSingle}  (Left: 1; Top: 2; Right: 1; Bottom: 1));
  2544. begin
  2545.   Result := aMargins[FStyle];
  2546. end;
  2547.  
  2548. function TDCFooters.GetOwner: TPersistent;
  2549. begin
  2550.   Result := FOwner;
  2551. end;
  2552.  
  2553. procedure TDCFooters.InsertItem(Item: TDCFooter);
  2554. begin
  2555.   FItems.Add(Item);
  2556.   Item.FOwner := Self;
  2557.   Changed;
  2558. end;
  2559.  
  2560. procedure TDCFooters.RemoveItem(Item: TDCFooter);
  2561. begin
  2562.   FItems.Remove(Item);
  2563.   Item.FOwner := nil;
  2564.   Changed;
  2565. end;
  2566.  
  2567. procedure TDCFooters.SetItem(Index: Integer; const Value: TDCFooter);
  2568. begin
  2569.  
  2570. end;
  2571.  
  2572. procedure TDCFooters.Update(Item: TDCFooter);
  2573. begin
  2574.   FOwner.BeginLayout;
  2575.   UpdateSize;
  2576.   FOwner.EndLayout;
  2577. end;
  2578.  
  2579. function TDCFooters.UpdateSize: integer;
  2580.  var
  2581.   i, nCount: integer;
  2582.   Footer: TDCFooter;
  2583.   mRect: TRect;
  2584. begin
  2585.   nCount  := Count;
  2586.   mRect   := GetMargins;
  2587.   FHeight := 0;
  2588.   for i := 0 to nCount -1 do
  2589.   begin
  2590.     Footer := Items[i];
  2591.     if Footer.Visible then Inc(FHeight, Footer.Height);
  2592.   end;
  2593.   if FHeight > 0 then Inc(FHeight, mRect.Top + mRect.Bottom);
  2594.   Result := FHeight;
  2595. end;
  2596.  
  2597. procedure TDCFooters.SetStyle(const Value: TBevelStyle);
  2598. begin
  2599.   if FStyle <> Value then
  2600.   begin
  2601.     FStyle := Value;
  2602.     Changed;
  2603.   end;
  2604. end;
  2605.  
  2606. procedure TDCFooters.ColumnMoved(FromIndex, ToIndex: Integer);
  2607.  var
  2608.   i, nCount: integer;
  2609. begin
  2610.   BeginUpdate;
  2611.   nCount  := Count;
  2612.   for i := 0 to nCount -1 do Items[i].ColumnMoved(FromIndex, ToIndex);
  2613.   EndUpdate;
  2614. end;
  2615.  
  2616. procedure TDCFooters.RedrawItem(Item: TDCFooter; Index: integer);
  2617.  var
  2618.   ARect, BRect, mRect: TRect;
  2619.   i, nCount, SaveIndex: integer;
  2620.   Footer: TDCFooter;
  2621.   DrawInfo: TGridDrawInfo;
  2622. begin
  2623.   SaveIndex := SaveDC(Grid.Canvas.Handle);
  2624.   try
  2625.     ARect := BoundsRect;
  2626.     BRect := PaintEdge(ARect);
  2627.     mRect := GetMargins;
  2628.  
  2629.     Inc(ARect.Left, mRect.Left);
  2630.     Inc(ARect.Top, mRect.Top);
  2631.     Dec(ARect.Right, mRect.Right);
  2632.  
  2633.     nCount := Count;
  2634.     Grid.CalcDrawInfo(DrawInfo);
  2635.     for i := 0 to nCount -1 do
  2636.     begin
  2637.       Footer := Items[i];
  2638.       if Footer = Item then
  2639.       begin
  2640.         Footer.DrawItem(Grid.Canvas, DrawInfo,
  2641.           Rect(ARect.Left, ARect.Top, ARect.Right, ARect.Top + Footer.Height), Index);
  2642.         Break;
  2643.       end;
  2644.       if Footer.Visible then Inc(ARect.Top, Footer.Height);
  2645.     end;
  2646.   finally
  2647.     RestoreDC(Grid.Canvas.Handle, SaveIndex);
  2648.   end;
  2649. end;
  2650.  
  2651. procedure TDCFooters.Invalidate;
  2652.  var
  2653.   R: TRect;
  2654. begin
  2655.   R := BoundsRect;
  2656.   InvalidateRect(Grid.Canvas.Handle, @R, False);
  2657. end;
  2658.  
  2659. { TDataGridDesigner }
  2660.  
  2661. constructor TDataGridDesigner.Create(DataGrid: TDCCustomGrid);
  2662. begin
  2663.   FDataGrid := DataGrid;
  2664.   FDataGrid.FDesigner := Self;
  2665. end;
  2666.  
  2667. destructor TDataGridDesigner.Destroy;
  2668. begin
  2669.   FDataGrid.FDesigner := nil;
  2670.   inherited;
  2671. end;
  2672.  
  2673. { TDCFooterTextPanel }
  2674.  
  2675. function TDCFooterTextPanel.AdjustHeight: integer;
  2676.  var
  2677.   DC: HDC;
  2678.   Rect: TRect;
  2679. begin
  2680.   if Visible then
  2681.   begin
  2682.     Rect := Footer.Grid.GetGridBounds;
  2683.     DC := GetDC(0);
  2684.     try
  2685.       Footer.Canvas.Handle := DC;
  2686.       SetRectEmpty(Rect);
  2687.       DoDrawText(Rect, DT_EXPANDTABS or DT_CALCRECT);
  2688.       Canvas.Handle := 0;
  2689.     finally
  2690.       ReleaseDC(0, DC);
  2691.       Result := Rect.Bottom  - Rect.Top + 4;
  2692.       case Style of
  2693.         beNone:
  2694.           ;
  2695.         beLowered:
  2696.           Inc(Result, 2);
  2697.         beRaised:
  2698.           Inc(Result, 2);
  2699.         beFlat:
  2700.           ;
  2701.         beSingle:
  2702.           Inc(Result, 2);
  2703.       end;
  2704.     end
  2705.   end
  2706.   else
  2707.     Result := 0;
  2708. end;
  2709.  
  2710. procedure TDCFooterTextPanel.DoDrawText(var Rect: TRect; Flags: Integer);
  2711. begin
  2712.   DrawText(Canvas.Handle, PChar(Text), Length(Text), Rect, Flags);
  2713. end;
  2714.  
  2715. function TDCFooterTextPanel.Draw(const Rect: TRect; DrawInfo: TGridDrawInfo): boolean;
  2716.  var
  2717.   R: TRect;
  2718. begin
  2719.   R := PaintEdge(Rect, DrawInfo);
  2720.   Canvas.FillRect(R);
  2721.   InflateRect(R, -1, -1);
  2722.   DoDrawText(R, DT_VCENTER or DT_SINGLELINE or DT_WORDBREAK or DT_END_ELLIPSIS);
  2723.   Result := True;
  2724. end;
  2725.  
  2726. function TDCFooterTextPanel.PaintEdge(Rect: TRect; DrawInfo: TGridDrawInfo): TRect;
  2727.  var
  2728.   Brush: HBRUSH;
  2729. begin
  2730.   Result := Rect;
  2731.   if ColIndex = DrawInfo.Horz.LastFullVisibleCell + 1 then Inc(Result.Right);
  2732.   case Style of
  2733.     beNone:;
  2734.     beLowered:
  2735.       begin
  2736.         DrawEdge(Canvas.Handle, Result, BDR_SUNKENOUTER, BF_RECT);
  2737.         InflateRect(Result, -1, -1);
  2738.       end;
  2739.     beRaised:
  2740.       begin
  2741.         DrawEdge(Canvas.Handle, Result, BDR_RAISEDINNER, BF_RECT);
  2742.         InflateRect(Result, -1, -1);
  2743.       end;
  2744.     beFlat:
  2745.       begin
  2746.         {!}
  2747.       end;
  2748.     beSingle:
  2749.       begin
  2750.         Brush := CreateSolidBrush(ColorToRGB(clBtnShadow));
  2751.         try
  2752.           FrameRect(Canvas.Handle, Result, Brush);
  2753.           InflateRect(Result, -1, -1);
  2754.         finally
  2755.           DeleteObject(Brush);
  2756.         end;
  2757.       end;
  2758.   end;
  2759. end;
  2760.  
  2761. procedure TDCFooterTextPanel.SetText(const Value: string);
  2762. begin
  2763.   if FText <> Value then
  2764.   begin
  2765.     FText := Value;
  2766.     Changed(False);
  2767.   end;
  2768. end;
  2769.  
  2770. { TSelectedArea }
  2771.  
  2772. constructor TSelectedArea.Create(AGrid: TDCCustomGrid);
  2773. begin
  2774.   inherited Create;
  2775.   FGrid := AGrid;
  2776. end;
  2777.  
  2778. destructor TSelectedArea.Destroy;
  2779. begin
  2780.   inherited;
  2781. end;
  2782.  
  2783. function TSelectedArea.GetGrid: TDCCustomGrid;
  2784. begin
  2785.   Result := FGrid;
  2786. end;
  2787.  
  2788. function TSelectedArea.IsEmpty: boolean;
  2789. begin
  2790.   Result := True;
  2791. end;
  2792.  
  2793. initialization
  2794.   ArrowsBitmap := TBitmap.Create;
  2795.   CreateGridIndicators;
  2796.  
  2797. finalization
  2798.   ArrowsBitmap.Free;
  2799.   DestroyGridIndicators;
  2800.  
  2801. end.
  2802.