first round updates from usability test

This commit is contained in:
haven1433
2022-11-04 00:29:03 -05:00
parent b4cf482a28
commit a30ce2ea95
7 changed files with 110 additions and 26 deletions

View File

@@ -415,6 +415,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
private double cursorX, cursorY, deltaX, deltaY;
public event EventHandler AutoscrollBlocks;
private bool showHighlightCursor;
public bool ShowHighlightCursor { get => showHighlightCursor; set => Set(ref showHighlightCursor, value); }
private double highlightCursorX, highlightCursorY, highlightCursorWidth, highlightCursorHeight;
public double HighlightCursorX { get => highlightCursorX; set => Set(ref highlightCursorX, value); }
public double HighlightCursorY { get => highlightCursorY; set => Set(ref highlightCursorY, value); }
@@ -458,6 +461,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
var (prevW, prevH) = (highlightCursorWidth, highlightCursorHeight);
var border = primaryMap.GetBorderThickness();
ShowHighlightCursor = true;
HighlightCursorX = (left + border.West + width / 2.0) * 16 * primaryMap.SpriteScale + primaryMap.LeftEdge;
HighlightCursorY = (top + border.North + height / 2.0) * 16 * primaryMap.SpriteScale + primaryMap.TopEdge;
HighlightCursorWidth = width * 16 * primaryMap.SpriteScale + 4;
@@ -479,7 +483,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
if (map != null) UpdatePrimaryMap(map);
}
public void DragMove(double x, double y) {
public void DragMove(double x, double y, bool isMiddleClickMap) {
deltaX += x - cursorX;
deltaY += y - cursorY;
var (intX, intY) = ((int)deltaX, (int)deltaY);
@@ -487,8 +491,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
deltaY -= intY;
(cursorX, cursorY) = (x, y);
Pan(intX, intY);
if (intX != 0 || intY != 0) Tutorials.Complete(Tutorial.MiddleClick_PanMap);
Hover(x, y);
if ((intX != 0 || intY != 0) && isMiddleClickMap) Tutorials.Complete(Tutorial.MiddleClick_PanMap);
if (isMiddleClickMap) Hover(x, y);
}
public void DragUp(double x, double y) { }
@@ -594,6 +598,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
signpost.Pointer < model.Count
) {
viewPort.Goto.Execute(signpost.Pointer);
Tutorials.Complete(Tutorial.DoubleClickEvent_SeeScript);
} else {
Tutorials.Complete(Tutorial.LeftClick_SelectEvent);
interactionType = PrimaryInteractionType.Event;

View File

@@ -9,6 +9,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
public const int SliderSize = 20;
protected readonly int id;
public abstract string Tooltip { get; }
private MapSliderIcons icon;
public MapSliderIcons Icon { get => icon; set => SetEnum(ref icon, value); }
@@ -57,6 +59,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
private Action notify;
private ConnectionModel connection, inverse;
public override string Tooltip => "Drag to adjust the connection between the maps.";
public ConnectionSlider(ConnectionModel connection, (int group, int num) sourceMapInfo, Action notify, int id, MapSliderIcons icon, MapTutorialsViewModel tutorials, int left = int.MinValue, int top = int.MinValue, int right = int.MinValue, int bottom = int.MinValue) : base(id, icon, left, top, right, bottom) {
(this.notify, this.connection) = (notify, connection);
this.tutorials = tutorials;
@@ -103,6 +107,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
public class ExpansionSlider : MapSlider {
private Action<MapDirection, int> resize;
public override string Tooltip => $"Drag to change the {(Icon == MapSliderIcons.LeftRight ? "width" : "height")} of the map";
public ExpansionSlider(Action<MapDirection, int> resize, int id, MapSliderIcons icon, IEnumerable<IMenuCommand> contextItems, int left = int.MinValue, int top = int.MinValue, int right = int.MinValue, int bottom = int.MinValue) : base(id, icon, left, top, right, bottom) {
foreach (var item in contextItems) ContextItems.Add(item);
this.resize = resize;

View File

@@ -58,32 +58,34 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
double completed = Tutorials.Sum(tut => tut.Incomplete ? 0 : 1);
return $"{completed/Tutorials.Count:p}";
}
}
}
public bool SeeMore => Tutorials.Count(tut => tut.Incomplete) > VisibleCount;
public MapTutorialsViewModel() {
// general navigation
{
Tutorials.Add(new(MiddleClick, "Pan Map", "Middle-Click and drag to move the maps around on the screen."));
Tutorials.Add(new("ArrowKeys", "Pan Map", "Use the arrow keys to move the maps around on the screen."));
Tutorials.Add(new(MiddleClick, "Move Map", "Middle-Click and drag to move the maps around on the screen."));
Tutorials.Add(new("ArrowKeys", "Move Map", "Use the arrow keys to move the maps around on the screen."));
Tutorials.Add(new(MiddleClick, "Zoom Map", "Use the scroll wheel to zoom in and out of the map. Zooming in will hide the border blocks."));
}
// select block / draw / paint
{
Tutorials.Add(new(LeftClick, "Select Block", "Click a block in the block panel to select it."));
Tutorials.Add(new(LeftClick, "Select Block", "Click a block in the Blocks panel to select it."));
Tutorials.Add(new(LeftClick, "Draw Block", "Click/Drag over the map to draw with the selected block."));
Tutorials.Add(new("UndoArrow", "Undo", "Use the Undo button in the toolbar to undo any mistakes."));
Tutorials.Add(new("LeftMouseDoubleClick", "Paint Block", "Double-Click over the map to paint with the selected block."));
Tutorials.Add(new("FillBucket", "Paint Blocks", "Double-Click over the map to paint with the selected block."));
Tutorials.Add(new("EscapeKey", "Unselect Block", "Press the escape key to unselect a block."));
Tutorials.Add(new(LeftClick, "Select Blocks", "Left-Click and drag on the block panel to select multiple blocks. When multiple blocks are selected, you can draw, but not paint."));
}
// editing blocks
{
Tutorials.Add(new("RightAngleArrow", "Edit Blocks", "Select a block, then click this button in the block panel to show the tile panel."));
Tutorials.Add(new(LeftClick, "Select Tile", "Click a tile to select it."));
Tutorials.Add(new(LeftClick, "Draw Tile", "Click on a block's tile at the top of the block panel to replace it with your selected tile/palette."));
Tutorials.Add(new("ArrowsLeftRight", "Flip Tile", "Click the arrows next to a tile to flip that tile vertically or horizontally."));
Tutorials.Add(new("RightAngleArrow", "Edit Block", "Blocks are made of Tiles in a 2x2 grid, with foreground and background layers. Select a block, then click 'Edit Block' in the block panel to show the tile panel."));
Tutorials.Add(new(LeftClick, "Select Tile", "Click a tile in the Tile panel to select it."));
Tutorials.Add(new(LeftClick, "Draw Tile", "Click on a block's foreground or background tile at the top of the block panel to replace it with your selected tile/palette."));
Tutorials.Add(new("ArrowsLeftRight", "Flip Tile", "Click the arrows next to the selected block's foreground/background tile to flip that tile vertically or horizontally."));
}
// right-click map
@@ -94,8 +96,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
// editing events
{
Tutorials.Add(new(LeftClick, "Select Event", "Click an event in the map to select it. Selecting an event will unselect any active blocks."));
Tutorials.Add(new("LeftMouseDoubleClick", "Follow Warp", "Double-Click on a warp to go to the map it references."));
Tutorials.Add(new(LeftClick, "Select Event", "Click an event (character, blue warp, green script, or red signpost) in the map to select it. Selecting an event will unselect any active blocks."));
Tutorials.Add(new("LeftMouseDoubleClick", "Follow Warp", "Double-Click on a warp event to go to the map it references."));
Tutorials.Add(new("LeftArrow", "Go Back", "Use the back arrow in the toolbar to return to the previous map or data."));
Tutorials.Add(new("FourDirectionArrows", "Move Event", "Drag an event to move it on the map."));
Tutorials.Add(new(LeftClick, "Unselect Event", "Click on any part of the map to unselect the event."));
@@ -118,12 +120,13 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
Tutorials.Add(new("Selection", "Create Object", "Drag the character sprite from the top toolbar to create object events."));
Tutorials.Add(new("Selection", "Create Event", "Drag the Blue/Green/Red squares from the top toolbar to create warp events, script events, and signpost events."));
Tutorials.Add(new(RightClick, "Warp New Map", "Right-Click a warp to create a new map to warp to."));
Tutorials.Add(new("Settings", "Configure Object", "Click the icon next to the character sprite to choose what type of object you want to add."));
Tutorials.Add(new("Settings", "Configure Object", "Click the gear icon next to the character sprite to choose what type of object you want to add."));
}
Reset();
foreach (var tut in Tutorials) {
tut.RequestClose += (sender, e) => Complete((Tutorial)Tutorials.IndexOf((MapTutorialViewModel)sender));
for(int i = 0; i < Tutorials.Count; i++) {
Tutorials[i].RequestClose += (sender, e) => Complete((Tutorial)Tutorials.IndexOf((MapTutorialViewModel)sender));
Tutorials[i].Index = i + 1;
}
}
@@ -167,7 +170,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
Tutorials[i].TargetPosition -= 1;
if (Tutorials[i].Incomplete && Tutorials[i].TargetPosition < VisibleCount) Tutorials[i].TriggerAnimation();
}
NotifyPropertyChanged(nameof(CompletionPercent));
NotifyPropertiesChanged(nameof(CompletionPercent), nameof(SeeMore));
}
}
@@ -181,6 +184,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
public bool Incomplete { get => incomplete; set => PropertyChanged.TryUpdate(this, ref incomplete, value); }
public double TargetPosition { get => target; set => PropertyChanged.TryUpdate(this, ref target, value); }
public double TopEdge => TargetPosition * 90;
public int Index { get; set; }
public string IndexText => $"{Index} of 32";
public void TriggerAnimation() => AnimateMovement.Raise(this);

View File

@@ -25,7 +25,7 @@
<KeyBinding Key="Delete" Command="{Binding DeleteCommand}" />
<KeyBinding Key="Backspace" Command="{Binding DeleteCommand}" />
</UserControl.InputBindings>
<Grid ClipToBounds="True">
<Grid ClipToBounds="True" Background="Transparent" MouseDown="BackgroundDown" MouseMove="BackgroundMove" MouseUp="BackgroundUp" MouseWheel="Wheel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -60,7 +60,7 @@
<local:AngleComboBox Direction="Out" Width="50" Height="20"
ItemsSource="{Binding CollisionOptions}" SelectedIndex="{Binding CollisionIndex}" />
</StackPanel>
<Decorator Grid.Row="1" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,35,55" Visibility="{Binding BlockEditorVisible, Converter={StaticResource BoolToVisibility}}">
<Decorator Grid.Row="1" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,30,55" Visibility="{Binding BlockEditorVisible, Converter={StaticResource BoolToVisibility}}">
<local:AngleButton DataContext="{Binding PrimaryMap.BlockEditor}" Content="Edit Block"
Direction="Right" Padding="2,0" Command="{res:MethodCommand ToggleShowTiles}" />
</Decorator>
@@ -694,7 +694,7 @@
<!-- Main View -->
<ItemsControl Grid.Column="1" Grid.Row="1" Name="MapView" ItemsSource="{Binding VisibleMaps}"
SnapsToDevicePixels="True" ClipToBounds="True" Focusable="False"
MouseDown="ButtonDown" MouseMove="ButtonMove" MouseUp="ButtonUp" MouseWheel="Wheel">
MouseDown="ButtonDown" MouseMove="ButtonMove" MouseUp="ButtonUp" MouseLeave="ButtonLeave" MouseWheel="Wheel">
<ItemsControl.RenderTransform>
<TranslateTransform/>
</ItemsControl.RenderTransform>
@@ -764,6 +764,9 @@
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Border.ContextMenu>
<Border.ToolTip>
<ToolTip Content="{Binding Tooltip}" />
</Border.ToolTip>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Icon}" Value="LeftRight">
@@ -776,7 +779,7 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Rectangle Grid.Column="1" Grid.Row="1" Name="HighlightCursorRect" StrokeThickness="2" IsHitTestVisible="False" Margin="-2,-2,0,0"
<Rectangle Grid.Column="1" Grid.Row="1" Name="HighlightCursorRect" StrokeThickness="2" IsHitTestVisible="False" Margin="-2,-2,0,0" Visibility="{Binding ShowHighlightCursor, Converter={StaticResource BoolToVisibility}}"
HorizontalAlignment="Center" VerticalAlignment="Center" Stroke="{DynamicResource Backlight}"
Width="{Binding HighlightCursorWidth, Mode=OneWay}" Height="{Binding HighlightCursorHeight, Mode=OneWay}">
<Rectangle.RenderTransform>

View File

@@ -130,7 +130,7 @@ namespace HavenSoft.HexManiac.WPF.Controls {
if (withinMapInteraction == MouseButton.Left) {
vm.PrimaryMove(p.X, p.Y);
} else if (withinMapInteraction == MouseButton.Middle) {
vm.DragMove(p.X, p.Y);
vm.DragMove(p.X, p.Y, true);
} else if (withinMapInteraction == MouseButton.Right) {
vm.SelectMove(p.X, p.Y);
}
@@ -156,6 +156,56 @@ namespace HavenSoft.HexManiac.WPF.Controls {
}
}
private void ButtonLeave(object sender, MouseEventArgs e) {
UpdateTooltipContent(NoTooltip);
ViewModel.ShowHighlightCursor = false;
}
private void BackgroundDown(object sender, MouseButtonEventArgs e) {
if (e.ChangedButton == MouseButton.XButton1 && ViewModel.Back.CanExecute(null)) {
ViewModel.Back.Execute();
return;
}
if (e.ChangedButton == MouseButton.XButton2 && ViewModel.Forward.CanExecute(null)) {
ViewModel.Forward.Execute();
return;
}
if (withinMapInteraction != MouseButton.XButton1) return;
UpdateTooltipContent(NoTooltip);
Focus();
e.Handled = true;
var element = (FrameworkElement)sender;
var vm = ViewModel;
var p = GetCoordinates(element, e);
element.CaptureMouse();
withinMapInteraction = MouseButton.Middle;
vm.DragDown(p.X, p.Y);
}
private void BackgroundMove(object sender, MouseEventArgs e) {
var element = (FrameworkElement)sender;
var vm = ViewModel;
if (vm == null) return;
var p = GetCoordinates(element, e);
e.Handled = true;
if (withinMapInteraction == MouseButton.XButton1) return;
vm.DragMove(p.X, p.Y, false);
}
private void BackgroundUp(object sender, MouseButtonEventArgs e) {
e.Handled = true;
var element = (FrameworkElement)sender;
var previousInteraction = withinMapInteraction;
withinMapInteraction = MouseButton.XButton1;
element.ReleaseMouseCapture();
if (previousInteraction == MouseButton.XButton1) return;
if (e.ChangedButton != previousInteraction) return;
var vm = ViewModel;
if (vm == null) return;
var p = GetCoordinates(element, e);
vm.DragUp(p.X, p.Y);
}
private void Wheel(object sender, MouseWheelEventArgs e) {
var element = (FrameworkElement)sender;
var vm = ViewModel;

View File

@@ -17,10 +17,11 @@
<DataTemplate>
<Border BorderThickness="1" BorderBrush="{DynamicResource Secondary}" Background="{DynamicResource Backlight}">
<Canvas Width="398" Height="88">
<Decorator Width="98" Height="88">
<Decorator Width="98" Height="78">
<Path Data="{Binding Icon, Converter={StaticResource IconConverter}}" Stretch="Uniform" Margin="5,20,5,5" Fill="{DynamicResource Secondary}" />
</Decorator>
<TextBlock FontWeight="Bold" Width="98" TextAlignment="Center" Text="{Binding Title}" Canvas.Top="2" />
<TextBlock FontStyle="Italic" Width="98" TextAlignment="Center" Text="{Binding IndexText}" Canvas.Bottom="2" />
<Decorator Width="300" Height="88" Canvas.Left="98">
<TextBlock TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10" Text="{Binding Content}" />
</Decorator>
@@ -44,6 +45,7 @@
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Dismiss All" Command="{res:MethodCommand DismissAll}" />
<MenuItem Header="Restart All" Command="{res:MethodCommand Reset}" />
</ContextMenu>
</Border.ContextMenu>
<TextBlock HorizontalAlignment="Center">
@@ -52,5 +54,20 @@
<Run Text=")" />
</TextBlock>
</Border>
<Border Canvas.Bottom="0" Canvas.Right="0" Height="20" Width="110" Visibility="{Binding SeeMore, Converter={StaticResource BoolToVisibility}}">
<Border Background="{DynamicResource Backlight}" BorderBrush="{StaticResource Secondary}" ToolTipService.InitialShowDelay="0"
BorderThickness="1" Visibility="{Binding IsMouseOver, ElementName=ContentPanel, Converter={StaticResource BoolToVisibility}}">
<Border.ToolTip>
<ToolTip>
<TextBlock>
Complete actions to clear tutorials.
<LineBreak />
Additional tutorials will show until you've completed them all.
</TextBlock>
</ToolTip>
</Border.ToolTip>
<TextBlock HorizontalAlignment="Center" Text="See More..."/>
</Border>
</Border>
</Canvas>
</UserControl>

View File

@@ -1,11 +1,9 @@
using HavenSoft.HexManiac.Core.ViewModels.Map;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Xml.Linq;
namespace HavenSoft.HexManiac.WPF.Controls {
public partial class TutorialControl {