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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants