Skip to content
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

Add separate padding settings for left, top, right and bottom #17909

Merged
merged 10 commits into from
Dec 6, 2024

Conversation

nukoseer
Copy link
Contributor

@nukoseer nukoseer commented Sep 11, 2024

Left, Top, Right and Bottom paddings can be set separetely in Appearance. I tried to make it as close as possible to one of the suggestions in #9127. I hope it doesn't look that bad.

resim

Relevant Issue: #9127

@@ -51,9 +51,32 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Opacity(static_cast<float>(value) / 100.0f);
};

void SetPadding(double value)
void SetLeftPadding(double value)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe SetXXXPadding(double value) functions can be overloaded but idk how to make it work with XAML.

@@ -140,6 +163,47 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

Model::CascadiaSettings _appSettings;
Editor::AppearanceViewModel _unfocusedAppearanceViewModel;

enum class PaddingDirection
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used this enum just to clarify the intention.

@@ -105,4 +105,35 @@ namespace winrt::Microsoft::Terminal::UI::implementation

return maxVal;
}

double Converters::PaddingValueFromIndex(const winrt::hstring& paddingString, uint32_t paddingIndex)
Copy link
Contributor Author

@nukoseer nukoseer Sep 11, 2024

Choose a reason for hiding this comment

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

Maybe this should also take an enum parameter instead of index but this is only called from XAML.

LOG_CAUGHT_EXCEPTION();
}

result << values[0] << L", " << values[1] << L", " << values[2] << L", " << values[3];
Copy link
Member

Choose a reason for hiding this comment

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

We use fmt instead of sstream almost everywhere. This would also allow us to easily round the padding to e.g. 6 digits during formatting, just in case (to avoid 0.3000000000000001 situations).

Something like this:

const auto result = fmt::format(
    FMT_COMPILE(L"{:.6f},{:.6f},{:.6f},{:.6f}"),
    values[0],
    values[1],
    values[2],
    values[3]
);
return winrt::hstring{ result };

Theoretically you should also have access to fmt::join so this may work:

const auto result = fmt::format(FMT_COMPILE(L"{:.6f}"), fmt::join(values, L","));

@lhecker
Copy link
Member

lhecker commented Sep 12, 2024

I think the way you made it looks amazing! I'm overall fine with this PR already.

However, I was wondering: Couldn't we parse the margin string once, when the ViewModel loads, store it as a member and then expose them as 4 doubles? Your PR introduces the 4 Set*Padding methods, but we could also have 4 get/set properties instead. That would mean you'd have to write 8 methods which is a lot of boiler plate, but on the other hand you won't need the Converters::PaddingValueFromIndex function. I'm not entirely sure if that's a good trade off...

@nukoseer
Copy link
Contributor Author

However, I was wondering: Couldn't we parse the margin string once, when the ViewModel loads, store it as a member and then expose them as 4 doubles? Your PR introduces the 4 Set*Padding methods, but we could also have 4 get/set properties instead. That would mean you'd have to write 8 methods which is a lot of boiler plate, but on the other hand you won't need the Converters::PaddingValueFromIndex function. I'm not entirely sure if that's a good trade off...

If you think it is worth I can change it to the way you described. I know that Converters::PaddingValueFromIndex function looks a bit strange, because it works directly with index. Actually, I am okay with that because it is only called from one place in XAML. But, if you think it is better to remove it and add more functions to set padding values I also understand that.

@lhecker
Copy link
Member

lhecker commented Sep 16, 2024

I think it would be better, because it would better contain the changes within this class and avoid adding more dependencies between different parts of the code base. It would also simplify _GetNewPadding because then it would only need to do the single fmt::format call.

However, I also don't want to force you to spend more time on this, so I've approved it for now. 🙂

@nukoseer
Copy link
Contributor Author

nukoseer commented Sep 16, 2024

I think it would be better, because it would better contain the changes within this class and avoid adding more dependencies between different parts of the code base. It would also simplify _GetNewPadding because then it would only need to do the single fmt::format call.

This definitely needs a review 🙂. I tried to update it according to your suggestions but I ran into some problems so I couldn't make it that simpler. I got rid of the Converters::PaddingValueFromIndex function but I added a new similar _GetPaddingValue function inside the class and the _GetNewPadding function is still the same. Actually, first I implemented everything you said, parsed the initial padding, stored it inside the class as an array of 4 padding values, made the _GetNewPadding function simpler so it only formats and returns the array, made 4 get / set (LeftPadding(double), LeftPadding() etc.) functions for use in XAML etc. It worked perfectly except when I clicked the reset button in the settings menu. When the reset button is clicked, it calls Profile.ClearPadding and I think it changes the value of Profile.Padding. So, if I bind the Profile.LeftPadding value to the XAML, it no longer knows that the Profile.Padding value has changed and it doesn't get updated. This is why the _GetPaddingValue function is a bit complex and takes the const hstring& padding parameter. I'm not sure if this is the right way to handle this situation. Should I implement ClearPadding and HasPadding functions for each edge? I didn't want to do that because I thought it would make things more complicated (maybe not). Or maybe there is a much easier way that I didn't realize.

@lhecker
Copy link
Member

lhecker commented Sep 16, 2024

This week we've got an internal hackathon so attention will be stretched a little thin. I'll try to take a look soon though (unless someone else gets here first^^). 🙂

@nukoseer
Copy link
Contributor Author

This week we've got an internal hackathon so attention will be stretched a little thin. I'll try to take a look soon though (unless someone else gets here first^^). 🙂

Ok, no problem for me 🙂. Just for info, I will also be off for a month from this Saturday, so if I can't finish it until Saturday, I won't be able to work on it for a long time.

@DHowett
Copy link
Member

DHowett commented Sep 16, 2024

This UI is exactly what I had imagined! Thank you

@DHowett
Copy link
Member

DHowett commented Sep 16, 2024

So, if I bind the Profile.LeftPadding value to the XAML, it no longer knows that the Profile.Padding value has changed

So, the normal way to do this is to raise a PropertyChanged notification for all impacted properties - that is, when LeftPadding changes, you can raise a notification saying that Padding has changed (in addition to LeftPadding and HasPadding!)

We have this pattern elsewhere in the Profile View Model. You can look at CreateUnfocusedAppearance for an instance of a method that is not a setter which fires a related event, or you can look at the PropertyChanged handler (search for "Add a property changed handler") to see how we transform some events into other secondary events (like UseCustomStartingDirectory).

@DHowett
Copy link
Member

DHowett commented Sep 16, 2024

Since you have true implementations for the directional padding setters, you may want to use the first pattern (that is: call _NotifyChanges directly inside the setter)

@DHowett
Copy link
Member

DHowett commented Sep 16, 2024

This is silly, but you may also need to send a notification when Padding changes so the View knows that all 4 padding values might have changed. This will make sure that when you click Rest/Clear it properly cascades to the 4 text boxes.

Padding(to_hstring(value));
const hstring& padding = _GetNewPadding(PaddingDirection::Left, value);

Padding(padding);
Copy link
Member

Choose a reason for hiding this comment

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

Oh, I understand now. This will properly propagate the change notification through to Padding. You may still need to do the other notifications yourself.

Copy link
Member

Choose a reason for hiding this comment

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

That will allow you to turn this into a setter and a getter with normal two-way binding.

@@ -76,6 +76,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_NotifyChanges(L"HideIcon");
}
else if (viewModelProperty == L"Padding")
{
_NotifyChanges(L"LeftPadding", L"TopPadding", L"RightPadding", L"BottomPadding");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the directional padding setters Padding(padding) will call _notifyChanges(L "Padding") and _notifyChanges(L "HasPadding"). If I call _notifyChanges for all directional paddings here, it works, including the ClearPadding case.

@nukoseer
Copy link
Contributor Author

nukoseer commented Sep 17, 2024

It could probably still be simpler, the _GetNewPadding and _GetPaddingValue functions are not trivial. The main reason why I don't want to store directional padding values separately as doubles is the ClearPadding case. If I would do it, probably _GetNewPadding and _GetPaddingValue functions would be a lot simpler but then another mechanism is needed to keep Padding and stored values synchronized because ClearPadding changes Padding without calling the directional padding setters. And, we would probably need a function very similar to _GetNewPadding to do this, but I'm not exactly sure. I am open to suggestions 🙂

@carlos-zamora carlos-zamora mentioned this pull request Sep 18, 2024
65 tasks
Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

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

So sorry for the delay!

@@ -74,7 +77,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean ShowMarksAvailable { get; };
Boolean AutoMarkPromptsAvailable { get; };
Boolean RepositionCursorWithMouseAvailable { get; };

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Oct 3, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Oct 11, 2024
@DHowett
Copy link
Member

DHowett commented Oct 11, 2024

I know you’re unavailable so I’m going to clear the no-activity label!

@microsoft-github-policy-service microsoft-github-policy-service bot removed the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Oct 11, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Oct 18, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. labels Oct 18, 2024
@nukoseer nukoseer requested a review from DHowett October 31, 2024 12:29
@lhecker lhecker added Needs-Attention The core contributors need to come back around and look at this ASAP. Needs-Second It's a PR that needs another sign-off labels Dec 4, 2024
@zadjii-msft
Copy link
Member

@DHowett if @nukoseer is unavailable, should one of the rest of us tidy up your concern in #17909 (comment) to get this merged?

@nukoseer
Copy link
Contributor Author

nukoseer commented Dec 5, 2024

@DHowett if @nukoseer is unavailable, should one of the rest of us tidy up your concern in #17909 (comment) to get this merged?

Actually, I have updated this but there was no review :)

@zadjii-msft
Copy link
Member

Ah my bad, that's what I get for reading review threads at 6am. I'll stick this back in @DHowett's court then ☺️

@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Second It's a PR that needs another sign-off label Dec 5, 2024
@DHowett
Copy link
Member

DHowett commented Dec 5, 2024

OH NO!! I missed the notification about this update!
I'm so sorry.

@DHowett DHowett enabled auto-merge (squash) December 5, 2024 23:12
@DHowett DHowett merged commit 86a6245 into microsoft:main Dec 6, 2024
15 checks passed
DHowett added a commit that referenced this pull request Dec 10, 2024
The code in #17909 was not completely right for padding values with
fewer than four components, and it was doing some fragile string math
(that is: if you wanted to change the third element in the padding it
would parse out the whole thing, edit the third value, and then format
it again).

This pull request moves the control's padding parser into cppwinrt_utils
(for lack of a better place) and makes the settings UI use it to parse
the padding out into a `Thickness` as early as possible. Then, the
controls operate directly on the Thickness' members rather than parsing
the padding string again.

To handle two-way serialization properly, we also required a function
that converts a thickness back into a reduced string representation
(i.e. when all four values are N, it will return "N").

As a bonus, this pull request also:
- removes another use of `std::getline`
- fixes an issue where resetting the padding would change it
  (infinitesimally) and cause it to be set again
- adds a readout of the current padding value in the expander itself
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Attention The core contributors need to come back around and look at this ASAP.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants