Fix editor drag feedback and surface overlays
This commit is contained in:
@@ -136,8 +136,10 @@
|
|||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<TextBlock x:Name="HoveredCellText" Text="Hovered Cell:" FontSize="16" FontWeight="SemiBold" Foreground="#F4F1E8" />
|
<TextBlock x:Name="HoveredCellText" Text="Hovered Cell:" FontSize="16" FontWeight="SemiBold"
|
||||||
<TextBlock x:Name="SelectedCellText" Text="Selected Cell:" FontSize="16" FontWeight="SemiBold" Foreground="#F4F1E8" />
|
Foreground="#F4F1E8" />
|
||||||
|
<TextBlock x:Name="SelectedCellText" Text="Selected Cell:" FontSize="16" FontWeight="SemiBold"
|
||||||
|
Foreground="#F4F1E8" />
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -148,7 +150,8 @@
|
|||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Grid.Row="0" Text="Terrain" Foreground="#9EA7AE" FontSize="11" />
|
<TextBlock Grid.Column="0" Grid.Row="0" Text="Terrain" Foreground="#9EA7AE" FontSize="11" />
|
||||||
<TextBlock Grid.Column="0" Grid.Row="1" x:Name="TerrainText" Foreground="#F4F1E8" FontSize="16" Margin="0,0,10,0" />
|
<TextBlock Grid.Column="0" Grid.Row="1" x:Name="TerrainText" Foreground="#F4F1E8" FontSize="16"
|
||||||
|
Margin="0,0,10,0" />
|
||||||
<TextBlock Grid.Column="1" Grid.Row="0" Text="Prop" Foreground="#9EA7AE" FontSize="11" />
|
<TextBlock Grid.Column="1" Grid.Row="0" Text="Prop" Foreground="#9EA7AE" FontSize="11" />
|
||||||
<TextBlock Grid.Column="1" Grid.Row="1" x:Name="PropText" Foreground="#F4F1E8" FontSize="16" />
|
<TextBlock Grid.Column="1" Grid.Row="1" x:Name="PropText" Foreground="#F4F1E8" FontSize="16" />
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -167,7 +170,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11" TextWrapping="NoWrap" />
|
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11"
|
||||||
|
TextWrapping="NoWrap" />
|
||||||
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@@ -188,7 +192,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11" TextWrapping="NoWrap" />
|
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11"
|
||||||
|
TextWrapping="NoWrap" />
|
||||||
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@@ -204,8 +209,10 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Text="{Binding Label}" Foreground="#F4F1E8" FontSize="16" Margin="0,0,10,0" />
|
<TextBlock Text="{Binding Label}" Foreground="#F4F1E8" FontSize="16"
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
Margin="0,0,10,0" />
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding Value}" Foreground="#F4F1E8"
|
||||||
|
FontSize="16" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
@@ -225,7 +232,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11" TextWrapping="NoWrap" />
|
<TextBlock Text="{Binding Label}" Foreground="#9EA7AE" FontSize="11"
|
||||||
|
TextWrapping="NoWrap" />
|
||||||
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
<TextBlock Grid.Row="1" Text="{Binding Value}" Foreground="#F4F1E8" FontSize="16" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ public sealed partial class MainWindow
|
|||||||
m_EditorFeedback = string.Empty;
|
m_EditorFeedback = string.Empty;
|
||||||
m_LastPaintedCell = null;
|
m_LastPaintedCell = null;
|
||||||
if (!m_IsPanning && m_SelectedTool.Tool == EEditorTool.Cursor && TryGetGridPosition(point.Position, out var position))
|
if (!m_IsPanning && m_SelectedTool.Tool == EEditorTool.Cursor && TryGetGridPosition(point.Position, out var position))
|
||||||
StartCursorDrag(position);
|
m_CursorDragStartCell = position;
|
||||||
else if (!m_IsPanning && IsDragPaintTool(m_SelectedTool.Tool) && TryGetGridPosition(point.Position, out position))
|
else if (!m_IsPanning && IsDragPaintTool(m_SelectedTool.Tool) && TryGetGridPosition(point.Position, out position))
|
||||||
{
|
{
|
||||||
m_LastPaintedCell = position;
|
m_LastPaintedCell = position;
|
||||||
@@ -306,7 +306,7 @@ public sealed partial class MainWindow
|
|||||||
}
|
}
|
||||||
else if (m_CursorDragStartCell is not null && m_DragExceededClickThreshold && TryGetGridPosition(point.Position, out var destination))
|
else if (m_CursorDragStartCell is not null && m_DragExceededClickThreshold && TryGetGridPosition(point.Position, out var destination))
|
||||||
{
|
{
|
||||||
m_DragPreviewDestination = destination;
|
UpdateCursorDragPreview(destination);
|
||||||
LevelCanvas.Invalidate();
|
LevelCanvas.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ public sealed partial class MainWindow
|
|||||||
{
|
{
|
||||||
LevelCanvas.Invalidate();
|
LevelCanvas.Invalidate();
|
||||||
}
|
}
|
||||||
else if (m_CursorDragStartCell is { } source && m_DragExceededClickThreshold && TryGetGridPosition(point.Position, out var destination))
|
else if (m_CursorDragStartCell is { } source && m_DragExceededClickThreshold && !m_CursorDragStartRejected && TryGetGridPosition(point.Position, out var destination))
|
||||||
{
|
{
|
||||||
var result = LevelEditor.TryMoveOccupant(m_Level, source, destination);
|
var result = LevelEditor.TryMoveOccupant(m_Level, source, destination);
|
||||||
m_Level = result.Level;
|
m_Level = result.Level;
|
||||||
@@ -343,6 +343,7 @@ public sealed partial class MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clearRejectedDragFeedback = m_CursorDragStartRejected;
|
||||||
m_LeftPointerDown = false;
|
m_LeftPointerDown = false;
|
||||||
m_IsPanning = false;
|
m_IsPanning = false;
|
||||||
m_CursorDragStartCell = null;
|
m_CursorDragStartCell = null;
|
||||||
@@ -350,6 +351,13 @@ public sealed partial class MainWindow
|
|||||||
m_DragPreviewDestination = null;
|
m_DragPreviewDestination = null;
|
||||||
m_LastPaintedCell = null;
|
m_LastPaintedCell = null;
|
||||||
m_DragExceededClickThreshold = false;
|
m_DragExceededClickThreshold = false;
|
||||||
|
if (clearRejectedDragFeedback)
|
||||||
|
{
|
||||||
|
ClearDragFeedback();
|
||||||
|
RefreshInspector();
|
||||||
|
LevelCanvas.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
LevelCanvas.ReleasePointerCapture(e.Pointer);
|
LevelCanvas.ReleasePointerCapture(e.Pointer);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
@@ -363,6 +371,9 @@ public sealed partial class MainWindow
|
|||||||
m_DragPreviewDestination = null;
|
m_DragPreviewDestination = null;
|
||||||
m_LastPaintedCell = null;
|
m_LastPaintedCell = null;
|
||||||
m_DragExceededClickThreshold = false;
|
m_DragExceededClickThreshold = false;
|
||||||
|
ClearDragFeedback();
|
||||||
|
RefreshInspector();
|
||||||
|
LevelCanvas.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LevelCanvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
|
private void LevelCanvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
|
||||||
@@ -415,22 +426,34 @@ public sealed partial class MainWindow
|
|||||||
return tool is EEditorTool.Floor or EEditorTool.Wall or EEditorTool.Underground;
|
return tool is EEditorTool.Floor or EEditorTool.Wall or EEditorTool.Underground;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartCursorDrag(GridPosition position)
|
private void UpdateCursorDragPreview(GridPosition destination)
|
||||||
{
|
{
|
||||||
m_SelectedCell = position;
|
if (m_CursorDragStartCell is not { } source)
|
||||||
if (HasMovableAt(position))
|
return;
|
||||||
|
|
||||||
|
if (m_CursorDragStartRejected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasMovableAt(source))
|
||||||
{
|
{
|
||||||
m_CursorDragStartCell = position;
|
m_CursorDragStartRejected = true;
|
||||||
|
m_DragPreviewDestination = null;
|
||||||
|
m_InvalidDragCell = source;
|
||||||
|
m_EditorFeedback = "No movable robot, prop, source, or leak starts here.";
|
||||||
RefreshInspector();
|
RefreshInspector();
|
||||||
LevelCanvas.Invalidate();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CursorDragStartRejected = true;
|
m_DragPreviewDestination = destination;
|
||||||
m_InvalidDragCell = position;
|
m_InvalidDragCell = null;
|
||||||
m_EditorFeedback = "No movable robot, prop, source, or leak starts here.";
|
m_EditorFeedback = string.Empty;
|
||||||
RefreshInspector();
|
RefreshInspector();
|
||||||
LevelCanvas.Invalidate();
|
}
|
||||||
|
|
||||||
|
private void ClearDragFeedback()
|
||||||
|
{
|
||||||
|
m_InvalidDragCell = null;
|
||||||
|
m_EditorFeedback = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearAt(Point point)
|
private void ClearAt(Point point)
|
||||||
@@ -613,23 +636,39 @@ public sealed partial class MainWindow
|
|||||||
{
|
{
|
||||||
var surface = m_Level.GetSurface(position);
|
var surface = m_Level.GetSurface(position);
|
||||||
var rect = layout.CellRect(position);
|
var rect = layout.CellRect(position);
|
||||||
FillHazard(drawing, rect, surface.Fuel, c_FuelColor, 0.08, opacity);
|
FillHazard(drawing, rect, surface.Fuel, c_FuelColor, 0.08, opacity, Balancing.Current.FuelCaution, Balancing.Current.FuelCritical);
|
||||||
FillHazard(drawing, rect, surface.Coolant, c_CoolantColor, 0.18, opacity);
|
FillHazard(drawing, rect, surface.Coolant, c_CoolantColor, 0.18, opacity, Balancing.Current.CoolantCaution, Balancing.Current.CoolantCritical);
|
||||||
FillHazard(drawing, rect, surface.Electricity, c_ElectricityColor, 0.28, opacity);
|
FillHazard(drawing, rect, surface.Electricity, c_ElectricityColor, 0.28, opacity, Balancing.Current.ElectricityCaution, Balancing.Current.ElectricityCritical);
|
||||||
if (surface.Heat > 0)
|
|
||||||
DrawImage(drawing, m_HeatSprite, Inset(rect, 0.18), Math.Clamp(surface.Heat / Balancing.Current.MaxValue, 0.25f, 0.9f) * opacity);
|
var heatOpacity = SurfaceOverlayOpacity(surface.Heat, Balancing.Current.HeatCaution, Balancing.Current.HeatCritical);
|
||||||
|
if (heatOpacity > 0)
|
||||||
|
DrawImage(drawing, m_HeatSprite, Inset(rect, 0.18), heatOpacity * opacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillHazard(CanvasDrawingSession drawing, Rect rect, float amount, Color color, double inset, float opacity)
|
private static void FillHazard(CanvasDrawingSession drawing, Rect rect, float amount, Color color, double inset, float opacity, float caution, float critical)
|
||||||
{
|
{
|
||||||
if (amount <= 0)
|
var overlayOpacity = SurfaceOverlayOpacity(amount, caution, critical);
|
||||||
|
if (overlayOpacity <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var alpha = (byte)Math.Clamp((40 + (amount / Balancing.Current.MaxValue * 130)) * opacity, 0, 170);
|
var alpha = (byte)Math.Clamp(170 * overlayOpacity * opacity, 0, 170);
|
||||||
drawing.FillRectangle(Inset(rect, inset), ColorHelper.FromArgb(alpha, color.R, color.G, color.B));
|
drawing.FillRectangle(Inset(rect, inset), ColorHelper.FromArgb(alpha, color.R, color.G, color.B));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static float SurfaceOverlayOpacity(float amount, float caution, float critical)
|
||||||
|
{
|
||||||
|
if (amount < caution)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (amount >= critical)
|
||||||
|
return 0.9f;
|
||||||
|
|
||||||
|
var cautionRange = Math.Max(0.001f, critical - caution);
|
||||||
|
var t = (amount - caution) / cautionRange;
|
||||||
|
return 0.3f + (t * 0.35f);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawDoors(CanvasDrawingSession drawing, CanvasLayout layout, float opacity)
|
private void DrawDoors(CanvasDrawingSession drawing, CanvasLayout layout, float opacity)
|
||||||
{
|
{
|
||||||
foreach (var position in AllPositions())
|
foreach (var position in AllPositions())
|
||||||
@@ -805,7 +844,7 @@ public sealed partial class MainWindow
|
|||||||
new InspectorItemViewModel("Fuel", $"{m_Level.Robot.FuelNeutralizers}"),
|
new InspectorItemViewModel("Fuel", $"{m_Level.Robot.FuelNeutralizers}"),
|
||||||
new InspectorItemViewModel("Coolant", $"{m_Level.Robot.CoolantNeutralizers}"),
|
new InspectorItemViewModel("Coolant", $"{m_Level.Robot.CoolantNeutralizers}"),
|
||||||
new InspectorItemViewModel("Electricity", $"{m_Level.Robot.ElectricityNeutralizers}"),
|
new InspectorItemViewModel("Electricity", $"{m_Level.Robot.ElectricityNeutralizers}"),
|
||||||
new InspectorItemViewModel("Heat", $"{m_Level.Robot.HeatShields} ({m_Level.Robot.HeatImmunitySteps.ToString(CultureInfo.InvariantCulture)} steps)"),
|
new InspectorItemViewModel("Heat", $"{m_Level.Robot.HeatShields} ({m_Level.Robot.HeatImmunitySteps.ToString(CultureInfo.InvariantCulture)} steps)")
|
||||||
};
|
};
|
||||||
RequiredGrid.ItemsSource = new[] {
|
RequiredGrid.ItemsSource = new[] {
|
||||||
new InspectorItemViewModel("Fuel", m_Level.RequiredFuelConsumers.ToString(CultureInfo.InvariantCulture)),
|
new InspectorItemViewModel("Fuel", m_Level.RequiredFuelConsumers.ToString(CultureInfo.InvariantCulture)),
|
||||||
@@ -822,13 +861,13 @@ public sealed partial class MainWindow
|
|||||||
ServicesGrid.ItemsSource = new[] {
|
ServicesGrid.ItemsSource = new[] {
|
||||||
new InspectorItemViewModel("Fuel", prop.FuelServiceState.ToString()),
|
new InspectorItemViewModel("Fuel", prop.FuelServiceState.ToString()),
|
||||||
new InspectorItemViewModel("Coolant", prop.CoolantServiceState.ToString()),
|
new InspectorItemViewModel("Coolant", prop.CoolantServiceState.ToString()),
|
||||||
new InspectorItemViewModel("Electricity", prop.ElectricityServiceState.ToString()),
|
new InspectorItemViewModel("Electricity", prop.ElectricityServiceState.ToString())
|
||||||
};
|
};
|
||||||
var surface = m_Level.GetSurface(position);
|
var surface = m_Level.GetSurface(position);
|
||||||
ConsumersGrid.ItemsSource = new[] {
|
ConsumersGrid.ItemsSource = new[] {
|
||||||
new InspectorItemViewModel("Fuel", surface.FuelBlockTurns.ToString()),
|
new InspectorItemViewModel("Fuel", surface.FuelBlockTurns.ToString()),
|
||||||
new InspectorItemViewModel("Coolant", surface.CoolantBlockTurns.ToString()),
|
new InspectorItemViewModel("Coolant", surface.CoolantBlockTurns.ToString()),
|
||||||
new InspectorItemViewModel("Electricity", surface.ElectricityBlockTurns.ToString()),
|
new InspectorItemViewModel("Electricity", surface.ElectricityBlockTurns.ToString())
|
||||||
};
|
};
|
||||||
LeaksGrid.ItemsSource = m_Level.Leaks.Select(leak => new InspectorItemViewModel(leak.Carrier.ToString(), $"{leak.UndergroundPosition.X}, {leak.UndergroundPosition.Y}"));
|
LeaksGrid.ItemsSource = m_Level.Leaks.Select(leak => new InspectorItemViewModel(leak.Carrier.ToString(), $"{leak.UndergroundPosition.X}, {leak.UndergroundPosition.Y}"));
|
||||||
SurfaceGrid.ItemsSource = SurfaceInspectionItems(position);
|
SurfaceGrid.ItemsSource = SurfaceInspectionItems(position);
|
||||||
|
|||||||
Reference in New Issue
Block a user