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
Fix RemoteObjectTree branch folder nodes sometimes becoming bold #5686
Fix RemoteObjectTree branch folder nodes sometimes becoming bold #5686
Conversation
GitCommands/Settings/AppSettings.cs
Outdated
} | ||
} | ||
|
||
private static Dictionary<FontStyle, Font> _fontByStyle = new Dictionary<FontStyle, Font>(); |
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 would have liked to have used an array indexed by FontStyle, except that FontStyle's values are bit masks. I could still use them, but we'd have a sparse array of size 8 where only 1, 2, 4, and 8 indices would be used. It would be faster than using a dictionary. Or we could also convert bit position to index, but that requires looping to count number of right bit shifts. Thoughts?
How many different fonts are we talking about?
…On Sat, Nov 3, 2018, 8:12 AM Antonio Maiorano ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In GitCommands/Settings/AppSettings.cs
<#5686 (comment)>
:
> @@ -1215,7 +1215,29 @@ public static Font MonospaceFont
public static Font Font
{
get => GetFont("font", SystemFonts.MessageBoxFont);
- set => SetFont("font", value);
+ set
+ {
+ SetFont("font", value);
+ _fontByStyle.Clear();
+ }
+ }
+
+ private static Dictionary<FontStyle, Font> _fontByStyle = new Dictionary<FontStyle, Font>();
I would have liked to have used an array indexed by FontStyle, except that
FontStyle's values are bit masks. I could still use them, but we'd have a
sparse array of size 8 where only 1, 2, 4, and 8 indices would be used. It
would be faster than using a dictionary. Or we could also convert bit
position to index, but that requires looping to count number of right bit
shifts. Thoughts?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5686 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsYxIAwMO28I5uTcjuuOCR7azLrj0ks5urYhJgaJpZM4YMpL9>
.
|
So FontStyle from System.Drawing looks like this (currently): [Flags]
public enum FontStyle
{
Regular = 0,
Bold = 1,
Italic = 2,
Underline = 4,
Strikeout = 8 In my case, Regular is handled separately, returning Application.Font, while Bold, Italic, Underline, and Strikeout are created lazily if requested. So at most 4 more Font objects will get created. My current use case is just for the Bold, but for my Submodules ROT change, I will use Italic as well. |
Another thing worth mentioning is that we could also add similar functions for the other fonts in AppSettings - FixedWidthFont, CommitFont, and MonospaceFont - if we need styled versions of these in GE. Also, this might be a step in the right direction for being able to fix the problem of having to restart GE after changing fonts. If everything uses these centralized fonts - even for style - then we have one place to change, and we can use some kind of callback/reload mechanism. |
GitCommands/Settings/AppSettings.cs
Outdated
set | ||
{ | ||
SetFont("font", value); | ||
_fontByStyle.Clear(); |
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.
This here clears the cache when we change Font (through Settings), so future calls to GetFontByStyle will do the right thing. Of course, presently we don't have a mechanism to reload UI based on font change, but this is a step in the right direction, I believe.
Ok. So frankly a dictionary would be best. You have a few named fonts not a
ton. Then a few variances based on style. So why not make the key a
composite of string and a fontstyle.
Yes. We do need a font reset/load functionality.
…On Sat, Nov 3, 2018, 8:36 AM Antonio Maiorano ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In GitCommands/Settings/AppSettings.cs
<#5686 (comment)>
:
> @@ -1215,7 +1215,29 @@ public static Font MonospaceFont
public static Font Font
{
get => GetFont("font", SystemFonts.MessageBoxFont);
- set => SetFont("font", value);
+ set
+ {
+ SetFont("font", value);
+ _fontByStyle.Clear();
This here clears the cache when we change Font (through Settings), so
future calls to GetFontByStyle will do the right thing. Of course,
presently we don't have a mechanism to reload UI based on font change, but
this is a step in the right direction, I believe.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5686 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsdv8BpJBLT8MUQ5h0swJbdvHMbxOks5urY1sgaJpZM4YMpL9>
.
|
I hear you, but I feel like doing this now would be making us pay for something we don't use. Having to hash the name and enum value will be more costly than just the enum value in terms of dictionary lookup. If we see that it would be useful to have styled versions of the other fonts, then sure, we could do as you suggest. In any case, this would be a detail of the implementation, not exposed via the public API. For example, we'd add GetMonospaceFontByStyle, and internally, it and GetFontByStyle could use the same dictionary keyed by font name + style enum value. Having said that, clearing the cache would be more difficult since changing a single font shouldn't clear the entire cache. So maybe we'd really just want separate dictionaries for each font, in which case, we're back to what I've done here. |
You don't have unique fonts per style. You have fonts with styles and they
are linked to where they are used.
…On Sat, Nov 3, 2018, 8:53 AM Antonio Maiorano ***@***.***> wrote:
Ok. So frankly a dictionary would be best. You have a few named fonts not
a ton. Then a few variances based on style. So why not make the key a
composite of string and a fontstyle. Yes. We do need a font reset/load
functionality.
I hear you, but I feel like doing this now would be making us pay for
something we don't use. Having to hash the name and enum value will be more
costly than just the enum value in terms of dictionary lookup. If we see
that it would be useful to have styled versions of the other fonts, then
sure, we could do as you suggest. In any case, this would be a detail of
the implementation, not exposed via the public API. For example, we'd add
GetMonospaceFontByStyle, and internally, it and GetFontByStyle could use
the same dictionary keyed by font name + style enum value. Having said
that, clearing the cache would be more difficult since changing a single
font shouldn't clear the entire cache. So maybe we'd really just want
separate dictionaries for each font, in which case, we're back to what I've
done here.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5686 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsRlt7JzHQdxPD_oOGW7qe-ZvcLweks5urZHbgaJpZM4YMpL9>
.
|
I don't understand what you're trying to say. I know that conceptually we have fonts with styles, but concretely, we instantiate unique Font objects per font per style. |
Nobody said hash.
struct fontkey
string Location
Fontstyle style
Dictionary<fontkey, font>
…On Sat, Nov 3, 2018, 8:55 AM Jay Asbury ***@***.***> wrote:
You don't have unique fonts per style. You have fonts with styles and they
are linked to where they are used.
On Sat, Nov 3, 2018, 8:53 AM Antonio Maiorano ***@***.***>
wrote:
> Ok. So frankly a dictionary would be best. You have a few named fonts not
> a ton. Then a few variances based on style. So why not make the key a
> composite of string and a fontstyle. Yes. We do need a font reset/load
> functionality.
>
> I hear you, but I feel like doing this now would be making us pay for
> something we don't use. Having to hash the name and enum value will be more
> costly than just the enum value in terms of dictionary lookup. If we see
> that it would be useful to have styled versions of the other fonts, then
> sure, we could do as you suggest. In any case, this would be a detail of
> the implementation, not exposed via the public API. For example, we'd add
> GetMonospaceFontByStyle, and internally, it and GetFontByStyle could use
> the same dictionary keyed by font name + style enum value. Having said
> that, clearing the cache would be more difficult since changing a single
> font shouldn't clear the entire cache. So maybe we'd really just want
> separate dictionaries for each font, in which case, we're back to what I've
> done here.
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <#5686 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ADdhsRlt7JzHQdxPD_oOGW7qe-ZvcLweks5urZHbgaJpZM4YMpL9>
> .
>
|
My point is we have a store of fonts that get lazy loaded based on use. The
dictionary has a location key that says it is font x for commit header or
whatever. Now. The backing store of this cache can store only unique so if
commit header and treenode root share the same font, they will be the same
object.
…On Sat, Nov 3, 2018, 8:59 AM Jay Asbury ***@***.***> wrote:
Nobody said hash.
struct fontkey
string Location
Fontstyle style
Dictionary<fontkey, font>
On Sat, Nov 3, 2018, 8:55 AM Jay Asbury ***@***.***> wrote:
> You don't have unique fonts per style. You have fonts with styles and
> they are linked to where they are used.
>
> On Sat, Nov 3, 2018, 8:53 AM Antonio Maiorano ***@***.***>
> wrote:
>
>> Ok. So frankly a dictionary would be best. You have a few named fonts
>> not a ton. Then a few variances based on style. So why not make the key a
>> composite of string and a fontstyle. Yes. We do need a font reset/load
>> functionality.
>>
>> I hear you, but I feel like doing this now would be making us pay for
>> something we don't use. Having to hash the name and enum value will be more
>> costly than just the enum value in terms of dictionary lookup. If we see
>> that it would be useful to have styled versions of the other fonts, then
>> sure, we could do as you suggest. In any case, this would be a detail of
>> the implementation, not exposed via the public API. For example, we'd add
>> GetMonospaceFontByStyle, and internally, it and GetFontByStyle could use
>> the same dictionary keyed by font name + style enum value. Having said
>> that, clearing the cache would be more difficult since changing a single
>> font shouldn't clear the entire cache. So maybe we'd really just want
>> separate dictionaries for each font, in which case, we're back to what I've
>> done here.
>>
>> —
>> You are receiving this because you commented.
>>
>>
>> Reply to this email directly, view it on GitHub
>> <#5686 (comment)>,
>> or mute the thread
>> <https://github.com/notifications/unsubscribe-auth/ADdhsRlt7JzHQdxPD_oOGW7qe-ZvcLweks5urZHbgaJpZM4YMpL9>
>> .
>>
>
|
To be clear, what is "location" supposed to be? "difffont", "commitfont", "monospacefont", or "font"? |
Right. DiffFont, CommitFont.....
…On Sat, Nov 3, 2018, 9:10 AM Antonio Maiorano ***@***.***> wrote:
My point is we have a store of fonts that get lazy loaded based on use.
The dictionary has a location key that says it is font x for commit header
or whatever. Now. The backing store of those cache can store only unique so
if commit header and treenode root share the same font, they will be the
same object.
To be clear, what is "location" supposed to be? "difffont", "commitfont",
"monospacefont", or "font"?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5686 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsZQ9n8cMkad_9SYAqApJrJt1gvuXks5urZXGgaJpZM4YMpL9>
.
|
Okay, so this is what I understood before, and as I said before, this will be slower than what I presented here since we will pay for the longer dictionary lookups (comparing structs is slower than enum values). Also, upon changing a single font, I can't clear the entire dictionary; instead, I'll have to clear only the entries who's location is the current font being changed. If you really want this, I can make this change. |
Do you see how keying on the style would mean you would only have possible
keys per unique style value? So only one regular font. Only one bold
font. Only one bold italic font. See the issue?
…On Sat, Nov 3, 2018, 9:17 AM Antonio Maiorano ***@***.***> wrote:
Right. DiffFont, CommitFont.....
Okay, so this is what I understood before, and as I said before, this will
be slower than what I presented here since we will pay for the longer
dictionary lookups (comparing structs is slower than enum values). Also,
upon changing a single font, I can't clear the entire dictionary; instead,
I'll have to clear only the entries who's location is the current font
being changed.
If you really want this, I can make this change.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5686 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsej8zHD46Ffwzz2s3Nnox5npAKzBks5urZdZgaJpZM4YMpL9>
.
|
/facepalm! Okay, I see now what you mean. I wasn't thinking about the combinations of styles! Okay, okay, that makes a lot of sense. Sorry for the confusion. I'll go ahead with your suggestion. Thanks. |
If you want an enum of locations then that could work too. My point is you need to not key it just to the style. We have multiple fonts per style being used. |
Yes. But just to be clear, my code was to get only variants of Application.Font with different styles, not the other types of fonts by style. |
Now that I've thought of this... Really want a cache of unique fonts. If
the font is arial, 12pt bold then that is one font object we use everywhere
we want that specific font.
So instead key the cache to a key of those properties.
Getfont(name, size, style)
If it is in the cache we use that value.
Then add a font location class. That acts the same way encoding does.
FontLocation fnt = FontLocation CommitFont
fnt can then have the functionality to retrieve the correct font using
getfont.
…On Sat, Nov 3, 2018, 9:26 AM Antonio Maiorano ***@***.***> wrote:
If you want an enum of locations then that could work too. My point is you
need to not key it just to the style. We have multiple fonts per style
being used.
Yes. But just to be clear, my code was to get only variants of
Application.Font with different styles, not the other types of fonts by
style.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#5686 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADdhsezeI0qI5E7sWqnj11S6YcuZ3Zbvks5urZlygaJpZM4YMpL9>
.
|
You can make FontLocation lazy and each property can return the same obiect
if already initialized.
…On Sat, Nov 3, 2018, 9:38 AM Jay Asbury ***@***.***> wrote:
Now that I've thought of this... Really want a cache of unique fonts. If
the font is arial, 12pt bold then that is one font object we use everywhere
we want that specific font.
So instead key the cache to a key of those properties.
Getfont(name, size, style)
If it is in the cache we use that value.
Then add a font location class. That acts the same way encoding does.
FontLocation fnt = FontLocation CommitFont
fnt can then have the functionality to retrieve the correct font using
getfont.
On Sat, Nov 3, 2018, 9:26 AM Antonio Maiorano ***@***.***>
wrote:
> If you want an enum of locations then that could work too. My point is
> you need to not key it just to the style. We have multiple fonts per style
> being used.
>
> Yes. But just to be clear, my code was to get only variants of
> Application.Font with different styles, not the other types of fonts by
> style.
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <#5686 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ADdhsezeI0qI5E7sWqnj11S6YcuZ3Zbvks5urZlygaJpZM4YMpL9>
> .
>
|
Sounds like a good idea, but it's outside the scope of this change. My goal was to fix the problem of nodes being incorrectly bolded, which came as a result of cd68a51. Would you accept this change as is for now, and perhaps you can work on improving the Font handling as per your idea? |
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.
This PR reverses something that was "fixed" in #3795
It is possible to set not just the font but style too.
I would not mind if that PR was reversed, but the font selection should be reimplemented if so.
@RussKie took a decision, I suggest we stick with that.
Of course, if you for some exotic reason like described in #3795 selects another font, the bold (and italics) override can be weird, but that you will have to live with.
So likely should FontStyle.Regular be replaced with a custom type with Default or use null.
It feels incomplete to only use a cache for the application font and not the other fonts, even if not used there (right now, I have not checked though).
What would the performance impact be to not use the cache after this change?
What about a correction where the active branch is reset when closing (or when opening, if style differs)?
@gerhardol Ah, I didn't realize that the AppSettings.*Font included style, but that makes sense. I will rework my change to be simpler and address only the bug here, even if it's not as efficient. |
This bug was introduced in cd68a51 where setting TreeViewNode.NodeFont = AppSettings.Font was removed as an optimization. Problem is that for performance reasons, nodes are recycled, and it's possible for a node that was a LocalBranchNode for the active branch (thus, with bold font) to become a BranchPathNode. This would leave the BranchPathNode with bold font instead of the regular font. This change brings back the former change, except this time we only update the node's font if required.
96905c3
to
f39bfa6
Compare
I rewrote the commit. I still kept the idea of setting the style for the nodes, but it's localized to the node code. This doesn't break #3795 as you pointed out. If you choose a bold font as AppSettings.Font, you won't be able to distinguish the active branch, but as you said, @gerhardol, this is something we'll have to live with for now (maybe in the future, we'll be able to expose more font settings, including which fonts to use for the ROT nodes). |
If a user choses to use bold/italic fonts, they should be free to do so. The fileviewer control can't be easily customised, so #3795 ended up being half baked. |
I'll throw a spanner in the works. |
I believe bold/italics is a good way to mark differences. This should be included in 3.0, even if not in rc1/beta2. |
I plan to re-instate the highlighting before the official release, I'm struggling without it |
I agree that using bold is nice here, even if it doesn't work with the default font being set to bold. So are we good with this PR? I know it looks a bit complicated in the SetNodeFont, but I think eventually if there's work done to improve font handling overall, this would eventually disappear (see discussion above). |
For me it is, but @RussKie decides and he has been working hard to get 3.0 RC1 out of the door and he has not decided yet. @amaiorano I appreciate your contributions. Sorry that I cannot dedicate more time, busy in real life and I need to look at the 3.0 too. |
@amaiorano <https://github.com/amaiorano> - I too appreciate your
contribution, but this won't be merged until we release v3. Right now we're
in a "freeze" period, where only critical bug fixes get merged in. I know
it feels disappointing, but we can't risk delaying the release.
Please hang tight.
…On Mon, 5 Nov 2018 at 08:12, Gerhard Olsson ***@***.***> wrote:
So are we good with this PR?
For me it is, but @RussKie <https://github.com/RussKie> decides and he
has been working hard to get 3.0 RC1 out of the door and he has not decided
yet.
@amaiorano <https://github.com/amaiorano> I appreciate your
contributions. Sorry that I cannot dedicate more time, busy in real life
and I need to look at the 3.0 too.
If the 3.0RC1 is a success, development should be more normal again.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5686 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AEMyXsAFC8L2JKMM_U_0WKIo9ZwyYYOqks5ur1hJgaJpZM4YMpL9>
.
|
Oh no, it's fine, I understand needing to lock down to make the next release as stable as possible. I have no problem with any of my changes coming in afterwards. |
Actually I've this is a significant issue, so it will need to be fixed before v3. I stand corrected. |
TreeViewNode.NodeFont = new Font(AppSettings.Font, style); | ||
} | ||
} | ||
} |
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.
Can we simplify it as follows?
protected void SetNodeFont(FontStyle style)
{
if (style != FontStyle.Regular && TreeViewNode.NodeFont.Style.HasFlag(style))
{
return;
}
TreeViewNode.NodeFont.Dispose();
TreeViewNode.NodeFont = new Font(AppSettings.Font, style);
}
Any reason a node font would be null
?
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.
We definitely want the NodeFont to be null by default so that it uses the font that was set on the NativeTreeView. This is the 99% case (or whatever), and in that case, we avoid allocating/disposing of node fonts. In the end, we only pay to dispose/allocate for the bold nodes. It's this optimization of making the nodes null for regular style that makes this code more complex, unfortunately.
It can be made a lot more simple at this level if we work on doing proper font management at the AppSettings level, like I did in the initial commit for this PR. But my change was flawed, and as per the long discussion with @vbjay, a system where we'd cache font + style + context with callbacks for when fonts change would probably be the way to go. For now, though, the change I provide here is optimal, behaves correctly, at the cost of a little complexity in the one function (SetNodeFont).
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.
Thank you for the explanation. Makes sense.
Fixes RemoteObjectTree sometimes resulting in font bolding for branch path nodes upon switching repo.
Screenshots before and after (if PR changes UI):
This is what can happen:
Note that "amaiorano" should not be bolded. This happened because the previous repo's 2 root nodes had the second node bolded, not the first; upon switching to this repo, it recycled the 2nd node for the branch path "amaiorano", but left it bold. This happened because the font reset for all nodes was removed as an optimization in cd68a51. This change brings it back, but in an optimal way.
What did I do to test the code and ensure quality:
Has been tested on (remove any that don't apply):