Add size param to splitPane action, split-pane subcommand (#8543)

## Summary of the Pull Request

Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one. 

This also adds the param to the `split-pane` subcommand.

### Examples
 
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) | 
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |

## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208

## Detailed Description of the Pull Request / Additional comments

I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version. 

## Validation Steps Performed

Added actions, played with the commandline, ran tests
This commit is contained in:
Mike Griese 2020-12-17 21:51:53 -06:00 committed by GitHub
parent 2485a638cb
commit 4f46129cb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 186 additions and 139 deletions

View file

@ -369,6 +369,13 @@
"splitMode": {
"default": "duplicate",
"description": "Control how the pane splits. Only accepts \"duplicate\" which will duplicate the focused pane's profile into a new pane."
},
"size": {
"default": 0.5,
"description": "Specify how large the new pane should be, as a fraction of the current pane's size. 1.0 would be 'all of the current pane', and 0.0 is 'None of the parent'. Accepts floating point values from 0-1 (default 0.5).",
"maximum": 1,
"minimum": 0,
"type": "number"
}
}
}

View file

@ -37,6 +37,7 @@ namespace SettingsModelLocalTests
TEST_METHOD(ManyCommandsSameAction);
TEST_METHOD(LayerCommand);
TEST_METHOD(TestSplitPaneArgs);
TEST_METHOD(TestSplitPaneBadSize);
TEST_METHOD(TestResourceKeyName);
TEST_METHOD(TestAutogeneratedName);
TEST_METHOD(TestLayerOnAutogeneratedName);
@ -147,7 +148,8 @@ namespace SettingsModelLocalTests
{ "name": "command1", "command": { "action": "splitPane", "split": "vertical" } },
{ "name": "command2", "command": { "action": "splitPane", "split": "horizontal" } },
{ "name": "command4", "command": { "action": "splitPane" } },
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } }
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } },
{ "name": "command6", "command": { "action": "splitPane", "size": 0.25 } },
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
@ -156,7 +158,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(4u, commands.Size());
VERIFY_ARE_EQUAL(5u, commands.Size());
{
auto command = commands.Lookup(L"command1");
@ -167,6 +169,7 @@ namespace SettingsModelLocalTests
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command2");
@ -177,6 +180,7 @@ namespace SettingsModelLocalTests
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command4");
@ -187,6 +191,7 @@ namespace SettingsModelLocalTests
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command5");
@ -197,8 +202,51 @@ namespace SettingsModelLocalTests
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
}
{
auto command = commands.Lookup(L"command6");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
}
}
void CommandTests::TestSplitPaneBadSize()
{
const std::string commands0String{ R"([
{ "name": "command1", "command": { "action": "splitPane", "size": 0.25 } },
{ "name": "command2", "command": { "action": "splitPane", "size": 1.0 } },
{ "name": "command3", "command": { "action": "splitPane", "size": 0 } },
{ "name": "command4", "command": { "action": "splitPane", "size": 50 } },
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
IMap<winrt::hstring, Command> commands = winrt::single_threaded_map<winrt::hstring, Command>();
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(3u, warnings.size());
VERIFY_ARE_EQUAL(1u, commands.Size());
{
auto command = commands.Lookup(L"command1");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
}
}
void CommandTests::TestResourceKeyName()
{
// This test checks looking up a name from a resource key.

View file

@ -486,7 +486,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, nullptr);
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@ -504,7 +504,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, nullptr);
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));

View file

@ -122,7 +122,11 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>())
{
_SplitPane(realArgs.SplitStyle(), realArgs.SplitMode(), realArgs.TerminalArgs());
_SplitPane(realArgs.SplitStyle(),
realArgs.SplitMode(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
realArgs.TerminalArgs());
args.Handled(true);
}
}

View file

@ -247,6 +247,10 @@ void AppCommandlineArgs::_buildSplitPaneParser()
_splitVertical,
RS_A(L"CmdSplitPaneVerticalArgDesc"));
subcommand._verticalOption->excludes(subcommand._horizontalOption);
auto* sizeOpt = subcommand.subcommand->add_option("-s,--size",
_splitPaneSize,
RS_A(L"CmdSplitPaneSizeArgDesc"));
sizeOpt->check(CLI::Range(0.01f, 0.99f));
// When ParseCommand is called, if this subcommand was provided, this
// callback function will be triggered on the same thread. We can be sure
@ -274,7 +278,7 @@ void AppCommandlineArgs::_buildSplitPaneParser()
style = SplitState::Vertical;
}
}
SplitPaneArgs args{ style, terminalArgs };
SplitPaneArgs args{ style, _splitPaneSize, terminalArgs };
splitPaneActionAndArgs.Args(args);
_startupActions.push_back(splitPaneActionAndArgs);
});

View file

@ -86,6 +86,7 @@ private:
bool _splitVertical{ false };
bool _splitHorizontal{ false };
float _splitPaneSize{ 0.5f };
int _focusTabIndex{ -1 };
bool _focusNextTab{ false };

View file

@ -42,7 +42,8 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
USES_RESOURCE(L"LegacyGlobalsProperty"),
USES_RESOURCE(L"FailedToParseCommandJson"),
USES_RESOURCE(L"FailedToWriteToSettings"),
USES_RESOURCE(L"InvalidColorSchemeInCmd")
USES_RESOURCE(L"InvalidColorSchemeInCmd"),
USES_RESOURCE(L"InvalidSplitSize")
};
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels {
USES_RESOURCE(L"NoProfilesText"),

View file

@ -21,7 +21,6 @@ using namespace TerminalApp;
static const int PaneBorderSize = 2;
static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
static const float Half = 0.50f;
// WARNING: Don't do this! This won't work
// Duration duration{ std::chrono::milliseconds{ 200 } };
@ -1216,32 +1215,6 @@ void Pane::_SetupEntranceAnimation()
setupAnimation(secondSize, false);
}
// Method Description:
// - Determines whether the pane can be split
// Arguments:
// - splitType: what type of split we want to create.
// Return Value:
// - True if the pane can be split. False otherwise.
bool Pane::CanSplit(SplitState splitType)
{
if (_IsLeaf())
{
return _CanSplit(splitType);
}
if (_firstChild->_HasFocusedChild())
{
return _firstChild->CanSplit(splitType);
}
if (_secondChild->_HasFocusedChild())
{
return _secondChild->CanSplit(splitType);
}
return false;
}
// Method Description:
// - This is a helper to determine if a given Pane can be split, but without
// using the ActualWidth() and ActualHeight() methods. This is used during
@ -1272,12 +1245,15 @@ bool Pane::CanSplit(SplitState splitType)
// - This method is highly similar to Pane::PreCalculateAutoSplit
std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> target,
SplitState splitType,
const float splitSize,
const winrt::Windows::Foundation::Size availableSpace) const
{
if (_IsLeaf())
{
if (target.get() == this)
{
const auto firstPrecent = 1.0f - splitSize;
const auto secondPercent = splitSize;
// If this pane is a leaf, and it's the pane we're looking for, use
// the available space to calculate which direction to split in.
const Size minSize = _GetMinSize();
@ -1290,17 +1266,19 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
else if (splitType == SplitState::Vertical)
{
const auto widthMinusSeparator = availableSpace.Width - CombinedPaneBorderSize;
const auto newWidth = widthMinusSeparator * Half;
const auto newFirstWidth = widthMinusSeparator * firstPrecent;
const auto newSecondWidth = widthMinusSeparator * secondPercent;
return { newWidth > minSize.Width };
return { newFirstWidth > minSize.Width && newSecondWidth > minSize.Width };
}
else if (splitType == SplitState::Horizontal)
{
const auto heightMinusSeparator = availableSpace.Height - CombinedPaneBorderSize;
const auto newHeight = heightMinusSeparator * Half;
const auto newFirstHeight = heightMinusSeparator * firstPrecent;
const auto newSecondHeight = heightMinusSeparator * secondPercent;
return { newHeight > minSize.Height };
return { newFirstHeight > minSize.Height && newSecondHeight > minSize.Height };
}
}
else
@ -1329,8 +1307,8 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
(availableSpace.Height - firstHeight) - PaneBorderSize :
availableSpace.Height;
const auto firstResult = _firstChild->PreCalculateCanSplit(target, splitType, { firstWidth, firstHeight });
return firstResult.has_value() ? firstResult : _secondChild->PreCalculateCanSplit(target, splitType, { secondWidth, secondHeight });
const auto firstResult = _firstChild->PreCalculateCanSplit(target, splitType, splitSize, { firstWidth, firstHeight });
return firstResult.has_value() ? firstResult : _secondChild->PreCalculateCanSplit(target, splitType, splitSize, { secondWidth, secondHeight });
}
// We should not possibly be getting here - both the above branches should
@ -1348,23 +1326,26 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
// - control: A TermControl to use in the new pane.
// Return Value:
// - The two newly created Panes
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType, const GUID& profile, const TermControl& control)
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType,
const float splitSize,
const GUID& profile,
const TermControl& control)
{
if (!_IsLeaf())
{
if (_firstChild->_HasFocusedChild())
{
return _firstChild->Split(splitType, profile, control);
return _firstChild->Split(splitType, splitSize, profile, control);
}
else if (_secondChild->_HasFocusedChild())
{
return _secondChild->Split(splitType, profile, control);
return _secondChild->Split(splitType, splitSize, profile, control);
}
return { nullptr, nullptr };
}
return _Split(splitType, profile, control);
return _Split(splitType, splitSize, profile, control);
}
// Method Description:
@ -1392,45 +1373,6 @@ SplitState Pane::_convertAutomaticSplitState(const SplitState& splitType) const
return splitType;
}
// Method Description:
// - Determines whether the pane can be split.
// Arguments:
// - splitType: what type of split we want to create.
// Return Value:
// - True if the pane can be split. False otherwise.
bool Pane::_CanSplit(SplitState splitType)
{
const Size actualSize{ gsl::narrow_cast<float>(_root.ActualWidth()),
gsl::narrow_cast<float>(_root.ActualHeight()) };
const Size minSize = _GetMinSize();
auto actualSplitType = _convertAutomaticSplitState(splitType);
if (actualSplitType == SplitState::None)
{
return false;
}
if (actualSplitType == SplitState::Vertical)
{
const auto widthMinusSeparator = actualSize.Width - CombinedPaneBorderSize;
const auto newWidth = widthMinusSeparator * Half;
return newWidth > minSize.Width;
}
if (actualSplitType == SplitState::Horizontal)
{
const auto heightMinusSeparator = actualSize.Height - CombinedPaneBorderSize;
const auto newHeight = heightMinusSeparator * Half;
return newHeight > minSize.Height;
}
return false;
}
// Method Description:
// - Does the bulk of the work of creating a new split. Initializes our UI,
// creates a new Pane to host the control, registers event handlers.
@ -1440,7 +1382,10 @@ bool Pane::_CanSplit(SplitState splitType)
// - control: A TermControl to use in the new pane.
// Return Value:
// - The two newly created Panes
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState splitType, const GUID& profile, const TermControl& control)
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState splitType,
const float splitSize,
const GUID& profile,
const TermControl& control)
{
if (splitType == SplitState::None)
{
@ -1465,7 +1410,7 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
_gotFocusRevoker.revoke();
_splitState = actualSplitType;
_desiredSplitPosition = Half;
_desiredSplitPosition = 1.0f - splitSize;
// Remove any children we currently have. We can't add the existing
// TermControl to a new grid until we do this.

View file

@ -58,14 +58,16 @@ public:
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
const GUID& profile,
const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target, const winrt::Windows::Foundation::Size parentSize) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,
const winrt::Windows::Foundation::Size parentSize) const;
std::optional<bool> PreCalculateCanSplit(const std::shared_ptr<Pane> target,
winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
const winrt::Windows::Foundation::Size availableSpace) const;
void Shutdown();
void Close();
@ -120,8 +122,8 @@ private:
bool _HasFocusedChild() const noexcept;
void _SetupChildCloseHandlers();
bool _CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
const GUID& profile,
const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);

View file

@ -249,6 +249,10 @@
<value>Found a command with an invalid "colorScheme". This command will be ignored. Make sure that when setting a "colorScheme", the value matches the "name" of a color scheme in the "schemes" list.</value>
<comment>{Locked="\"colorScheme\"","\"name\"","\"schemes\""}</comment>
</data>
<data name="InvalidSplitSize" xml:space="preserve">
<value>Found a "splitPane" command with an invalid "size". This command will be ignored. Make sure the size is between 0 and 1, exclusive.</value>
<comment>{Locked="\"splitPane\"","\"size\""}</comment>
</data>
<data name="CmdCommandArgDesc" xml:space="preserve">
<value>An optional command, with arguments, to be spawned in the new tab or pane</value>
</data>
@ -268,6 +272,9 @@
<data name="CmdFocusTabTargetArgDesc" xml:space="preserve">
<value>Move focus the tab at the given index</value>
</data>
<data name="CmdSplitPaneSizeArgDesc" xml:space="preserve">
<value>Specify the size as a percentage of the parent pane. Valid values are between (0,1), exclusive.</value>
</data>
<data name="CmdNewTabDesc" xml:space="preserve">
<value>Create a new tab</value>
</data>

View file

@ -209,6 +209,7 @@ namespace winrt::TerminalApp::implementation
{
page->_SplitPane(SplitState::Automatic,
SplitType::Manual,
0.5f,
nullptr);
}
else
@ -560,6 +561,7 @@ namespace winrt::TerminalApp::implementation
{
page->_SplitPane(SplitState::Automatic,
SplitType::Manual,
0.5f,
newTerminalArgs);
}
else
@ -809,7 +811,7 @@ namespace winrt::TerminalApp::implementation
TermControl newControl{ settings, debugConnection };
_RegisterTerminalEvents(newControl, *newTabImpl);
// Split (auto) with the debug tap.
newTabImpl->SplitPane(SplitState::Automatic, profileGuid, newControl);
newTabImpl->SplitPane(SplitState::Automatic, 0.5f, profileGuid, newControl);
}
// This kicks off TabView::SelectionChanged, in response to which
@ -1578,6 +1580,7 @@ namespace winrt::TerminalApp::implementation
// configurations. See CascadiaSettings::BuildSettings for more details.
void TerminalPage::_SplitPane(const SplitState splitType,
const SplitType splitMode,
const float splitSize,
const NewTerminalArgs& newTerminalArgs)
{
// Do nothing if we're requesting no split.
@ -1647,7 +1650,7 @@ namespace winrt::TerminalApp::implementation
realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, availableSpace);
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
@ -1660,7 +1663,7 @@ namespace winrt::TerminalApp::implementation
_UnZoomIfNeeded();
focusedTab->SplitPane(realSplitType, realGuid, newControl);
focusedTab->SplitPane(realSplitType, splitSize, realGuid, newControl);
}
CATCH_LOG();
}

View file

@ -192,8 +192,13 @@ namespace winrt::TerminalApp::implementation
// Todo: add more event implementations here
// MSFT:20641986: Add keybindings for New Window
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType, const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
const float splitSize = 0.5f,
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ScrollPage(ScrollDirection scrollDirection);
void _ScrollToBufferEdge(ScrollDirection scrollDirection);
void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::TerminalControl::KeyChord& keyChord);

View file

@ -293,17 +293,6 @@ namespace winrt::TerminalApp::implementation
control.ScrollViewport(currentOffset + delta);
}
// Method Description:
// - Determines whether the focused pane has sufficient space to be split.
// Arguments:
// - splitType: The type of split we want to create.
// Return Value:
// - True if the focused pane can be split. False otherwise.
bool TerminalTab::CanSplitPane(SplitState splitType)
{
return _activePane->CanSplit(splitType);
}
// Method Description:
// - Split the focused pane in our tree of panes, and place the
// given TermControl into the newly created pane.
@ -313,11 +302,14 @@ namespace winrt::TerminalApp::implementation
// - control: A TermControl to use in the new pane.
// Return Value:
// - <none>
void TerminalTab::SplitPane(SplitState splitType, const GUID& profile, TermControl& control)
void TerminalTab::SplitPane(SplitState splitType,
const float splitSize,
const GUID& profile,
TermControl& control)
{
// Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID
const auto activePaneId = _activePane->Id();
auto [first, second] = _activePane->Split(splitType, profile, control);
auto [first, second] = _activePane->Split(splitType, splitSize, profile, control);
first->Id(activePaneId);
second->Id(_nextPaneId);
++_nextPaneId;
@ -943,9 +935,11 @@ namespace winrt::TerminalApp::implementation
return _rootPane->PreCalculateAutoSplit(_activePane, availableSpace).value_or(SplitState::Vertical);
}
bool TerminalTab::PreCalculateCanSplit(SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const
bool TerminalTab::PreCalculateCanSplit(SplitState splitType,
const float splitSize,
winrt::Windows::Foundation::Size availableSpace) const
{
return _rootPane->PreCalculateCanSplit(_activePane, splitType, availableSpace).value_or(false);
return _rootPane->PreCalculateCanSplit(_activePane, splitType, splitSize, availableSpace).value_or(false);
}
// Method Description:

View file

@ -30,15 +30,19 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget Scroll(const int delta);
bool CanSplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const GUID& profile, winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
const GUID& profile,
winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);
winrt::fire_and_forget HideIcon(const bool hide);
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
winrt::Microsoft::Terminal::Settings::Model::SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) const;
bool PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const;
bool PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
winrt::Windows::Foundation::Size availableSpace) const;
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);

View file

@ -231,8 +231,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
winrt::hstring SplitPaneArgs::GenerateName() const
{
// The string will be similar to the following:
// * "Duplicate pane[, split: <direction>][, new terminal arguments...]"
// * "Split pane[, split: <direction>][, new terminal arguments...]"
// * "Duplicate pane[, split: <direction>][, size: <size>%][, new terminal arguments...]"
// * "Split pane[, split: <direction>][, size: <size>%][, new terminal arguments...]"
//
// Direction will only be added to the string if the split direction is
// not "auto".
@ -262,6 +262,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
break;
}
if (_SplitSize != .5f)
{
ss << L"size: " << (_SplitSize * 100) << L"%, ";
}
winrt::hstring newTerminalArgsStr;
if (_TerminalArgs)
{

View file

@ -379,6 +379,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct SplitPaneArgs : public SplitPaneArgsT<SplitPaneArgs>
{
SplitPaneArgs() = default;
SplitPaneArgs(SplitState style, double size, const Model::NewTerminalArgs& terminalArgs) :
_SplitStyle{ style },
_SplitSize{ size },
_TerminalArgs{ terminalArgs } {};
SplitPaneArgs(SplitState style, const Model::NewTerminalArgs& terminalArgs) :
_SplitStyle{ style },
_TerminalArgs{ terminalArgs } {};
@ -387,9 +391,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
GETSET_PROPERTY(SplitState, SplitStyle, SplitState::Automatic);
GETSET_PROPERTY(Model::NewTerminalArgs, TerminalArgs, nullptr);
GETSET_PROPERTY(SplitType, SplitMode, SplitType::Manual);
GETSET_PROPERTY(double, SplitSize, .5);
static constexpr std::string_view SplitKey{ "split" };
static constexpr std::string_view SplitModeKey{ "splitMode" };
static constexpr std::string_view SplitSizeKey{ "size" };
public:
hstring GenerateName() const;
@ -402,6 +408,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return otherAsUs->_SplitStyle == _SplitStyle &&
(otherAsUs->_TerminalArgs ? otherAsUs->_TerminalArgs.Equals(_TerminalArgs) :
otherAsUs->_TerminalArgs == _TerminalArgs) &&
otherAsUs->_SplitSize == _SplitSize &&
otherAsUs->_SplitMode == _SplitMode;
}
return false;
@ -413,6 +420,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
args->_TerminalArgs = NewTerminalArgs::FromJson(json);
JsonUtils::GetValueForKey(json, SplitKey, args->_SplitStyle);
JsonUtils::GetValueForKey(json, SplitModeKey, args->_SplitMode);
JsonUtils::GetValueForKey(json, SplitSizeKey, args->_SplitSize);
if (args->_SplitSize >= 1 || args->_SplitSize <= 0)
{
return { nullptr, { SettingsLoadWarnings::InvalidSplitSize } };
}
return { *args, {} };
}
IActionArgs Copy() const
@ -421,6 +433,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
copy->_SplitStyle = _SplitStyle;
copy->_TerminalArgs = _TerminalArgs.Copy();
copy->_SplitMode = _SplitMode;
copy->_SplitSize = _SplitSize;
return *copy;
}
};

View file

@ -135,12 +135,14 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass SplitPaneArgs : IActionArgs
{
SplitPaneArgs(SplitState split, Double size, NewTerminalArgs terminalArgs);
SplitPaneArgs(SplitState split, NewTerminalArgs terminalArgs);
SplitPaneArgs(SplitType splitMode);
SplitState SplitStyle { get; };
NewTerminalArgs TerminalArgs { get; };
SplitType SplitMode { get; };
Double SplitSize { get; };
};
[default_interface] runtimeclass OpenSettingsArgs : IActionArgs

View file

@ -19,6 +19,7 @@ namespace Microsoft.Terminal.Settings.Model
FailedToParseCommandJson = 9,
FailedToWriteToSettings = 10,
InvalidColorSchemeInCmd = 11,
InvalidSplitSize = 12,
WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder.
};

View file

@ -24,5 +24,6 @@ call %TAEF% ^
%OPENCON%\bin\%PLATFORM%\%_LAST_BUILD_CONF%\til.unit.tests.dll ^
%OPENCON%\bin\%PLATFORM%\%_LAST_BUILD_CONF%\UnitTests_TerminalApp\Terminal.App.Unit.Tests.dll ^
%_TestHostAppPath%\TerminalApp.LocalTests.dll ^
%_TestHostAppPath%\SettingsModel.LocalTests.dll ^
%*