Hi Jesus and the rest,

Attached is a patch to allow 'subrows' in a row in a grid. You can say,
for example that each row should contain two subrows. Then the columns
will be divided over those two rows. Second you can specify for each
column how much subrows it has to 'span'.

For example, with two subrows, and a subrowspan of two for the first
column, you can get something like this:
http://menora.cnoc.nl/public/GridSubrows.png

Attached is a patch. It works reasonable, but there are still some
issues. For example if 'subrows mod columncount<>0' then no background
is painted for the 'empty' part. 

I also think that resizing columns and reordening them will give
problems.

But what do you guys think of the idea and patch?

Joost.
Index: grids.pas
===================================================================
--- grids.pas	(revision 11333)
+++ grids.pas	(working copy)
@@ -362,6 +362,7 @@
     FisDefaultFont: Boolean;
     FPickList: TStrings;
     FMinSize, FMaxSize, FSizePriority: ^Integer;
+    FSpanSubRows: Integer;
 
     procedure FontChanged(Sender: TObject);
     function GetAlignment: TAlignment;
@@ -442,6 +443,7 @@
     property Title: TGridColumnTitle read FTitle write SetTitle;
     property Width: Integer read GetWidth write SetWidth stored IsWidthStored default DEFCOLWIDTH;
     property Visible: Boolean read GetVisible write SetVisible stored IsVisibleStored default true;
+    property SpanSubRows: Integer read FSpanSubRows write FSpanSubRows stored IsVisibleStored default 1;
   end;
 
   TGridPropertyBackup=record
@@ -501,6 +503,7 @@
       ValidGrid: boolean;     // true if there are not fixed cells to show
       AccumWidth: TList;      // Accumulated width per column
       AccumHeight: TList;     // Accumulated Height per row
+      SubRow: TList;          // Place this column in subrow X
       TLColOff,TLRowOff: Integer;   // TopLeft Offset in pixels
       MaxTopLeft: TPoint;     // Max Top left ( cell coorditates)
       HotCell: TPoint;        // currently hot cell
@@ -534,6 +537,7 @@
     FFastEditing: boolean;
     FAltColorStartNormal: boolean;
     FFlat: Boolean;
+    FSubRowcount: Integer;
     FTitleStyle: TTitleStyle;
     FOnCompareCells: TOnCompareCells;
     FGridLineStyle: TPenStyle;
@@ -702,7 +706,7 @@
     procedure ColRowExchanged(IsColumn: Boolean; index,WithIndex: Integer); dynamic;
     procedure ColRowInserted(IsColumn: boolean; index: integer); dynamic;
     procedure ColRowMoved(IsColumn: Boolean; FromIndex,ToIndex: Integer); dynamic;
-    function  ColRowToOffset(IsCol, Relative: Boolean; Index:Integer;
+    function  ColRowToOffset(IsCol, Relative: Boolean; Index:Integer; Col : integer;
                              var StartPos, EndPos: Integer): Boolean;
     function  ColumnIndexFromGridColumn(Column: Integer): Integer;
     function  ColumnFromGridColumn(Column: Integer): TGridColumn;
@@ -904,6 +908,8 @@
     property VisibleColCount: Integer read GetVisibleColCount stored false;
     property VisibleRowCount: Integer read GetVisibleRowCount stored false;
 
+    property SubRowCount: Integer read FSubRowcount write FSubRowcount default 1;
+
     property OnBeforeSelection: TOnSelectEvent read FOnBeforeSelection write FOnBeforeSelection;
     property OnCompareCells: TOnCompareCells read FOnCompareCells write FOnCompareCells;
     property OnPrepareCanvas: TOnPrepareCanvasEvent read FOnPrepareCanvas write FOnPrepareCanvas;
@@ -1313,6 +1319,7 @@
     property RowCount;
     property ScrollBars;
     property ShowHint;
+    property SubRowCount;
     property TabOrder;
     property TabStop;
     property TitleFont;
@@ -1611,7 +1618,6 @@
   Count: Integer;
   aPriority, aMin, aMax: Integer;
   AvailableSize: Integer;
-  TotalWidth: Integer;     // total grid's width
   FixedSizeWidth: Integer; // total width of Fixed Sized Columns
 begin
   if not AutoFillColumns then
@@ -1635,15 +1641,15 @@
 
     Count := 0;
     FixedSizeWidth := 0;
-    TotalWidth := 0;
     for i:=0 to ColCount-1 do begin
       GetAutoFillColumnInfo(i, aMin, aMax, aPriority);
       AvailableSize := GetColWidths(i);
-      if aPriority>0 then
-        Inc(Count)
+      if aPriority>0 then begin
+        if PtrInt(FGCache.SubRow[i]) = 0 then
+          Inc(Count)
+        end
       else
         Inc(FixedSizeWidth, AvailableSize);
-      Inc(TotalWidth, AvailableSize);
     end;
 
     if Count=0 then begin
@@ -2014,6 +2020,7 @@
   if IsColumn then begin
     AddDel(FCols, NewValue);
     FGCache.AccumWidth.Count:=NewValue;
+    FGCache.SubRow.Count:=newValue;
     OldCount:=RowCount;
     if (OldValue=0)and(NewValue>=0) then begin
       FTopLeft.X:=FFixedCols;
@@ -2041,6 +2048,7 @@
         FTopLeft.X:=0;
         AddDel(FCols, 1);
         FGCache.AccumWidth.Count:=1;
+        FGCache.SubRow.Count:=1;
       end;
     end;
     SizeChanged(OldCount, OldValue);
@@ -2261,13 +2269,19 @@
   procedure CalcNewCachedSizes;
   var
     i: Integer;
+    SubRow : PtrInt;
+    C: TGridColumn;
   begin
     // Calculate New Cached Values
     FGCache.GridWidth:=0;
     FGCache.FixedWidth:=0;
+    SubRow := 0;
     For i:=0 To ColCount-1 do begin
       FGCache.AccumWidth[i]:=Pointer(PtrInt(FGCache.GridWidth));
-      FGCache.GridWidth:=FGCache.GridWidth + GetColWidths(i);
+      FGCache.SubRow[i]:=Pointer(SubRow mod FSubRowcount);
+      C := ColumnFromGridColumn(i);
+      if (not assigned(C)) then inc(subrow) else subrow := subrow+c.SpanSubRows;
+      if (subrow mod FSubRowcount) = 0 then FGCache.GridWidth:=FGCache.GridWidth + GetColWidths(i);
       if i<FixedCols then FGCache.FixedWidth:=FGCache.GridWidth;
       {$IfDef dbgVisualChange}
       //DebugLn('FGCache.AccumWidth[',dbgs(i),']=',dbgs(Integer(FGCache.AccumWidth[i])));
@@ -2498,8 +2512,8 @@
 function TCustomGrid.CellRect(ACol, ARow: Integer): TRect;
 begin
   //Result:=ColRowToClientCellRect(aCol,aRow);
-  ColRowToOffset(True, True, ACol, Result.Left, Result.Right);
-  ColRowToOffSet(False,True, ARow, Result.Top, Result.Bottom);
+  ColRowToOffset(True, True, ACol, ACol, Result.Left, Result.Right);
+  ColRowToOffSet(False,True, ARow, ACol, Result.Top, Result.Bottom);
 end;
 
 // The visible grid Depends on  TopLeft and ClientWidht,ClientHeight,
@@ -2968,7 +2982,7 @@
 begin
 
   // Upper and Lower bounds for this row
-  ColRowToOffSet(False, True, aRow, R.Top, R.Bottom);
+  ColRowToOffSet(False, True, aRow, -1, R.Top, R.Bottom);
 
   // is this row within the ClipRect?
   ClipArea := Canvas.ClipRect;
@@ -2982,7 +2996,8 @@
   // Draw columns in this row
   with FGCache.VisibleGrid do begin
     for aCol:=left to Right do begin
-      ColRowToOffset(True, True, aCol, R.Left, R.Right);
+      ColRowToOffset(True, True, aCol, aCol, R.Left, R.Right);
+      ColRowToOffSet(False, True, aRow, aCol, R.Top, R.Bottom);
       if not HorizontalIntersect(R, ClipArea) then
         continue;
       gds := [];
@@ -3011,7 +3026,8 @@
       //if EditorAlwaysShown and (FEditor<>nil) and FEditor.Visible then begin
         //DebugLn('No Draw Focus Rect');
       end else begin
-        ColRowToOffset(True, True, FCol, R.Left, R.Right);
+        ColRowToOffset(True, True, FCol, FCol, R.Left, R.Right);
+        ColRowToOffset(False, True, FRow, FCol, R.Top, R.Bottom);
         // is this column within the ClipRect?
         if HorizontalIntersect( R, ClipArea) then
           DrawFocusRect(FCol,FRow, R);
@@ -3024,7 +3040,7 @@
   // Draw Fixed Columns
   For aCol:=0 to FFixedCols-1 do begin
     gds:=[gdFixed];
-    ColRowToOffset(True, True, aCol, R.Left, R.Right);
+    ColRowToOffset(True, True, aCol, aCol , R.Left, R.Right);
     // is this column within the ClipRect?
     if HorizontalIntersect( R, ClipArea) then
       DoDrawCell;
@@ -4005,7 +4021,7 @@
   begin
     //fSplitter.Y:=OffsetToColRow(False, True, Y, OffTop{dummy});
     if OffsetToColRow(False, True, Y, FSplitter.Y, OffTop{dummy}) then begin
-      ColRowToOffset(False, True, FSplitter.Y, OffTop, OffBottom);
+      ColRowToOffset(False, True, FSplitter.Y,FSplitter.X, OffTop, OffBottom);
       FSplitter.X:=Y;
       if (OffBottom-Y)<(Y-OffTop) then SwapInt(OffTop, OffBottom)
       else Dec(FSplitter.y);
@@ -4150,18 +4166,28 @@
   IsCol=true, Index:=100, TopLeft.x:=98, FixedCols:=1, all ColWidths:=20
   Relative => StartPos := WidthfixedCols+WidthCol98+WidthCol99
   not Relative = Absolute => StartPos := WidthCols(0..99) }
-function TCustomGrid.ColRowToOffset(IsCol, Relative: Boolean; Index:Integer;
+function TCustomGrid.ColRowToOffset(IsCol, Relative: Boolean; Index:Integer; Col : integer;
   var StartPos, EndPos: Integer): Boolean;
 var
   Dim: Integer;
+  c: TGridColumn;
 begin
   with FGCache do begin
     if IsCol then begin
       StartPos:=PtrInt(AccumWidth[index]);
       Dim:=GetColWidths(index);
     end else begin
-      StartPos:=PtrInt(AccumHeight[index]);
-      Dim:= GetRowHeights(index);
+      if col = -1 then begin
+        Dim:= (GetRowHeights(index));
+        StartPos:=PtrInt(AccumHeight[index]);
+      end else begin
+        C := ColumnFromGridColumn(Col);
+        if (not assigned(C)) then
+          Dim := (GetRowHeights(index)) div FSubRowcount
+        else
+          Dim := (GetRowHeights(index)) div FSubRowcount * C.SpanSubRows;
+        StartPos := PtrInt(AccumHeight[index])+(PtrInt(FGCache.SubRow[Col]) * Dim);
+      end;
     end;
     StartPos := StartPos + GetBorderWidth;
     if not Relative then begin
@@ -4308,10 +4334,12 @@
     end else begin
       FCols.Insert(Index, pointer(-1));
       FGCache.AccumWidth.Insert(Index, nil);
+      FGCache.SubRow.Insert(Index,nil);
     end;
   end else begin
     Frows.Insert(Index, pointer(-1));
     FGCache.AccumHeight.Insert(Index, nil);
+    FGCache.SubRow.Insert(Index,nil);
   end;
   ColRowInserted(IsColumn, index);
   VisualChange;
@@ -4349,6 +4377,7 @@
       end;
       FCols.Delete(Index);
       FGCache.AccumWidth.Delete(Index);
+      FGCache.SubRow.Delete(Index);
       ColRowDeleted(True, Index);
       FixPosition;
     end;
@@ -5041,6 +5070,13 @@
   // Do not raise Exception if out of range
   OffsetToColRow(True, True, X, ACol, dummy);
   OffsetToColRow(False,True, Y, ARow, dummy);
+
+  while (dummy > (GetRowHeights(ARow) div FSubRowcount)*FColumns[ACol].SpanSubRows) and
+        (ACol < FColumns.Count-1) do
+    begin
+    dummy := dummy - (GetRowHeights(ARow) div FSubRowcount)*FColumns[ACol].SpanSubRows;
+    inc(ACol);
+    end;
 end;
 
 { Convert a fisical Mouse coordinate into a logical cell coordinate }
@@ -6397,7 +6433,9 @@
   // fGrid needs to be created before that
   FCols:=TList.Create;
   FRows:=TList.Create;
+  FSubRowcount := 1;
   FGCache.AccumWidth:=TList.Create;
+  FGCache.SubRow:=TList.Create;
   FGCache.AccumHeight:=TList.Create;
   FGSMHBar := GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetricsGapSize(SM_CYHSCROLL);
   FGSMVBar := GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetricsGapSize(SM_CXVSCROLL);
@@ -6481,6 +6519,7 @@
   FreeThenNil(FButtonEditor);
   FreeThenNil(FColumns);
   FreeThenNil(FGCache.AccumWidth);
+  FreeThenNil(FGCache.SubRow);
   FreeThenNil(FGCache.AccumHeight);
   FreeThenNil(FCols);
   FreeThenNil(FRows);
@@ -8271,6 +8310,7 @@
       Title := TGridColumn(Source).Title;
       Width := TGridCOlumn(Source).Width;
       Visible := TGridColumn(Source).Visible;
+      SpanSubRows := TGridColumn(Source).SpanSubRows;
     finally
       Collection.EndUpdate;
     end;
@@ -8321,6 +8361,8 @@
   FPickList:= TStringList.Create;
   FButtonStyle := cbsAuto;
   FDropDownRows := 7;
+
+  FSpanSubRows := 1;
 end;
 
 destructor TGridColumn.Destroy;

Reply via email to