From 679b4fc61dead31c33169749575c214729a2cd94 Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Thu, 29 May 2025 19:44:33 +0300 Subject: [PATCH 1/6] Version changed to 2.4; TODO features: Application: - Copy-Paste now uses System clipboard and it is possible to copy-paste from/to different instances of running program Bugs fixed: - Switching between symbols while select tool is active and small area selected trows an error - Full frame Copy in Clipboard does not respect selection on Paste operation --- McBitFont/Form1.Designer.cs | 39 +++++++++-------- McBitFont/Form1.cs | 83 +++++++++++++++++++------------------ McBitFont/McBitFont.csproj | 6 +-- TODO.txt | 3 ++ 4 files changed, 67 insertions(+), 64 deletions(-) diff --git a/McBitFont/Form1.Designer.cs b/McBitFont/Form1.Designer.cs index cec5515..5609c89 100644 --- a/McBitFont/Form1.Designer.cs +++ b/McBitFont/Form1.Designer.cs @@ -64,10 +64,12 @@ openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); importTextToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); importImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); exportFontLayoutPNGToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); undoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -84,6 +86,7 @@ removeBeforeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); removeAfterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); CodeShiftToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); testFontToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); canvasToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ClearToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -110,9 +113,6 @@ lblSelection = new System.Windows.Forms.Label(); lblModified = new System.Windows.Forms.Label(); dlgSavePNG = new System.Windows.Forms.SaveFileDialog(); - toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); ((System.ComponentModel.ISupportInitialize)nudX).BeginInit(); ((System.ComponentModel.ISupportInitialize)nudY).BeginInit(); panel1.SuspendLayout(); @@ -535,7 +535,7 @@ // fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { newToolStripMenuItem, openToolStripMenuItem, saveToolStripMenuItem, saveAsToolStripMenuItem, toolStripSeparator1, importTextToolStripMenuItem1, importImageToolStripMenuItem, exportToolStripMenuItem, exportFontLayoutPNGToolStripMenuItem, toolStripSeparator2, exitToolStripMenuItem }); fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - fileToolStripMenuItem.Size = new System.Drawing.Size(122, 20); + fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); fileToolStripMenuItem.Text = "File"; // // newToolStripMenuItem @@ -582,6 +582,11 @@ saveAsToolStripMenuItem.ToolTipText = "Save changes to another file"; saveAsToolStripMenuItem.Click += SaveToolStripMenuItem_Click; // + // toolStripSeparator1 + // + toolStripSeparator1.Name = "toolStripSeparator1"; + toolStripSeparator1.Size = new System.Drawing.Size(221, 6); + // // importTextToolStripMenuItem1 // importTextToolStripMenuItem1.Image = Properties.Resources.folder_table; @@ -620,6 +625,11 @@ exportFontLayoutPNGToolStripMenuItem.ToolTipText = "Create an image with all a table showing all 256 symbols"; exportFontLayoutPNGToolStripMenuItem.Click += ExportPNG; // + // toolStripSeparator2 + // + toolStripSeparator2.Name = "toolStripSeparator2"; + toolStripSeparator2.Size = new System.Drawing.Size(221, 6); + // // exitToolStripMenuItem // exitToolStripMenuItem.Image = Properties.Resources.Famfamfam_Silk_Door_out_16; @@ -672,7 +682,6 @@ // // pasteToolStripMenuItem // - pasteToolStripMenuItem.Enabled = false; pasteToolStripMenuItem.Image = Properties.Resources.Famfamfam_Silk_Page_paste_16; pasteToolStripMenuItem.Name = "pasteToolStripMenuItem"; pasteToolStripMenuItem.ShortcutKeyDisplayString = ""; @@ -785,6 +794,11 @@ CodeShiftToolStripMenuItem.ToolTipText = "Shift the font on the code line"; CodeShiftToolStripMenuItem.Click += CodeShiftToolStripMenuItem_Click; // + // toolStripSeparator3 + // + toolStripSeparator3.Name = "toolStripSeparator3"; + toolStripSeparator3.Size = new System.Drawing.Size(212, 6); + // // testFontToolStripMenuItem // testFontToolStripMenuItem.Image = Properties.Resources.font; @@ -1055,21 +1069,6 @@ dlgSavePNG.DefaultExt = "png"; dlgSavePNG.Filter = "PNG Image|*.png;*.PNG"; // - // toolStripSeparator1 - // - toolStripSeparator1.Name = "toolStripSeparator1"; - toolStripSeparator1.Size = new System.Drawing.Size(221, 6); - // - // toolStripSeparator2 - // - toolStripSeparator2.Name = "toolStripSeparator2"; - toolStripSeparator2.Size = new System.Drawing.Size(221, 6); - // - // toolStripSeparator3 - // - toolStripSeparator3.Name = "toolStripSeparator3"; - toolStripSeparator3.Size = new System.Drawing.Size(212, 6); - // // MainForm // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); diff --git a/McBitFont/Form1.cs b/McBitFont/Form1.cs index 3977053..95bb9e2 100644 --- a/McBitFont/Form1.cs +++ b/McBitFont/Form1.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; +using System.Text.Json; using System.Windows.Forms; @@ -52,18 +53,18 @@ namespace McBitFont { private CanvasHistory history = new(); private int cellSize = 10; public int dotWidth, dotHeight; - private int pixelOffset = 5; + private readonly int pixelOffset = 5; private int gap; private int w, h; public bool monospaced = false; private bool modified = false; private bool prjModified = false; - public const string version = "2.3"; + public const string version = "2.4"; public string prjName = "Untitled"; public string prjFileName = ""; public int codepage = 1251; private FrameMiniature fbuf; - private bool fbuffer = false; + private readonly DataFormats.Format clpbFormat = DataFormats.GetFormat("McBitFontFrame"); private int baseline = 0; private bool set_base = false; private Point selection1, selection2; @@ -148,8 +149,8 @@ namespace McBitFont { } private FrameMiniature CopyFrame(FrameMiniature frame, bool clipboard = false) { - int width = chkRectSelect.Checked ? selection2.X - selection1.X + 1 : frame.width; - int height = chkRectSelect.Checked ? selection2.Y - selection1.Y + 1 : frame.height; + int width = chkRectSelect.Checked && clipboard ? selection2.X - selection1.X + 1 : frame.width; + int height = chkRectSelect.Checked && clipboard ? selection2.Y - selection1.Y + 1 : frame.height; var ff = new FrameMiniature(frame.code, width, height); if (chkRectSelect.Checked && clipboard) { @@ -817,7 +818,6 @@ namespace McBitFont { SetWindowCap(); SetModified(false); ; CheckForAdd(); - fbuffer = false; miniList.Items[0].Selected = true; miniList.Refresh(); dotPanel.Refresh(); @@ -839,10 +839,8 @@ namespace McBitFont { tsmiRemoveSymbol.Enabled = false; tsmiRemoveBefore.Enabled = false; tsmiRemoveAfter.Enabled = false; - //copyToolStripMenuItem.Enabled = false; - pasteToolStripMenuItem.Enabled = false; + return; - //miniList.Items[0].Selected = true; } // Clear history @@ -863,7 +861,7 @@ namespace McBitFont { removeSymbolToolStripMenuItem.Enabled = false; tsmiRemoveSymbol.Enabled = false; } - //copyToolStripMenuItem.Enabled = true; + if (frames.Count > 1 && ff.Equals(frames.First())) { removeBeforeToolStripMenuItem.Enabled = false; removeAfterToolStripMenuItem.Enabled = true; @@ -881,8 +879,6 @@ namespace McBitFont { tsmiRemoveAfter.Enabled = true; } - if (fbuffer) pasteToolStripMenuItem.Enabled = true; - else pasteToolStripMenuItem.Enabled = false; } private void SaveToolStripMenuItem_Click(object sender, EventArgs e) { @@ -940,8 +936,6 @@ namespace McBitFont { miniList.Items[0].Selected = true; CheckForAdd(); - fbuffer = false; - //copyToolStripMenuItem.Enabled = true; // Re-create history object history = new CanvasHistory(); @@ -1041,37 +1035,44 @@ namespace McBitFont { } private void copyToolStripMenuItem_Click(object sender, EventArgs e) { - fbuffer = true; - fbuf = CopyFrame(f, true); - pasteToolStripMenuItem.Enabled = true; + var bb = MessagePackSerializer.Serialize(CopyFrame(f, true)); + DataObject clpbObj = new DataObject(clpbFormat.Name, bb); + Clipboard.SetDataObject(clpbObj, true); } private void pasteToolStripMenuItem_Click(object sender, EventArgs e) { - history.AddPre(f); - if (fbuf.width == f.width && fbuf.height == f.height) { - Array.Copy(fbuf.data, f.data, fbuf.data.Length); - } else { - int di, dj, wmax, hmax, selw, selh; - if (chkRectSelect.Checked) { - di = selection1.X; - dj = selection1.Y; - selw = selection2.X - selection1.X + 1; - selh = selection2.Y - selection1.Y + 1; - wmax = fbuf.width > selw ? selw : fbuf.width; - hmax = fbuf.height > selh ? selh : fbuf.height; - } else { - di = 0; - dj = 0; - wmax = (fbuf.width > f.width) ? f.width : fbuf.width; - hmax = (fbuf.height > f.height) ? f.height : fbuf.height; - } + // Try to read from clipboard + try { + IDataObject clpbObj = Clipboard.GetDataObject(); + byte[] bb = (byte[])clpbObj.GetData(clpbFormat.Name); + fbuf = MessagePackSerializer.Deserialize(bb); + } + catch { + return; + } - for (int i = 0; i < wmax; i++) { - for (int j = 0; j < hmax; j++) { - f.data[i + di, j + dj] = fbuf.data[i, j]; - } + history.AddPre(f); + int di, dj, wmax, hmax, selw, selh; + if (chkRectSelect.Checked) { + di = selection1.X; + dj = selection1.Y; + selw = selection2.X - selection1.X + 1; + selh = selection2.Y - selection1.Y + 1; + wmax = fbuf.width > selw ? selw : fbuf.width; + hmax = fbuf.height > selh ? selh : fbuf.height; + } else { + di = 0; + dj = 0; + wmax = (fbuf.width > f.width) ? f.width : fbuf.width; + hmax = (fbuf.height > f.height) ? f.height : fbuf.height; + } + + for (int i = 0; i < wmax; i++) { + for (int j = 0; j < hmax; j++) { + f.data[i + di, j + dj] = fbuf.data[i, j]; } } + history.AddPost(f); CheckHistoryButtons(); dotPanel.Refresh(); @@ -1436,7 +1437,7 @@ namespace McBitFont { private void ExportPNG(object sender, EventArgs e) { CheckModifiedFrame(); CheckModifiedProject(); - + if (dlgSavePNG.ShowDialog() == DialogResult.OK) { int pixelSize = 3; int symbolMargin = 2 * pixelSize; @@ -1474,7 +1475,7 @@ namespace McBitFont { g.DrawString("First code: " + frames.First().code.ToString(), font, tb, 250, 38); g.DrawString("Last code: " + frames.Last().code.ToString(), font, tb, 250, 62); g.DrawString("Codepage: " + codepage.ToString(), font, tb, 250, 86); - + // Draw grid Pen p = new(Color.FromArgb(64, 0, 0, 0), 1); diff --git a/McBitFont/McBitFont.csproj b/McBitFont/McBitFont.csproj index 5f7f705..126e4a8 100644 --- a/McBitFont/McBitFont.csproj +++ b/McBitFont/McBitFont.csproj @@ -20,9 +20,9 @@ true true icon_64.ico - 2.3.0.0 - 2.3.0.0 - $(VersionPrefix)2.3.0 + 2.4.0.0 + 2.4.0.0 + $(VersionPrefix)2.4.0 Anton Mukhin diff --git a/TODO.txt b/TODO.txt index 4e808ca..88eaba7 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,6 @@ Application: - Consider migrating to WPF in order to make DPI aware UI +V Copy-Paste now uses System clipboard and it is possible to copy-paste from/to different instances of running program Functionality: V Allow to add frames to Single-frame "fonts" @@ -8,3 +9,5 @@ V Export image with All characers table Bugs: - In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) +V Switching between symbols while select tool is active and small area selected trows an error +V Full frame Copy in Clipboard does not respect selection on Paste operation \ No newline at end of file From 313f35bb3e92c11668bd452aa5419fe01b10d831 Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Thu, 29 May 2025 19:48:56 +0300 Subject: [PATCH 2/6] Update TODO --- TODO.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO.txt b/TODO.txt index 88eaba7..d0ace15 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,9 +3,6 @@ Application: V Copy-Paste now uses System clipboard and it is possible to copy-paste from/to different instances of running program Functionality: -V Allow to add frames to Single-frame "fonts" -V Type a string to see the result (test the font) -V Export image with All characers table Bugs: - In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) From 2f86598a2a35aed60c21965c160b24bb8c344b62 Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Fri, 30 May 2025 07:15:43 +0300 Subject: [PATCH 3/6] WIP: working on a new history class --- McBitFont/ChangeHistory.cs | 114 +++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 McBitFont/ChangeHistory.cs diff --git a/McBitFont/ChangeHistory.cs b/McBitFont/ChangeHistory.cs new file mode 100644 index 0000000..639b507 --- /dev/null +++ b/McBitFont/ChangeHistory.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static McBitFont.ChangeHistory; +using static McBitFont.MainForm; + +namespace McBitFont { + internal class ChangeHistory(int depth = 50) { + private List timeline = []; + private List canvasChanges = []; + private List> fontChanges = []; + public int Depth { get; set; } = depth; + public int Index { get; set; } = -1; + public int Count { + get { return timeline.Count; } + } + + public enum ChangeType { + None = 0, + Canvas = 1, // Changes made to canvas + Font = 2 // Symbol width has been changed + } + public class ChangeEvent(ChangeType type, int index) { + public ChangeType Type { get; set; } = type; + public int Index { get; set; } = index; + } + + private static FrameMiniature CopyFrameSimple(FrameMiniature f) { + FrameMiniature newf = new(f.code, f.width, f.height); + Array.Copy(f.data, newf.data, f.data.Length); + return newf; + } + + public void Clear() { + timeline.Clear(); + canvasChanges.Clear(); + fontChanges.Clear(); + Index = -1; + } + + // Remove oldest event and recalculate indices + private bool RemoveOldest() { + if (Count == 0) return false; + ChangeType ct = timeline.First().Type; + + switch (ct) { + case ChangeType.Canvas: + if (canvasChanges.Count == 0) return false; + canvasChanges.RemoveAt(0); + break; + case ChangeType.Font: + if (fontChanges.Count == 0) return false; + fontChanges.RemoveAt(0); + break; + default: + return false; + } + timeline.RemoveAt(0); + for (int i = 0; i < Count; i++) { + if (timeline[i].Type == ct) timeline[i].Index--; + } + return true; + } + + public bool Remove(bool useIndex = true) { + if (Index == -1) return false; + var ce = timeline.Last(); + switch (ce.Type) { + case ChangeType.Canvas: + canvasChanges.RemoveAt(ce.Index); + break; + case ChangeType.Font: + fontChanges.RemoveAt(ce.Index); + break; + default: + return false; + } + timeline.Remove(ce); + if (useIndex) Index--; + return true; + } + + // Remove history tail + private void TruncateTail() { + // Check if the Index does not point to the last event + if (Index >= 0 && Index < Count - 1) { + timeline.RemoveRange(Index + 1, Count - Index - 1); + } + } + + // Add canvas change + public void Add(FrameMiniature f) { + TruncateTail(); + + canvasChanges.Add(CopyFrameSimple(f)); + timeline.Add(new ChangeEvent(ChangeType.Canvas, canvasChanges.Count - 1)); + if (Count > Depth) RemoveOldest(); + else Index++; + } + + // Add Font change + public void Add(List ff) { + //TruncateTail(); + + //fontChanges.Add(CopyFrameSimple(f)); + //timeline.Add(new ChangeEvent(ChangeType.Canvas, canvasChanges.Count - 1)); + //if (Count > Depth) RemoveOldest(); + //else Index++; + } + } +} From a05352acf772592aaca8c8776207ba53db0c52e7 Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Fri, 30 May 2025 16:56:38 +0300 Subject: [PATCH 4/6] WIP: working on new history class --- McBitFont/ChangeHistory.cs | 247 +++++++++++++++++++++++++++++------- McBitFont/Form1.Designer.cs | 20 +-- McBitFont/Form1.cs | 124 +++++++++++------- TODO.txt | 1 + 4 files changed, 286 insertions(+), 106 deletions(-) diff --git a/McBitFont/ChangeHistory.cs b/McBitFont/ChangeHistory.cs index 639b507..861d2c8 100644 --- a/McBitFont/ChangeHistory.cs +++ b/McBitFont/ChangeHistory.cs @@ -2,31 +2,66 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; using static McBitFont.ChangeHistory; using static McBitFont.MainForm; namespace McBitFont { - internal class ChangeHistory(int depth = 50) { - private List timeline = []; + internal class ChangeHistory { + private MainForm mainForm; + private List timeline = []; private List canvasChanges = []; private List> fontChanges = []; - public int Depth { get; set; } = depth; + private List selFrameChanges = []; + private int canvasIndex = 0; + private int fontIndex = 0; + private int selFrameIndex = 0; + public int Depth { get; set; } public int Index { get; set; } = -1; public int Count { get { return timeline.Count; } } + public int Undos { + get { return Index < 0 ? 0 : Index + 1; } + } + public int Redos { + get { return Index < 0 ? Count : Count - Index - 1; } + } + public bool HistoryAction { get; set; } = false; + + // Constructor + public ChangeHistory(MainForm form, int depth = 100) { + timeline = []; + canvasChanges = []; + fontChanges = []; + selFrameChanges = []; + mainForm = form; + Depth = depth; + ResetIndices(); + Add(); + HistoryAction = false; + } + + private void ResetIndices() { + Index = -1; + canvasIndex = 0; + fontIndex = 0; + selFrameIndex = 0; + } public enum ChangeType { None = 0, Canvas = 1, // Changes made to canvas - Font = 2 // Symbol width has been changed - } - public class ChangeEvent(ChangeType type, int index) { - public ChangeType Type { get; set; } = type; - public int Index { get; set; } = index; + Font = 2, // Symbol width has been changed + Frame = 3 // Selected another frame } + //public class ChangeEvent(ChangeType type, int index) { + // public ChangeType Type { get; set; } = type; + // public int Index { get; set; } = index; + //} private static FrameMiniature CopyFrameSimple(FrameMiniature f) { FrameMiniature newf = new(f.code, f.width, f.height); @@ -38,77 +73,191 @@ namespace McBitFont { timeline.Clear(); canvasChanges.Clear(); fontChanges.Clear(); - Index = -1; + selFrameChanges.Clear(); + ResetIndices(); + Add(); } - // Remove oldest event and recalculate indices - private bool RemoveOldest() { - if (Count == 0) return false; - ChangeType ct = timeline.First().Type; - + // Remove from a proper list by change type + private bool RemoveByType(ChangeType ct, bool first = true) { switch (ct) { case ChangeType.Canvas: - if (canvasChanges.Count == 0) return false; - canvasChanges.RemoveAt(0); + if (canvasChanges.Count <= 1) return false; + if ((first && canvasIndex > 0) || (!first && canvasIndex == canvasChanges.Count - 1)) canvasIndex--; + canvasChanges.RemoveAt(first ? 0 : canvasChanges.Count - 1); break; case ChangeType.Font: - if (fontChanges.Count == 0) return false; - fontChanges.RemoveAt(0); + if (fontChanges.Count <= 1) return false; + if ((first && fontIndex > 0) || (!first && fontIndex == fontChanges.Count - 1)) fontIndex--; + fontChanges.RemoveAt(first ? 0 : fontChanges.Count - 1); + break; + case ChangeType.Frame: + if (selFrameChanges.Count <= 1) return false; + if ((first && selFrameIndex > 0) || (!first && selFrameIndex == selFrameChanges.Count - 1)) selFrameIndex--; + selFrameChanges.RemoveAt(first ? 0 : selFrameChanges.Count - 1); break; default: return false; } - timeline.RemoveAt(0); - for (int i = 0; i < Count; i++) { - if (timeline[i].Type == ct) timeline[i].Index--; - } + if ((first && Index > 0) || (!first && Index == Count - 1) || Count == 1) Index--; + timeline.RemoveAt(first ? 0 : Count - 1); + + return true; } - public bool Remove(bool useIndex = true) { - if (Index == -1) return false; - var ce = timeline.Last(); - switch (ce.Type) { - case ChangeType.Canvas: - canvasChanges.RemoveAt(ce.Index); - break; - case ChangeType.Font: - fontChanges.RemoveAt(ce.Index); - break; - default: - return false; - } - timeline.Remove(ce); - if (useIndex) Index--; + // Remove oldest event + private bool RemoveOldest() { + if (Count == 0) return false; + ChangeType ct = timeline.First(); + RemoveByType(ct); + + return true; + } + + // Remove last event + public bool RemoveLast() { + if (Count == 0) return false; + var ct = timeline.Last(); + RemoveByType(ct, false); + return true; } // Remove history tail private void TruncateTail() { // Check if the Index does not point to the last event - if (Index >= 0 && Index < Count - 1) { - timeline.RemoveRange(Index + 1, Count - Index - 1); + //while (Index < Count - 1) Remove + if (Index >= -1 && Index < Count - 1) { + timeline.RemoveRange( Index + 1, Count - Index - 1); + canvasChanges.RemoveRange( canvasIndex + 1, canvasChanges.Count - canvasIndex - 1); + fontChanges.RemoveRange( fontIndex + 1, fontChanges.Count - fontIndex - 1); + selFrameChanges.RemoveRange(selFrameIndex + 1, selFrameChanges.Count - selFrameIndex - 1); } } + // Checks and resets HistoryAction property to abort Add action + private bool CheckHistoryAction() { + if (HistoryAction) { + HistoryAction = false; + return true; + } else { + return false; + } + } + + // Add first states to all lists + private void Add() { + Add(mainForm.f, false); + Add(mainForm.frames, false); + var fff = mainForm.f; // Marshal-by-reference warning workaround + int ccс = fff.code; // + Add(ccс, false); + } + // Add canvas change - public void Add(FrameMiniature f) { + public void Add(FrameMiniature f, bool useIndex = true) { + if (useIndex && CheckHistoryAction()) return; TruncateTail(); - canvasChanges.Add(CopyFrameSimple(f)); - timeline.Add(new ChangeEvent(ChangeType.Canvas, canvasChanges.Count - 1)); if (Count > Depth) RemoveOldest(); - else Index++; + canvasChanges.Add(CopyFrameSimple(f)); + if (useIndex) { + timeline.Add(ChangeType.Canvas); + Index++; + canvasIndex++; + } } // Add Font change - public void Add(List ff) { - //TruncateTail(); + public void Add(List ff, bool useIndex = true) { + if (useIndex && CheckHistoryAction()) return; + TruncateTail(); - //fontChanges.Add(CopyFrameSimple(f)); - //timeline.Add(new ChangeEvent(ChangeType.Canvas, canvasChanges.Count - 1)); - //if (Count > Depth) RemoveOldest(); - //else Index++; + var l = new List(); + foreach (var f in ff) { + l.Add(CopyFrameSimple(f)); + } + + if (Count > Depth) RemoveOldest(); + fontChanges.Add(l); + if (useIndex) { + timeline.Add(ChangeType.Font); + Index++; + fontIndex++; + } } + + // Add Frame selection change + public void Add(int code, bool useIndex = true) { + if (useIndex && CheckHistoryAction()) return; + if (useIndex) { + Add(mainForm.frames.Find(x => x.code == code)); + //Add(mainForm.f); + } + TruncateTail(); + + if (Count > Depth) RemoveOldest(); + selFrameChanges.Add(code); + if (useIndex) { + timeline.Add(ChangeType.Frame); + Index++; + selFrameIndex++; + } + + } + + private void Do(bool undo = true) { + ChangeType ct = timeline.ElementAt(Index + (undo ? 0 : 1)); + int dIndex = undo ? -1 : 1; + switch (ct) { + case ChangeType.Canvas: + canvasIndex += dIndex; + mainForm.f = CopyFrameSimple(canvasChanges[canvasIndex]); + break; + case ChangeType.Font: + Cursor.Current = Cursors.WaitCursor; + fontIndex += dIndex; + mainForm.frames.Clear(); + mainForm.miniList.Clear(); + mainForm.ilMiniatures.Images.Clear(); + foreach (var f in fontChanges[fontIndex]) { + mainForm.frames.Add(CopyFrameSimple(f)); + } + mainForm.FillFrameLists(); + Cursor.Current = Cursors.Default; + break; + case ChangeType.Frame: + HistoryAction = true; + selFrameIndex += dIndex; + var s = selFrameChanges[selFrameIndex].ToString().PadLeft(3, '0'); + var sel = mainForm.miniList.Items.Find(s, false); + if (sel.Length > 0) sel[0].Selected = true; + //if (undo) Undo(); else Redo(); + break; + default: + break; + } + Index += dIndex; + if (ct == ChangeType.Frame) + if (undo) Undo(); else Redo(); + } + + // Undo last change + public bool Undo() { + if (Undos < 1) return false; + Do(); + + return true; + } + + // Redo last ondone change + public bool Redo() { + if (Redos < 1) return false; + Do(false); + + return true; + } + } } diff --git a/McBitFont/Form1.Designer.cs b/McBitFont/Form1.Designer.cs index 5609c89..58b8f32 100644 --- a/McBitFont/Form1.Designer.cs +++ b/McBitFont/Form1.Designer.cs @@ -370,7 +370,7 @@ btnExport.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; toolTip1.SetToolTip(btnExport, "Configure and export data"); btnExport.UseVisualStyleBackColor = true; - btnExport.Click += button1_Click; + btnExport.Click += Export_Click; // // miniList // @@ -614,7 +614,7 @@ exportToolStripMenuItem.Size = new System.Drawing.Size(224, 22); exportToolStripMenuItem.Text = "Export"; exportToolStripMenuItem.ToolTipText = "Configure and export data"; - exportToolStripMenuItem.Click += button1_Click; + exportToolStripMenuItem.Click += Export_Click; // // exportFontLayoutPNGToolStripMenuItem // @@ -654,7 +654,7 @@ undoToolStripMenuItem.Image = Properties.Resources.arrow_undo; undoToolStripMenuItem.Name = "undoToolStripMenuItem"; undoToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z; - undoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + undoToolStripMenuItem.Size = new System.Drawing.Size(164, 22); undoToolStripMenuItem.Text = "Undo"; undoToolStripMenuItem.ToolTipText = "Undo last canvas change"; undoToolStripMenuItem.Click += undoToolStripMenuItem_Click; @@ -664,7 +664,7 @@ redoToolStripMenuItem.Image = Properties.Resources.arrow_redo; redoToolStripMenuItem.Name = "redoToolStripMenuItem"; redoToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y; - redoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + redoToolStripMenuItem.Size = new System.Drawing.Size(164, 22); redoToolStripMenuItem.Text = "Redo"; redoToolStripMenuItem.ToolTipText = "Redo canvas change"; redoToolStripMenuItem.Click += redoToolStripMenuItem_Click; @@ -675,7 +675,7 @@ copyToolStripMenuItem.Name = "copyToolStripMenuItem"; copyToolStripMenuItem.ShortcutKeyDisplayString = ""; copyToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C; - copyToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + copyToolStripMenuItem.Size = new System.Drawing.Size(164, 22); copyToolStripMenuItem.Text = "Copy"; copyToolStripMenuItem.ToolTipText = "Copy current symbol to clipboard"; copyToolStripMenuItem.Click += copyToolStripMenuItem_Click; @@ -686,7 +686,7 @@ pasteToolStripMenuItem.Name = "pasteToolStripMenuItem"; pasteToolStripMenuItem.ShortcutKeyDisplayString = ""; pasteToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V; - pasteToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + pasteToolStripMenuItem.Size = new System.Drawing.Size(164, 22); pasteToolStripMenuItem.Text = "Paste"; pasteToolStripMenuItem.ToolTipText = "Paste from clipboard to current symbol"; pasteToolStripMenuItem.Click += pasteToolStripMenuItem_Click; @@ -696,7 +696,7 @@ selectToolStripMenuItem.Image = Properties.Resources.fam_rectt; selectToolStripMenuItem.Name = "selectToolStripMenuItem"; selectToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.R; - selectToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + selectToolStripMenuItem.Size = new System.Drawing.Size(164, 22); selectToolStripMenuItem.Text = "Select"; selectToolStripMenuItem.ToolTipText = "Toggle Rectangle selection tool"; selectToolStripMenuItem.Click += selectToolStripMenuItem_Click; @@ -707,7 +707,7 @@ selectAllToolStripMenuItem.Image = Properties.Resources.arrow_out; selectAllToolStripMenuItem.Name = "selectAllToolStripMenuItem"; selectAllToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.A; - selectAllToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + selectAllToolStripMenuItem.Size = new System.Drawing.Size(164, 22); selectAllToolStripMenuItem.Text = "Select All"; selectAllToolStripMenuItem.ToolTipText = "Select entire canvas"; selectAllToolStripMenuItem.Click += selectAllToolStripMenuItem_Click; @@ -1138,8 +1138,6 @@ private System.Windows.Forms.Button btnMirrorX; private System.Windows.Forms.Button btnMirrorY; private System.Windows.Forms.Button btnExport; - private System.Windows.Forms.ListView miniList; - private System.Windows.Forms.ImageList ilMiniatures; private System.Windows.Forms.Button btnApply; private System.Windows.Forms.HScrollBar hScroll; private System.Windows.Forms.VScrollBar vScroll; @@ -1209,6 +1207,8 @@ private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + public System.Windows.Forms.ListView miniList; + public System.Windows.Forms.ImageList ilMiniatures; } } diff --git a/McBitFont/Form1.cs b/McBitFont/Form1.cs index 95bb9e2..c3e861b 100644 --- a/McBitFont/Form1.cs +++ b/McBitFont/Form1.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; -using System.Text.Json; using System.Windows.Forms; @@ -48,9 +47,10 @@ namespace McBitFont { public List frames; } - private FrameMiniature f; + public FrameMiniature f; public List frames = new List(); - private CanvasHistory history = new(); + //private CanvasHistory history = new(); + private ChangeHistory history; private int cellSize = 10; public int dotWidth, dotHeight; private readonly int pixelOffset = 5; @@ -139,6 +139,8 @@ namespace McBitFont { CodeShiftToolStripMenuItem.Visible = frames.Count > 1; CheckForAdd(); + + history = new(this); } [DllImport("user32.dll")] @@ -281,7 +283,7 @@ namespace McBitFont { cbZoom_SelectedIndexChanged(cbZoom, null); // Re-create history object - history = new CanvasHistory(); + //history = new CanvasHistory(); } private void cbZoom_SelectedIndexChanged(object sender, EventArgs e) { @@ -329,7 +331,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (int i = x; i <= x2; i++) { c = f.data[i, y]; for (int j = y; j <= y2; j++) { @@ -340,7 +342,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -352,7 +355,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (int i = x; i <= x2; i++) { c = f.data[i, y2]; for (int j = y2; j >= y; j--) { @@ -363,7 +366,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -375,7 +379,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (int j = y; j <= y2; j++) { c = f.data[x, j]; for (int i = x; i <= x2; i++) { @@ -386,7 +390,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -397,7 +402,7 @@ namespace McBitFont { bool c; (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (int j = y; j <= y2; j++) { c = f.data[x2, j]; for (int i = x2; i >= x; i--) { @@ -408,7 +413,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -458,6 +464,7 @@ namespace McBitFont { } } if (e.Button != MouseButtons.None && !mouseDown) { + // Started to move a mouse with button held mouseDown = true; if (rectSel) { selection1.X = i; @@ -465,20 +472,23 @@ namespace McBitFont { selection2.X = i; selection2.Y = j; dotPanel.Invalidate(); - } else history.AddPre(f, false); + } //else history.AddPre(f, false); } if (e.Button == MouseButtons.None && mouseDown) { + // Released a mouse button mouseDown = false; if (rectSel) { NormPoints(ref selection1, ref selection2); dotPanel.Invalidate(); } else { - if (!fChanged) { - history.Remove(false); - } else { + //if (!fChanged) { + // history.Remove(false); + //} else { + if (fChanged) { fChanged = false; - history.ApplyAdded(); - history.AddPost(f); + //history.ApplyAdded(); + //history.AddPost(f); + history.Add(f); } CheckHistoryButtons(); } @@ -540,7 +550,7 @@ namespace McBitFont { private void btnInvert_Click(object sender, EventArgs e) { int x, y, x2, y2; - history.AddPre(f); + //history.AddPre(f); (x, y, x2, y2) = RectSelCoords(); @@ -550,7 +560,8 @@ namespace McBitFont { } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -562,7 +573,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (j = y; j <= y2; j++) { a = x; b = x2; @@ -574,7 +585,8 @@ namespace McBitFont { b--; } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -586,7 +598,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (i = x; i <= x2; i++) { a = y; b = y2; @@ -598,13 +610,14 @@ namespace McBitFont { b--; } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); } - private void button1_Click(object sender, EventArgs e) { + private void Export_Click(object sender, EventArgs e) { if (modified) { if (MessageBox.Show("Current symbol is modified.\nDo you want to save the changes?", "Symbol was modified!", MessageBoxButtons.YesNo) == DialogResult.Yes) { SaveFrame(); @@ -636,7 +649,7 @@ namespace McBitFont { SetModified(true, true); } - private static Bitmap GetMiniPictue(FrameMiniature m) { + public static Bitmap GetMiniPictue(FrameMiniature m) { int picSize = (m.width > m.height) ? m.width : m.height; var bmp = new Bitmap(picSize, picSize); int imin = m.width < picSize ? (picSize - m.width) / 2 : 0; @@ -648,7 +661,7 @@ namespace McBitFont { bmp.SetPixel(i + imin, j + jmin, c); } } - Bitmap sbmp = new Bitmap(50, 50); + Bitmap sbmp = new(50, 50); using (Graphics g = Graphics.FromImage(sbmp)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.PixelOffsetMode = PixelOffsetMode.Half; @@ -823,7 +836,8 @@ namespace McBitFont { dotPanel.Refresh(); // Re-create history object - history = new CanvasHistory(); + //history = new CanvasHistory(); + history.Clear(); Cursor.Current = Cursors.Default; } @@ -842,9 +856,9 @@ namespace McBitFont { return; } - + dotPanel.SuspendLayout(); // Clear history - history.Clear(); + //history.Clear(); var sel = miniList.SelectedItems[0]; int code = Convert.ToInt32(sel.ImageKey); @@ -852,7 +866,10 @@ namespace McBitFont { nudX.Value = ff.width; nudY.Value = ff.height; f = ff; - dotPanel.Refresh(); + + + history.Add(code); + ff = frames.Find(x => x.code == code); if (frames.Count > 1 && (ff.Equals(frames.First()) || ff.Equals(frames.Last()))) { removeSymbolToolStripMenuItem.Enabled = true; @@ -862,6 +879,9 @@ namespace McBitFont { tsmiRemoveSymbol.Enabled = false; } + dotPanel.ResumeLayout(); + dotPanel.Refresh(); + if (frames.Count > 1 && ff.Equals(frames.First())) { removeBeforeToolStripMenuItem.Enabled = false; removeAfterToolStripMenuItem.Enabled = true; @@ -888,6 +908,16 @@ namespace McBitFont { } } + public void FillFrameLists() { + foreach (FrameMiniature f in frames) { + var s = f.code.ToString().PadLeft(3, '0'); + var sHex = 'x' + Convert.ToString(f.code, 16).PadLeft(2, '0').ToUpper(); + var sss = DecodeSymbol(f.code); + ilMiniatures.Images.Add(s, (Image)GetMiniPictue(f)); + miniList.Items.Add(s, (chkHexCodes.Checked ? sHex : s) + ' ' + sss, s); + } + } + private void LoadProject(string filename) { SaveBlock sav; @@ -905,13 +935,7 @@ namespace McBitFont { tsmiMakeVarWidth.Visible = monospaced; miniList.Items.Clear(); ilMiniatures.Images.Clear(); - foreach (FrameMiniature ff in frames) { - var s = ff.code.ToString().PadLeft(3, '0'); - var sHex = 'x' + Convert.ToString(ff.code, 16).PadLeft(2, '0').ToUpper(); - var sss = DecodeSymbol(ff.code); - ilMiniatures.Images.Add(s, (Image)GetMiniPictue(ff)); - miniList.Items.Add(s, (chkHexCodes.Checked ? sHex : s) + ' ' + sss, s); - } + FillFrameLists(); nudX.ValueChanged -= nudX_ValueChanged; nudY.ValueChanged -= nudY_ValueChanged; nudX.Value = frames.First().width; @@ -938,7 +962,8 @@ namespace McBitFont { CheckForAdd(); // Re-create history object - history = new CanvasHistory(); + //history = new CanvasHistory(); + history.Clear(); tsmiMakeVarWidth.Visible = monospaced; makeVarWidthToolStripMenuItem.Visible = monospaced; @@ -1051,7 +1076,7 @@ namespace McBitFont { return; } - history.AddPre(f); + //history.AddPre(f); int di, dj, wmax, hmax, selw, selh; if (chkRectSelect.Checked) { di = selection1.X; @@ -1073,7 +1098,8 @@ namespace McBitFont { } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); dotPanel.Refresh(); SetModified(); @@ -1122,7 +1148,7 @@ namespace McBitFont { private void FillFrame(bool val) { int x, y, x2, y2; - history.AddPre(f); + //history.AddPre(f); (x, y, x2, y2) = RectSelCoords(); @@ -1132,7 +1158,8 @@ namespace McBitFont { } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -1213,13 +1240,15 @@ namespace McBitFont { } private void undoToolStripMenuItem_Click(object sender, EventArgs e) { - history.Undo(f); + //history.Undo(f); + history.Undo(); dotPanel.Refresh(); CheckHistoryButtons(); } private void redoToolStripMenuItem_Click(object sender, EventArgs e) { - history.Redo(f); + //history.Redo(f); + history.Redo(); dotPanel.Refresh(); CheckHistoryButtons(); } @@ -1270,13 +1299,14 @@ namespace McBitFont { private void importImageToolStripMenuItem_Click(object sender, EventArgs e) { ImageImporter iform = new ImageImporter(f.width, f.height); if (iform.ShowDialog() == DialogResult.OK) { - history.AddPre(f); + //history.AddPre(f); for (int i = 0; i < iform.bmpScaled.Width; i++) { for (int j = 0; j < iform.bmpScaled.Height; j++) { f.data[i, j] = iform.bmpScaled.GetPixel(i, j).ToArgb().Equals(Color.Black.ToArgb()); } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); dotPanel.Refresh(); SetModified(); diff --git a/TODO.txt b/TODO.txt index d0ace15..f1f8932 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,6 +3,7 @@ Application: V Copy-Paste now uses System clipboard and it is possible to copy-paste from/to different instances of running program Functionality: +- Rewrite history class so it tracks all changes, not only a canvas changes Bugs: - In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) From 1c034fded1f45cd0e1ab31feda0d0b5d1e12e82d Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Sun, 1 Jun 2025 21:18:15 +0300 Subject: [PATCH 5/6] ljhgfljiukghlkuyfgiyu --- McBitFont/ChangeHistory.cs | 55 +++++++++++++++++++++++++++++++++---- McBitFont/Form1.Designer.cs | 4 +-- McBitFont/Form1.cs | 3 +- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/McBitFont/ChangeHistory.cs b/McBitFont/ChangeHistory.cs index 861d2c8..23d90a0 100644 --- a/McBitFont/ChangeHistory.cs +++ b/McBitFont/ChangeHistory.cs @@ -31,6 +31,7 @@ namespace McBitFont { get { return Index < 0 ? Count : Count - Index - 1; } } public bool HistoryAction { get; set; } = false; + public bool Doing { get; set; } = false; // Constructor public ChangeHistory(MainForm form, int depth = 100) { @@ -43,6 +44,7 @@ namespace McBitFont { ResetIndices(); Add(); HistoryAction = false; + Doing = false; } private void ResetIndices() { @@ -157,6 +159,7 @@ namespace McBitFont { // Add canvas change public void Add(FrameMiniature f, bool useIndex = true) { + if (Doing) return; if (useIndex && CheckHistoryAction()) return; TruncateTail(); @@ -171,6 +174,7 @@ namespace McBitFont { // Add Font change public void Add(List ff, bool useIndex = true) { + if (Doing) return; if (useIndex && CheckHistoryAction()) return; TruncateTail(); @@ -185,11 +189,13 @@ namespace McBitFont { timeline.Add(ChangeType.Font); Index++; fontIndex++; + Add(mainForm.f); } } // Add Frame selection change public void Add(int code, bool useIndex = true) { + if (Doing) return; if (useIndex && CheckHistoryAction()) return; if (useIndex) { Add(mainForm.frames.Find(x => x.code == code)); @@ -208,7 +214,8 @@ namespace McBitFont { } private void Do(bool undo = true) { - ChangeType ct = timeline.ElementAt(Index + (undo ? 0 : 1)); + Doing = true; + var ct = timeline.ElementAt(Index + (undo ? 0 : 1)); int dIndex = undo ? -1 : 1; switch (ct) { case ChangeType.Canvas: @@ -217,6 +224,12 @@ namespace McBitFont { break; case ChangeType.Font: Cursor.Current = Cursors.WaitCursor; + string selItem = ""; + int selCode = 0; + if (mainForm.miniList.SelectedItems.Count > 0) { + selItem = mainForm.miniList.SelectedItems[0].Name; + selCode = Convert.ToInt32(selItem); + } fontIndex += dIndex; mainForm.frames.Clear(); mainForm.miniList.Clear(); @@ -225,6 +238,18 @@ namespace McBitFont { mainForm.frames.Add(CopyFrameSimple(f)); } mainForm.FillFrameLists(); + FrameMiniature fff; + if (selItem != "") { + var selection = mainForm.miniList.Items.Find(selItem, false); + if (selection.Length > 0) selection[0].Selected = true; + fff = mainForm.frames.Find(x => x.code == selCode); + } else { + mainForm.miniList.Items[0].Selected = true; + fff = mainForm.frames[0]; + } + mainForm.f = mainForm.CopyFrame(fff); + mainForm.nudY.Value = mainForm.dotHeight = fff.height; + mainForm.nudX.Value = mainForm.dotWidth = fff.width; Cursor.Current = Cursors.Default; break; case ChangeType.Frame: @@ -233,14 +258,34 @@ namespace McBitFont { var s = selFrameChanges[selFrameIndex].ToString().PadLeft(3, '0'); var sel = mainForm.miniList.Items.Find(s, false); if (sel.Length > 0) sel[0].Selected = true; - //if (undo) Undo(); else Redo(); - break; + break; default: break; } Index += dIndex; - if (ct == ChangeType.Frame) - if (undo) Undo(); else Redo(); + Doing = false; + // Frame select change + Canvas change workarounds + if (ct == ChangeType.Frame && undo) { + Undo(); + return; + } + if (Index < Count - 1) { + var nextctframe = timeline.ElementAt(Index + 1) == ChangeType.Frame; + if (ct == ChangeType.Canvas && !undo && nextctframe) { + Redo(); + return; + } + } + //Font change + Canvas change workarounds + if (Index >= 0) { + var prevctfont = timeline.ElementAt(Index) == ChangeType.Font; + if (ct == ChangeType.Canvas && undo && prevctfont) { + Undo(); + return; + } + } + if (!undo && ct == ChangeType.Font) + Redo(); } // Undo last change diff --git a/McBitFont/Form1.Designer.cs b/McBitFont/Form1.Designer.cs index 58b8f32..ffd5494 100644 --- a/McBitFont/Form1.Designer.cs +++ b/McBitFont/Form1.Designer.cs @@ -1122,8 +1122,6 @@ #endregion private System.Windows.Forms.Panel dotPanel; - private System.Windows.Forms.NumericUpDown nudX; - private System.Windows.Forms.NumericUpDown nudY; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label lblType; @@ -1209,6 +1207,8 @@ private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; public System.Windows.Forms.ListView miniList; public System.Windows.Forms.ImageList ilMiniatures; + public System.Windows.Forms.NumericUpDown nudX; + public System.Windows.Forms.NumericUpDown nudY; } } diff --git a/McBitFont/Form1.cs b/McBitFont/Form1.cs index c3e861b..2543232 100644 --- a/McBitFont/Form1.cs +++ b/McBitFont/Form1.cs @@ -150,7 +150,7 @@ namespace McBitFont { return (int)(((ushort)lowPart) | (uint)(highPart << 16)); } - private FrameMiniature CopyFrame(FrameMiniature frame, bool clipboard = false) { + public FrameMiniature CopyFrame(FrameMiniature frame, bool clipboard = false) { int width = chkRectSelect.Checked && clipboard ? selection2.X - selection1.X + 1 : frame.width; int height = chkRectSelect.Checked && clipboard ? selection2.Y - selection1.Y + 1 : frame.height; var ff = new FrameMiniature(frame.code, width, height); @@ -236,6 +236,7 @@ namespace McBitFont { } DotResize(dotWidth, (int)nudY.Value); + history.Add(frames); Cursor.Current = Cursors.Default; } From d1d653bc34c29b53ce28c7437d3804371efb7bd5 Mon Sep 17 00:00:00 2001 From: Anton Mukhin Date: Mon, 2 Jun 2025 13:37:35 +0300 Subject: [PATCH 6/6] TODO features: Functionality: - Rewrite history class so it tracks all changes, not only a canvas changes Bugs fixed: - In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) --- McBitFont/ChangeHistory.cs | 168 ++++++++++++++++++------------------- McBitFont/Form1.cs | 11 ++- TODO.txt | 4 +- 3 files changed, 93 insertions(+), 90 deletions(-) diff --git a/McBitFont/ChangeHistory.cs b/McBitFont/ChangeHistory.cs index 23d90a0..d96713c 100644 --- a/McBitFont/ChangeHistory.cs +++ b/McBitFont/ChangeHistory.cs @@ -6,19 +6,18 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using static McBitFont.ChangeHistory; using static McBitFont.MainForm; namespace McBitFont { internal class ChangeHistory { private MainForm mainForm; - private List timeline = []; + private List timeline = []; private List canvasChanges = []; private List> fontChanges = []; - private List selFrameChanges = []; + private List selectionChanges = []; private int canvasIndex = 0; private int fontIndex = 0; - private int selFrameIndex = 0; + private int selectionIndex = 0; public int Depth { get; set; } public int Index { get; set; } = -1; public int Count { @@ -30,7 +29,6 @@ namespace McBitFont { public int Redos { get { return Index < 0 ? Count : Count - Index - 1; } } - public bool HistoryAction { get; set; } = false; public bool Doing { get; set; } = false; // Constructor @@ -38,32 +36,34 @@ namespace McBitFont { timeline = []; canvasChanges = []; fontChanges = []; - selFrameChanges = []; + selectionChanges = []; mainForm = form; Depth = depth; ResetIndices(); Add(); - HistoryAction = false; Doing = false; } + + private void ResetIndices() { Index = -1; canvasIndex = 0; fontIndex = 0; - selFrameIndex = 0; + selectionIndex = 0; } public enum ChangeType { None = 0, - Canvas = 1, // Changes made to canvas - Font = 2, // Symbol width has been changed - Frame = 3 // Selected another frame + Canvas = 1, // Changes made to canvas + Font = 2, // Symbol width has been changed + Selection = 3 // Selected another frame + } + + public class ChangeEvent(ChangeType type, FrameMiniature? canvas = null) { + public ChangeType Type { get; set; } = type; + public FrameMiniature? Canvas { get; set; } = canvas; } - //public class ChangeEvent(ChangeType type, int index) { - // public ChangeType Type { get; set; } = type; - // public int Index { get; set; } = index; - //} private static FrameMiniature CopyFrameSimple(FrameMiniature f) { FrameMiniature newf = new(f.code, f.width, f.height); @@ -75,14 +75,14 @@ namespace McBitFont { timeline.Clear(); canvasChanges.Clear(); fontChanges.Clear(); - selFrameChanges.Clear(); + selectionChanges.Clear(); ResetIndices(); Add(); } // Remove from a proper list by change type - private bool RemoveByType(ChangeType ct, bool first = true) { - switch (ct) { + private bool RemoveByType(ChangeEvent ce, bool first = true) { + switch (ce.Type) { case ChangeType.Canvas: if (canvasChanges.Count <= 1) return false; if ((first && canvasIndex > 0) || (!first && canvasIndex == canvasChanges.Count - 1)) canvasIndex--; @@ -91,12 +91,20 @@ namespace McBitFont { case ChangeType.Font: if (fontChanges.Count <= 1) return false; if ((first && fontIndex > 0) || (!first && fontIndex == fontChanges.Count - 1)) fontIndex--; + if (ce.Canvas != null) { + if ((first && canvasIndex > 0) || (!first && canvasIndex == canvasChanges.Count - 1)) canvasIndex--; + canvasChanges.Remove((FrameMiniature)ce.Canvas); + } fontChanges.RemoveAt(first ? 0 : fontChanges.Count - 1); break; - case ChangeType.Frame: - if (selFrameChanges.Count <= 1) return false; - if ((first && selFrameIndex > 0) || (!first && selFrameIndex == selFrameChanges.Count - 1)) selFrameIndex--; - selFrameChanges.RemoveAt(first ? 0 : selFrameChanges.Count - 1); + case ChangeType.Selection: + if (selectionChanges.Count <= 1) return false; + if ((first && selectionIndex > 0) || (!first && selectionIndex == selectionChanges.Count - 1)) selectionIndex--; + if (ce.Canvas != null) { + if ((first && canvasIndex > 0) || (!first && canvasIndex == canvasChanges.Count - 1)) canvasIndex--; + canvasChanges.Remove((FrameMiniature)ce.Canvas); + } + selectionChanges.RemoveAt(first ? 0 : selectionChanges.Count - 1); break; default: return false; @@ -111,8 +119,8 @@ namespace McBitFont { // Remove oldest event private bool RemoveOldest() { if (Count == 0) return false; - ChangeType ct = timeline.First(); - RemoveByType(ct); + ChangeEvent ce = timeline.First(); + RemoveByType(ce); return true; } @@ -120,8 +128,8 @@ namespace McBitFont { // Remove last event public bool RemoveLast() { if (Count == 0) return false; - var ct = timeline.Last(); - RemoveByType(ct, false); + var ce = timeline.Last(); + RemoveByType(ce, false); return true; } @@ -134,17 +142,7 @@ namespace McBitFont { timeline.RemoveRange( Index + 1, Count - Index - 1); canvasChanges.RemoveRange( canvasIndex + 1, canvasChanges.Count - canvasIndex - 1); fontChanges.RemoveRange( fontIndex + 1, fontChanges.Count - fontIndex - 1); - selFrameChanges.RemoveRange(selFrameIndex + 1, selFrameChanges.Count - selFrameIndex - 1); - } - } - - // Checks and resets HistoryAction property to abort Add action - private bool CheckHistoryAction() { - if (HistoryAction) { - HistoryAction = false; - return true; - } else { - return false; + selectionChanges.RemoveRange(selectionIndex + 1, selectionChanges.Count - selectionIndex - 1); } } @@ -158,24 +156,23 @@ namespace McBitFont { } // Add canvas change - public void Add(FrameMiniature f, bool useIndex = true) { - if (Doing) return; - if (useIndex && CheckHistoryAction()) return; + public FrameMiniature? Add(FrameMiniature f, bool useIndex = true) { + if (Doing) return null ; TruncateTail(); - if (Count > Depth) RemoveOldest(); + if (Count >= Depth) RemoveOldest(); canvasChanges.Add(CopyFrameSimple(f)); if (useIndex) { - timeline.Add(ChangeType.Canvas); + timeline.Add(new ChangeEvent(ChangeType.Canvas)); Index++; canvasIndex++; } + return canvasChanges.Last(); } // Add Font change public void Add(List ff, bool useIndex = true) { if (Doing) return; - if (useIndex && CheckHistoryAction()) return; TruncateTail(); var l = new List(); @@ -183,44 +180,52 @@ namespace McBitFont { l.Add(CopyFrameSimple(f)); } - if (Count > Depth) RemoveOldest(); + if (Count >= Depth) RemoveOldest(); fontChanges.Add(l); if (useIndex) { - timeline.Add(ChangeType.Font); + var canv = Add(mainForm.f, false); + canvasIndex++; + timeline.Add(new ChangeEvent(ChangeType.Font, canv)); Index++; fontIndex++; - Add(mainForm.f); } } // Add Frame selection change public void Add(int code, bool useIndex = true) { if (Doing) return; - if (useIndex && CheckHistoryAction()) return; - if (useIndex) { - Add(mainForm.frames.Find(x => x.code == code)); - //Add(mainForm.f); - } TruncateTail(); - if (Count > Depth) RemoveOldest(); - selFrameChanges.Add(code); + if (Count >= Depth) RemoveOldest(); + selectionChanges.Add(code); if (useIndex) { - timeline.Add(ChangeType.Frame); + var canv = Add(mainForm.f, false); + canvasIndex++; + timeline.Add(new ChangeEvent(ChangeType.Selection, canv)); Index++; - selFrameIndex++; + selectionIndex++; } } private void Do(bool undo = true) { + if (!undo && Index >= Count - 1) return; Doing = true; - var ct = timeline.ElementAt(Index + (undo ? 0 : 1)); + var ce = timeline.ElementAt(Index + (undo ? 0 : 1)); int dIndex = undo ? -1 : 1; - switch (ct) { + FrameMiniature fff; + switch (ce.Type) { case ChangeType.Canvas: canvasIndex += dIndex; mainForm.f = CopyFrameSimple(canvasChanges[canvasIndex]); + mainForm.SetModified(); + mainForm.nudX.ValueChanged -= mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged -= mainForm.nudY_ValueChanged; + mainForm.nudY.Value = mainForm.dotHeight = canvasChanges[canvasIndex].height; + mainForm.nudX.Value = mainForm.dotWidth = canvasChanges[canvasIndex].width; + mainForm.SetNewWH(); + mainForm.nudX.ValueChanged += mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged += mainForm.nudY_ValueChanged; break; case ChangeType.Font: Cursor.Current = Cursors.WaitCursor; @@ -231,6 +236,7 @@ namespace McBitFont { selCode = Convert.ToInt32(selItem); } fontIndex += dIndex; + canvasIndex += dIndex; mainForm.frames.Clear(); mainForm.miniList.Clear(); mainForm.ilMiniatures.Images.Clear(); @@ -238,7 +244,7 @@ namespace McBitFont { mainForm.frames.Add(CopyFrameSimple(f)); } mainForm.FillFrameLists(); - FrameMiniature fff; + if (selItem != "") { var selection = mainForm.miniList.Items.Find(selItem, false); if (selection.Length > 0) selection[0].Selected = true; @@ -248,44 +254,38 @@ namespace McBitFont { fff = mainForm.frames[0]; } mainForm.f = mainForm.CopyFrame(fff); + mainForm.nudX.ValueChanged -= mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged -= mainForm.nudY_ValueChanged; mainForm.nudY.Value = mainForm.dotHeight = fff.height; mainForm.nudX.Value = mainForm.dotWidth = fff.width; + mainForm.SetNewWH(); + mainForm.nudX.ValueChanged += mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged += mainForm.nudY_ValueChanged; + Cursor.Current = Cursors.Default; break; - case ChangeType.Frame: - HistoryAction = true; - selFrameIndex += dIndex; - var s = selFrameChanges[selFrameIndex].ToString().PadLeft(3, '0'); + case ChangeType.Selection: + selectionIndex += dIndex; + canvasIndex += dIndex; + var s = selectionChanges[selectionIndex].ToString().PadLeft(3, '0'); var sel = mainForm.miniList.Items.Find(s, false); if (sel.Length > 0) sel[0].Selected = true; + fff = mainForm.frames.Find(x => x.code == selectionChanges[selectionIndex]); + mainForm.f = CopyFrameSimple(fff); + mainForm.nudX.ValueChanged -= mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged -= mainForm.nudY_ValueChanged; + mainForm.nudY.Value = mainForm.dotHeight = fff.height; + mainForm.nudX.Value = mainForm.dotWidth = fff.width; + mainForm.SetNewWH(); + mainForm.nudX.ValueChanged += mainForm.nudX_ValueChanged; + mainForm.nudY.ValueChanged += mainForm.nudY_ValueChanged; break; default: break; } Index += dIndex; Doing = false; - // Frame select change + Canvas change workarounds - if (ct == ChangeType.Frame && undo) { - Undo(); - return; - } - if (Index < Count - 1) { - var nextctframe = timeline.ElementAt(Index + 1) == ChangeType.Frame; - if (ct == ChangeType.Canvas && !undo && nextctframe) { - Redo(); - return; - } - } - //Font change + Canvas change workarounds - if (Index >= 0) { - var prevctfont = timeline.ElementAt(Index) == ChangeType.Font; - if (ct == ChangeType.Canvas && undo && prevctfont) { - Undo(); - return; - } - } - if (!undo && ct == ChangeType.Font) - Redo(); + } // Undo last change diff --git a/McBitFont/Form1.cs b/McBitFont/Form1.cs index 2543232..407f9e7 100644 --- a/McBitFont/Form1.cs +++ b/McBitFont/Form1.cs @@ -76,7 +76,7 @@ namespace McBitFont { this.dotPanel.MouseWheel += new MouseEventHandler(this.DotPanel_MouseWheel); } - private void SetNewWH() { + public void SetNewWH() { w = pixelOffset + dotWidth * (cellSize + gap); h = pixelOffset + dotHeight * (cellSize + gap); } @@ -85,7 +85,7 @@ namespace McBitFont { lblSelection.Text = width.ToString() + ',' + height.ToString(); } - private void SetModified(bool modif = true, bool prj = false) { + public void SetModified(bool modif = true, bool prj = false) { string suffix = ""; if (prj) { prjModified = modif; @@ -197,7 +197,7 @@ namespace McBitFont { } } - private void nudX_ValueChanged(object sender, EventArgs e) { + public void nudX_ValueChanged(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; if (monospaced) { Bitmap bmp; @@ -216,10 +216,13 @@ namespace McBitFont { } DotResize((int)nudX.Value, dotHeight); + if (monospaced) history.Add(frames); + else history.Add(f); + Cursor.Current = Cursors.Default; } - private void nudY_ValueChanged(object sender, EventArgs e) { + public void nudY_ValueChanged(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; Bitmap bmp; for (int i = 0; i < frames.Count; i++) { diff --git a/TODO.txt b/TODO.txt index f1f8932..239e159 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,9 +3,9 @@ Application: V Copy-Paste now uses System clipboard and it is possible to copy-paste from/to different instances of running program Functionality: -- Rewrite history class so it tracks all changes, not only a canvas changes +V Rewrite history class so it tracks all changes, not only a canvas changes Bugs: -- In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) +V In some cases after switching to a symbol dotPanel mouse move causes "Out of range" exception (history.Pre after width change?) V Switching between symbols while select tool is active and small area selected trows an error V Full frame Copy in Clipboard does not respect selection on Paste operation \ No newline at end of file