Skip to content

Commit

Permalink
Make window resizing actually work (#11)
Browse files Browse the repository at this point in the history
* resizing the window now resizes the underlying console, bugs remain

* make shrinking window work right

* clean up a bit, set grid background to palette background with a hack for now
  • Loading branch information
doubleyewdee authored Dec 18, 2018
1 parent b49626d commit 978c4ff
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 35 deletions.
36 changes: 34 additions & 2 deletions src/ConsoleBuffer/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace ConsoleBuffer

public sealed class Buffer : INotifyPropertyChanged
{
public const int MinimumWidth = 80;
public const int MinimumHeight = 25;

private readonly SequenceParser parser = new SequenceParser();
private readonly CircularBuffer<Line> lines = new CircularBuffer<Line>(short.MaxValue);
private readonly object renderLock = new object();
Expand All @@ -20,6 +23,11 @@ public sealed class Buffer : INotifyPropertyChanged
private int currentChar;
private Character characterTemplate = new Character { Glyph = 0x0 };

/// <summary>
/// The viewable dimensions of the buffer.
/// </summary>
public (int X, int Y) ViewDimensions => (this.Width, this.Height);

/// <summary>
/// we store X/Y as 0-offset indexes for convenience. escape codes will pass these around as 1-offset (top left is 1,1)
/// and we'll translate that nonsense where we have to.
Expand Down Expand Up @@ -48,11 +56,11 @@ private int CurrentLine
/// <summary>
/// Width of the console in characters.
/// </summary>
public short Width { get; set; }
public short Width { get; private set; }
/// <summary>
/// Height of the console in characters.
/// </summary>
public short Height { get; set; }
public short Height { get; private set; }

/// <summary>
/// Returns the total number of lines in the buffer.
Expand All @@ -78,6 +86,30 @@ public Buffer(short width, short height)
this.bottomVisibleLine = this.MaxCursorY;
}

public void SetDimensions(int width, int height)
{
if (width < MinimumWidth || width > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(width));
}
if (height < MinimumHeight || height > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(height));
}

lock (this.renderLock)
{
if (height != this.Height || width != this.Width)
{
var heightDiff = height - this.Height;
this.Width = (short)width;
this.Height = (short)height;
this.topVisibleLine -= heightDiff;
this.OnPropertyChanged(nameof(this.ViewDimensions));
}
}
}

/// <summary>
/// Append the given string to the buffer. The string will be converted to UTF8 and then written to the buffer as usual.
/// </summary>
Expand Down
14 changes: 12 additions & 2 deletions src/ConsoleBuffer/ConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ namespace ConsoleBuffer
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;

Expand Down Expand Up @@ -65,6 +63,18 @@ public ConsoleWrapper(string command)
this.Height = 25;
this.Width = 80;
this.Buffer = new Buffer(this.Width, this.Height);
this.Buffer.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == nameof(this.Buffer.ViewDimensions))
{
if ((this.Width, this.Height) != this.Buffer.ViewDimensions)
{
this.Width = this.Buffer.Width;
this.Height = this.Buffer.Height;
NativeMethods.ResizePseudoConsole(this.consoleHandle, new NativeMethods.COORD { X = this.Width, Y = this.Height });
}
}
};

this.CreatePTY();
this.InitializeStartupInfo();
Expand Down
7 changes: 4 additions & 3 deletions src/condo/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
Title="MainWindow" SizeToContent="WidthAndHeight">
<Grid Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer Name="scrollViewer" Grid.Column="0" Grid.Row="0"
CanContentScroll="true" IsDeferredScrollingEnabled="true" Focusable="False">
CanContentScroll="true" IsDeferredScrollingEnabled="true" Focusable="False"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<local:Screen x:Name="screen" />
</ScrollViewer>
</Grid>
Expand Down
9 changes: 3 additions & 6 deletions src/condo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace condo
using System.ComponentModel;
using System.Security;
using System.Windows;
using System.Windows.Media;
using ConsoleBuffer;
using Microsoft.Win32;

Expand Down Expand Up @@ -57,6 +58,8 @@ public MainWindow()
this.mellowPalette[14] = new Character.ColorInfo { R = 0x8a, G = 0xbe, B = 0xb7 };
this.mellowPalette[15] = new Character.ColorInfo { R = 0xc5, G = 0xc8, B = 0xc6 };
this.screen.Palette = this.mellowPalette;
// XXX: this is hacky but keeps things from being default ugly. ideally want to snap to cells while resizing window.
this.grid.Background = new SolidColorBrush(new Color { R = this.mellowPalette[0].R, G = this.mellowPalette[0].G, B = this.mellowPalette[0].B, A = 255 });

this.Loaded += this.OnLoaded;
}
Expand Down Expand Up @@ -132,12 +135,6 @@ private void InitializeWindowSizeHandling()

this.MinWidth = this.ActualWidth;
this.MinHeight = this.ActualHeight;

this.scrollViewer.SizeChanged += (_, args) =>
{
this.MinWidth = this.windowFrameWidth + args.NewSize.Width;
this.MinHeight = this.windowFrameHeight + args.NewSize.Height;
};
}

private void HandleClosing(object sender, CancelEventArgs e)
Expand Down
54 changes: 32 additions & 22 deletions src/condo/Screen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public ConsoleBuffer.Buffer Buffer
}

public XtermPalette Palette { get; set; } = XtermPalette.Default;
public double CellWidth { get; private set; }
public double CellHeight { get; private set; }

private bool RenderCursor => this.Buffer.CursorVisible && this.VerticalOffset == this.ExtentHeight - this.ViewportHeight;

Expand All @@ -39,7 +41,6 @@ public ConsoleBuffer.Buffer Buffer
private Typeface typeface;
private GlyphTypeface glyphTypeface;
private int fontSizeEm = 16;
private double cellWidth, cellHeight;
private Point baselineOrigin;
private Rect cellRectangle;
private double underlineY;
Expand Down Expand Up @@ -83,7 +84,7 @@ public Screen() : this(new ConsoleBuffer.Buffer(80, 25))
public Screen(ConsoleBuffer.Buffer buffer)
{
this.dpiInfo = VisualTreeHelper.GetDpi(this);
this.children = new VisualCollection(this);
this.children = new VisualCollection(this) { new DrawingVisual { Offset = new Vector(0, 0) } };
this.Buffer = buffer;

this.cursorBlinkWatch.Start();
Expand Down Expand Up @@ -123,6 +124,10 @@ private void OnBufferPropertyChanged(object sender, PropertyChangedEventArgs arg
this.shouldRedraw = 1;
}
}
else if (args.PropertyName == nameof(this.Buffer.ViewDimensions))
{
this.Resize();
}
}

private void RenderFrame(object sender, EventArgs e)
Expand Down Expand Up @@ -170,7 +175,22 @@ protected override Visual GetVisualChild(int index)

protected override Size MeasureOverride(Size availableSize)
{
return new Size(this.cellWidth * this.horizontalCells, this.cellHeight * this.verticalCells);
if (this.ActualHeight > availableSize.Height || this.ActualWidth > availableSize.Width)
{
var x = Math.Max(ConsoleBuffer.Buffer.MinimumWidth, (int)Math.Floor(availableSize.Width / this.CellWidth));
var y = Math.Max(ConsoleBuffer.Buffer.MinimumHeight, (int)Math.Floor(availableSize.Height / this.CellHeight));
return new Size(this.CellWidth * x, this.CellHeight * y);
}

return new Size(this.horizontalCells * this.CellWidth, this.verticalCells * this.CellHeight);
}

protected override Size ArrangeOverride(Size finalSize)
{
var x = (int)Math.Floor(finalSize.Width / this.CellWidth);
var y = (int)Math.Floor(finalSize.Height / this.CellHeight);
this.Buffer.SetDimensions(x, y);
return new Size(this.CellWidth * x, this.CellHeight * y);
}

private void Resize()
Expand All @@ -179,23 +199,18 @@ private void Resize()
this.verticalCells = this.Buffer.Height;
this.characters = new Character[this.Buffer.Width, this.Buffer.Height];

this.children.Clear();
this.children.Add(new DrawingVisual { Offset = new Vector(0, 0) });

this.cellGuidelines = new GuidelineSet();
this.cellGuidelines.GuidelinesX.Add(0);
this.cellGuidelines.GuidelinesY.Add(0);
for (var x = 0; x < this.horizontalCells; ++x)
{
this.cellGuidelines.GuidelinesX.Add(this.cellWidth * (x + 1));
this.cellGuidelines.GuidelinesX.Add(this.CellWidth * (x + 1));
}
for (var y = 0; y < this.verticalCells; ++y)
{
this.cellGuidelines.GuidelinesY.Add(this.cellHeight * (y + 1));
this.cellGuidelines.GuidelinesY.Add(this.CellHeight * (y + 1));
}

this.Width = this.horizontalCells * this.cellWidth;
this.Height = this.verticalCells * this.cellHeight;
this.consoleBufferSize = this.Buffer.BufferSize;
this.cellGuidelines.Freeze();

Expand All @@ -218,21 +233,16 @@ private void SetFontSize(int newFontSizeEm)
{
throw new InvalidOperationException("Could not get desired font.");
}
this.cellWidth = this.glyphTypeface.AdvanceWidths[0] * this.fontSizeEm;
this.cellHeight = this.glyphTypeface.Height * this.fontSizeEm;
this.CellWidth = this.glyphTypeface.AdvanceWidths[0] * this.fontSizeEm;
this.CellHeight = this.glyphTypeface.Height * this.fontSizeEm;
this.baselineOrigin = new Point(0, this.glyphTypeface.Baseline * this.fontSizeEm);
this.underlineY = this.baselineOrigin.Y - this.glyphTypeface.UnderlinePosition * this.fontSizeEm;
this.underlineHeight = (this.cellHeight * this.glyphTypeface.UnderlineThickness);
this.cellRectangle = new Rect(new Size(this.cellWidth, this.cellHeight));
this.underlineHeight = (this.CellHeight * this.glyphTypeface.UnderlineThickness);
this.cellRectangle = new Rect(new Size(this.CellWidth, this.CellHeight));

this.Resize();
}

private DrawingVisual GetCell(int x, int y)
{
return this.children[x + y * this.horizontalCells] as DrawingVisual;
}

private (Character.ColorInfo fg, Character.ColorInfo bg) GetCharacterColors(Character ch)
{
var cfg = ch.Foreground;
Expand Down Expand Up @@ -336,7 +346,7 @@ private void Redraw()
var backgroundBrush = this.brushCache.GetBrush(bg.R, bg.G, bg.B);
var foregroundBrush = this.brushCache.GetBrush(fg.R, fg.G, fg.B);

dc.DrawRectangle(backgroundBrush, null, new Rect(runStart * this.cellWidth, y * this.cellHeight, charCount * this.cellWidth, this.cellHeight));
dc.DrawRectangle(backgroundBrush, null, new Rect(runStart * this.CellWidth, y * this.CellHeight, charCount * this.CellWidth, this.CellHeight));

// if all characters are null and we're at EOL stop after rendering only the background
// XXX: this feels REALLY hacky to me
Expand All @@ -345,10 +355,10 @@ private void Redraw()
continue;
}

var glyphOrigin = new Point((runStart * this.cellWidth) + this.baselineOrigin.X, (y * this.cellHeight) + this.baselineOrigin.Y);
var glyphOrigin = new Point((runStart * this.CellWidth) + this.baselineOrigin.X, (y * this.CellHeight) + this.baselineOrigin.Y);
if (startChar.Underline)
{
var underlineRectangle = new Rect(glyphOrigin.X, y * this.cellHeight + this.underlineY, charCount * this.cellWidth, this.underlineHeight);
var underlineRectangle = new Rect(glyphOrigin.X, y * this.CellHeight + this.underlineY, charCount * this.CellWidth, this.underlineHeight);
dc.DrawRectangle(foregroundBrush, null, underlineRectangle);
}

Expand Down

0 comments on commit 978c4ff

Please sign in to comment.