Skip to content

Commit

Permalink
Improve save editing UI (#339)
Browse files Browse the repository at this point in the history
  • Loading branch information
WiIIiam278 authored Jan 29, 2024
1 parent ccd9ae8 commit f4af006
Show file tree
Hide file tree
Showing 10 changed files with 1,037 additions and 375 deletions.
154 changes: 154 additions & 0 deletions src/SerialLoops.Lib/SaveFile/SaveFilePreview.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using HaruhiChokuretsuLib.Save;
using SerialLoops.Lib.Items;
using SerialLoops.Lib.Script.Parameters;
using SerialLoops.Lib.Util;
using SkiaSharp;

namespace SerialLoops.Lib.SaveFile {
public class SaveFilePreview {

private const int WIDTH = 250;
private const int HEIGHT = 42;
private const float SCALE = 2f;

private SaveSlotData _slotData;
private Project _project;

public SaveFilePreview(SaveSlotData slotData, Project project)
{
_slotData = slotData;
_project = project;
}

public SKBitmap DrawPreview()
{
SKBitmap bitmap = new(WIDTH, HEIGHT);

using SKCanvas canvas = new(bitmap);
DrawBox(canvas);
if (_slotData.EpisodeNumber == 0)
{
DrawText(canvas, _project.UiText.Messages[27]);
}
else
{
DrawEpisodeNumber(canvas, _slotData.EpisodeNumber);
DrawText(canvas, GetEpisodeTitle(_slotData.EpisodeNumber), 90);
DrawSaveTime(canvas, _slotData.SaveTime);
}

canvas.Flush();
return bitmap.Resize(
new SKImageInfo(
(int) (WIDTH * SCALE),
(int) (HEIGHT * SCALE)
),
SKFilterQuality.None
);
}

private void DrawText(SKCanvas canvas, string text, int x = 10, int y = 5, SKPaint paint = null)
{
canvas.DrawHaroohieText(
_project.LangCode != "ja" ? text.GetOriginalString(_project) : text,
paint ?? DialogueScriptParameter.Paint00,
_project,
x,
y
);
}

private void DrawBox(SKCanvas canvas)
{
// Draw outer dark gray outline
canvas.Clear(new(93, 93, 93));
SKRect textArea = new(3, 2, WIDTH - 3, HEIGHT - 2);

// Draw inner green fill
using SKPaint paint = new();
paint.Color = new(12, 36, 20);
paint.Style = SKPaintStyle.Fill;
canvas.DrawRect(textArea, paint);

// Draw inner light grey outline
paint.Color = new(150, 150, 150);
paint.Style = SKPaintStyle.Stroke;
paint.StrokeWidth = 1;
canvas.DrawRect(textArea, paint);
}

private void DrawEpisodeNumber(SKCanvas canvas, int number)
{
if (_project.Items.Find(item => item.Type == ItemDescription.ItemType.System_Texture
&& item.Name == "SYSTEX_SYS_CMN_B38") is not SystemTextureItem graphic)
{
DrawText(canvas, $"EPISODE: {number}");
return;
}

// Draw the top half of the image onto the canvas, treating (0, 255, 0) as transparent
var bitmap = graphic.Grp.GetImage(transparentIndex: 0);
SKBitmap episodeNumber = new(bitmap.Width + 8, bitmap.Height / 2);
SKCanvas episodeCanvas = new(episodeNumber);

// Draw "EPISODE: (number)"
var numberXOffSet = 8 * (number - 1);
episodeCanvas.DrawBitmap(bitmap, 0, 0);
episodeCanvas.DrawBitmap(
bitmap,
new SKRectI(numberXOffSet, bitmap.Height / 2, numberXOffSet + 8, bitmap.Height),
new SKRectI(bitmap.Width - 8, 0, bitmap.Width, bitmap.Height / 2)
);
episodeCanvas.Flush();

canvas.DrawBitmap(episodeNumber, 10, 5);
}

private void DrawSaveTime(SKCanvas canvas, DateTimeOffset saveTime)
{
string date = saveTime.ToString("yyyy/MM/dd");
string time = saveTime.ToString("HH:mm:ss");
if (_project.Items.Find(item => item.Type == ItemDescription.ItemType.System_Texture
&& item.Name == "SYSTEX_SYS_MNU_B00") is not SystemTextureItem graphic)
{
DrawText(canvas, date, 60, 25, DialogueScriptParameter.Paint01);
DrawText(canvas, time, 180, 25, DialogueScriptParameter.Paint01);
return;
}
SKBitmap bitmap = graphic.Grp.GetImage(transparentIndex: 0);
SKBitmap timeBitmap = new(WIDTH, 16);
SKCanvas timeCanvas = new(timeBitmap);
// Draw date, for each char
for (int i = 0; i < date.Length; i++)
{
DrawLargeGlyph(date[i], timeCanvas, bitmap, 30 + i * 8);
}
for (int i = 0; i < time.Length; i++)
{
DrawLargeGlyph(time[i], timeCanvas, bitmap, 160 + i * 8);
}
timeCanvas.Flush();
canvas.DrawBitmap(timeBitmap, 0, 23);
}

private void DrawLargeGlyph(char glyph, SKCanvas canvas, SKBitmap bitmap, int x, int y = 0)
{
int offset = glyph switch
{
'0' => 0, '1' => 8, '2' => 16, '3' => 24, '4' => 32, '5' => 40, '6' => 48,
'7' => 56, '8' => 64, '9' => 72, ':' => 80, '/' => 88, '%' => 96, _ => 104
};
canvas.DrawBitmap(
bitmap,
new SKRectI(offset, 0, offset + 8, bitmap.Height),
new SKRectI(x, y, x + 8, y + bitmap.Height)
);
}

private string GetEpisodeTitle(int number)
{
return _project.UiText.Messages[16 + number];
}
}
}
10 changes: 9 additions & 1 deletion src/SerialLoops/Controls/HomePanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ private void InitializeComponents()

LinkButton openProjectLink = new() { Text = "Open Project" };
openProjectLink.Click += _mainForm.OpenProject_Executed;

LinkButton editSaveLink = new() { Text = "Edit Save File" };
editSaveLink.Click += _mainForm.EditSaveFileCommand_Executed;

LinkButton aboutLink = new() { Text = "About" };
aboutLink.Click += _mainForm.AboutCommand_Executed;

LinkButton preferencesLink = new() { Text = "Preferences" };
preferencesLink.Click += _mainForm.PreferencesCommand_Executed;
Expand All @@ -55,7 +61,9 @@ private void InitializeComponents()
ControlGenerator.GetTextHeader("Start"),
ControlGenerator.GetControlWithIcon(newProjectLink, "New", _log),
ControlGenerator.GetControlWithIcon(openProjectLink, "Open", _log),
ControlGenerator.GetControlWithIcon(preferencesLink, "Options", _log)
ControlGenerator.GetControlWithIcon(editSaveLink, "Edit_Save", _log),
ControlGenerator.GetControlWithIcon(preferencesLink, "Options", _log),
ControlGenerator.GetControlWithIcon(aboutLink, "Help", _log),
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/SerialLoops/Dialogs/ProjectSettingsDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private void InitializeComponent()
applyButton.Click += ApplyButton_OnClick;

Button cancelButton = new() { Text = "Cancel" };
cancelButton.Click += (sender, e) => { Close(); };
cancelButton.Click += (sender, e) => Close();

Content = new TableLayout(
new TableRow(
Expand Down
147 changes: 121 additions & 26 deletions src/SerialLoops/Dialogs/SaveEditorDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using SerialLoops.Lib;
using System;
using System.IO;
using SerialLoops.Lib.SaveFile;
using SerialLoops.Utility;

namespace SerialLoops.Dialogs
{
Expand Down Expand Up @@ -41,16 +43,17 @@ public SaveEditorDialog(ILogger log, Project project, EditorTabsPanel tabs, stri

void InitializeComponent()
{
Title = $"Save Editor - {Path.GetFileName(_saveLoc)}";
Width = 400;
Height = 400;
Button saveCommonButton = new() { Text = "Common Save Data", Height = 64 };
saveCommonButton.Click += (sender, args) =>
{
SaveSlotEditorDialog saveSlotEditorDialog = new(_log, _save.CommonData, _project, _tabs);
saveSlotEditorDialog.Show();
};
Title = $"Edit Save File - {Path.GetFileName(_saveLoc)}";
Width = 600;
Height = 390;
Resizable = false;
Padding = 10;

UpdateContent();
}

private void UpdateContent()
{
Button saveButton = new() { Text = "Save" };
saveButton.Click += (sender, args) =>
{
Expand All @@ -67,15 +70,12 @@ void InitializeComponent()
};

Button cancelButton = new() { Text = "Cancel" };
cancelButton.Click += (sender, args) =>
{
Close();
};

cancelButton.Click += (sender, args) => Close();

StackLayout buttonsLayout = new()
{
Orientation = Orientation.Horizontal,
Spacing = 3,
Spacing = 5,
HorizontalContentAlignment = HorizontalAlignment.Right,
Items =
{
Expand All @@ -86,36 +86,131 @@ void InitializeComponent()

Content = new TableLayout
{
Spacing = new(5, 5),
Rows =
{
new(saveCommonButton),
new(GetSaveSlotPreviewButton(_save.CheckpointSaveSlots[0])),
new(GetSaveSlotPreviewButton(_save.CheckpointSaveSlots[1])),
new(GetSaveSlotPreviewButton(_save.QuickSaveSlot)),
new(),
new(buttonsLayout),
GetSaveFiles(),
buttonsLayout
},
Spacing = new(0, 20)
};
}

private Button GetSaveSlotPreviewButton(SaveSlotData slot)
private Control GetSaveFiles()
{
Button slotButton = new() { Text = slot.EpisodeNumber == 0 ? "New Save" : $"EPISODE: {slot.EpisodeNumber}\n\n{slot.SaveTime:yyyy/MM/dd H:mm:ss}", Height = 64 };
Button saveCommonButton = new()
{
Text = "Common Save Data...",
Image = ControlGenerator.GetIcon("Edit_Save", _log)
};
saveCommonButton.Click += (sender, args) =>
{
SaveSlotEditorDialog saveSlotEditorDialog = new(
_log,
_save.CommonData,
Path.GetFileName(_saveLoc),
"Common Save Data",
_project,
_tabs,
UpdateContent
);
saveSlotEditorDialog.Show();
};
StackLayout commonDataRow = new(saveCommonButton) { HorizontalContentAlignment = HorizontalAlignment.Center };

return new TableLayout
{
Rows =
{
new GroupBox
{
Text = "Save Files",
Padding = 5,
Content = new TableLayout
{
Spacing = new(0, 10),
Rows =
{
GetSaveSlotPreview(_save.CheckpointSaveSlots[0], 1),
GetSaveSlotPreview(_save.CheckpointSaveSlots[1], 2),
GetSaveSlotPreview(_save.QuickSaveSlot, 3),
},
}
},
commonDataRow,
},
Spacing = new(0, 15)
};
}

private TableRow GetSaveSlotPreview(SaveSlotData data, int slotNum)
{
return new TableLayout
{
Size = new(430, 64),
Spacing = new(6, 6),
Rows =
{
new TableRow(
new SKGuiImage(
new SaveFilePreview(data, _project).DrawPreview()
),
new StackLayout(
slotNum == 3 ? "Quick Save" : $"File {slotNum}",
new StackLayout
{
Orientation = Orientation.Horizontal,
Spacing = 5,
Items =
{
GetSlotEditButton(data, Path.GetFileName(_saveLoc), slotNum),
// GetSlotClearButton(data, Path.GetFileName(_saveLoc), slotNum) TODO
},
}
)
{
Orientation = Orientation.Vertical,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
Spacing = 5,
}
)
}
};
}

private Button GetSlotEditButton(SaveSlotData slot, string fileName, int slotNumber)
{
Button slotButton = new() { Width = 22, Image = ControlGenerator.GetIcon("Edit_Save", _log) };
slotButton.Click += (sender, args) =>
{
SaveSlotEditorDialog saveSlotEditorDialog;
if (slot is QuickSaveSlotData quickSave)
{
saveSlotEditorDialog = new(_log, quickSave, _project, _tabs);
saveSlotEditorDialog = new(_log, quickSave, fileName, "Quick Save Data", _project, _tabs, UpdateContent);
}
else
{
saveSlotEditorDialog = new(_log, slot, _project, _tabs);
saveSlotEditorDialog = new(_log, slot, fileName, $"File {slotNumber}", _project, _tabs, UpdateContent);
}
saveSlotEditorDialog.Show();
};
return slotButton;
}

private Button GetSlotClearButton(SaveSlotData slot, string fileName, int slotNumber)
{
Button slotButton = new()
{
Width = 22,
Image = ControlGenerator.GetIcon("Clear", _log),
Enabled = slot.EpisodeNumber > 0
};
slotButton.Click += (sender, args) =>
{
slot.EpisodeNumber = 0;
_log.Log($"Cleared Save File {slotNumber}.");
};
return slotButton;
}
}
}
Loading

0 comments on commit f4af006

Please sign in to comment.