TODO feature: Rectangle selection to mass-paint, shift and mirror pixels etc...

This commit is contained in:
2025-05-24 08:31:05 +03:00
parent 1034bd98d6
commit b1986c0f28
3 changed files with 237 additions and 104 deletions

View File

@@ -82,6 +82,7 @@
CodeShiftToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
canvasToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
ClearToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
FillToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
shiftUpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
shiftDownToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
shiftLeftToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -99,7 +100,7 @@
chkTopSide = new System.Windows.Forms.CheckBox();
chkHexCodes = new System.Windows.Forms.CheckBox();
label3 = new System.Windows.Forms.Label();
FillToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
chkRectSelect = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)nudX).BeginInit();
((System.ComponentModel.ISupportInitialize)nudY).BeginInit();
panel1.SuspendLayout();
@@ -111,7 +112,7 @@
//
dotPanel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
dotPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
dotPanel.BackColor = System.Drawing.SystemColors.ControlDark;
dotPanel.BackColor = System.Drawing.Color.Gray;
dotPanel.Location = new System.Drawing.Point(14, 31);
dotPanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
dotPanel.Name = "dotPanel";
@@ -120,6 +121,7 @@
dotPanel.Paint += dotPanel_Paint;
dotPanel.MouseDown += dotPanel_MouseMove;
dotPanel.MouseMove += dotPanel_MouseMove;
dotPanel.MouseUp += dotPanel_MouseMove;
dotPanel.Resize += cbZoom_SelectedIndexChanged;
//
// nudX
@@ -191,7 +193,7 @@
cbZoom.Location = new System.Drawing.Point(619, 52);
cbZoom.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
cbZoom.Name = "cbZoom";
cbZoom.Size = new System.Drawing.Size(68, 23);
cbZoom.Size = new System.Drawing.Size(75, 23);
cbZoom.TabIndex = 6;
cbZoom.TabStop = false;
toolTip1.SetToolTip(cbZoom, "Canvas zoom level");
@@ -476,7 +478,7 @@
hScroll.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
hScroll.Location = new System.Drawing.Point(14, 609);
hScroll.Name = "hScroll";
hScroll.Size = new System.Drawing.Size(454, 21);
hScroll.Size = new System.Drawing.Size(427, 21);
hScroll.TabIndex = 14;
hScroll.ValueChanged += scroll_ValueChanged;
//
@@ -494,7 +496,7 @@
//
lblCoords.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
lblCoords.AutoSize = true;
lblCoords.Location = new System.Drawing.Point(616, 132);
lblCoords.Location = new System.Drawing.Point(616, 138);
lblCoords.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
lblCoords.Name = "lblCoords";
lblCoords.Size = new System.Drawing.Size(24, 15);
@@ -745,6 +747,15 @@
ClearToolStripMenuItem.ToolTipText = "Clear canvas";
ClearToolStripMenuItem.Click += btnClear_Click;
//
// FillToolStripMenuItem
//
FillToolStripMenuItem.Image = Properties.Resources.Canvas_Fill;
FillToolStripMenuItem.Name = "FillToolStripMenuItem";
FillToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B;
FillToolStripMenuItem.Size = new System.Drawing.Size(197, 22);
FillToolStripMenuItem.Text = "Fill canvas";
FillToolStripMenuItem.Click += btnFill_Click;
//
// shiftUpToolStripMenuItem
//
shiftUpToolStripMenuItem.Image = Properties.Resources.z_uo;
@@ -909,26 +920,29 @@
//
label3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
label3.AutoSize = true;
label3.Location = new System.Drawing.Point(615, 117);
label3.Location = new System.Drawing.Point(615, 123);
label3.Name = "label3";
label3.Size = new System.Drawing.Size(45, 15);
label3.TabIndex = 21;
label3.Text = "Cursor:";
//
// FillToolStripMenuItem
// chkRectSelect
//
FillToolStripMenuItem.Image = Properties.Resources.Canvas_Fill;
FillToolStripMenuItem.Name = "FillToolStripMenuItem";
FillToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B;
FillToolStripMenuItem.Size = new System.Drawing.Size(197, 22);
FillToolStripMenuItem.Text = "Fill canvas";
FillToolStripMenuItem.Click += btnFill_Click;
chkRectSelect.Appearance = System.Windows.Forms.Appearance.Button;
chkRectSelect.Location = new System.Drawing.Point(620, 92);
chkRectSelect.Name = "chkRectSelect";
chkRectSelect.Size = new System.Drawing.Size(74, 27);
chkRectSelect.TabIndex = 23;
chkRectSelect.Text = "Rect Select";
chkRectSelect.UseVisualStyleBackColor = true;
chkRectSelect.CheckedChanged += chkRectSelect_CheckedChanged;
//
// MainForm
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(915, 647);
Controls.Add(chkRectSelect);
Controls.Add(chkHexCodes);
Controls.Add(label3);
Controls.Add(chkTopSide);
@@ -1047,6 +1061,7 @@
private System.Windows.Forms.CheckBox chkHexCodes;
private System.Windows.Forms.Button btnFill;
private System.Windows.Forms.ToolStripMenuItem FillToolStripMenuItem;
private System.Windows.Forms.CheckBox chkRectSelect;
}
}

View File

@@ -55,22 +55,29 @@ namespace McBitFont {
private int gap;
private int w, h;
public bool monospaced = false;
bool modified = false;
bool prjModified = false;
private bool modified = false;
private bool prjModified = false;
public const string version = "2.0";
public string prjName = "Untitled";
public string prjFileName = "";
public int codepage = 1251;
private int codepage = 1251;
private FrameMiniature fbuf;
private bool fbuffer = false;
public int baseline = 0;
public bool set_base = false;
private int baseline = 0;
private bool set_base = false;
private Point selection1, selection2;
public MainForm() {
InitializeComponent();
this.dotPanel.MouseWheel += new MouseEventHandler(this.DotPanel_MouseWheel);
}
private void SetNewWH() {
w = pixelOffset + dotWidth * (cellSize + gap);
h = pixelOffset + dotHeight * (cellSize + gap);
}
private void Form1_Load(object sender, EventArgs e) {
lblType.Text = monospaced ? "Monospaced" : "Variable width / Single";
tsmiMakeVarWidth.Visible = monospaced;
@@ -78,9 +85,11 @@ namespace McBitFont {
dotWidth = (int)nudX.Value;
dotHeight = (int)nudY.Value;
selection1 = new Point(0, 0);
selection2 = new Point(dotWidth - 1, dotHeight - 1);
gap = (cellSize < 5) ? 0 : 1;
w = pixelOffset + dotWidth * (cellSize + gap);
h = pixelOffset + dotHeight * (cellSize + gap);
SetNewWH();
cbZoom.SelectedIndex = 3;
@@ -230,8 +239,7 @@ namespace McBitFont {
f = FrameResize(f, ww, hh);
dotWidth = ww;
dotHeight = hh;
w = pixelOffset + dotWidth * (cellSize + gap);
h = pixelOffset + dotHeight * (cellSize + gap);
SetNewWH();
cbZoom_SelectedIndexChanged(cbZoom, null);
// Re-create history object
@@ -242,8 +250,7 @@ namespace McBitFont {
cellSize = Convert.ToInt32(cbZoom.Text);
gap = (cellSize < 5) ? 0 : 1;
w = pixelOffset + dotWidth * (cellSize + gap);
h = pixelOffset + dotHeight * (cellSize + gap);
SetNewWH();
if (w <= dotPanel.Width) {
hScroll.Enabled = false;
hScroll.Value = 0;
@@ -265,14 +272,76 @@ namespace McBitFont {
dotPanel.Refresh();
}
private void btnShiftLeft_Click(object sender, EventArgs e) {
// Deconstruct selection coords from points
private (int x, int y, int x2, int y2) RectSelCoords() {
int x, y, x2, y2;
if (chkRectSelect.Checked) {
x = selection1.X; y = selection1.Y;
x2 = selection2.X; y2 = selection2.Y;
} else {
x = y = 0;
x2 = dotWidth - 1; y2 = dotHeight - 1;
}
return (x, y, x2, y2);
}
private void btnShiftUp_Click(object sender, EventArgs e) {
int x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (int j = 0; j < dotHeight; j++) {
c = f.data[0, j];
for (int i = 0; i < dotWidth; i++) {
if (i == dotWidth - 1) {
for (int i = x; i <= x2; i++) {
c = f.data[i, y];
for (int j = y; j <= y2; j++) {
if (j == y2) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i, j + 1];
}
}
}
history.AddPost(f);
CheckHistoryButtons();
modified = true;
dotPanel.Refresh();
}
private void btnShiftDown_Click(object sender, EventArgs e) {
int x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (int i = x; i <= x2; i++) {
c = f.data[i, y2];
for (int j = y2; j >= y; j--) {
if (j == y) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i, j - 1];
}
}
}
history.AddPost(f);
CheckHistoryButtons();
modified = true;
dotPanel.Refresh();
}
private void btnShiftLeft_Click(object sender, EventArgs e) {
int x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (int j = y; j <= y2; j++) {
c = f.data[x, j];
for (int i = x; i <= x2; i++) {
if (i == x2) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i + 1, j];
@@ -286,13 +355,15 @@ namespace McBitFont {
}
private void btnShiftRight_Click(object sender, EventArgs e) {
int x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (int j = 0; j < dotHeight; j++) {
c = f.data[dotWidth - 1, j];
for (int i = dotWidth - 1; i >= 0; i--) {
if (i == 0) {
for (int j = y; j <= y2; j++) {
c = f.data[x2, j];
for (int i = x2; i >= x; i--) {
if (i == x) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i - 1, j];
@@ -308,6 +379,9 @@ namespace McBitFont {
private bool mouseDown = false;
private bool fChanged = false;
private void dotPanel_MouseMove(object sender, MouseEventArgs e) {
var rectSel = chkRectSelect.Checked;
bool rectSelUpdated = false;
// Moving baseline
Rectangle rect1, rect2;
if (set_base) {
@@ -337,21 +411,67 @@ namespace McBitFont {
int j = (e.Y - pixelOffset + vScroll.Value) / (cellSize + gap);
lblCoords.Text = i.ToString() + ',' + j.ToString();
// history management
// History and Rectangle selection management
if (rectSel && mouseDown && e.Button != MouseButtons.None) {
if (selection2.X != i || selection2.Y != j) {
rectSelUpdated = true;
selection2.X = i;
selection2.Y = j;
}
}
if (e.Button != MouseButtons.None && !mouseDown) {
mouseDown = true;
history.AddPre(f, false);
if (rectSel) {
selection1.X = i;
selection1.Y = j;
selection2.X = i;
selection2.Y = j;
dotPanel.Invalidate();
} else history.AddPre(f, false);
}
if (e.Button == MouseButtons.None && mouseDown) {
mouseDown = false;
if (!fChanged) {
history.Remove(false);
if (rectSel) {
NormPoints(ref selection1, ref selection2);
dotPanel.Invalidate();
} else {
fChanged = false;
history.ApplyAdded();
history.AddPost(f);
if (!fChanged) {
history.Remove(false);
} else {
fChanged = false;
history.ApplyAdded();
history.AddPost(f);
}
CheckHistoryButtons();
}
CheckHistoryButtons();
}
if (rectSel) {
if (mouseDown && rectSelUpdated) {
int x, xx, x2, xx2, y, yy, y2, yy2;
Point p1 = new(selection1.X, selection1.Y);
Point p2 = new(selection2.X, selection2.Y);
NormPoints(ref p1, ref p2);
x = pixelOffset + (p1.X - 1) * (cellSize + gap) - hScroll.Value - 1;
y = pixelOffset + (p1.Y - 1) * (cellSize + gap) - vScroll.Value - 1;
x2 = pixelOffset + (p2.X + 2) * (cellSize + gap) - hScroll.Value - 1;
y2 = pixelOffset + (p2.Y + 2) * (cellSize + gap) - vScroll.Value - 1;
xx = x + 2 * (cellSize + gap);
yy = y + 2 * (cellSize + gap);
xx2 = x2 - 2 * (cellSize + gap);
yy2 = y2 - 2 * (cellSize + gap);
Region reg, reg2;
reg = new(new Rectangle(x, y, x2 - x + 1, y2 - y + 1));
reg.Exclude(new Rectangle(x + 1, y + 1, x2 - x - 1, y2 - y - 1));
reg2 = new(new Rectangle(xx, yy, xx2 - xx + 1, yy2 - yy + 1));
reg2.Exclude(new Rectangle(xx + 1, yy + 1, xx2 - xx - 1, yy2 - yy - 1));
reg.Union(reg2);
dotPanel.Invalidate(reg);
}
return;
}
// Paint black / white
@@ -376,53 +496,19 @@ namespace McBitFont {
}
private void btnShiftUp_Click(object sender, EventArgs e) {
bool c;
history.AddPre(f);
for (int i = 0; i < dotWidth; i++) {
c = f.data[i, 0];
for (int j = 0; j < dotHeight; j++) {
if (j == dotHeight - 1) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i, j + 1];
}
}
}
history.AddPost(f);
CheckHistoryButtons();
modified = true;
dotPanel.Refresh();
}
private void btnShiftDown_Click(object sender, EventArgs e) {
bool c;
history.AddPre(f);
for (int i = 0; i < dotWidth; i++) {
c = f.data[i, dotHeight - 1];
for (int j = dotHeight - 1; j >= 0; j--) {
if (j == 0) {
f.data[i, j] = c;
} else {
f.data[i, j] = f.data[i, j - 1];
}
}
}
history.AddPost(f);
CheckHistoryButtons();
modified = true;
dotPanel.Refresh();
}
private void btnInvert_Click(object sender, EventArgs e) {
int x, y, x2, y2;
history.AddPre(f);
for (int i = 0; i < dotWidth; i++) {
for (int j = 0; j < dotHeight; j++) {
(x, y, x2, y2) = RectSelCoords();
for (int i = x; i <= x2; i++) {
for (int j = y; j <= y2; j++) {
f.data[i, j] = !f.data[i, j];
}
}
history.AddPost(f);
CheckHistoryButtons();
modified = true;
@@ -430,13 +516,15 @@ namespace McBitFont {
}
private void btnMirrorX_Click(object sender, EventArgs e) {
int a, b, j;
int a, b, j, x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (j = 0; j < dotHeight; j++) {
a = 0;
b = dotWidth - 1;
for (j = y; j <= y2; j++) {
a = x;
b = x2;
while (a < b) {
c = f.data[a, j];
f.data[a, j] = f.data[b, j];
@@ -452,13 +540,15 @@ namespace McBitFont {
}
private void btnMirrorY_Click(object sender, EventArgs e) {
int a, b, i;
int a, b, i, x, y, x2, y2;
bool c;
(x, y, x2, y2) = RectSelCoords();
history.AddPre(f);
for (i = 0; i < dotWidth; i++) {
a = 0;
b = dotHeight - 1;
for (i = x; i <= x2; i++) {
a = y;
b = y2;
while (a < b) {
c = f.data[i, a];
f.data[i, a] = f.data[i, b];
@@ -532,34 +622,57 @@ namespace McBitFont {
SolidBrush sbb = new SolidBrush(Color.Black);
SolidBrush sbw = new SolidBrush(Color.White);
SolidBrush sb;
Pen p = new Pen(Color.FromArgb(64, Color.Green));
Pen p = new Pen(Color.FromArgb(100, 20, 120, 20));
int x, y;
// Draw the grid
for (int i = 0; i < dotWidth; i++) {
x = pixelOffset + i * (cellSize + gap) - hScroll.Value;
// Green lines every 8 cells
if (gap > 0 && i != 0 && (i % 8) == 0) {
g.DrawLine(p, x - 1, pixelOffset - vScroll.Value, x - 1, h);
}
for (int j = 0; j < dotHeight; j++) {
y = pixelOffset + j * (cellSize + gap) - vScroll.Value;
// Green lines every 8 cells
if (gap > 0 && i == 0 && j != 0 && (j % 8) == 0) {
g.DrawLine(p, pixelOffset - hScroll.Value, y - 1, w, y - 1);
}
// Fill the cell with color
if (f.data[i, j]) sb = sbb;
else sb = sbw;
g.FillRectangle(sb, x, (baseline == j ? y + 1 : y), cellSize, (baseline == j ? cellSize - 1 : cellSize));
}
}
// Draw the baseline
if (baseline > 0 && gap > 0) {
x = pixelOffset - hScroll.Value;
y = pixelOffset + baseline * (cellSize + gap) - vScroll.Value;
g.DrawLine(
new Pen(Color.Blue, 2),
x, y,
w, y
);
Pen sbBase = new(Color.Blue, 2);
g.DrawLine(sbBase, x, y, w, y);
}
// Draw the Rect selection
if (chkRectSelect.Checked) {
Point p1 = new(selection1.X, selection1.Y);
Point p2 = new(selection2.X, selection2.Y);
NormPoints(ref p1, ref p2);
Pen sbRect = new(Color.FromArgb(200, 0, 200, 0), 3);
x = pixelOffset + p1.X * (cellSize + gap) - hScroll.Value - 1;
y = pixelOffset + p1.Y * (cellSize + gap) - vScroll.Value - 1;
int ww = pixelOffset + (p2.X + 1) * (cellSize + gap) - hScroll.Value - x - 1;
int hh = pixelOffset + (p2.Y + 1) * (cellSize + gap) - vScroll.Value - y - 1;
g.DrawRectangle(sbRect, x, y, ww, hh);
}
}
private static void NormPoints(ref Point a, ref Point b) {
int bot;
if (a.X > b.X) { bot = a.X; a.X = b.X; b.X = bot; }
if (a.Y > b.Y) { bot = a.Y; a.Y = b.Y; b.Y = bot; }
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
@@ -940,15 +1053,17 @@ namespace McBitFont {
}
private void FillFrame(bool val) {
int x, y, x2, y2;
history.AddPre(f);
if (!val) Array.Clear(f.data);
else
for (int i = 0; i < f.width; i++) {
for (int j = 0; j < f.height; j++) {
f.data[i, j] = val;
}
(x, y, x2, y2) = RectSelCoords();
for (int i = x; i <= x2; i++) {
for (int j = y; j <= y2; j++) {
f.data[i, j] = val;
}
}
history.AddPost(f);
CheckHistoryButtons();
@@ -1116,5 +1231,8 @@ namespace McBitFont {
}
}
private void chkRectSelect_CheckedChanged(object sender, EventArgs e) {
dotPanel.Refresh();
}
}
}

View File

@@ -18,7 +18,7 @@ V Ability to make monospaced font a variable width one
V Undo/Redo for canvas changes
V Image import from a file
- Import from a text array
- Rectangle selection to mass-paint, shift and mirror pixels
V Rectangle selection to mass-paint, shift and mirror pixels etc...
V "Packed" fonts export
V "Bytes total comment in export