spartan mode (first pass)

Some 'nice-to-have' features make the application very slow. Add a 'spartan mode' that turns off these optional features to make the app run faster.
* Multiple tables in the table tool
* "Show Uses" map option within table tool
* long-line text warning in script editor
* <auto> insertion in script editor
* right-click options within scripts
* hover tips on events within map editor
* hover previews for blocksets
* image preview behind data for images
* image editor pixel-display during palette hover
* reduce the number of neighbor maps shown in the map editor
This commit is contained in:
haven1433 2023-08-02 22:04:38 -05:00
parent b6cfcb3577
commit 730d06509b
24 changed files with 107 additions and 38 deletions

View File

@ -23,7 +23,7 @@ namespace HavenSoft.HexManiac.Core.Models
}
public Action ResetChanges { get; set; }
void IDataModel.ResetChanges()
{
if (this.ResetChanges != null)
@ -31,7 +31,9 @@ namespace HavenSoft.HexManiac.Core.Models
this.ResetChanges();
}
}
public bool SpartanMode { get; set; }
public delegate System.Collections.Generic.IEnumerable<T> AllDelegate_<T>() where T : Runs.IFormattedRun;
private readonly Dictionary<Type[], object> AllDelegates_ = new Dictionary<Type[], object>(new EnumerableEqualityComparer<Type>());
public void ImplementAll<T>(AllDelegate_<T> implementation) where T : Runs.IFormattedRun

View File

@ -50,6 +50,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels
return this.Name.get();
}
}
public bool SpartanMode { get; set; }
public PropertyImplementation<bool> IsMetadataOnlyChange = new PropertyImplementation<bool>();
bool ITabContent.IsMetadataOnlyChange

View File

@ -150,7 +150,9 @@ namespace HavenSoft.HexManiac.Core.ViewModels
}
}
public PropertyImplementation<int> Width = new PropertyImplementation<int>();
public bool SpartanMode { get; set; }
int IViewPort.Width
{
get

View File

@ -20,6 +20,7 @@ namespace HavenSoft.HexManiac.Core.Models {
byte[] RawData { get; }
ModelCacheScope CurrentCacheScope { get; }
bool SpartanMode { get; set; }
bool HasChanged(int index);
int ChangeCount { get; }
void ResetChanges();
@ -177,6 +178,8 @@ namespace HavenSoft.HexManiac.Core.Models {
}
}
public bool SpartanMode { get; set; }
public bool HasChanged(int index) => changes.Contains(index);
public int ChangeCount => changes.Count;
public void ResetChanges() => changes.Clear();

View File

@ -54,7 +54,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Sprites {
int lastFormatRequested = int.MaxValue;
public override IDataFormat CreateDataFormat(IDataModel data, int index) {
var basicFormat = base.CreateDataFormat(data, index);
if (!CreateForLeftEdge) return basicFormat;
if (!CreateForLeftEdge || data.SpartanMode) return basicFormat;
if (lastFormatRequested < index) {
lastFormatRequested = index;
return basicFormat;

View File

@ -474,7 +474,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Sprites {
int lastFormatRequested = int.MaxValue;
public override IDataFormat CreateDataFormat(IDataModel data, int index) {
var basicFormat = base.CreateDataFormat(data, index);
if (!CreateForLeftEdge) return basicFormat;
if (!CreateForLeftEdge || data.SpartanMode) return basicFormat;
if (lastFormatRequested < index) {
lastFormatRequested = index;
return basicFormat;

View File

@ -122,7 +122,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Sprites {
int lastFormatRequested = int.MaxValue;
public override IDataFormat CreateDataFormat(IDataModel data, int index) {
var basicFormat = base.CreateDataFormat(data, index);
if (!CreateForLeftEdge) return basicFormat;
if (!CreateForLeftEdge || data.SpartanMode) return basicFormat;
if (lastFormatRequested < index) {
lastFormatRequested = index;
return basicFormat;

View File

@ -43,7 +43,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Sprites {
int lastFormatRequested = int.MaxValue;
public override IDataFormat CreateDataFormat(IDataModel data, int index) {
var basicFormat = new LzUncompressed(index);
if (!CreateForLeftEdge) return basicFormat;
if (!CreateForLeftEdge || data.SpartanMode) return basicFormat;
if (lastFormatRequested < index) {
lastFormatRequested = index;
return basicFormat;

View File

@ -80,7 +80,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs.Sprites {
int lastFormatRequested = int.MaxValue;
public override IDataFormat CreateDataFormat(IDataModel data, int index) {
var basicFormat = CreateDataFormatCore(data, index);
if (!CreateForLeftEdge) return basicFormat;
if (!CreateForLeftEdge || data.SpartanMode) return basicFormat;
if (lastFormatRequested < index) {
lastFormatRequested = index;
return basicFormat;

View File

@ -82,6 +82,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public string FullFileName => this[0].FullFileName;
public bool SpartanMode { get; set; }
public int PreferredWidth { get => this[0].PreferredWidth; set => ForEach(child => child.PreferredWidth = value); }
public int Width { get => this[0].Width; set => ForEach(child => child.Width = value); }
public int Height { get => this[0].Height; set => this[0].Height = value; }

View File

@ -24,6 +24,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public string FullFileName { get; }
public bool SpartanMode { get; set; }
private string filter = string.Empty;
public string Filter {
get => filter;

View File

@ -70,6 +70,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public string FullFileName => Name;
public bool SpartanMode { get; set; }
public int Width { get => leftWidth + rightWidth + 1; set { } }
private int height;

View File

@ -360,6 +360,19 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
}
}
private bool spartanMode = false;
public bool SpartanMode {
get => spartanMode;
set {
Set(ref spartanMode, value, arg => {
foreach (var tab in tabs) {
tab.SpartanMode = spartanMode;
tab.Refresh();
}
});
}
}
private bool focusOnGotoShortcuts = true;
public bool FocusOnGotoShortcuts {
get => focusOnGotoShortcuts;
@ -562,6 +575,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
LogAppStartupProgress = metadata.Contains("LogAppStartupProgress = True");
UseTableEntryHeaders = !metadata.Contains("UseTableEntryHeaders = False");
AllowSingleTableMode = !metadata.Contains("AllowSingleTableMode = False");
SpartanMode = metadata.Contains("SpartanMode = True");
InsertAutoActive = !metadata.Contains("InsertAutoActive = False");
ShowMatrix = !metadata.Contains("ShowMatrixGrid = False");
FocusOnGotoShortcuts = !metadata.Contains("FocusOnGotoShortcuts = False");
@ -615,6 +629,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
$"LastUpdateCheck = {LastUpdateCheck}",
$"AcknowledgeTutorials = {TutorialsAcknowledged}",
$"Base10Length = {Base10Length}",
$"SpartanMode = {SpartanMode}",
MapTutorials.Serialize(),
SerializeRecentFiles(),
string.Empty
@ -813,6 +828,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
}
public void Add(ITabContent content) {
content.SpartanMode = spartanMode;
tabs.Add(content);
SelectedIndex = tabs.Count - 1;
AddContentListeners(content);

View File

@ -1,7 +1,6 @@
using HavenSoft.HexManiac.Core.Models;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
namespace HavenSoft.HexManiac.Core.ViewModels {
@ -42,6 +41,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
event EventHandler<CanPatchEventArgs> RequestCreatePatch;
event EventHandler RequestRefreshGotoShortcuts;
bool SpartanMode { get; set; }
bool CanIpsPatchRight { get; }
bool CanUpsPatchRight { get; }
void IpsPatchRight();

View File

@ -39,6 +39,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public string Name => "Image Editor";
public string FullFileName { get; }
public bool SpartanMode { get; set; }
public bool IsMetadataOnlyChange => false;
public ICommand Save { get; }
public ICommand SaveAs => null;
@ -772,6 +773,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
}
private void UpdateSelectionFromPaletteHover(PaletteCollection sender, PropertyChangedEventArgs e) {
if (SpartanMode) return;
int paletteStart = ReadPalette().initialBlankPages * 16;
paletteStart += PalettePage * 16;
var matches = new List<Point>();

View File

@ -198,6 +198,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
public string Name => (primaryMap?.FullName ?? "Map") + (history.HasDataChange ? "*" : string.Empty);
public string FullFileName => viewPort.FullFileName;
public bool SpartanMode { get; set; }
public bool IsMetadataOnlyChange => false;
public ICommand Save => viewPort.Save;
public ICommand SaveAs => viewPort.SaveAs;
@ -555,6 +556,16 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
private IEnumerable<BlockMapViewModel> GetMapNeighbors(BlockMapViewModel map, int recursionLevel) {
if (recursionLevel < 1) return new BlockMapViewModel[0];
if (SpartanMode) {
// return only neighbors based on the current map position
var centerX = (map.LeftEdge + map.RightEdge) / 2;
var centerY = (map.TopEdge + map.BottomEdge) / 2;
if (centerX > 0 && map.LeftEdge > map.TopEdge && map.LeftEdge > -map.BottomEdge) return map.GetNeighbors(MapDirection.Left);
if (centerX < 0 && map.RightEdge < map.BottomEdge && map.RightEdge < -map.TopEdge) return map.GetNeighbors(MapDirection.Right);
if (centerY > 0) return map.GetNeighbors(MapDirection.Up);
if (centerY < 0) return map.GetNeighbors(MapDirection.Down);
return Enumerable.Empty<BlockMapViewModel>();
}
var directions = new List<MapDirection> {
MapDirection.Up, MapDirection.Down, MapDirection.Left, MapDirection.Right, MapDirection.Dive, MapDirection.Emerge,
};
@ -574,14 +585,6 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
}
}
return newMaps.Values.ToList();
//var newMaps = new List<BlockMapViewModel>(directions.SelectMany(map.GetNeighbors));
//foreach (var m in newMaps) {
// yield return m;
// if (recursionLevel > 1 && m.ZIndex >= 0) {
// foreach (var mm in GetMapNeighbors(m, recursionLevel - 1)) yield return mm;
// }
//}
}
#region Map Interaction
@ -625,7 +628,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
var p = ToBoundedMapTilePosition(map, x, y, 1, 1);
map.HoverPoint = ToPixelPosition(map, x, y);
if (UpdateHover(map, p.X, p.Y, 1, 1)) {
if (interactionType == PrimaryInteractionType.None && map.EventUnderCursor(x, y, false) is BaseEventViewModel ev) {
if (!SpartanMode && interactionType == PrimaryInteractionType.None && map.EventUnderCursor(x, y, false) is BaseEventViewModel ev) {
return ShowEventHover(map, ev);
} else {
return EmptyTooltip;
@ -672,9 +675,6 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
PrimaryMap.BorderEditor.ShowBorderPanel = false;
(cursorX, cursorY) = (x, y);
(deltaX, deltaY) = (0, 0);
var map = MapUnderCursor(x, y);
if (map != null) UpdatePrimaryMap(map);
}
public void DragMove(double x, double y, bool isMiddleClickMap) {
@ -689,7 +689,10 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
if (isMiddleClickMap) Hover(x, y);
}
public void DragUp(double x, double y) { }
public void DragUp(double x, double y) {
var map = MapUnderCursor(x, y);
if (map != null) UpdatePrimaryMap(map);
}
#region Primary Interaction (left-click)

View File

@ -222,13 +222,13 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
private readonly Lazy<IPixelViewModel> render;
public IDataModel Model { get; }
public int Address { get; }
public IPixelViewModel Render => render.Value;
public IPixelViewModel Render => render?.Value;
public string AddressText => Address.ToAddress();
public BlocksetOption(IDataModel model, int address) {
Model = model;
Address = address;
render = new Lazy<IPixelViewModel>(() => new BlocksetModel(Model, Address).RenderBlockset(.5));
if (!model.SpartanMode) render = new Lazy<IPixelViewModel>(() => new BlocksetModel(Model, Address).RenderBlockset(.5));
}
}
}

View File

@ -85,6 +85,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public string Name { get; }
public string FullFileName { get; }
public string FileName => string.Empty;
public bool SpartanMode { get; set; }
public bool IsMetadataOnlyChange => false;
public byte[] FindBytes { get; set; }
public ICommand Save { get; } = new StubCommand();

View File

@ -51,7 +51,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
public bool CanInsertFlag {
get {
if (investigator == null) return false;
if (investigator == null || model.SpartanMode) return false;
var context = SplitCurrentLine();
if (context.ContentBoundaryCount != 0) return false;
@ -72,7 +72,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
public bool CanInsertVar {
get {
if (investigator == null) return false;
if (investigator == null || model.SpartanMode) return false;
var context = SplitCurrentLine();
if (context.ContentBoundaryCount != 0) return false;
@ -140,7 +140,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
/// </summary>
public bool CanFindUses {
get {
if (CaretPosition < 0) return false;
if (CaretPosition < 0 || model.SpartanMode) return false;
var context = SplitCurrentLine();
if (context.ContentBoundaryCount != 0) return false;
int left = context.Index, right = context.Index;
@ -176,7 +176,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
public bool CanGotoAddress {
get {
if (CaretPosition < 0) return false;
if (CaretPosition < 0 || model.SpartanMode) return false;
var context = SplitCurrentLine();
if (context.ContentBoundaryCount != 0) return false;
int left = context.Index, right = context.Index;
@ -211,6 +211,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
private bool TryGetSourceInfo(out string table, out string parsedToken) {
table = null;
parsedToken = null;
if (model.SpartanMode) return false;
var context = SplitCurrentLine();
var tokens = ScriptLine.Tokenize(context.Line);
var token = 0;
@ -264,6 +265,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
#region <auto> complete
public bool TryInsertAuto() {
if (model.SpartanMode) return false;
var context = SplitCurrentLine();
var tokens = ScriptLine.Tokenize(context.Line);
if (context.Line.Length > context.Index + 1) return false;
@ -382,6 +384,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
}
public void EvaluateTextLength() {
if (model.SpartanMode) return;
foreach (var streamLine in LookForStreamLines()) {
if (streamLine.Type != ExpectedPointerType.Text) continue; // 35*6
foreach (var error in model.TextConverter.GetOverflow(streamLine.Text, MaxEventTextWidth)) {

View File

@ -293,10 +293,11 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
//nameof(Theme.Text1),
//nameof(Theme.Text2),
//nameof(Theme.Data1),
nameof(Theme.Data2),
nameof(Theme.Accent),
//nameof(Theme.Data2),
//nameof(Theme.Accent),
//nameof(Theme.Stream1),
//nameof(Theme.Stream2),
nameof(Theme.Background),
};
private int childIndexGroup = 0, themeIndex = 0;
@ -405,7 +406,8 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
var originalTableName = basename;
if (!string.IsNullOrEmpty(arrayRun.LengthFromAnchor) && model.GetMatchedWords(arrayRun.LengthFromAnchor).Count == 0) basename = arrayRun.LengthFromAnchor; // basename is now a 'parent table' name, if there is one
var groups = model.GetTableGroups(basename) ?? new[] { new TableGroup(TableGroupViewModel.DefaultName, new[] { originalTableName }) };
IReadOnlyList<TableGroup> groups = new[] { new TableGroup(TableGroupViewModel.DefaultName, new[] { originalTableName }) };
if (!viewPort.SpartanMode) groups = model.GetTableGroups(basename) ?? groups;
if (groups.Count == 1) {
if (Groups.Count == 2) {
streamGroup = Groups[1];
@ -620,7 +622,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Tools {
}
// maps
if (viewPort.MapEditor != null && viewPort.MapEditor.IsValidState) {
if (viewPort.MapEditor != null && viewPort.MapEditor.IsValidState && !viewPort.SpartanMode) {
var mapOptions = new MapOptionsArrayElementViewModel(dispatcher, viewPort.MapEditor, basename, index);
mapOptions.MapPreviews.CollectionChanged += (sender, e) => NotifyPropertyChanged(nameof(HasUsageOptions));
AddUsageChild(mapOptions); // always add, but invisible when empty

View File

@ -91,6 +91,16 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
private string fullFileName;
public string FullFileName { get => fullFileName; private set => TryUpdate(ref fullFileName, value); }
private bool spartanMode;
public bool SpartanMode {
get => spartanMode;
set {
Set(ref spartanMode, value, arg => {
Model.SpartanMode = spartanMode;
});
}
}
#region Scrolling Properties
private readonly ScrollRegion scroll;

View File

@ -881,6 +881,11 @@
</Setter.Value>
</Setter>
<Setter Property="ToolTipService.InitialShowDelay" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding Render}" Value="{x:Null}">
<Setter Property="ToolTip" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>

View File

@ -333,7 +333,7 @@
</ItemsControl.ItemContainerStyle>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type hsg3hvmtr:SplitterArrayElementViewModel}">
<DockPanel Name="ContainerPanel" Height="20" Margin="0,6,0,0"
<DockPanel Name="ContainerPanel" Height="20" Margin="0,14,0,0"
hsg3hv:ColumnStackPanel.IsHeader="True"
Background="{DynamicResource Backlight}"
Visibility="{Binding ShowSection, Converter={StaticResource BoolToVisibility}}">
@ -352,8 +352,7 @@
<MenuItem Header="Collapse All" Command="{Binding CollapseAll}"/>
</ContextMenu>
</DockPanel.ContextMenu>
<Rectangle SnapsToDevicePixels="True" Height="1" DockPanel.Dock="Top" HorizontalAlignment="Stretch" Fill="{Binding Theme, Converter={StaticResource Theme}}" />
<Rectangle Width="1" DockPanel.Dock="Left" VerticalAlignment="Stretch" Fill="{Binding Theme, Converter={StaticResource Theme}}" />
<Rectangle SnapsToDevicePixels="True" Height="1" DockPanel.Dock="Top" HorizontalAlignment="Stretch" Fill="{DynamicResource Primary}" />
<Grid DockPanel.Dock="Right">
<Rectangle Width="4" HorizontalAlignment="Right" Stretch="Fill" Fill="{DynamicResource Background}" />
<hsg3hv:AngleButton Command="{Binding FollowLink}" Direction="Right"

View File

@ -242,8 +242,8 @@
<MenuItem Header="_Tools">
<MenuItem Header="_Hide All Tools" Command="{Binding Tools.HideCommand}"/>
<Separator/>
<MenuItem Header="Toggle T_able Tool" Command="{Binding Tools.TableToolCommand}"/>
<MenuItem Header="Toggle _Text Tool" Command="{Binding Tools.StringToolCommand}"/>
<MenuItem Header="Toggle _Table Tool" Command="{Binding Tools.TableToolCommand}"/>
<MenuItem Header="Toggle Te_xt Tool" Command="{Binding Tools.StringToolCommand}"/>
<MenuItem Header="Toggle _Image Tool" Command="{Binding Tools.SpriteToolCommand}"/>
<MenuItem Header="Toggle _Code Tool" Command="{Binding Tools.CodeToolCommand}"/>
<MenuItem Header="Show _Hex Converter" Command="{Binding ShowHexConverter}" InputGestureText="Ctrl+H">
@ -251,7 +251,19 @@
<sys:Boolean>true</sys:Boolean>
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem Header="Show Automation Tool" IsCheckable="True" IsChecked="{Binding ShowAutomationPanel}" InputGestureText="Ctrl+R" />
<MenuItem Header="Toggle _Automation Tool" IsCheckable="True" IsChecked="{Binding ShowAutomationPanel}" InputGestureText="Ctrl+R" />
<Separator/>
<MenuItem Header="_Spartan Mode" IsCheckable="True" IsChecked="{Binding SpartanMode}">
<MenuItem.ToolTip>
<ToolTip>
<TextBlock>
Spartan Mode runs faster and uses less memory,
<LineBreak/>
but disables optional ease-of-use features.
</TextBlock>
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_Update" IsEnabled="{Binding IsNewVersionAvailable}" Click="UpdateClick" MouseMove="AcknowledgeAccentItem" Tag="NewVersionAcknowledged">