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;