diff --git a/SMTx/ViewModels/MainWindowViewModel.cs b/SMTx/ViewModels/MainWindowViewModel.cs index cdf5710b..5dd29e3b 100644 --- a/SMTx/ViewModels/MainWindowViewModel.cs +++ b/SMTx/ViewModels/MainWindowViewModel.cs @@ -7,6 +7,7 @@ using Dock.Model.Core; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; namespace SMTx.ViewModels; @@ -68,5 +69,9 @@ public void ResetLayout() public void QuitApp() { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopAppLifetime) + desktopAppLifetime.Shutdown(); + else if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledAppLifetime) + controlledAppLifetime.Shutdown(); } } diff --git a/SMTx/Views/Documents/UniverseView.axaml b/SMTx/Views/Documents/UniverseView.axaml index 54e12536..5ce9129b 100644 --- a/SMTx/Views/Documents/UniverseView.axaml +++ b/SMTx/Views/Documents/UniverseView.axaml @@ -19,7 +19,11 @@ Grid.ColumnSpan="3" MaxZoomX="2" MaxZoomY="2" MinZoomX="0.2" MinZoomY="0.2" - SizeChanged="ZoomBorder_OnSizeChanged"> + MaxOffsetX="2500" MaxOffsetY="2500" + MinOffsetX="-2500" MinOffsetY="-2500" + EnableConstrains="False" + SizeChanged="ZoomBorder_OnSizeChanged" + ZoomChanged="ZoomBorder_ZoomChanged"> diff --git a/SMTx/Views/Documents/UniverseView.axaml.cs b/SMTx/Views/Documents/UniverseView.axaml.cs index c717b0be..53b965f5 100644 --- a/SMTx/Views/Documents/UniverseView.axaml.cs +++ b/SMTx/Views/Documents/UniverseView.axaml.cs @@ -7,6 +7,9 @@ using Avalonia.Controls.Shapes; using Avalonia.Interactivity; using Avalonia.Layout; +using System; +using Avalonia.Controls.PanAndZoom; +using System.Diagnostics; namespace SMTx.Views.Documents { @@ -39,6 +42,8 @@ public partial class UniverseView : UserControl private Brush ConstellationLinkStroke; private Brush BackgroundFill; + private List canvasObjects = new List(); + private struct GateHelper { public SMT.EVEData.System from { get; set; } @@ -81,9 +86,32 @@ private void AddSystems() // cache all system links List systemLinks = new List(); + SMT.EVEData.MapRegion mr = SMT.EVEData.EveManager.Instance.GetRegion("Delve"); + + // absolute coodinate variables + double minX, maxX, minY, maxY, absWidth, absHeight; + minX = maxX = minY = maxY = absWidth = absHeight = 0; + // offsets + double xOffset, yOffset; - SMT.EVEData.MapRegion mr = SMT.EVEData.EveManager.Instance.GetRegion("Delve"); + // Iterate all systems (points) in the region data to find the min and max coordinate offsets + foreach (SMT.EVEData.System s in SMT.EVEData.EveManager.Instance.Systems) + { + minX = Math.Min(minX, s.UniverseX); + maxX = Math.Max(maxX, s.UniverseX); + minY = Math.Min(minY, s.UniverseY); + maxY = Math.Max(maxY, s.UniverseY); + } + // Calculate absolute width and height + absWidth = maxX - minX; + absHeight = maxY - minY; + // Calculate an offset for each object on the canvas to normalize + xOffset = (SystemTextWidth / 2d) - minX; + yOffset = (SystemShapeSize / 2d) - minY; + + UniverseViewGrid.Width = absWidth + SystemTextWidth; + UniverseViewGrid.Height = absHeight + SystemShapeSize + SystemShapeTextYOffset; // Add all of the systems foreach (SMT.EVEData.System s in SMT.EVEData.EveManager.Instance.Systems) @@ -119,9 +147,10 @@ private void AddSystems() } - Canvas.SetLeft(sys, s.UniverseX - SystemShapeOffset); - Canvas.SetTop(sys, s.UniverseY - SystemShapeOffset); + Canvas.SetLeft(sys, s.UniverseX - SystemShapeOffset + xOffset); + Canvas.SetTop(sys, s.UniverseY - SystemShapeOffset + yOffset); UniverseViewGrid.Children.Add(sys); + canvasObjects.Add(sys); // System Name TextBlock systemName = new TextBlock @@ -140,10 +169,12 @@ private void AddSystems() VerticalAlignment = VerticalAlignment.Top, }; - Canvas.SetLeft(systemName, s.UniverseX - SystemTextWidthOffset); - Canvas.SetTop(systemName, s.UniverseY + SystemShapeTextYOffset); + Canvas.SetLeft(systemName, s.UniverseX - SystemTextWidthOffset + xOffset); + Canvas.SetTop(systemName, s.UniverseY + SystemShapeTextYOffset + yOffset); UniverseViewGrid.Children.Add(systemName); + // TODO put the text block into a collection along with the canvas objects. + // canvasObjects.Add(systemName); // generate the list of links @@ -175,8 +206,8 @@ private void AddSystems() foreach (GateHelper gh in systemLinks) { Line sysLink = new Line(); - sysLink.StartPoint = new Point(gh.from.UniverseX, gh.from.UniverseY); - sysLink.EndPoint = new Point(gh.to.UniverseX, gh.to.UniverseY); + sysLink.StartPoint = new Point(gh.from.UniverseX + xOffset, gh.from.UniverseY + yOffset); + sysLink.EndPoint = new Point(gh.to.UniverseX + xOffset, gh.to.UniverseY + yOffset); sysLink.Stroke = LinkStroke; if (gh.from.ConstellationID != gh.to.ConstellationID) @@ -192,6 +223,7 @@ private void AddSystems() sysLink.StrokeThickness = 1.2; sysLink.ZIndex = SystemLinkZIndex; UniverseViewGrid.Children.Add(sysLink); + canvasObjects.Add(sysLink); } } @@ -202,9 +234,11 @@ private void AddSystems() private void SldZoom_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e) { double zoomTo = SldZoom.Value; - double zoomCentreX = ZoomBorder.DesiredSize.Width / 2; - double zoomCentreY = ZoomBorder.DesiredSize.Height / 2; + var desiredSize = ZoomBorder.DesiredSize; + + double zoomCentreX = ZoomBorder.Bounds.Width / 2.0; + double zoomCentreY = ZoomBorder.Bounds.Height / 2.0; ZoomBorder.Zoom(zoomTo, zoomCentreX, zoomCentreY, true); } @@ -230,6 +264,52 @@ private void ZoomBorder_OnSizeChanged(object sender, SizeChangedEventArgs e) } } + private void ZoomBorder_ZoomChanged(object sender, ZoomChangedEventArgs e) + { + Debug.WriteLine($"[ZoomChanged] {e.ZoomX} {e.ZoomY} {e.OffsetX} {e.OffsetY}"); + double normalizedX = e.OffsetX / e.ZoomX; + double normalizedY = e.OffsetY / e.ZoomY; + Debug.WriteLine($"[Normalized X] {normalizedX} [Normalized Y] {normalizedY}"); + if (sender is ZoomBorder zoomBorder) + { + double maxBaseOffsetX = zoomBorder.Bounds.Width; + double maxBaseOffsetY = zoomBorder.Bounds.Height; + + Point originVector = new Point(UniverseViewGrid.Bounds.Left, UniverseViewGrid.Bounds.Top); + Point boundsVector = new Point(UniverseViewGrid.Bounds.Right, UniverseViewGrid.Bounds.Bottom); + + Avalonia.Matrix zoomMatrix = Avalonia.Matrix.CreateScale(e.ZoomX, e.ZoomY); + + /* + double newFromX = zoomBorder.Matrix.Transform(originVector).X; + double newFromY = zoomBorder.Matrix.Transform(originVector).Y; + double newToX = zoomBorder.Matrix.Transform(boundsVector).X; + double newToY = zoomBorder.Matrix.Transform(boundsVector).Y; + */ + + double newFromX = zoomMatrix.Transform(originVector).X; + double newFromY = zoomMatrix.Transform(originVector).Y; + double newToX = zoomMatrix.Transform(boundsVector).X; + double newToY = zoomMatrix.Transform(boundsVector).Y; + + if (Math.Round(zoomBorder.MinOffsetX) != Math.Round(newFromX)) + zoomBorder.MinOffsetX = newFromX; + if (Math.Round(zoomBorder.MinOffsetY) != Math.Round(newFromY)) + zoomBorder.MinOffsetY = newFromY; + if (Math.Round(zoomBorder.MaxOffsetX) != Math.Round(newToX)) + zoomBorder.MaxOffsetX = newToX; + if (Math.Round(zoomBorder.MaxOffsetY) != Math.Round(newToY)) + zoomBorder.MaxOffsetY = newToY; + + /* + foreach (Shape sys in canvasObjects) + { + // TODO iterate and clip objects based on their bounds + } + */ + } + } + #endregion }