Skip to content

Commit 3dc55b1

Browse files
committed
refactor(GUI): correctly align gutter and clean up event code
1 parent 27ac9e7 commit 3dc55b1

2 files changed

Lines changed: 67 additions & 70 deletions

File tree

src/TinyCompiler/Compiler.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22

33
namespace TinyCompiler
44
{
@@ -9,9 +9,7 @@ public static class Compiler
99

1010
public static void Compile(string sourceCode)
1111
{
12-
Errors.Clear();
13-
TokenStream.Clear();
14-
treeRoot = null;
12+
Clear();
1513

1614
//Scanner
1715
Scanner scanner = new Scanner(sourceCode);
@@ -28,8 +26,13 @@ public static void Compile(string sourceCode)
2826
Errors.ReportError($"========== compile: {Errors.Count()} parse error ==========");
2927
return;
3028
}
29+
}
3130

32-
//Sematic Analysis
31+
public static void Clear()
32+
{
33+
Errors.Clear();
34+
TokenStream.Clear();
35+
treeRoot = null;
3336
}
3437
}
3538
}

src/TinyCompiler/WindowForm.cs

Lines changed: 59 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using System.Drawing;
2-
using System;
1+
using System;
2+
using System.Drawing;
3+
using System.Linq;
34
using System.Windows.Forms;
45

56
namespace TinyCompiler
@@ -10,36 +11,21 @@ public WindowForm()
1011
{
1112
InitializeComponent();
1213

13-
// Subscribe to the necessary events
14+
// Subscribe to the necessary events for line number gutter
1415
tfSourceCode.TextChanged += (object sender, EventArgs e) => Invalidate();
1516
tfSourceCode.VScroll += (object sender, EventArgs e) => Invalidate();
16-
tfSourceCode.KeyDown += RichTextBox1_KeyDown;
17+
tfSourceCode.KeyDown += HandleRichTextBoxPaste;
1718
}
1819

19-
private void RichTextBox1_KeyDown(object sender, KeyEventArgs e)
20+
protected override void OnPaint(PaintEventArgs e)
2021
{
21-
// Check if Ctrl+V is pressed (paste command)
22-
if (e.Control && e.KeyCode == Keys.V)
23-
{
24-
// Check if clipboard contains plain text
25-
if (Clipboard.ContainsText())
26-
{
27-
// Get plain text from clipboard
28-
string plainText = Clipboard.GetText(TextDataFormat.Text);
29-
30-
// Insert the plain text into the RichTextBox (at current cursor position)
31-
tfSourceCode.SelectedText = plainText;
32-
}
33-
34-
// Prevent default paste behavior (i.e., disabling rich text paste)
35-
e.SuppressKeyPress = true;
36-
}
22+
base.OnPaint(e);
23+
DrawLineNumbers(tfSourceCode, e.Graphics);
3724
}
3825

39-
private void btnCompile_Click(object sender, System.EventArgs e)
26+
private void btnCompile_Click(object sender, EventArgs e)
4027
{
41-
string sourceCode = tfSourceCode.Text;
42-
Compiler.Compile(sourceCode);
28+
Compiler.Compile(tfSourceCode.Text);
4329

4430
PopulateTokensTable();
4531
PopulateParseTree();
@@ -64,23 +50,21 @@ private void PrintErrors()
6450
private void PopulateParseTree()
6551
{
6652
treePrase.Nodes.Clear();
67-
treePrase.Nodes.Add(PrintParaseTree(Compiler.treeRoot));
53+
treePrase.Nodes.Add(PrintParseTree(Compiler.treeRoot));
6854
}
6955

70-
private void btnClear_Click(object sender, System.EventArgs e)
56+
private void btnClear_Click(object sender, EventArgs e)
7157
{
7258
// Resest UI Elements
7359
tfSourceCode.Clear();
7460
tfErrors.Clear();
7561
tblTokens.Rows.Clear();
7662
treePrase.Nodes.Clear();
7763

78-
// Reset Global Data
79-
Compiler.TokenStream.Clear();
80-
Errors.Clear();
64+
Compiler.Clear();
8165
}
8266

83-
private static TreeNode PrintParaseTree(Node root)
67+
private static TreeNode PrintParseTree(Node root)
8468
{
8569
TreeNode tree = new TreeNode("Parse Tree");
8670
TreeNode treeRoot = PrintTree(root);
@@ -103,53 +87,63 @@ private static TreeNode PrintTree(Node root)
10387
TreeNode tree = new TreeNode(root.Name);
10488
foreach (Node child in root.Children)
10589
{
106-
if (child == null)
90+
if (child != null)
10791
{
108-
continue;
92+
tree.Nodes.Add(PrintTree(child));
10993
}
110-
111-
tree.Nodes.Add(PrintTree(child));
11294
}
11395

11496
return tree;
11597
}
11698

117-
protected override void OnPaint(PaintEventArgs e)
99+
private void HandleRichTextBoxPaste(object sender, KeyEventArgs e)
118100
{
119-
base.OnPaint(e);
120-
DrawLineNumbers(e.Graphics);
101+
if (e.Control && (e.KeyCode == Keys.V))
102+
{
103+
if (Clipboard.ContainsText())
104+
{
105+
string plainText = Clipboard.GetText(TextDataFormat.Text);
106+
tfSourceCode.SelectedText = plainText;
107+
}
108+
109+
// Prevent default paste behavior (i.e., disabling rich text paste)
110+
e.SuppressKeyPress = true;
111+
}
121112
}
122113

123-
private void DrawLineNumbers(Graphics graphics)
114+
private void DrawLineNumbers(RichTextBox richTextBox, Graphics graphics)
124115
{
125-
// Set the font and brush for the line numbers
126-
Font lineNumberFont = new Font("Consolas", 10);
127-
Brush lineNumberBrush = Brushes.Gray;
128-
129-
// Calculate the height of a single line based on the font
130-
// Use GetLineFromCharIndex and GetPositionFromCharIndex to get the correct line height
131-
int lineHeight = tfSourceCode.GetPositionFromCharIndex(tfSourceCode.GetFirstCharIndexFromLine(1)).Y
132-
- tfSourceCode.GetPositionFromCharIndex(tfSourceCode.GetFirstCharIndexFromLine(0)).Y;
133-
134-
// Get the first and last visible lines
135-
int firstVisibleLine = tfSourceCode.GetLineFromCharIndex(tfSourceCode.GetCharIndexFromPosition(new Point(0, 4)));
136-
int lastVisibleLine = tfSourceCode.GetLineFromCharIndex(tfSourceCode.GetCharIndexFromPosition(new Point(0, tfSourceCode.ClientRectangle.Bottom)));
137-
138-
// Get the position of the RichTextBox control (Top is the distance from the top of the form)
139-
int richTextBoxTop = tfSourceCode.Top;
140-
int richTextBoxLeft = tfSourceCode.Left;
141-
142-
// Set the initial position for drawing the line numbers
143-
// Align with the left of the RichTextBox
144-
int xPosition = richTextBoxLeft;
145-
int yPosition = richTextBoxTop + tfSourceCode.GetPositionFromCharIndex(tfSourceCode.GetFirstCharIndexFromLine(firstVisibleLine)).Y;
146-
147-
// Draw the line numbers for all visible lines
148-
for (int i = firstVisibleLine; i <= lastVisibleLine; i++)
116+
Font font = richTextBox.Font;
117+
Brush brush = Brushes.Gray;
118+
119+
const float xPosMargin = 4.0f;
120+
float yPos = richTextBox.Top;
121+
122+
int firstIndex = richTextBox.GetCharIndexFromPosition(Point.Empty);
123+
int firstLine = richTextBox.GetLineFromCharIndex(firstIndex);
124+
125+
Point bottomLeft = new Point(0, richTextBox.ClientRectangle.Height);
126+
int lastIndex = richTextBox.GetCharIndexFromPosition(bottomLeft);
127+
int lastLine = richTextBox.GetLineFromCharIndex(lastIndex);
128+
129+
if (richTextBox.Lines.Any() && string.IsNullOrEmpty(richTextBox.Lines.Last()))
149130
{
150-
SizeF size = graphics.MeasureString((i + 1).ToString(), lineNumberFont);
151-
graphics.DrawString((i + 1).ToString(), lineNumberFont, lineNumberBrush, xPosition - size.Width, yPosition);
152-
yPosition += lineHeight; // Move to the next line position
131+
lastLine++;
132+
}
133+
134+
int maxLines = richTextBox.ClientRectangle.Height / Font.Height;
135+
for (int i = firstLine; (i <= lastLine) && (i - firstLine <= maxLines); i++)
136+
{
137+
string numStr = (i + 1).ToString();
138+
PointF pos = new PointF(richTextBox.Left - xPosMargin, yPos);
139+
yPos += font.Height;
140+
141+
using (StringFormat sf = new StringFormat())
142+
{
143+
sf.Alignment = StringAlignment.Far;
144+
sf.LineAlignment = StringAlignment.Near;
145+
graphics.DrawString(numStr, font, brush, pos, sf);
146+
}
153147
}
154148
}
155149
}

0 commit comments

Comments
 (0)