Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion Examples/UICatalog/Scenarios/RegionScenario.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,45 @@ public override void Main ()
break;

case RegionDrawStyles.OuterBoundary:
_region.DrawOuterBoundary (sendingView.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
// Demo simplification: iterate the region's rectangles and add the four edges of each
// to the LineCanvas. Shared edges between adjacent rectangles will overlap; LineCanvas's
// line-style joining handles the visual result, matching how Border/Adornment draw.
foreach (Rectangle rect in _region.GetRectangles ())
{
if (rect.IsEmpty || rect.Width <= 0 || rect.Height <= 0)
{
continue;
}

sendingView.LineCanvas.AddLine (
new (rect.Left, rect.Top),
rect.Width,
Orientation.Horizontal,
LineStyle.Single,
tools.CurrentAttribute);

sendingView.LineCanvas.AddLine (
new (rect.Left, rect.Bottom - 1),
rect.Width,
Orientation.Horizontal,
LineStyle.Single,
tools.CurrentAttribute);

sendingView.LineCanvas.AddLine (
new (rect.Left, rect.Top),
rect.Height,
Orientation.Vertical,
LineStyle.Single,
tools.CurrentAttribute);

sendingView.LineCanvas.AddLine (
new (rect.Right - 1, rect.Top),
rect.Height,
Orientation.Vertical,
LineStyle.Single,
tools.CurrentAttribute);
}

_region.FillRectangles (sendingView.App?.Driver, tools.CurrentAttribute!.Value, (Rune)' ');

break;
Expand Down
199 changes: 0 additions & 199 deletions Terminal.Gui/Drawing/Region.cs
Original file line number Diff line number Diff line change
Expand Up @@ -982,203 +982,4 @@ public void DrawBoundaries (LineCanvas canvas, LineStyle style, Attribute? attri
}
}
}

// BUGBUG: DrawOuterBoundary does not work right. it draws all regions +1 too tall/wide. It should draw single width/height regions as just a line.
//
// Example: There are 3 regions here. the first is a rect (0,0,1,4). Second is (10, 0, 2, 4).
// This is how they should draw:
//
// |123456789|123456789|123456789
// 1 │ ┌┐ ┌─┐
// 2 │ ││ │ │
// 3 │ ││ │ │
// 4 │ └┘ └─┘
//
// But this is what it draws:
// |123456789|123456789|123456789
// 1┌┐ ┌─┐ ┌──┐
// 2││ │ │ │ │
// 3││ │ │ │ │
// 4││ │ │ │ │
// 5└┘ └─┘ └──┘
//
// Example: There are two rectangles in this region. (0,0,3,3) and (3, 3, 3, 3).
// This is fill - correct:
// |123456789
// 1░░░
// 2░░░
// 3░░░░░
// 4 ░░░
// 5 ░░░
// 6
//
// This is what DrawOuterBoundary should draw
// |123456789|123456789
// 1┌─┐
// 2│ │
// 3└─┼─┐
// 4 │ │
// 5 └─┘
// 6
//
// This is what DrawOuterBoundary actually draws
// |123456789|123456789
// 1┌──┐
// 2│ │
// 3│ └─┐
// 4└─┐ │
// 5 │ │
// 6 └──┘

/// <summary>
/// Draws the outer perimeter of the region to <paramref name="lineCanvas"/> using <paramref name="style"/> and
/// <paramref name="attribute"/>.
/// The outer perimeter follows the shape of the rectangles in the region, even if non-rectangular, by drawing
/// boundaries and excluding internal lines.
/// </summary>
/// <param name="lineCanvas">The LineCanvas to draw on.</param>
/// <param name="style">The line style to use for drawing.</param>
/// <param name="attribute">The attribute (color/style) to use for the lines. If <c>null</c>.</param>
public void DrawOuterBoundary (LineCanvas lineCanvas, LineStyle style, Attribute? attribute = null)
{
if (_rectangles.Count == 0)
{
return;
}

// Get the bounds of the region
Rectangle bounds = GetBounds ();

// Add protection against extremely large allocations
if (bounds.Width > 1000 || bounds.Height > 1000)
{
// Fall back to drawing each rectangle's boundary
DrawBoundaries (lineCanvas, style, attribute);

return;
}

// Create a grid to track which cells are inside the region
var insideRegion = new bool [bounds.Width + 1, bounds.Height + 1];

// Fill the grid based on rectangles
foreach (Rectangle rect in _rectangles)
{
if (rect.IsEmpty || rect.Width <= 0 || rect.Height <= 0)
{
continue;
}

for (int x = rect.Left; x < rect.Right; x++)
{
for (int y = rect.Top; y < rect.Bottom; y++)
{
// Adjust coordinates to grid space
int gridX = x - bounds.Left;
int gridY = y - bounds.Top;

if (gridX >= 0 && gridX < bounds.Width && gridY >= 0 && gridY < bounds.Height)
{
insideRegion [gridX, gridY] = true;
}
}
}
}

// Find horizontal boundary lines
for (var y = 0; y <= bounds.Height; y++)
{
int startX = -1;

for (var x = 0; x <= bounds.Width; x++)
{
bool above = y > 0 && insideRegion [x, y - 1];
bool below = y < bounds.Height && insideRegion [x, y];

// A boundary exists where one side is inside and the other is outside
bool isBoundary = above != below;

if (isBoundary)
{
// Start a new segment or continue the current one
if (startX == -1)
{
startX = x;
}
}
else
{
// End the current segment if one exists
if (startX == -1)
{
continue;
}
int length = x - startX + 1; // Add 1 to make sure lines connect

lineCanvas.AddLine (new Point (startX + bounds.Left, y + bounds.Top), length, Orientation.Horizontal, style, attribute);
startX = -1;
}
}

// End any segment that reaches the right edge
if (startX == -1)
{
continue;
}

{
int length = bounds.Width + 1 - startX + 1; // Add 1 to make sure lines connect

lineCanvas.AddLine (new Point (startX + bounds.Left, y + bounds.Top), length, Orientation.Horizontal, style, attribute);
}
}

// Find vertical boundary lines
for (var x = 0; x <= bounds.Width; x++)
{
int startY = -1;

for (var y = 0; y <= bounds.Height; y++)
{
bool left = x > 0 && insideRegion [x - 1, y];
bool right = x < bounds.Width && insideRegion [x, y];

// A boundary exists where one side is inside and the other is outside
bool isBoundary = left != right;

if (isBoundary)
{
// Start a new segment or continue the current one
if (startY == -1)
{
startY = y;
}
}
else
{
// End the current segment if one exists
if (startY == -1)
{
continue;
}
int length = y - startY + 1; // Add 1 to make sure lines connect

lineCanvas.AddLine (new Point (x + bounds.Left, startY + bounds.Top), length, Orientation.Vertical, style, attribute);
startY = -1;
}
}

// End any segment that reaches the bottom edge
if (startY == -1)
{
continue;
}

{
int length = bounds.Height + 1 - startY + 1; // Add 1 to make sure lines connect

lineCanvas.AddLine (new Point (x + bounds.Left, startY + bounds.Top), length, Orientation.Vertical, style, attribute);
}
}
}
}
Loading
Loading