-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework and simplify selection in TermControl #5096
Conversation
This commit rewrites selection handling at the TermControl layer. Previously, we were keeping track of a number of redundant variables that were easy to get out of sync. The new selection model is as follows: * A single left click will always begin a _pending_ selection operation * A single left click will always clear a selection (#4477) * A double left click will always begin a word selection * A triple left click will always begin a line selection * A selection will only truly start when the cursor moves a quarter of the smallest dimension of a cell (usually its width) in any direction _This eliminates the selection of a single cell on one click._ (#4282, #5082) * We now keep track of whether the selection has been "copied", or "updated" since it was last copied. If an endpoint moves, it is updated. For copy-on-select, it is only copied if it's updated. (#4740) Because of this, we can stop tracking the position of the focus-raising click, and whether it was part of click-drag operation. All clicks can _become_ part of a click-drag operation if the user drags. We can also eliminate the special handling of single cell selection at the TerminalCore layer: since TermControl determines when to begin a selection, TerminalCore no longer needs to know whether copy on select is enabled _or_ whether the user has started and then backtracked over a single cell. This is now implicit in TermControl. Fixes #4082; Fixes #4477
This one is a bit concerning. Really only because ConHost does not do this. I hate to say it, but it makes me wonder if we should make this particular setting a pointer binding in #1553
These are all things I really like and want. I think the only reason we needed Side note: #4082 is probably not the issue you want to link here? |
Yeah, I meant #5082. Let’s talk about selection clearing: why do we want to keep the selection when you click somewhere else? All other text buffer applications clear it to start another selection. Right now there’s no way to even abort a selection with the mouse (see complaints in 4477) |
I legit think “because conhost did it” is an okay reason for some things, but Terminal also presents a chance to change the things conhost did that don’t make sense. Right now, conhost always starts and completes a selection on a single click so there isn’t a clear state—all you can do is move to another single cell selection, which we’ve established isn’t useful 😄 If people are using single cell selection to pause output, that’s a failing on our part for us having not provided any other way to pause. |
I agree and I think this updated behavior is more correct. Rather, my only concern is that we'll have a number of users coming from ConHost expecting it to work somewhat similarly. That said, we could do what we've done with other features and introduce this new behavior as the default. Then if somebody submits an issue expecting it to work the other way, we then address it by adding it in as a customization option. I genuinely think what you are proposing is the right behavior. I just don't want people familiar with Windows-isms to suddenly get confused. Even though I think this is one of those bad Windows-isms. |
Also, this diff is +35 -120 😄 you know how much I love deleting code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you're still in draft, but I added some comments since I'll have to review this at some point anyways.
auto& touchdownPoint{ *_singleClickTouchdownPos }; | ||
auto distance{ std::sqrtf(std::powf(cursorPosition.X - touchdownPoint.X, 2) + std::powf(cursorPosition.Y - touchdownPoint.Y, 2)) }; | ||
const auto fontSize{ _actualFont.GetSize() }; | ||
if (distance >= (std::min(fontSize.X, fontSize.Y) / 4.f)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could/should we cache this? Also, isn't X always smaller than Y?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X isn't always smaller than Y; some fonts are strange. Consider that caching requires cache invalidation, which is a lot to ask for a few simple floating point operations.
std::optional<winrt::Windows::Foundation::Point> _focusRaisedClickPos; | ||
bool _clickDrag; | ||
std::optional<winrt::Windows::Foundation::Point> _singleClickTouchdownPos; | ||
bool _selectionUpdatedThisCycle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a description here or somewhere for this new bool?
@@ -980,7 +975,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation | |||
else if (point.Properties().IsRightButtonPressed()) | |||
{ | |||
// CopyOnSelect right click always pastes | |||
if (_terminal->IsCopyOnSelectActive() || !_terminal->IsSelectionActive()) | |||
if (!_selectionUpdatedThisCycle || !_terminal->IsSelectionActive()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having a bit of trouble understanding why the change in this if statement is still equivalent to the comment above of "CopyOnSelect right click always pastes", can you explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Iiiii might have forgotten to push the commit that changed the condition here back to CoS 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Played with it a bit. Looks great. Just add the comment in too please. And Leon's comment.
@leonMSFT after playing with it, any strong feelings on whether focusing a window with a selection should preserve or destroy the selection? Notepad/word destroy it; xterm destroys it; putty destroys it |
I think it's fine to clear selection when focusing, makes the click-to-clear selection behavior more consistent 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea this looks good to me, and feels good too
Hello @DHowett-MSFT! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
@DHowett-MSFT hey so I'm stoked you implemented my idea so thanks! When will this make its way into a release? Do I just wait for the app to update from the store or what? Sorry I've literally used the MS store only once before this! :-) |
@aybiss thanks! So, we're trying to release approximately monthly, and since this is a behavior change we're probably going to hold it until the next preview build when we change the version number. It should not be too long 😄 |
…on (#5374) ## Summary of the Pull Request This pull request ports #5096 to WpfTerminalControl, bringing it in line with the selection mechanics in Terminal. It also introduces double- and triple-click selection and makes sure we clear the selection when we resize. Please read #5096 for more details. ## Detailed Description of the Pull Request / Additional comments This code is, largely, copy-and-pasted from TermControl with some updates to use `std::chrono` and `til::point`. I love `til::point`. A lot. ## Validation Steps Performed Lots of manual selection.
🎉 Handy links: |
This commit rewrites selection handling at the TermControl layer.
Previously, we were keeping track of a number of redundant variables
that were easy to get out of sync.
The new selection model is as follows:
the smallest dimension of a cell (usually its width) in any direction
This eliminates the selection of a single cell on one click.
(Behaviour of click-and-drag text selection depends inconsistently on prior pane and application focus state #4282, Determine proper behavior for single-cell selection; only highlight on click + threshold-drag? #5082)
"updated" since it was last copied. If an endpoint moves, it is
updated. For copy-on-select, it is only copied if it's updated.
(Duplicate copyOnSelect actions part 2 #4740)
Because of this, we can stop tracking the position of the focus-raising
click, and whether it was part of click-drag operation. All clicks can
become part of a click-drag operation if the user drags.
We can also eliminate the special handling of single cell selection at
the TerminalCore layer: since TermControl determines when to begin a
selection, TerminalCore no longer needs to know whether copy on select
is enabled or whether the user has started and then backtracked over a
single cell. This is now implicit in TermControl.
Fixes #5082; Fixes #4477