diff --git a/McBitFont/ChangeHistory.cs b/McBitFont/ChangeHistory.cs new file mode 100644 index 0000000..d96713c --- /dev/null +++ b/McBitFont/ChangeHistory.cs @@ -0,0 +1,308 @@ +using System; +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.MainForm; + +namespace McBitFont { + internal class ChangeHistory { + private MainForm mainForm; + private List timeline = []; + private List canvasChanges = []; + private List> fontChanges = []; + private List selectionChanges = []; + private int canvasIndex = 0; + private int fontIndex = 0; + private int selectionIndex = 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 Doing { get; set; } = false; + + // Constructor + public ChangeHistory(MainForm form, int depth = 100) { + timeline = []; + canvasChanges = []; + fontChanges = []; + selectionChanges = []; + mainForm = form; + Depth = depth; + ResetIndices(); + Add(); + Doing = false; + } + + + + private void ResetIndices() { + Index = -1; + canvasIndex = 0; + fontIndex = 0; + selectionIndex = 0; + } + + public enum ChangeType { + None = 0, + 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; + } + + 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(); + selectionChanges.Clear(); + ResetIndices(); + Add(); + } + + // Remove from a proper list by change type + 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--; + canvasChanges.RemoveAt(first ? 0 : canvasChanges.Count - 1); + break; + 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.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; + } + if ((first && Index > 0) || (!first && Index == Count - 1) || Count == 1) Index--; + timeline.RemoveAt(first ? 0 : Count - 1); + + + return true; + } + + // Remove oldest event + private bool RemoveOldest() { + if (Count == 0) return false; + ChangeEvent ce = timeline.First(); + RemoveByType(ce); + + return true; + } + + // Remove last event + public bool RemoveLast() { + if (Count == 0) return false; + var ce = timeline.Last(); + RemoveByType(ce, false); + + return true; + } + + // Remove history tail + private void TruncateTail() { + // Check if the Index does not point to the last event + //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); + selectionChanges.RemoveRange(selectionIndex + 1, selectionChanges.Count - selectionIndex - 1); + } + } + + // 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 FrameMiniature? Add(FrameMiniature f, bool useIndex = true) { + if (Doing) return null ; + TruncateTail(); + + if (Count >= Depth) RemoveOldest(); + canvasChanges.Add(CopyFrameSimple(f)); + if (useIndex) { + 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; + TruncateTail(); + + var l = new List(); + foreach (var f in ff) { + l.Add(CopyFrameSimple(f)); + } + + if (Count >= Depth) RemoveOldest(); + fontChanges.Add(l); + if (useIndex) { + var canv = Add(mainForm.f, false); + canvasIndex++; + timeline.Add(new ChangeEvent(ChangeType.Font, canv)); + Index++; + fontIndex++; + } + } + + // Add Frame selection change + public void Add(int code, bool useIndex = true) { + if (Doing) return; + TruncateTail(); + + if (Count >= Depth) RemoveOldest(); + selectionChanges.Add(code); + if (useIndex) { + var canv = Add(mainForm.f, false); + canvasIndex++; + timeline.Add(new ChangeEvent(ChangeType.Selection, canv)); + Index++; + selectionIndex++; + } + + } + + private void Do(bool undo = true) { + if (!undo && Index >= Count - 1) return; + Doing = true; + var ce = timeline.ElementAt(Index + (undo ? 0 : 1)); + int dIndex = undo ? -1 : 1; + 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; + string selItem = ""; + int selCode = 0; + if (mainForm.miniList.SelectedItems.Count > 0) { + selItem = mainForm.miniList.SelectedItems[0].Name; + selCode = Convert.ToInt32(selItem); + } + fontIndex += dIndex; + canvasIndex += dIndex; + mainForm.frames.Clear(); + mainForm.miniList.Clear(); + mainForm.ilMiniatures.Images.Clear(); + foreach (var f in fontChanges[fontIndex]) { + mainForm.frames.Add(CopyFrameSimple(f)); + } + mainForm.FillFrameLists(); + + 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.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.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; + + } + + // 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 cec5515..ffd5494 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(); @@ -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 // @@ -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; @@ -609,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 // @@ -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; @@ -644,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; @@ -654,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; @@ -665,19 +675,18 @@ 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; // // pasteToolStripMenuItem // - pasteToolStripMenuItem.Enabled = false; pasteToolStripMenuItem.Image = Properties.Resources.Famfamfam_Silk_Page_paste_16; 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; @@ -687,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; @@ -698,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; @@ -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); @@ -1123,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; @@ -1139,8 +1136,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; @@ -1210,6 +1205,10 @@ 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; + public System.Windows.Forms.NumericUpDown nudX; + public System.Windows.Forms.NumericUpDown nudY; } } diff --git a/McBitFont/Form1.cs b/McBitFont/Form1.cs index 3977053..407f9e7 100644 --- a/McBitFont/Form1.cs +++ b/McBitFont/Form1.cs @@ -47,23 +47,24 @@ 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 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; @@ -75,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); } @@ -84,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; @@ -138,6 +139,8 @@ namespace McBitFont { CodeShiftToolStripMenuItem.Visible = frames.Count > 1; CheckForAdd(); + + history = new(this); } [DllImport("user32.dll")] @@ -147,9 +150,9 @@ namespace McBitFont { return (int)(((ushort)lowPart) | (uint)(highPart << 16)); } - 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; + 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); if (chkRectSelect.Checked && clipboard) { @@ -194,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; @@ -213,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++) { @@ -233,6 +239,7 @@ namespace McBitFont { } DotResize(dotWidth, (int)nudY.Value); + history.Add(frames); Cursor.Current = Cursors.Default; } @@ -280,7 +287,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) { @@ -328,7 +335,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++) { @@ -339,7 +346,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -351,7 +359,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--) { @@ -362,7 +370,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -374,7 +383,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++) { @@ -385,7 +394,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -396,7 +406,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--) { @@ -407,7 +417,8 @@ namespace McBitFont { } } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -457,6 +468,7 @@ namespace McBitFont { } } if (e.Button != MouseButtons.None && !mouseDown) { + // Started to move a mouse with button held mouseDown = true; if (rectSel) { selection1.X = i; @@ -464,20 +476,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(); } @@ -539,7 +554,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(); @@ -549,7 +564,8 @@ namespace McBitFont { } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -561,7 +577,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (j = y; j <= y2; j++) { a = x; b = x2; @@ -573,7 +589,8 @@ namespace McBitFont { b--; } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -585,7 +602,7 @@ namespace McBitFont { (x, y, x2, y2) = RectSelCoords(); - history.AddPre(f); + //history.AddPre(f); for (i = x; i <= x2; i++) { a = y; b = y2; @@ -597,13 +614,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(); @@ -635,7 +653,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; @@ -647,7 +665,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; @@ -817,13 +835,13 @@ namespace McBitFont { SetWindowCap(); SetModified(false); ; CheckForAdd(); - fbuffer = false; miniList.Items[0].Selected = true; miniList.Refresh(); dotPanel.Refresh(); // Re-create history object - history = new CanvasHistory(); + //history = new CanvasHistory(); + history.Clear(); Cursor.Current = Cursors.Default; } @@ -839,14 +857,12 @@ namespace McBitFont { tsmiRemoveSymbol.Enabled = false; tsmiRemoveBefore.Enabled = false; tsmiRemoveAfter.Enabled = false; - //copyToolStripMenuItem.Enabled = false; - pasteToolStripMenuItem.Enabled = false; - return; - //miniList.Items[0].Selected = true; - } + return; + } + dotPanel.SuspendLayout(); // Clear history - history.Clear(); + //history.Clear(); var sel = miniList.SelectedItems[0]; int code = Convert.ToInt32(sel.ImageKey); @@ -854,7 +870,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; @@ -863,7 +882,10 @@ namespace McBitFont { removeSymbolToolStripMenuItem.Enabled = false; tsmiRemoveSymbol.Enabled = false; } - //copyToolStripMenuItem.Enabled = true; + + dotPanel.ResumeLayout(); + dotPanel.Refresh(); + if (frames.Count > 1 && ff.Equals(frames.First())) { removeBeforeToolStripMenuItem.Enabled = false; removeAfterToolStripMenuItem.Enabled = true; @@ -881,8 +903,6 @@ namespace McBitFont { tsmiRemoveAfter.Enabled = true; } - if (fbuffer) pasteToolStripMenuItem.Enabled = true; - else pasteToolStripMenuItem.Enabled = false; } private void SaveToolStripMenuItem_Click(object sender, EventArgs e) { @@ -892,6 +912,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; @@ -909,13 +939,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; @@ -940,11 +964,10 @@ namespace McBitFont { miniList.Items[0].Selected = true; CheckForAdd(); - fbuffer = false; - //copyToolStripMenuItem.Enabled = true; // Re-create history object - history = new CanvasHistory(); + //history = new CanvasHistory(); + history.Clear(); tsmiMakeVarWidth.Visible = monospaced; makeVarWidthToolStripMenuItem.Visible = monospaced; @@ -1041,38 +1064,46 @@ 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); + + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); dotPanel.Refresh(); SetModified(); @@ -1121,7 +1152,7 @@ namespace McBitFont { private void FillFrame(bool val) { int x, y, x2, y2; - history.AddPre(f); + //history.AddPre(f); (x, y, x2, y2) = RectSelCoords(); @@ -1131,7 +1162,8 @@ namespace McBitFont { } } - history.AddPost(f); + //history.AddPost(f); + history.Add(f); CheckHistoryButtons(); SetModified(); dotPanel.Refresh(); @@ -1212,13 +1244,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(); } @@ -1269,13 +1303,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(); @@ -1436,7 +1471,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 +1509,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..239e159 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,10 +1,11 @@ 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" -V Type a string to see the result (test the font) -V Export image with All characers table +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