diff --git a/CODESTYLE.md b/CODESTYLE.md
index eeb4e9d..3bc7baf 100644
--- a/CODESTYLE.md
+++ b/CODESTYLE.md
@@ -25,6 +25,7 @@ This repository follows the local `.editorconfig` and the style visible in the c
## Braces And Blocks
- Use braces for multi-line bodies.
+- If nesting a for-loop under another for-loop, always include curly braces in the parent for-loop.
- Omit braces for simple single-line embedded statements when readability stays clear.
- Nested control flow with multi-line bodies should use braces at every multi-line level.
- Keep opening braces on the next line for types, methods, properties, accessors, and control blocks.
diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml b/src/ReactorMaintenance.Win2D/MainWindow.xaml
index bb45e54..4868552 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml
@@ -21,7 +21,7 @@
-
+
@@ -30,19 +30,18 @@
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -61,6 +60,7 @@
PointerPressed="LevelCanvas_PointerPressed"
PointerMoved="LevelCanvas_PointerMoved"
PointerReleased="LevelCanvas_PointerReleased"
+ PointerExited="LevelCanvas_PointerExited"
PointerWheelChanged="LevelCanvas_PointerWheelChanged" />
diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
index f961752..9d86e0c 100644
--- a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
+++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs
@@ -2,7 +2,6 @@
using Microsoft.Graphics.Canvas.UI;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.UI;
-using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
@@ -12,9 +11,7 @@ using System.Globalization;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Pickers;
-using Windows.System;
using Windows.UI;
-using Windows.UI.Core;
using Windows.UI.Popups;
using WinRT.Interop;
@@ -86,7 +83,7 @@ public sealed partial class MainWindow
return await CanvasBitmap.LoadAsync(sender, path);
}
- private void ToolRadio_Checked(object sender, RoutedEventArgs e)
+ private void ToolToggle_Checked(object sender, RoutedEventArgs e)
{
if ((sender as FrameworkElement)?.DataContext is EditorToolViewModel tool)
{
@@ -176,15 +173,6 @@ public sealed partial class MainWindow
private void LevelCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var point = e.GetCurrentPoint(LevelCanvas);
- if (point.Properties.IsLeftButtonPressed && IsShiftDown())
- {
- m_Panning = true;
- m_LastPanPoint = point.Position;
- _ = LevelCanvas.CapturePointer(e.Pointer);
- e.Handled = true;
- return;
- }
-
if (point.Properties.IsRightButtonPressed)
{
RemovePropAt(point.Position);
@@ -195,8 +183,10 @@ public sealed partial class MainWindow
if (point.Properties.IsLeftButtonPressed)
{
_ = LevelCanvas.CapturePointer(e.Pointer);
- SelectOrPaintAt(point.Position);
- m_Painting = m_SelectedTool != EEditorTool.Cursor;
+ m_LeftPointerDown = true;
+ m_LeftPointerDownPoint = point.Position;
+ m_LastPanPoint = point.Position;
+ m_DragExceededClickThreshold = false;
e.Handled = true;
}
}
@@ -204,11 +194,17 @@ public sealed partial class MainWindow
private void LevelCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var point = e.GetCurrentPoint(LevelCanvas);
- if (m_Panning)
+ if (m_LeftPointerDown)
{
var deltaX = point.Position.X - m_LastPanPoint.X;
var deltaY = point.Position.Y - m_LastPanPoint.Y;
m_LastPanPoint = point.Position;
+
+ var totalDeltaX = point.Position.X - m_LeftPointerDownPoint.X;
+ var totalDeltaY = point.Position.Y - m_LeftPointerDownPoint.Y;
+ if (Math.Sqrt((totalDeltaX * totalDeltaX) + (totalDeltaY * totalDeltaY)) > c_ClickPixelThreshold)
+ m_DragExceededClickThreshold = true;
+
m_PanX += deltaX;
m_PanY += deltaY;
ClampPan();
@@ -217,21 +213,26 @@ public sealed partial class MainWindow
return;
}
- if (m_Painting)
- {
- PaintAt(point.Position);
- e.Handled = true;
- }
+ SetHoveredCell(point.Position);
}
private void LevelCanvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
- m_Painting = false;
- m_Panning = false;
+ var point = e.GetCurrentPoint(LevelCanvas);
+ if (m_LeftPointerDown && !m_DragExceededClickThreshold)
+ SelectOrPaintAt(point.Position);
+
+ m_LeftPointerDown = false;
+ m_DragExceededClickThreshold = false;
LevelCanvas.ReleasePointerCapture(e.Pointer);
e.Handled = true;
}
+ private void LevelCanvas_PointerExited(object sender, PointerRoutedEventArgs e)
+ {
+ ClearHoveredCell();
+ }
+
private void LevelCanvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
var point = e.GetCurrentPoint(LevelCanvas);
@@ -243,11 +244,6 @@ public sealed partial class MainWindow
e.Handled = true;
}
- private static bool IsShiftDown()
- {
- return InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
- }
-
private void ZoomAt(Point point, double zoomFactor)
{
var oldLayout = GetLayout();
@@ -314,7 +310,7 @@ public sealed partial class MainWindow
drawing.Clear(ColorHelper.FromArgb(255, 16, 18, 21));
DrawTerrain(drawing, layout);
DrawCellOverlays(drawing, layout);
- DrawGrid(drawing, layout);
+ //DrawGrid(drawing, layout);
DrawRobot(drawing, layout);
}
@@ -350,10 +346,13 @@ public sealed partial class MainWindow
if (cell.Hazards.Fire)
DrawImage(drawing, m_FireSprite, Inset(rect, 0.08));
+ DrawCellProp(drawing, cell, rect);
+
+ if (m_HoveredCell == position)
+ drawing.FillRectangle(rect, ColorHelper.FromArgb(72, 255, 255, 255));
+
if (m_SelectedCell == position)
drawing.DrawRectangle(rect, Colors.White, 3);
-
- DrawCellProp(drawing, cell, rect);
}
}
}
@@ -364,7 +363,7 @@ public sealed partial class MainWindow
return;
var sourceRect = PipeTileSourceRect(GetPipeConnectionMask(position, cell.Pipe));
- drawing.DrawImage(tilemap, rect, sourceRect);
+ drawing.DrawImage(tilemap, rect, sourceRect, 1.0f, CanvasImageInterpolation.HighQualityCubic);
}
private int GetPipeConnectionMask(GridPosition position, EPipeMedium medium)
@@ -422,7 +421,7 @@ public sealed partial class MainWindow
private static void DrawImage(CanvasDrawingSession drawing, CanvasBitmap? image, Rect rect, float opacity = 1)
{
if (image is not null)
- drawing.DrawImage(image, rect, image.Bounds, opacity);
+ drawing.DrawImage(image, rect, image.Bounds, opacity, CanvasImageInterpolation.HighQualityCubic);
}
private static Rect Inset(Rect rect, double fraction)
@@ -438,7 +437,7 @@ public sealed partial class MainWindow
var wallMask = c_AllCorners ^ floorMask;
var sourceRect = TilemapSourceRect(wallMask);
- drawing.DrawImage(m_TerrainTilemap, rect, sourceRect);
+ drawing.DrawImage(m_TerrainTilemap, rect, sourceRect, 1.0f, CanvasImageInterpolation.HighQualityCubic);
}
private static Rect TilemapSourceRect(int wallMask)
@@ -497,7 +496,7 @@ public sealed partial class MainWindow
private void DrawCellProp(CanvasDrawingSession drawing, CellState cell, Rect rect)
{
if (m_PropSprites.TryGetValue(cell.Prop, out var sprite))
- drawing.DrawImage(sprite, rect, sprite.Bounds);
+ drawing.DrawImage(sprite, rect, sprite.Bounds, 1.0f, CanvasImageInterpolation.HighQualityCubic);
}
private void DrawGrid(CanvasDrawingSession drawing, CanvasLayout layout)
@@ -530,6 +529,25 @@ public sealed partial class MainWindow
return m_Level.InBounds(position);
}
+ private void SetHoveredCell(Point point)
+ {
+ var hoveredCell = TryGetGridPosition(point, out var position) ? position : (GridPosition?)null;
+ if (m_HoveredCell == hoveredCell)
+ return;
+
+ m_HoveredCell = hoveredCell;
+ LevelCanvas.Invalidate();
+ }
+
+ private void ClearHoveredCell()
+ {
+ if (m_HoveredCell is null)
+ return;
+
+ m_HoveredCell = null;
+ LevelCanvas.Invalidate();
+ }
+
private CanvasLayout GetLayout()
{
ClampPan();
@@ -715,6 +733,7 @@ public sealed partial class MainWindow
private const double c_MinZoom = 0.5;
private const double c_MaxZoom = 4;
private const double c_ZoomStep = 1.15;
+ private const double c_ClickPixelThreshold = 5;
private readonly SimulationEngine m_Simulation = new();
private readonly Dictionary m_PropSprites = [];
@@ -722,9 +741,11 @@ public sealed partial class MainWindow
private StorageFile? m_CurrentFile;
private LevelState m_Level;
private IReadOnlyList m_EditorTools = [];
- private bool m_Painting;
- private bool m_Panning;
+ private bool m_LeftPointerDown;
+ private bool m_DragExceededClickThreshold;
+ private Point m_LeftPointerDownPoint;
private Point m_LastPanPoint;
+ private GridPosition? m_HoveredCell;
private GridPosition? m_SelectedCell;
private EEditorTool m_SelectedTool = EEditorTool.Cursor;
private double m_Zoom = 1;