CsConsoleFormat icon indicating copy to clipboard operation
CsConsoleFormat copied to clipboard

Using a Negative Margin on a BlockElement Breaks Height Calculation

Open Jordan9232 opened this issue 4 years ago • 4 comments

I've tried using a negative top margin on a block element like this:

var div = new Div { Margin = new Thickness(0, -1, 0, 0) };

I've added some children to this element that should span 6 lines in height. Using the -1 top margin causes the element to only have a height of 1 line and the other lines are missing.

It will only render with the correct height if I remove the negative margin. It also seems to work okay if I use a bottom margin like this, but this causes an extra line to render after my div which is not what I want:

var div = new Div { Margin = new Thickness(0, -1, 0, 1) };

Jordan9232 avatar Oct 27 '21 13:10 Jordan9232

Please post a complete example which reproduces the problem (MCVE).

In case you've put the element with negative margins at the root, you won't get the library to output text above the caret. It always produces one rectangular area and prints it with Console methods.

What are you trying to achieve with negative margins? Maybe there's a simpler way to do that.

Athari avatar Oct 27 '21 22:10 Athari

Sorry I should have given a repeatable example. Basically what I was trying to do is have a grid inline with a span.

Here is an example:

var results = new List<dynamic>
{
  new { Id = 1, Name = "Paper", Count = 200 },
  new { Id = 2, Name = "Box", Count = 3 },
  new { Id = 3, Name = "Pen", Count = 20 }
};

var span = "Results: ".Red();

var grid = new Grid
{
  Columns = { Enumerable.Repeat(GridLength.Auto, 3) },
  Children =
  {
      new Cell("Id"),
      new Cell("Name"),
      new Cell("Count"),
      results.Select(item => new[] {
          new Cell(item.Id),
          new Cell(item.Name),
          new Cell(item.Count) { Align = Align.Right },
      })
  },
  Stroke = LineThickness.Single
};

var div = new Div(grid, "Count: ".Yellow(), new Span(results.Count.ToString()))
{
  Margin = new Thickness(span.Text.Length, -1, 0, 0)
};

var doc = new Document(span, div);

ConsoleRenderer.RenderDocument(doc);

If I change the top margin on the div from -1 to 0 I get this, which is close to what I want: image

The arrow I have there is showing I want the whole div to be up one line so it's inline with the "Results" span.

If I leave the -1 there I get this: image

On the other hand, if I get rid of the div and ONLY use the grid and have a -1 margin on the grid it works fine. It seems to be an issue on the Div.

Jordan9232 avatar Oct 28 '21 15:10 Jordan9232

What you need is a horizonal stacking container:

var doc = new Document(
  new Stack {
    Orientation = Horizontal,
    Children = {
      resultsHeaderSpan,
      resultsTableWithCountDiv,
    },
  }
);

You can also use a docking container:

var doc = new Document(
  new Dock(
    new Span("Results") { [Dock.ToProperty] = Left },
    new Span("Count") { [Dock.ToProperty] = Bottom },
    new Grid { ... },
  )
);

Grid would work too.

Not sure why exactly your approach doesn't work, but this should solve the problem in a clean way.

Athari avatar Oct 29 '21 11:10 Athari

Thanks! I like the Stack better, more readable than the Dock in my opinion, tried it out and it works perfect. I seen these elements mentioned in the readme but I didn't think to try them out because I didn't know what they did.

Jordan9232 avatar Oct 29 '21 12:10 Jordan9232