From 2bd215c91a9ebf13b98a6f86c173055b0a3473fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Kub=C3=AD=C4=8Dek?= Date: Sun, 29 Mar 2026 11:05:30 +0200 Subject: [PATCH] "Infinite" workspace for diagrams --- NetworkDiagram/MainWindow.xaml | 17 +++++- NetworkDiagram/MainWindow.xaml.cs | 97 +++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/NetworkDiagram/MainWindow.xaml b/NetworkDiagram/MainWindow.xaml index 3e6a5b4..b36c3ec 100644 --- a/NetworkDiagram/MainWindow.xaml +++ b/NetworkDiagram/MainWindow.xaml @@ -73,12 +73,23 @@ - - + + + + + + + + @@ -122,6 +133,6 @@ - + diff --git a/NetworkDiagram/MainWindow.xaml.cs b/NetworkDiagram/MainWindow.xaml.cs index 63272ec..4bdaca8 100644 --- a/NetworkDiagram/MainWindow.xaml.cs +++ b/NetworkDiagram/MainWindow.xaml.cs @@ -30,12 +30,85 @@ namespace NetworkDiagram private readonly Dictionary _connectionLines = new(); private readonly Dictionary _deviceElements = new(); + // Panning and Zooming + private Point _lastPanPoint; + private bool _isPanning; + public MainWindow() { InitializeComponent(); LoadTemplates(); + this.Loaded += MainWindow_Loaded; } + private void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + CenterView(); + } + + private void CenterView() + { + // Center logically on (20000, 20000) minus half the viewport size to put 0,0 in the middle + CanvasTranslate.X = -20000 + (CanvasViewport.ActualWidth / 2); + CanvasTranslate.Y = -20000 + (CanvasViewport.ActualHeight / 2); + CanvasScale.ScaleX = 1.0; + CanvasScale.ScaleY = 1.0; + } + + #region Panning and Zooming + private void Viewport_MouseDown(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Middle) + { + _isPanning = true; + _lastPanPoint = e.GetPosition(CanvasViewport); + CanvasViewport.CaptureMouse(); + } + } + + private void Viewport_MouseMove(object sender, MouseEventArgs e) + { + if (_isPanning) + { + Point currentPoint = e.GetPosition(CanvasViewport); + double deltaX = currentPoint.X - _lastPanPoint.X; + double deltaY = currentPoint.Y - _lastPanPoint.Y; + + CanvasTranslate.X += deltaX; + CanvasTranslate.Y += deltaY; + + _lastPanPoint = currentPoint; + } + } + + private void Viewport_MouseUp(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Middle) + { + _isPanning = false; + CanvasViewport.ReleaseMouseCapture(); + } + } + + private void Viewport_MouseWheel(object sender, MouseWheelEventArgs e) + { + double zoom = e.Delta > 0 ? 1.1 : 0.9; + + double newScale = CanvasScale.ScaleX * zoom; + if (newScale < 0.1 || newScale > 5) return; + + Point mousePos = e.GetPosition(DiagramCanvas); + + // Zoom centered on mouse + CanvasScale.ScaleX = newScale; + CanvasScale.ScaleY = newScale; + + Point newMousePos = e.GetPosition(DiagramCanvas); + CanvasTranslate.X += (newMousePos.X - mousePos.X) * CanvasScale.ScaleX; + CanvasTranslate.Y += (newMousePos.Y - mousePos.Y) * CanvasScale.ScaleY; + } + #endregion + private void LoadTemplates() { try @@ -457,9 +530,13 @@ namespace NetworkDiagram { _currentDiagram = new Diagram(); DiagramCanvas.Children.Clear(); + // Re-add selection rectangle after clearing + if (SelectionRect != null) DiagramCanvas.Children.Add(SelectionRect); + _connectionLines.Clear(); _deviceElements.Clear(); ClearSelection(); + CenterView(); } private void SaveDiagram_Click(object sender, RoutedEventArgs e) @@ -497,15 +574,35 @@ namespace NetworkDiagram } DiagramCanvas.Children.Clear(); + // Re-add selection rectangle after clearing + if (SelectionRect != null) DiagramCanvas.Children.Add(SelectionRect); + _connectionLines.Clear(); _deviceElements.Clear(); ClearSelection(); + foreach (var device in _currentDiagram.Devices) RenderDevice(device); foreach (var conn in model.Connections.Select(cModel => new Connection { StartDevice = _currentDiagram.Devices[cModel.StartIndex], EndDevice = _currentDiagram.Devices[cModel.EndIndex], Type = cModel.Type })) { _currentDiagram.Connections.Add(conn); RenderConnection(conn); } + + // Center on loaded content + if (_currentDiagram.Devices.Count > 0) + { + double minX = _currentDiagram.Devices.Min(d => d.X); + double minY = _currentDiagram.Devices.Min(d => d.Y); + double maxX = _currentDiagram.Devices.Max(d => d.X); + double maxY = _currentDiagram.Devices.Max(d => d.Y); + + CanvasTranslate.X = -((minX + maxX) / 2) * CanvasScale.ScaleX + (CanvasViewport.ActualWidth / 2); + CanvasTranslate.Y = -((minY + maxY) / 2) * CanvasScale.ScaleY + (CanvasViewport.ActualHeight / 2); + } + else + { + CenterView(); + } } private void WireTool_Click(object sender, RoutedEventArgs e) => _activeTool = ConnectionType.Wire;