Skip to content

Commit 7345f2d

Browse files
author
长安员外
committed
Support resizing result grid columns
1 parent 447ce9c commit 7345f2d

3 files changed

Lines changed: 213 additions & 6 deletions

File tree

SqlAnalyzer.App/Models/ResultColumnViewItem.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public sealed class ResultColumnViewItem
2626

2727
public bool HasExplicitAlias { get; set; }
2828

29+
public double? ManualWidth { get; set; }
30+
2931
public string EffectiveSourceColumn =>
3032
string.IsNullOrWhiteSpace(SourceColumn) ? RawName : SourceColumn!;
3133
}

SqlAnalyzer.App/Services/ResultWorkspaceController.cs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,31 @@ namespace SqlAnalyzer.App.Services;
1414

1515
public sealed class ResultWorkspaceController
1616
{
17+
private const double ColumnResizeHandleWidth = 7.0;
18+
private const double ColumnResizeHandleOverflow = 2.0;
19+
private const double MinDataColumnWidth = 48.0;
20+
private const double MaxDataColumnWidth = 720.0;
21+
1722
private readonly Dictionary<int, Border> _headerBorders = [];
1823
private readonly HashSet<int> _pinnedHeaderColumns = [];
1924
private readonly Dictionary<ResultRowViewItem, Border> _rowBorders = [];
2025
private readonly Dictionary<ResultRowViewItem, Border> _actionBorders = [];
2126
private readonly Dictionary<(ResultRowViewItem Row, int ColumnIndex), Border> _cellBorders = [];
27+
private readonly Dictionary<int, int> _columnVisualIndexes = [];
28+
private readonly List<Grid> _scrollableGrids = [];
2229
private readonly HashSet<ResultRowViewItem> _selectedRows = [];
2330
private readonly HashSet<(ResultRowViewItem Row, int ColumnIndex)> _selectedCells = [];
2431
private ResultRowViewItem? _selectedRow;
2532
private ResultRowViewItem? _selectionAnchorRow;
2633
private ResultCellContext? _cellSelectionAnchor;
2734
private ResultCellContext? _selectedCell;
35+
private int _resizingColumnIndex = -1;
36+
private double _resizeStartX;
37+
private double _resizeStartWidth;
2838
private bool _isDraggingSelection;
2939
private bool _isDraggingCellSelection;
3040
private bool _isDraggingHeaderSelection;
41+
private bool _isResizingColumn;
3142

3243
public ResultRowViewItem? SelectedRow => _selectedRow;
3344

@@ -41,6 +52,8 @@ public sealed class ResultWorkspaceController
4152

4253
public bool IsDraggingHeaderSelection => _isDraggingHeaderSelection;
4354

55+
public bool IsResizingColumn => _isResizingColumn;
56+
4457
public ResultCellContext? SelectedCell => _selectedCell;
4558

4659
public int SelectedCellSelectionCount => _selectedCells.Count;
@@ -93,10 +106,12 @@ public Border BuildScrollableHeaderRow(
93106
{
94107
ColumnDefinitions = new ColumnDefinitions(string.Join(",", columnWidths.Select(width => $"{width}")))
95108
};
109+
_scrollableGrids.Add(headerGrid);
96110

97111
for (int visualIndex = 0; visualIndex < orderedColumns.Count; visualIndex++)
98112
{
99113
int columnIndex = orderedColumns[visualIndex];
114+
_columnVisualIndexes[columnIndex] = visualIndex;
100115
ResultColumnViewItem column = resultSet.Columns[columnIndex];
101116
string subtitle = headerSubtitleFormatter(column);
102117
Border headerCell = new()
@@ -188,6 +203,7 @@ public Border BuildScrollableDataRow(
188203
{
189204
ColumnDefinitions = new ColumnDefinitions(string.Join(",", columnWidths.Select(width => $"{width}")))
190205
};
206+
_scrollableGrids.Add(rowGrid);
191207

192208
for (int visualIndex = 0; visualIndex < orderedColumns.Count; visualIndex++)
193209
{
@@ -407,15 +423,91 @@ public void Reset()
407423
_rowBorders.Clear();
408424
_actionBorders.Clear();
409425
_cellBorders.Clear();
426+
_columnVisualIndexes.Clear();
427+
_scrollableGrids.Clear();
410428
_selectedRows.Clear();
411429
_selectedCells.Clear();
412430
_selectedRow = null;
413431
_selectionAnchorRow = null;
414432
_cellSelectionAnchor = null;
415433
_selectedCell = null;
434+
_resizingColumnIndex = -1;
435+
_resizeStartX = 0;
436+
_resizeStartWidth = 0;
416437
_isDraggingSelection = false;
417438
_isDraggingCellSelection = false;
418439
_isDraggingHeaderSelection = false;
440+
_isResizingColumn = false;
441+
}
442+
public bool TryGetHeaderResizeColumnAtPoint(Visual relativeTo, Point point, out int columnIndex)
443+
{
444+
double bestDistance = double.MaxValue;
445+
int bestColumnIndex = -1;
446+
foreach ((int key, Border border) in _headerBorders)
447+
{
448+
if (!TryBuildHitRect(border, relativeTo, out Rect rect) ||
449+
point.Y < rect.Top ||
450+
point.Y > rect.Bottom ||
451+
point.X < rect.Right - ColumnResizeHandleWidth ||
452+
point.X > rect.Right + ColumnResizeHandleOverflow)
453+
{
454+
continue;
455+
}
456+
457+
double distance = Math.Abs(point.X - rect.Right);
458+
if (distance < bestDistance)
459+
{
460+
bestDistance = distance;
461+
bestColumnIndex = key;
462+
}
463+
}
464+
465+
columnIndex = bestColumnIndex;
466+
return bestColumnIndex >= 0;
467+
}
468+
public void BeginColumnResize(ResultSetViewItem resultSet, Visual relativeTo, Point point, int columnIndex)
469+
{
470+
if (columnIndex < 0 ||
471+
columnIndex >= resultSet.Columns.Count ||
472+
!_headerBorders.TryGetValue(columnIndex, out Border? border) ||
473+
!TryBuildHitRect(border, relativeTo, out Rect rect))
474+
{
475+
return;
476+
}
477+
478+
_isResizingColumn = true;
479+
_isDraggingSelection = false;
480+
_isDraggingCellSelection = false;
481+
_isDraggingHeaderSelection = false;
482+
_resizingColumnIndex = columnIndex;
483+
_resizeStartX = point.X;
484+
_resizeStartWidth = Math.Clamp(rect.Width, MinDataColumnWidth, MaxDataColumnWidth);
485+
resultSet.Columns[columnIndex].ManualWidth = _resizeStartWidth;
486+
}
487+
public bool UpdateColumnResize(ResultSetViewItem resultSet, double pointerX, bool isLeftButtonPressed)
488+
{
489+
if (!_isResizingColumn || !isLeftButtonPressed)
490+
{
491+
return false;
492+
}
493+
494+
if (_resizingColumnIndex < 0 || _resizingColumnIndex >= resultSet.Columns.Count)
495+
{
496+
EndColumnResize();
497+
return false;
498+
}
499+
500+
double width = Math.Clamp(_resizeStartWidth + pointerX - _resizeStartX, MinDataColumnWidth, MaxDataColumnWidth);
501+
resultSet.Columns[_resizingColumnIndex].ManualWidth = width;
502+
ApplyColumnWidth(_resizingColumnIndex, width);
503+
return true;
504+
}
505+
public void EndColumnResize()
506+
{
507+
_isResizingColumn = false;
508+
_resizingColumnIndex = -1;
509+
_resizeStartX = 0;
510+
_resizeStartWidth = 0;
419511
}
420512
public bool TryGetHeaderColumnAtPoint(Visual relativeTo, Point point, out int columnIndex, bool ignoreVerticalBounds = false)
421513
{
@@ -550,11 +642,29 @@ public double[] BuildColumnWidths(
550642

551643
widths[visualIndex] = columnIndex < 0
552644
? 14
553-
: Math.Clamp((maxLength * 7) + 16, 76, 210);
645+
: resultSet.Columns[columnIndex].ManualWidth is { } manualWidth
646+
? Math.Clamp(manualWidth, MinDataColumnWidth, MaxDataColumnWidth)
647+
: Math.Clamp((maxLength * 7) + 16, 76, 210);
554648
}
555649

556650
return widths;
557651
}
652+
private void ApplyColumnWidth(int columnIndex, double width)
653+
{
654+
if (!_columnVisualIndexes.TryGetValue(columnIndex, out int visualIndex))
655+
{
656+
return;
657+
}
658+
659+
GridLength gridLength = new(width);
660+
foreach (Grid grid in _scrollableGrids)
661+
{
662+
if (visualIndex >= 0 && visualIndex < grid.ColumnDefinitions.Count)
663+
{
664+
grid.ColumnDefinitions[visualIndex].Width = gridLength;
665+
}
666+
}
667+
}
558668
private static int GetHeaderMeasurementLength(ResultColumnViewItem column, Func<ResultColumnViewItem, string> headerFormatter)
559669
{
560670
string rawName = string.IsNullOrWhiteSpace(column.RawName) ? column.HeaderText : column.RawName;

SqlAnalyzer.App/Views/MainWindow.axaml.cs

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public partial class MainWindow : Window
4343

4444
private static readonly bool DiagnosticLoggingEnabled = string.Equals(Environment.GetEnvironmentVariable("SQLANALYZER_DIAGNOSTIC_LOGS"), "1", StringComparison.OrdinalIgnoreCase);
4545

46+
private static readonly Cursor ResultColumnResizeCursor = new(StandardCursorType.SizeWestEast);
47+
4648
private readonly RegistryOptions _registryOptions = new RegistryOptions(ThemeName.LightPlus);
4749

4850
private object? _textMateInstallation;
@@ -2845,6 +2847,11 @@ private void Window_PointerPressed(object? sender, PointerPressedEventArgs e)
28452847
if (selectedDocumentSelectedResultSet != null)
28462848
{
28472849
PointerPointProperties properties = e.GetCurrentPoint(this).Properties;
2850+
if (TryBeginResultColumnResize(e, relativeTo, position, control, selectedDocumentSelectedResultSet))
2851+
{
2852+
return;
2853+
}
2854+
28482855
if (properties.IsLeftButtonPressed && _resultWorkspaceController.TryGetHeaderColumnAtPoint(relativeTo, position, out var columnIndex) && columnIndex >= 0)
28492856
{
28502857
EndInlineCellEdit();
@@ -2890,17 +2897,42 @@ private void Window_PointerPressed(object? sender, PointerPressedEventArgs e)
28902897

28912898
private void Window_PointerMoved(object? sender, PointerEventArgs e)
28922899
{
2893-
if (e.KeyModifiers.HasFlag(KeyModifiers.Alt) || (!_resultWorkspaceController.IsDraggingSelection && !_resultWorkspaceController.IsDraggingCellSelection && !_resultWorkspaceController.IsDraggingHeaderSelection))
2900+
if (e.KeyModifiers.HasFlag(KeyModifiers.Alt))
28942901
{
2902+
ResetResultColumnResizeCursor();
28952903
return;
28962904
}
2905+
28972906
ResultSetViewItem? selectedDocumentSelectedResultSet = ViewModel.SelectedDocumentSelectedResultSet;
2898-
if (selectedDocumentSelectedResultSet == null || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
2907+
PointerPointProperties properties = e.GetCurrentPoint(this).Properties;
2908+
Visual relativeTo = ResultInteractionHost;
2909+
Point position = e.GetPosition(relativeTo);
2910+
if (_resultWorkspaceController.IsResizingColumn)
28992911
{
2912+
if (selectedDocumentSelectedResultSet == null || !properties.IsLeftButtonPressed)
2913+
{
2914+
_resultWorkspaceController.EndColumnResize();
2915+
ResetResultColumnResizeCursor();
2916+
return;
2917+
}
2918+
2919+
_resultWorkspaceController.UpdateColumnResize(selectedDocumentSelectedResultSet, position.X, properties.IsLeftButtonPressed);
2920+
ResultInteractionHost.Cursor = ResultColumnResizeCursor;
2921+
e.Handled = true;
29002922
return;
29012923
}
2902-
Visual relativeTo = ResultInteractionHost;
2903-
Point position = e.GetPosition(relativeTo);
2924+
2925+
if (!_resultWorkspaceController.IsDraggingSelection && !_resultWorkspaceController.IsDraggingCellSelection && !_resultWorkspaceController.IsDraggingHeaderSelection)
2926+
{
2927+
UpdateResultColumnResizeCursor(e);
2928+
return;
2929+
}
2930+
2931+
if (selectedDocumentSelectedResultSet == null || !properties.IsLeftButtonPressed)
2932+
{
2933+
return;
2934+
}
2935+
29042936
if (_resultWorkspaceController.IsDraggingHeaderSelection)
29052937
{
29062938
if (_resultWorkspaceController.TryGetHeaderColumnAtPoint(relativeTo, position, out var columnIndex, ignoreVerticalBounds: true) && columnIndex >= 0)
@@ -2926,13 +2958,69 @@ private void Window_PointerMoved(object? sender, PointerEventArgs e)
29262958

29272959
private void Window_PointerReleased(object? sender, PointerReleasedEventArgs e)
29282960
{
2961+
if (_resultWorkspaceController.IsResizingColumn)
2962+
{
2963+
e.Pointer.Capture(null);
2964+
_resultWorkspaceController.EndColumnResize();
2965+
ResetResultColumnResizeCursor();
2966+
e.Handled = true;
2967+
return;
2968+
}
2969+
29292970
if (!e.KeyModifiers.HasFlag(KeyModifiers.Alt) && (_resultWorkspaceController.IsDraggingSelection || _resultWorkspaceController.IsDraggingCellSelection || _resultWorkspaceController.IsDraggingHeaderSelection))
29302971
{
29312972
e.Pointer.Capture(null);
29322973
_resultWorkspaceController.EndSelection();
29332974
}
29342975
}
29352976

2977+
private bool TryBeginResultColumnResize(
2978+
PointerPressedEventArgs e,
2979+
Visual relativeTo,
2980+
Point position,
2981+
IInputElement captureTarget,
2982+
ResultSetViewItem resultSet)
2983+
{
2984+
PointerPointProperties properties = e.GetCurrentPoint(this).Properties;
2985+
if (!properties.IsLeftButtonPressed ||
2986+
!_resultWorkspaceController.TryGetHeaderResizeColumnAtPoint(relativeTo, position, out int columnIndex))
2987+
{
2988+
return false;
2989+
}
2990+
2991+
EndInlineCellEdit();
2992+
e.Pointer.Capture(captureTarget);
2993+
_resultWorkspaceController.BeginColumnResize(resultSet, relativeTo, position, columnIndex);
2994+
ResultInteractionHost.Cursor = ResultColumnResizeCursor;
2995+
ViewModel.ClearSelectedDocumentValueDetail();
2996+
e.Handled = true;
2997+
return true;
2998+
}
2999+
3000+
private void UpdateResultColumnResizeCursor(PointerEventArgs e)
3001+
{
3002+
ResultSetViewItem? resultSet = ViewModel.SelectedDocumentSelectedResultSet;
3003+
if (resultSet == null)
3004+
{
3005+
ResetResultColumnResizeCursor();
3006+
return;
3007+
}
3008+
3009+
Visual relativeTo = ResultInteractionHost;
3010+
Point position = e.GetPosition(relativeTo);
3011+
ResultInteractionHost.Cursor = _resultWorkspaceController.TryGetHeaderResizeColumnAtPoint(relativeTo, position, out _)
3012+
? ResultColumnResizeCursor
3013+
: null;
3014+
}
3015+
3016+
private void ResetResultColumnResizeCursor()
3017+
{
3018+
if (!_resultWorkspaceController.IsResizingColumn && ResultInteractionHost != null)
3019+
{
3020+
ResultInteractionHost.Cursor = null;
3021+
}
3022+
}
3023+
29363024
private void CompletionListBox_KeyDown(object? sender, KeyEventArgs e)
29373025
{
29383026
if (_completionController.GetPopupKeyAction(e.Key) == CompletionController.PopupKeyAction.Commit)
@@ -4190,10 +4278,17 @@ private void ResultHeaderCell_PointerPressed(object? sender, PointerPressedEvent
41904278
if (selectedDocumentSelectedResultSet != null)
41914279
{
41924280
EndInlineCellEdit();
4281+
IInputElement captureTarget = (IInputElement?)ResultInteractionHost ?? this;
4282+
Visual relativeTo = ResultInteractionHost!;
4283+
Point position = e.GetPosition(relativeTo);
4284+
if (TryBeginResultColumnResize(e, relativeTo, position, captureTarget, selectedDocumentSelectedResultSet))
4285+
{
4286+
return;
4287+
}
4288+
41934289
PointerPointProperties properties = e.GetCurrentPoint(this).Properties;
41944290
if (properties.IsLeftButtonPressed)
41954291
{
4196-
IInputElement captureTarget = (IInputElement?)ResultInteractionHost ?? this;
41974292
e.Pointer.Capture(captureTarget);
41984293
_resultWorkspaceController.BeginHeaderSelection(selectedDocumentSelectedResultSet, columnIndex);
41994294
}

0 commit comments

Comments
 (0)