View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0027000 | Lazarus | LCL | public | 2014-11-05 22:18 | 2014-11-07 16:45 |
Reporter | wp | Assigned To | Jesus Reyes | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | 1.3 (SVN) | Product Build | |||
Target Version | 1.2.8 | Fixed in Version | 1.3 (SVN) | ||
Summary | 0027000: [Patch] Multiple range select in grids | ||||
Description | Using TCustomGrid and its descendants, TDrawGrid and TStringGrid, it is possible to select only a single cell range. Standard behavior, particularly of spreadsheet applications, is selection of multiple ranges which is achieve by holding the CTRL key down while the next ranges are selected by the mouse. In the attached patch this behavior implemented also for TCustomGrid. There is a new property RangeSelectMode: TRangeSelectMode = (rsmSingle, rsmMulti). Multi-selection is achieved by setting this property to rsmMulti and having the grid option goRangeSelect set. The default behavior is rsmSingle and does not break existing programs. After application of the patch, the new behavior can be tested on the attached demo (see also attached screenshot). | ||||
Tags | No tags attached. | ||||
Fixed in Revision | 46767 | ||||
LazTarget | 1.4 | ||||
Widgetset | |||||
Attached Files |
|
|
Grid_MultiSelect.zip (2,320 bytes) |
|
|
|
grids.pas.patch (7,960 bytes)
Index: lcl/grids.pas =================================================================== --- lcl/grids.pas (revision 46762) +++ lcl/grids.pas (working copy) @@ -126,6 +126,9 @@ TAutoAdvance = (aaNone,aaDown,aaRight,aaLeft, aaRightDown, aaLeftDown, aaRightUp, aaLeftUp); + { Option goRangeSelect: --> select a single range only, or multiple ranges } + TRangeSelectMode = (rsmSingle, rsmMulti); + TItemType = (itNormal,itCell,itColumn,itRow,itFixed,itFixedColumn,itFixedRow,itSelected); TColumnButtonStyle = ( @@ -611,6 +614,7 @@ type TGridCoord = TPoint; TGridRect = TRect; + TGridRectArray = array of TGridRect; TSizingRec = record Index: Integer; @@ -675,6 +679,8 @@ FFastEditing: boolean; FAltColorStartNormal: boolean; FFlat: Boolean; + FRangeSelectMode: TRangeSelectMode; + FSelections: TGridRectArray; FOnUserCheckboxBitmap: TUserCheckboxBitmapEvent; FSortOrder: TSortOrder; FSortColumn: Integer; @@ -793,6 +799,8 @@ function GetBorderWidth: Integer; function GetRowCount: Integer; function GetRowHeights(Arow: Integer): Integer; + function GetSelectedRange(AIndex: Integer): TGridRect; + function GetSelectedRangeCount: Integer; function GetSelection: TGridRect; function GetTopRow: Longint; function GetVisibleColCount: Integer; @@ -833,6 +841,7 @@ procedure SetGridLineWidth(const AValue: Integer); procedure SetLeftCol(const AValue: Integer); procedure SetOptions(const AValue: TGridOptions); + procedure SetRangeSelectMode(const AValue: TRangeSelectMode); procedure SetRow(AValue: Integer); procedure SetRowCount(AValue: Integer); procedure SetRowHeights(Arow: Integer; Avalue: Integer); @@ -854,6 +863,7 @@ protected fGridState: TGridState; class procedure WSRegisterClass; override; + procedure AddSelectedRange; procedure AdjustClientRect(var ARect: TRect); override; procedure AdjustEditorBounds(NewCol,NewRow:Integer); virtual; procedure AssignTo(Dest: TPersistent); override; @@ -871,6 +881,7 @@ procedure CellClick(const aCol,aRow: Integer; const Button:TMouseButton); virtual; procedure CheckLimits(var aCol,aRow: Integer); procedure CheckLimitsWithError(const aCol, aRow: Integer); + procedure ClearSelections; procedure CMBiDiModeChanged(var Message: TLMessage); message CM_BIDIMODECHANGED; procedure CMMouseEnter(var Message: TLMessage); message CM_MOUSEENTER; procedure CMMouseLeave(var Message :TLMessage); message CM_MouseLeave; @@ -1112,6 +1123,7 @@ property LeftCol:Integer read GetLeftCol write SetLeftCol; property MouseWheelOption: TMouseWheelOption read FMouseWheelOption write FMouseWheelOption default mwCursor; property Options: TGridOptions read FOptions write SetOptions default DefaultGridOptions; + property RangeSelectMode: TRangeSelectMode read FRangeSelectMode write SetRangeSelectMode default rsmSingle; property Row: Integer read FRow write SetRow; property RowCount: Integer read GetRowCount write SetRowCount default 5; property RowHeights[aRow: Integer]: Integer read GetRowHeights write SetRowHeights; @@ -1171,7 +1183,7 @@ procedure EndUpdate(aRefresh: boolean = true); procedure EraseBackground(DC: HDC); override; function Focused: Boolean; override; - + function HasMultiSelection: Boolean; procedure InvalidateCell(aCol, aRow: Integer); overload; procedure InvalidateCol(ACol: Integer); procedure InvalidateRange(const aRange: TRect); @@ -1189,6 +1201,8 @@ procedure SaveToStream(AStream: TStream); procedure SetFocus; override; + property SelectedRange[AIndex: Integer]: TGridRect read GetSelectedRange; + property SelectedRangeCount: Integer read GetSelectedRangeCount; property SortOrder: TSortOrder read FSortOrder write FSortOrder; property SortColumn: Integer read FSortColumn; property TabStop default true; @@ -1428,6 +1442,7 @@ property ParentFont; property ParentShowHint; property PopupMenu; + property RangeSelectMode; property RowCount; property ScrollBars; property ShowHint; @@ -1644,6 +1659,7 @@ property ParentFont; property ParentShowHint; property PopupMenu; + property RangeSelectMode; property RowCount; property ScrollBars; property ShowHint; @@ -2908,6 +2924,13 @@ Click; end; +procedure TCustomGrid.SetRangeSelectMode(const AValue: TRangeSelectMode); +begin + if FRangeSelectMode=AValue then exit; + FRangeSelectMode := AValue; + ClearSelections; +end; + procedure TCustomGrid.SetRow(AValue: Integer); begin if AValue=FRow then Exit; @@ -4590,6 +4613,17 @@ RegisterCustomGrid; end; +procedure TCustomGrid.AddSelectedRange; +var + n: Integer; +begin + if (goRangeSelect in Options) and (FRangeSelectMode = rsmMulti) then begin + n := Length(FSelections); + SetLength(FSelections, n+1); + FSelections[n] := FRange; + end; +end; + procedure TCustomGrid.AdjustClientRect(var ARect: TRect); begin inherited AdjustClientRect(ARect); @@ -4955,11 +4989,25 @@ end; function TCustomGrid.GetIsCellSelected(aCol, aRow: Integer): boolean; +var + i: Integer; begin Result:= (FRange.Left<=aCol) and (aCol<=FRange.Right) and (FRange.Top<=aRow) and (aRow<=FRange.Bottom); + + if not Result and (goRangeSelect in FOptions) and (RangeSelectMode = rsmMulti) + then + for i:=0 to High(FSelections) do + if (FSelections[i].Left <= aCol) and + (ACol <= FSelections[i].Right) and + (FSelections[i].Top <= ARow) and + (ARow <= FSelections[i].Bottom) + then begin + Result := true; + exit; + end; end; function TCustomGrid.GetSelectedColumn: TGridColumn; @@ -5218,6 +5266,20 @@ SelectActive := False; end; +function TCustomGrid.GetSelectedRange(AIndex: Integer): TGridRect; +begin + if AIndex >= Length(FSelections) then + Result := FRange + else + Result := FSelections[AIndex]; +end; + +function TCustomGrid.GetSelectedRangeCount: Integer; +begin + Result := Length(FSelections) + 1; + // add 1 because the current selection (FRange) is not stored in the array +end; + function TCustomGrid.GetSelection: TGridRect; begin Result:=FRange; @@ -6096,6 +6158,16 @@ if ssShift in Shift then SelectActive:=(goRangeSelect in Options) else begin + if (goRangeSelect in Options) and (FRangeSelectMode = rsmMulti) + then begin + if (ssCtrl in Shift) then + AddSelectedRange + else begin + ClearSelections; + Invalidate; + end; + end; + // shift is not pressed any more cancel SelectActive if necessary if SelectActive then CancelSelection; @@ -7336,6 +7408,11 @@ raise EGridException.Create(rsGridIndexOutOfRange); end; +procedure TCustomGrid.ClearSelections; +begin + SetLength(FSelections, 0); +end; + procedure TCustomGrid.CMBiDiModeChanged(var Message: TLMessage); begin VisualChange; @@ -7457,6 +7534,12 @@ InvalidateCell(ACol,ARow, False); end; +function TCustomGrid.HasMultiSelection: Boolean; +begin + Result := (goRangeSelect in Options) and + (FRangeSelectMode = rsmMulti) and (Length(FSelections) > 0); +end; + procedure TCustomGrid.InvalidateCell(aCol, aRow: Integer; Redraw: Boolean); var R: TRect; @@ -10345,6 +10428,11 @@ procedure TCustomStringGrid.DoPasteFromClipboard; begin + // Unpredictable results when a multiple selection is pasted back in. + // Therefore we inhibit this here. + if HasMultiSelection then + exit; + if EditingAllowed(Col) and Clipboard.HasFormat(CF_TEXT) then begin SelectionSetText(Clipboard.AsText); end; |
|
Thanks, applied with a change: use ssMeta in Mac OS X and ssCtrl elsewhere |
|
Thank you |
Date Modified | Username | Field | Change |
---|---|---|---|
2014-11-05 22:18 | wp | New Issue | |
2014-11-05 22:18 | wp | File Added: grids.pas.patch | |
2014-11-05 22:19 | wp | File Added: Grid_MultiSelect.zip | |
2014-11-05 22:20 | wp | File Added: grid_multiselect.png | |
2014-11-05 22:21 | wp | Description Updated | View Revisions |
2014-11-05 23:44 | wp | Target Version | => 1.4 |
2014-11-05 23:44 | wp | Summary | Multiple range select in grids => [Patch] Multiple range select in grids |
2014-11-05 23:58 | wp | File Deleted: grids.pas.patch | |
2014-11-05 23:59 | wp | File Added: grids.pas.patch | |
2014-11-06 07:49 | Jesus Reyes | Assigned To | => Jesus Reyes |
2014-11-06 07:49 | Jesus Reyes | Status | new => assigned |
2014-11-06 21:57 | Jesus Reyes | Fixed in Revision | => 46767 |
2014-11-06 21:57 | Jesus Reyes | LazTarget | - => 1.4 |
2014-11-06 21:57 | Jesus Reyes | Note Added: 0078968 | |
2014-11-06 21:57 | Jesus Reyes | Status | assigned => resolved |
2014-11-06 21:57 | Jesus Reyes | Fixed in Version | => 1.3 (SVN) |
2014-11-06 21:57 | Jesus Reyes | Resolution | open => fixed |
2014-11-07 16:45 | wp | Note Added: 0078986 | |
2014-11-07 16:45 | wp | Status | resolved => closed |
2014-11-07 16:45 | wp | Target Version | 1.4 => 1.2.8 |