Skip to content

Commit

Permalink
Added autofill option for WPF container and exposed max columns and r…
Browse files Browse the repository at this point in the history
…ows that the container can host.
  • Loading branch information
javierdlg committed Oct 5, 2020
1 parent 4a11497 commit 6a5a4f7
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 26 deletions.
16 changes: 15 additions & 1 deletion src/cascadia/PublicTerminalCore/HwndTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data)
publicTerminal->SendOutput(data);
}

HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double height, _Out_ COORD* dimensions)
HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);

Expand All @@ -450,6 +450,20 @@ HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double heig
return publicTerminal->Refresh(windowSize, dimensions);
}

HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);

const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, { width, height });
const auto viewInCharacters = publicTerminal->_renderEngine->GetViewportInCharacters(viewInPixels);

dimensions->X = viewInCharacters.Width();
dimensions->Y = viewInCharacters.Height();

return S_OK;
}


void _stdcall TerminalDpiChanged(void* terminal, int newDpi)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/PublicTerminalCore/HwndTerminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ extern "C" {
__declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal);
__declspec(dllexport) void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data);
__declspec(dllexport) void _stdcall TerminalRegisterScrollCallback(void* terminal, void __stdcall callback(int, int, int));
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double height, _Out_ COORD* dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
__declspec(dllexport) void _stdcall TerminalDpiChanged(void* terminal, int newDpi);
__declspec(dllexport) void _stdcall TerminalUserScroll(void* terminal, int viewTop);
__declspec(dllexport) void _stdcall TerminalClearSelection(void* terminal);
Expand Down Expand Up @@ -91,6 +92,7 @@ struct HwndTerminal : ::Microsoft::Console::Types::IControlAccessibilityInfo

friend HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal);
friend HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions);
friend HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
friend void _stdcall TerminalDpiChanged(void* terminal, int newDpi);
friend void _stdcall TerminalUserScroll(void* terminal, int viewTop);
friend void _stdcall TerminalClearSelection(void* terminal);
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/WpfTerminalControl/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ public enum SetWindowPosFlags : uint
[DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint TerminalResize(IntPtr terminal, COORD dimensions);

[DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern uint TerminalCalculateResize(IntPtr terminal, short width, short height, out COORD dimensions);

[DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern void TerminalDpiChanged(IntPtr terminal, int newDpi);

Expand Down
85 changes: 63 additions & 22 deletions src/cascadia/WpfTerminalControl/TerminalContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,6 @@ namespace Microsoft.Terminal.Wpf
/// </remarks>
public class TerminalContainer : HwndHost
{
private static void UnpackKeyMessage(IntPtr wParam, IntPtr lParam, out ushort vkey, out ushort scanCode, out ushort flags)
{
ulong scanCodeAndFlags = (((ulong)lParam) & 0xFFFF0000) >> 16;
scanCode = (ushort)(scanCodeAndFlags & 0x00FFu);
flags = (ushort)(scanCodeAndFlags & 0xFF00u);
vkey = (ushort)wParam;
}

private static void UnpackCharMessage(IntPtr wParam, IntPtr lParam, out char character, out ushort scanCode, out ushort flags)
{
UnpackKeyMessage(wParam, lParam, out ushort vKey, out scanCode, out flags);
character = (char)vKey;
}

private ITerminalConnection connection;
private IntPtr hwnd;
private IntPtr terminal;
Expand Down Expand Up @@ -77,15 +63,33 @@ public TerminalContainer()
internal event EventHandler<int> UserScrolled;

/// <summary>
/// Gets the character rows available to the terminal.
/// Gets or sets a value indicating whether if the renderer should automatically resize to fill the control
/// on user action.
/// </summary>
public bool AutoFill { get; set; } = true;

/// <summary>
/// Gets the current character rows available to the terminal.
/// </summary>
internal int Rows { get; private set; }

/// <summary>
/// Gets the character columns available to the terminal.
/// Gets the current character columns available to the terminal.
/// </summary>
internal int Columns { get; private set; }

/// <summary>
/// Gets the maximum amount of character rows that can fit in this control.
/// </summary>
/// <remarks>This will be in sync with <see cref="Rows"/> unless autofit is set to false.</remarks>
internal int MaxRows { get; private set; }

/// <summary>
/// Gets the maximum amount of character columns that can fit in this control.
/// </summary>
/// <remarks>This will be in sync with <see cref="Columns"/> unless autofit is set to false.</remarks>
internal int MaxColumns { get; private set; }

/// <summary>
/// Gets the window handle of the terminal.
/// </summary>
Expand Down Expand Up @@ -172,7 +176,7 @@ internal string GetSelectedText()
}

/// <summary>
/// Resizes the terminal.
/// Resizes the terminal using row and column count as the new size.
/// </summary>
/// <param name="rows">Number of rows to show.</param>
/// <param name="columns">Number of columns to show.</param>
Expand All @@ -186,8 +190,16 @@ internal void Resize(uint rows, uint columns)

NativeMethods.TerminalResize(this.terminal, dimensions);

this.Rows = dimensions.Y;
// If AutoFill is true, keep Rows and Columns in sync with MaxRows and MaxColumns.
// Otherwise, MaxRows and MaxColumns will be set on startup and on control resize by the user.
if (this.AutoFill)
{
this.MaxColumns = dimensions.X;
this.MaxRows = dimensions.Y;
}

this.Columns = dimensions.X;
this.Rows = dimensions.Y;

this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X);
}
Expand Down Expand Up @@ -238,6 +250,20 @@ protected override void DestroyWindowCore(HandleRef hwnd)
this.terminal = IntPtr.Zero;
}

private static void UnpackKeyMessage(IntPtr wParam, IntPtr lParam, out ushort vkey, out ushort scanCode, out ushort flags)
{
ulong scanCodeAndFlags = (((ulong)lParam) & 0xFFFF0000) >> 16;
scanCode = (ushort)(scanCodeAndFlags & 0x00FFu);
flags = (ushort)(scanCodeAndFlags & 0xFF00u);
vkey = (ushort)wParam;
}

private static void UnpackCharMessage(IntPtr wParam, IntPtr lParam, out char character, out ushort scanCode, out ushort flags)
{
UnpackKeyMessage(wParam, lParam, out ushort vKey, out scanCode, out flags);
character = (char)vKey;
}

private void TerminalContainer_GotFocus(object sender, RoutedEventArgs e)
{
e.Handled = true;
Expand Down Expand Up @@ -299,13 +325,28 @@ private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam
break;
}

NativeMethods.TerminalTriggerResize(this.terminal, windowpos.cx, windowpos.cy, out var dimensions);
NativeMethods.COORD dimensions;

this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X);
this.Columns = dimensions.X;
this.Rows = dimensions.Y;
// We only trigger a resize if we want to autofill to maximum size.
if (this.AutoFill)
{
NativeMethods.TerminalTriggerResize(this.terminal, windowpos.cx, windowpos.cy, out dimensions);

this.Columns = dimensions.X;
this.Rows = dimensions.Y;
this.MaxColumns = dimensions.X;
this.MaxRows = dimensions.Y;
}
else
{
NativeMethods.TerminalCalculateResize(this.terminal, (short)windowpos.cx, (short)windowpos.cy, out dimensions);
this.MaxColumns = dimensions.X;
this.MaxRows = dimensions.Y;
}

this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X);
break;

case NativeMethods.WindowMessage.WM_MOUSEWHEEL:
var delta = (short)(((long)wParam) >> 16);
this.UserScrolled?.Invoke(this, delta);
Expand Down
24 changes: 22 additions & 2 deletions src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,35 @@ public TerminalControl()
}

/// <summary>
/// Gets the character rows available to the terminal.
/// Gets the current character rows available to the terminal.
/// </summary>
public int Rows => this.termContainer.Rows;

/// <summary>
/// Gets the character columns available to the terminal.
/// Gets the current character columns available to the terminal.
/// </summary>
public int Columns => this.termContainer.Columns;

/// <summary>
/// Gets the maximum amount of character rows that can fit in this control.
/// </summary>
public int MaxRows => this.termContainer.MaxRows;

/// <summary>
/// Gets the maximum amount of character columns that can fit in this control.
/// </summary>
public int MaxColumns => this.termContainer.MaxColumns;

/// <summary>
/// Gets or sets a value indicating whether if the renderer should automatically resize to fill the control
/// on user action.
/// </summary>
public bool AutoFill
{
get => this.termContainer.AutoFill;
set => this.termContainer.AutoFill = value;
}

/// <summary>
/// Sets the connection to a terminal backend.
/// </summary>
Expand Down

1 comment on commit 6a5a4f7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New misspellings found, please review:

  • autofill
  • autofit
To accept these changes, run the following commands
perl -e '
my @expect_files=qw('".github/actions/spell-check/expect/alphabet.txt
.github/actions/spell-check/expect/expect.txt
.github/actions/spell-check/expect/web.txt"');
@ARGV=@expect_files;
my @stale=qw('"akb appdata Autogenerated debian debugbreak decf DECLL DECSMBV esa guidgenerator Inplace keith keybound notypeopt openlogo restrictederrorinfo richturn Scs Switchto winver Wlk wslhome "');
my $re=join "|", @stale;
my $suffix=".".time();
my $previous="";
sub maybe_unlink { unlink($_[0]) if $_[0]; }
while (<>) {
  if ($ARGV ne $old_argv) { maybe_unlink($previous); $previous="$ARGV$suffix"; rename($ARGV, $previous); open(ARGV_OUT, ">$ARGV"); select(ARGV_OUT); $old_argv = $ARGV; }
  next if /^($re)(?:$| .*)/; print;
}; maybe_unlink($previous);'
perl -e '
my $new_expect_file=".github/actions/spell-check/expect/6a5a4f78bf72facc144fa9f9bfecfc5c2db2477a.txt";
open FILE, q{<}, $new_expect_file; chomp(my @words = <FILE>); close FILE;
my @add=qw('"autofill autofit autogenerated Debian inplace WINVER "');
my %items; @items{@words} = @words x (1); @items{@add} = @add x (1);
@words = sort {lc($a) cmp lc($b)} keys %items;
open FILE, q{>}, $new_expect_file; for my $word (@words) { print FILE "$word\n" if $word =~ /\w/; };
close FILE;'
git add .github/actions/spell-check/expect || echo '... you want to ensure .github/actions/spell-check/expect/6a5a4f78bf72facc144fa9f9bfecfc5c2db2477a.txt is added to your repository...'
✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. You can copy the contents of each perl command excluding the outer ' marks and dropping any '"/"' quotation mark pairs into a file and then run perl file.pl from the root of the repository to run the code. Alternatively, you can manually insert the items...

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spell-check/dictionary/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spell-check/dictionary/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spell-check/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spell-check/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The :check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

⚠️ Reviewers

At present, the action that triggered this message will not show its ❌ in this PR unless the branch is within this repository.
Thus, you should make sure that this comment has been addressed before encouraging the merge bot to merge this PR.

Please sign in to comment.