Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions UndertaleModTool/Editors/UndertaleEmbeddedTextureEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0" Margin="3">Scaled</TextBlock>
Expand Down Expand Up @@ -65,20 +66,49 @@
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<local:ButtonDark Grid.Column="0" Content="Import" Click="Import_Click"/>
<local:ButtonDark Grid.Column="2" Content="Export" Click="Export_Click"/>
</Grid>

<!-- Texture Viewer with Resizable Panel and Zoom Controls -->
<Grid Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" Margin="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" MinHeight="200"/>
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Grid.ColumnSpan="3" Margin="3" HorizontalAlignment="Center" Foreground="DarkGray" FontStyle="Italic" TextWrapping="Wrap" TextAlignment="Center">
Hint: This image is mouse interactable (3 mouse buttons and mouse wheel).
</TextBlock>
<ScrollViewer Name="TextureScroll" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" MaxHeight="450"
HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" ScrollChanged="TextureScroll_ScrollChanged">
<ScrollViewer.Background>
<DynamicResource ResourceKey="{x:Static SystemColors.MenuBrushKey}"/>
</ScrollViewer.Background>
<!-- Zoom Controls -->
<Grid Grid.Row="0" Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<local:ButtonDark Grid.Column="0" Content="Zoom In" Margin="0,0,5,0" Padding="8,4" Click="ZoomIn_Click"/>
<local:ButtonDark Grid.Column="1" Content="Zoom Out" Margin="0,0,5,0" Padding="8,4" Click="ZoomOut_Click"/>
<local:ButtonDark Grid.Column="2" Content="Fit to View" Margin="0,0,5,0" Padding="8,4" Click="FitToView_Click"/>
<local:ButtonDark Grid.Column="3" Content="Actual Size" Margin="0,0,10,0" Padding="8,4" Click="ActualSize_Click"/>

<TextBlock Grid.Column="4" Text="Zoom:" VerticalAlignment="Center" Margin="0,0,5,0"/>
<local:TextBoxDark Grid.Column="5" x:Name="ZoomTextBox" Width="60" Text="100%" VerticalAlignment="Center"
KeyDown="ZoomTextBox_KeyDown" LostFocus="ZoomTextBox_LostFocus" Margin="0,0,5,0"/>

<TextBlock Grid.Column="6" Text="Size:" VerticalAlignment="Center" Margin="10,0,5,0"/>
<TextBlock Grid.Column="7" x:Name="ImageSizeText" Text="0x0" VerticalAlignment="Center" Margin="0,0,5,0"/>
</Grid>

<!-- Resizable Sprite Viewer -->
<ScrollViewer Name="TextureScroll" Grid.Row="2"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
ScrollChanged="TextureScroll_ScrollChanged" Background="{DynamicResource {x:Static SystemColors.MenuBrushKey}}">
<Viewbox Name="TextureViewbox" Stretch="Uniform" StretchDirection="DownOnly"
SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor" MouseWheel="TextureViewbox_MouseWheel">
<Border Background="{DynamicResource TransparencyGridBrushBrush}">
Expand All @@ -92,9 +122,6 @@
</Border>
</Viewbox>
</ScrollViewer>

<local:ButtonDark Grid.Row="2" Grid.Column="0" Margin="0,2" Content="Import" Click="Import_Click"/>
<local:ButtonDark Grid.Row="2" Grid.Column="3" Margin="0,2" Content="Export" Click="Export_Click"/>
</Grid>
</Grid>
</local:DataUserControl>
151 changes: 150 additions & 1 deletion UndertaleModTool/Editors/UndertaleEmbeddedTextureEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public partial class UndertaleEmbeddedTextureEditor : DataUserControl
private bool isMenuOpen;
private UndertaleTexturePageItem[] items;
private UndertaleTexturePageItem hoveredItem;
private double currentZoom = 1.0;

/// <summary>
/// Handle on the texture data where we're listening for updates from.
Expand Down Expand Up @@ -72,12 +73,30 @@ private void UpdateImage(UndertaleEmbeddedTexture texture)
if (texture.TextureData?.Image is null)
{
TexturePageImage.Source = null;
UpdateImageSizeDisplay(0, 0);
return;
}

GMImage image = texture.TextureData.Image;
BitmapSource bitmap = mainWindow.GetBitmapSourceForImage(image);
TexturePageImage.Source = bitmap;
UpdateImageSizeDisplay(image.Width, image.Height);
}

private void UpdateImageSizeDisplay(int width, int height)
{
if (ImageSizeText != null)
{
ImageSizeText.Text = $"{width}x{height}";
}
}

private void UpdateZoomDisplay()
{
if (ZoomTextBox != null)
{
ZoomTextBox.Text = $"{Math.Round(currentZoom * 100)}%";
}
}

private void SwitchDataContext(object sender, DependencyPropertyChangedEventArgs e)
Expand Down Expand Up @@ -172,18 +191,28 @@ private void ScaleTextureToFit()
t = new MatrixTransform(Matrix.Identity);
top = 0;
left = 0;
currentZoom = 1.0;
}
else
{
t = OverriddenPreviewState.Transform;
top = OverriddenPreviewState.Top;
left = OverriddenPreviewState.Left;
if (t is MatrixTransform mt)
{
currentZoom = mt.Matrix.M11;
}
else
{
currentZoom = 1.0;
}
}

TextureViewbox.LayoutTransform = t;
TextureViewbox.UpdateLayout();
TextureScroll.ScrollToVerticalOffset(top);
TextureScroll.ScrollToHorizontalOffset(left);
UpdateZoomDisplay();
}
private void DataUserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Expand All @@ -201,7 +230,19 @@ private void DataUserControl_Loaded(object sender, RoutedEventArgs e)
}
private void DataUserControl_Unloaded(object sender, RoutedEventArgs e)
{
OverriddenPreviewState = default;
// Save current zoom state
if (TextureViewbox != null && TextureScroll != null)
{
OverriddenPreviewState = (
TextureViewbox.LayoutTransform,
TextureScroll.HorizontalOffset,
TextureScroll.VerticalOffset
);
}
else
{
OverriddenPreviewState = default;
}
}

private void Import_Click(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -372,9 +413,117 @@ private void TextureViewbox_MouseWheel(object sender, MouseWheelEventArgs e)
if ((matrix.M11 > 0.001 || (matrix.M11 <= 0.001 && scale > 1)) && (matrix.M11 < 1000 || (matrix.M11 >= 1000 && scale < 1)))
{
matrix.ScaleAtPrepend(scale, scale, mousePos.X, mousePos.Y);
currentZoom = matrix.M11;
UpdateZoomDisplay();
}
TextureViewbox.LayoutTransform = new MatrixTransform(matrix);
}

#region Zoom Controls

private void ZoomIn_Click(object sender, RoutedEventArgs e)
{
ApplyZoom(1.25, true);
}

private void ZoomOut_Click(object sender, RoutedEventArgs e)
{
ApplyZoom(0.8, true);
}

private void FitToView_Click(object sender, RoutedEventArgs e)
{
if (TexturePageImage.Source == null) return;

var scrollViewerSize = new System.Windows.Size(TextureScroll.ViewportWidth, TextureScroll.ViewportHeight);
var imageSize = new System.Windows.Size(TexturePageImage.Source.Width, TexturePageImage.Source.Height);

if (scrollViewerSize.Width <= 0 || scrollViewerSize.Height <= 0) return;

var scaleX = scrollViewerSize.Width / imageSize.Width;
var scaleY = scrollViewerSize.Height / imageSize.Height;
var scale = Math.Min(scaleX, scaleY) * 0.95;

SetZoom(scale);
}

private void ActualSize_Click(object sender, RoutedEventArgs e)
{
SetZoom(1.0);
}

private void ZoomTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
ApplyZoomFromTextBox();
e.Handled = true;
}
}

private void ZoomTextBox_LostFocus(object sender, RoutedEventArgs e)
{
ApplyZoomFromTextBox();
}

private void ApplyZoomFromTextBox()
{
if (ZoomTextBox == null) return;

string text = ZoomTextBox.Text.Replace("%", "").Trim();
if (double.TryParse(text, out double percentage))
{
double zoom = Math.Max(0.1, Math.Min(1000, percentage / 100.0));
SetZoom(zoom);
}
else
{
UpdateZoomDisplay();
}
}

private void ApplyZoom(double factor, bool centerOnViewport)
{
var transform = TextureViewbox.LayoutTransform as MatrixTransform;
var matrix = transform.Matrix;

System.Windows.Point center;
if (centerOnViewport)
{
center = new System.Windows.Point(TextureViewbox.ActualWidth / 2, TextureViewbox.ActualHeight / 2);
}
else
{
center = Mouse.GetPosition(TextureViewbox);
}

var newScale = matrix.M11 * factor;
if (newScale > 0.001 && newScale < 1000)
{
matrix.ScaleAtPrepend(factor, factor, center.X, center.Y);
currentZoom = newScale;
UpdateZoomDisplay();
TextureViewbox.LayoutTransform = new MatrixTransform(matrix);
}
}

private void SetZoom(double zoom)
{
zoom = Math.Max(0.001, Math.Min(1000, zoom));

var matrix = Matrix.Identity;
matrix.Scale(zoom, zoom);

currentZoom = zoom;
UpdateZoomDisplay();
TextureViewbox.LayoutTransform = new MatrixTransform(matrix);

TextureViewbox.UpdateLayout();
TextureScroll.ScrollToHorizontalOffset((TextureScroll.ExtentWidth - TextureScroll.ViewportWidth) / 2);
TextureScroll.ScrollToVerticalOffset((TextureScroll.ExtentHeight - TextureScroll.ViewportHeight) / 2);
}

#endregion
}

public class TextureLoadedWrapper : IMultiValueConverter
Expand Down
53 changes: 47 additions & 6 deletions UndertaleModTool/Editors/UndertaleSpriteEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,52 @@
</DataGrid.Columns>
</local:DataGridDark>

<Viewbox Grid.Row="11" Grid.Column="1" Stretch="Uniform" StretchDirection="DownOnly">
<Border Background="{StaticResource TransparencyGridBrushBrush}">
<local:UndertaleTexturePageItemDisplay DataContext="{Binding SelectedItem.Texture, Mode=OneWay, ElementName=TextureList}" x:Name="TextureDisplay"/>
</Border>
</Viewbox>
<Grid Grid.Row="11" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- Zoom Controls -->
<Grid Grid.Row="0" Margin="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>

<local:ButtonDark Grid.Column="0" Content="Zoom In" Margin="2" Click="ZoomIn_Click" ToolTip="Zoom In (Ctrl++)"/>
<local:ButtonDark Grid.Column="1" Content="Zoom Out" Margin="2" Click="ZoomOut_Click" ToolTip="Zoom Out (Ctrl+-)"/>
<local:ButtonDark Grid.Column="2" Content="Fit" Margin="2" Click="FitToView_Click" ToolTip="Fit to View"/>
<local:ButtonDark Grid.Column="3" Content="1:1" Margin="2" Click="ActualSize_Click" ToolTip="Actual Size"/>

<TextBlock Grid.Column="5" Text="Zoom:" VerticalAlignment="Center" Margin="5,0"/>
<local:TextBoxDark Grid.Column="6" Width="60" Margin="2" Text="{Binding ElementName=SpriteTextureContainer, Path=Tag, Mode=OneWay}"
ToolTip="Current zoom percentage" IsReadOnly="True"/>
</Grid>

<!-- Resizable Sprite Viewer -->
<ScrollViewer Grid.Row="1" Margin="3" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
x:Name="SpriteTextureScrollViewer" PreviewMouseWheel="SpriteTextureScrollViewer_PreviewMouseWheel"
VerticalAlignment="Top">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="SpriteTextureContainer"
RenderTransformOrigin="0.5,0.5" Cursor="Hand"
MouseDown="SpriteTextureContainer_MouseDown" MouseMove="SpriteTextureContainer_MouseMove"
MouseUp="SpriteTextureContainer_MouseUp" MouseLeave="SpriteTextureContainer_MouseLeave">
<Grid.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Grid.RenderTransform>
<Border Background="{StaticResource TransparencyGridBrushBrush}" x:Name="SpriteTextureBorder">
<local:UndertaleTexturePageItemDisplay DataContext="{Binding SelectedItem.Texture, Mode=OneWay, ElementName=TextureList}"
x:Name="SpriteTextureDisplay"/>
</Border>
</Grid>
</ScrollViewer>
</Grid>

<local:ButtonDark Grid.Row="12" Grid.Column="1" Content="Export all frames (or Spine data if this is a Spine sprite)" Click="ExportAll_Click"/>

Expand Down Expand Up @@ -207,7 +248,7 @@
</DataGrid.Columns>
</local:DataGridDark>

<ContentControl Grid.Row="14" Grid.Column="1" Margin="3" DataContext="{Binding SelectedItem, Mode=OneWay, ElementName=MaskList}">
<ContentControl Grid.Row="15" Grid.Column="1" Margin="3" DataContext="{Binding SelectedItem, Mode=OneWay, ElementName=MaskList}">
<ContentControl.Template>
<ControlTemplate>
<StackPanel Name="MaskEditor">
Expand Down
Loading