On Wed, 2007-06-20 at 17:51 -0500, Jesus Reyes wrote:
> > 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.
> 
> Looks nice!
> 
> About the patch, I just applied and didn't take a closer look, will
> try to do later, initially there seems to be many problems for
> example, the TStringGrid editor doesn't know about subrows, and
> crashed my lazarus badly, I also wasn't able to reproduce your image,
> if issues are fixed I think we should add it.

Here is a new patch. This one works better.

-- 
Met vriendelijke groeten,

  Joost van der Sluis
  CNOC Informatiesystemen en Netwerken
  http://www.cnoc.nl
Index: grids.pas
===================================================================
--- grids.pas	(revision 11403)
+++ 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;
@@ -763,6 +767,7 @@
     function  GetColumnReadonly(Column: Integer): boolean;
     function  GetColumnTitle(Column: Integer): string;
     function  GetColumnWidth(Column: Integer): Integer;
+    function  GetColumnSpanSubRows(Column: Integer): Integer;
     function  GetDeltaMoveNext(const Inverse: boolean; var ACol,ARow: Integer): boolean; virtual;
     function  GetDefaultColumnAlignment(Column: Integer): TAlignment; virtual;
     function  GetDefaultColumnWidth(Column: Integer): Integer; virtual;
@@ -904,6 +909,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 +1320,7 @@
     property RowCount;
     property ScrollBars;
     property ShowHint;
+    property SubRowCount;
     property TabOrder;
     property TabStop;
     property TitleFont;
@@ -1611,7 +1619,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 +1642,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 +2021,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 +2049,7 @@
         FTopLeft.X:=0;
         AddDel(FCols, 1);
         FGCache.AccumWidth.Count:=1;
+        FGCache.SubRow.Count:=1;
       end;
     end;
     SizeChanged(OldCount, OldValue);
@@ -2261,13 +2270,17 @@
   procedure CalcNewCachedSizes;
   var
     i: Integer;
+    SubRow : PtrInt;
   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);
+      subrow := subrow+GetColumnSpanSubRows(i);
+      if ((subrow mod FSubRowcount) = 0) or (i=colcount-1) 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 +2511,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,
@@ -2524,7 +2537,8 @@
     W:=GetColWidths(Result.Left) + FGCache.FixedWidth- FGCache.TLColOff;
     while (Result.Right<ColCount-1)and(W<FGCache.ClientWidth) do begin
       Inc(Result.Right);
-      W:=W+GetColWidths(Result.Right);
+      if (ptrint(FGCache.SubRow[Result.Right]) mod FSubRowcount)=0 then
+        W:=W+GetColWidths(Result.Right);
     end;
     FGCache.MaxClientXY.X := W;
   end else begin
@@ -2977,7 +2991,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;
@@ -2991,7 +3005,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 := [];
@@ -3020,7 +3035,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);
@@ -3033,7 +3049,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;
@@ -4026,7 +4042,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);
@@ -4171,7 +4187,7 @@
   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;
@@ -4181,8 +4197,13 @@
       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
+        Dim := (GetRowHeights(index)) div FSubRowcount * GetColumnSpanSubRows(col);
+        StartPos := PtrInt(AccumHeight[index])+(PtrInt(FGCache.SubRow[Col]) * Dim);
+      end;
     end;
     StartPos := StartPos + GetBorderWidth;
     if not Relative then begin
@@ -4329,10 +4350,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;
@@ -4370,6 +4393,7 @@
       end;
       FCols.Delete(Index);
       FGCache.AccumWidth.Delete(Index);
+      FGCache.SubRow.Delete(Index);
       ColRowDeleted(True, Index);
       FixPosition;
     end;
@@ -5062,6 +5086,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)*GetColumnSpanSubRows(ACol)) and
+        (ACol < FColumns.Count-1) do
+    begin
+    dummy := dummy - (GetRowHeights(ARow) div FSubRowcount)*GetColumnSpanSubRows(ACol);
+    inc(ACol);
+    end;
 end;
 
 { Convert a fisical Mouse coordinate into a logical cell coordinate }
@@ -6014,6 +6045,17 @@
     Result := GetDefaultColumnWidth(Column);
 end;
 
+function TCustomGrid.GetColumnSpanSubRows(Column: Integer): Integer;
+var
+  C: TGridColumn;
+begin
+  C := ColumnFromGridColumn(Column);
+  if C<>nil then
+    Result := C.SpanSubRows
+  else
+    Result := 1;
+end;
+
 // return the relative cell coordinate of the next cell
 // considering AutoAdvance property and selectable cells.
 function TCustomGrid.GetDeltaMoveNext(const Inverse: boolean;
@@ -6418,7 +6460,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);
@@ -6502,6 +6546,7 @@
   FreeThenNil(FButtonEditor);
   FreeThenNil(FColumns);
   FreeThenNil(FGCache.AccumWidth);
+  FreeThenNil(FGCache.SubRow);
   FreeThenNil(FGCache.AccumHeight);
   FreeThenNil(FCols);
   FreeThenNil(FRows);
@@ -8292,6 +8337,7 @@
       Title := TGridColumn(Source).Title;
       Width := TGridCOlumn(Source).Width;
       Visible := TGridColumn(Source).Visible;
+      SpanSubRows := TGridColumn(Source).SpanSubRows;
     finally
       Collection.EndUpdate;
     end;
@@ -8342,6 +8388,8 @@
   FPickList:= TStringList.Create;
   FButtonStyle := cbsAuto;
   FDropDownRows := 7;
+
+  FSpanSubRows := 1;
 end;
 
 destructor TGridColumn.Destroy;

Reply via email to