mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-05-31 20:42:43 -05:00
Allow drawing blocks of a color via the draw tool
This commit is contained in:
parent
0e17b057f1
commit
407db89b00
|
|
@ -99,7 +99,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
public event EventHandler RefreshSelection;
|
||||
private void RaiseRefreshSelection(params Point[] toSelect) {
|
||||
selectedPixels = new bool[PixelWidth, PixelHeight];
|
||||
foreach (var s in toSelect) selectedPixels[s.X, s.Y] = true;
|
||||
foreach (var s in toSelect) {
|
||||
if (WithinImage(s)) selectedPixels[s.X, s.Y] = true;
|
||||
}
|
||||
RefreshSelection?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +120,11 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
|
||||
public int SpritePointer { get; }
|
||||
|
||||
private StubCommand setCursorSize;
|
||||
public ICommand SetCursorSize => StubCommand<string>(ref setCursorSize, arg => CursorSize = int.Parse(arg));
|
||||
private int cursorSize = 1;
|
||||
public int CursorSize { get => cursorSize; set => Set(ref cursorSize, value, arg => BlockPreview.Clear()); }
|
||||
|
||||
public ImageEditorViewModel(ChangeHistory<ModelDelta> history, IDataModel model, int address) {
|
||||
this.history = history;
|
||||
this.model = model;
|
||||
|
|
@ -262,6 +269,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
SelectedTool = ImageEditorTools.Draw;
|
||||
}
|
||||
BlockPreview.Clear();
|
||||
if (CursorSize == 0) CursorSize = 1;
|
||||
break;
|
||||
case nameof(sc.Color):
|
||||
Palette.PushColorsToModel(); // this causes a Render
|
||||
|
|
@ -362,20 +370,20 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
point = parent.ToSpriteSpace(point);
|
||||
if (parent.WithinImage(point)) {
|
||||
var tile = parent.eyeDropperStrategy.Tile;
|
||||
if (tile == null) {
|
||||
drawSize = 1;
|
||||
drawPoint = point;
|
||||
parent.PixelData[parent.PixelIndex(point)] = element.Color;
|
||||
parent.pixels[point.X, point.Y] = element.Index;
|
||||
if (tile == null || !parent.BlockPreview.Enabled) {
|
||||
drawSize = parent.CursorSize;
|
||||
tile = new int[drawSize, drawSize];
|
||||
for (int x = 0; x < drawSize; x++) for (int y = 0; y < drawSize; y++) tile[x, y] = element.Index;
|
||||
} else {
|
||||
drawSize = tile.GetLength(0);
|
||||
drawPoint = new Point(point.X - point.X % drawSize, point.Y - point.Y % drawSize);
|
||||
for (int x = 0; x < drawSize; x++) {
|
||||
for (int y = 0; y < drawSize; y++) {
|
||||
var (xx, yy) = (drawPoint.X + x, drawPoint.Y + y);
|
||||
parent.PixelData[parent.PixelIndex(xx, yy)] = parent.Palette.Elements[tile[x, y]].Color;
|
||||
parent.pixels[xx, yy] = tile[x, y];
|
||||
}
|
||||
}
|
||||
|
||||
drawPoint = new Point(point.X - point.X % drawSize, point.Y - point.Y % drawSize);
|
||||
for (int x = 0; x < drawSize; x++) {
|
||||
for (int y = 0; y < drawSize; y++) {
|
||||
var (xx, yy) = (drawPoint.X + x, drawPoint.Y + y);
|
||||
parent.PixelData[parent.PixelIndex(xx, yy)] = parent.Palette.Elements[tile[x, y]].Color;
|
||||
parent.pixels[xx, yy] = tile[x, y];
|
||||
}
|
||||
}
|
||||
parent.NotifyPropertyChanged(nameof(PixelData));
|
||||
|
|
@ -388,13 +396,13 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
point = parent.ToSpriteSpace(point);
|
||||
if (parent.WithinImage(point)) {
|
||||
var tile = parent.eyeDropperStrategy.Tile;
|
||||
if (tile == null) {
|
||||
drawPoint = point;
|
||||
drawSize = 1;
|
||||
if (tile == null || !parent.BlockPreview.Enabled) {
|
||||
drawSize = parent.CursorSize;
|
||||
} else {
|
||||
drawSize = tile.GetLength(0);
|
||||
drawPoint = new Point(point.X - point.X % drawSize, point.Y - point.Y % drawSize);
|
||||
}
|
||||
|
||||
drawPoint = new Point(point.X - point.X % drawSize, point.Y - point.Y % drawSize);
|
||||
} else {
|
||||
drawPoint = default;
|
||||
drawSize = 0;
|
||||
|
|
@ -583,8 +591,6 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
|
||||
public EyeDropperTool(ImageEditorViewModel parent) => this.parent = parent;
|
||||
|
||||
public bool ShowSelectionRect(Point subPixelPosition) => false;
|
||||
|
||||
public void ToolDown(Point point) {
|
||||
underPixels = null; // old selection lost
|
||||
selectionStart = parent.ToSpriteSpace(point);
|
||||
|
|
@ -630,6 +636,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
for (int x = 0; x < selectionWidth; x++) for (int y = 0; y < selectionHeight; y++) {
|
||||
underPixels[x, y] = parent.pixels[selectionStart.X + x, selectionStart.Y + y];
|
||||
}
|
||||
parent.CursorSize = 0;
|
||||
parent.BlockPreview.Set(parent.PixelData, parent.PixelWidth, selectionStart, selectionWidth);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -505,6 +505,7 @@ namespace HavenSoft.HexManiac.Tests {
|
|||
Assert.Equal(2, editor.BlockPreview.PixelHeight);
|
||||
Assert.Equal(4, editor.BlockPreview.PixelData.Length);
|
||||
Assert.All(4.Range(), i => Assert.Equal(Rgb(31, 31, 31), editor.BlockPreview.PixelData[i]));
|
||||
Assert.Equal(0, editor.CursorSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -560,5 +561,36 @@ namespace HavenSoft.HexManiac.Tests {
|
|||
|
||||
Assert.False(editor.ShowSelectionRect(4, 2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Draw_SetCursorSize_LargeCursor() {
|
||||
editor.SelectedTool = ImageEditorTools.Draw;
|
||||
|
||||
editor.SetCursorSize.Execute("2");
|
||||
editor.Hover(default);
|
||||
|
||||
Assert.All( new[] {
|
||||
new Point(4, 4),
|
||||
new Point(4, 5),
|
||||
new Point(5, 4),
|
||||
new Point(5, 5),
|
||||
}, p => Assert.True(editor.ShowSelectionRect(p)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EyeDropperBlock_SelectColor_DrawSinglePixel() {
|
||||
editor.EyeDropperDown(0, 0);
|
||||
editor.Hover(1, 1);
|
||||
editor.EyeDropperUp(1, 1);
|
||||
|
||||
editor.Palette.SelectionStart = 1;
|
||||
editor.Hover(0, 0);
|
||||
|
||||
Assert.All(new[] {
|
||||
new Point(4, 5),
|
||||
new Point(5, 4),
|
||||
new Point(5, 5),
|
||||
}, p => Assert.False(editor.ShowSelectionRect(p)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,19 @@
|
|||
</UserControl.InputBindings>
|
||||
<DockPanel>
|
||||
<DockPanel DockPanel.Dock="Left">
|
||||
<DockPanel.Resources>
|
||||
<Style TargetType="Path">
|
||||
<Setter Property="Fill" Value="{DynamicResource Secondary}"/>
|
||||
<Setter Property="Stretch" Value="Uniform"/>
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=RadioButton}}" Value="True">
|
||||
<Setter Property="Fill" Value="{DynamicResource Primary}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DockPanel.Resources>
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="RadioButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
|
||||
|
|
@ -32,17 +45,6 @@
|
|||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style TargetType="Path">
|
||||
<Setter Property="Fill" Value="{DynamicResource Secondary}"/>
|
||||
<Setter Property="Stretch" Value="Uniform"/>
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=RadioButton}}" Value="True">
|
||||
<Setter Property="Fill" Value="{DynamicResource Primary}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<RadioButton CommandParameter="{x:Static hshmcvm:ImageEditorTools.Pan}"
|
||||
IsChecked="{Binding SelectedTool, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter={x:Static hshmcvm:ImageEditorTools.Pan}}">
|
||||
|
|
@ -136,7 +138,30 @@
|
|||
</RadioButton.ToolTip>
|
||||
</RadioButton>
|
||||
</StackPanel>
|
||||
<local:PixelImage DataContext="{Binding BlockPreview}" Visibility="{Binding Enabled, Converter={StaticResource BoolToVisibility}}" DockPanel.Dock="Top"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center"
|
||||
Visibility="{Binding Tag, RelativeSource={RelativeSource Self}, Converter={StaticResource BoolToVisibility}, ConverterParameter={x:Static Visibility.Hidden}}"
|
||||
Tag="{Binding SelectedTool, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter={x:Static hshmcvm:ImageEditorTools.Draw}}">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="RadioButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
|
||||
<Setter Property="Command" Value="{Binding SetCursorSize}"/>
|
||||
<Setter Property="Width" Value="30"/>
|
||||
<Setter Property="Height" Value="30"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<RadioButton CommandParameter="1" Content="1"
|
||||
IsChecked="{Binding CursorSize, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter=1}"/>
|
||||
<RadioButton CommandParameter="2" Content="2"
|
||||
IsChecked="{Binding CursorSize, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter=2}"/>
|
||||
<RadioButton CommandParameter="4" Content="4"
|
||||
IsChecked="{Binding CursorSize, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter=4}"/>
|
||||
<RadioButton CommandParameter="8" Content="8" Margin="0,0,30,0"
|
||||
IsChecked="{Binding CursorSize, Mode=OneWay, Converter={StaticResource EqualityCheck}, ConverterParameter=8}"/>
|
||||
</StackPanel>
|
||||
|
||||
<local:PixelImage DataContext="{Binding BlockPreview}" Visibility="{Binding Enabled, Converter={StaticResource BoolToVisibility}, ConverterParameter={x:Static Visibility.Hidden}}" DockPanel.Dock="Top"/>
|
||||
<hshmwpfc:PaletteControl DataContext="{Binding Palette}" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</DockPanel>
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace HavenSoft.HexManiac.WPF.Controls {
|
|||
|
||||
public class EqualityToBooleanConverter : IValueConverter {
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return Equals(value, parameter);
|
||||
return Equals(value.ToString(), parameter.ToString());
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
|
|
@ -85,6 +85,23 @@ namespace HavenSoft.HexManiac.WPF.Controls {
|
|||
}
|
||||
}
|
||||
|
||||
public class BooleanToVisibilityConverter : IValueConverter {
|
||||
private readonly System.Windows.Controls.BooleanToVisibilityConverter core = new System.Windows.Controls.BooleanToVisibilityConverter();
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (value is bool b) {
|
||||
if (parameter == null) return b ? Visibility.Visible : Visibility.Hidden;
|
||||
if (parameter is Visibility v && v == Visibility.Hidden) return b ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
return core.Convert(value, targetType, parameter, culture);
|
||||
}
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
if (value is Visibility vis) {
|
||||
return vis == Visibility.Visible;
|
||||
}
|
||||
return core.ConvertBack(value, targetType, parameter, culture);
|
||||
}
|
||||
}
|
||||
|
||||
public class PixelImage : Image {
|
||||
private IPixelViewModel ViewModel => DataContext as IPixelViewModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:hsc="clr-namespace:HavenSoft.HexManiac.WPF.Controls"
|
||||
xmlns:hsv="clr-namespace:HavenSoft.HexManiac.WPF.Resources">
|
||||
<Application.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
|
||||
<hsc:BooleanToVisibilityConverter x:Key="BoolToVisibility" />
|
||||
<hsc:PaletteColorConverter x:Key="PaletteColorConverter"/>
|
||||
<hsc:EqualityToBooleanConverter x:Key="EqualityCheck"/>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user