Skip to content

Draft: Separate text styling from Font#862

Draft
Didas-git wants to merge 4 commits into
david-vanderson:mainfrom
Didas-git:font_style
Draft

Draft: Separate text styling from Font#862
Didas-git wants to merge 4 commits into
david-vanderson:mainfrom
Didas-git:font_style

Conversation

@Didas-git
Copy link
Copy Markdown
Collaborator

Initial draft for #849

There are naming issues, Style ended up not being the best of ideas, going with FontStyle for now but perhaps something like TextStyle would be more ideal.

As of opening the draft it only includes a rough idea of what FontStyle is aiming to be, a way to unify font style in a place independent from the font itself.

@Didas-git Didas-git self-assigned this May 20, 2026
@Didas-git Didas-git added the enhancement New feature or request label May 20, 2026
Didas-git added 2 commits May 20, 2026 06:27
It did compile but... idk why i thought this would work tbh
@Didas-git
Copy link
Copy Markdown
Collaborator Author

Didas-git commented May 20, 2026

I have made some very very rough changes for it to compile* using FontStyle and there are a few things that do not work as intended/as before and need to be changed/updated. (kind of a todo list for myself as well)

  • Due to how Options.override works its impossible to only partially override its fields (like FontStyle.fill)
  • As it stands right now, there is no way to pass a Style to a FontStyle.Options (terrible name i know), this could be addressed by having something like base_style.
    • Due to this, all widgets that depended on font = themeGet().some_font are inherently broken
  • Setting the opacity to .65 seems to be a very very common case, maybe this could be worth a dimmed color inside FontStyle, that way users could also have different colors on dimmed text or just as a way to "stop" internals from dimming the text (debatable how good of an idea that is)
  • Overriding colors after FontStyle.Options has been created is quite the pain given text_style is nullable, this is probably the biggest issue as i don't see a way to really "fix" this.
  • Debug does some very unique things that need complete rewrites.

I'd like some feedback/input before i move forward with some more deep changes to address the above (and other) issues.

* Due to how decorations are set up right now it doesn't actually compile if they are uncommented...
* I didn't update the Examples either so it compiles if the Examples export is commented out.

@Didas-git
Copy link
Copy Markdown
Collaborator Author

The current state of my draft is also making me question if there is any reason for Font and Font.Source to be different things.
I would like to discuss this because there is probably something im missing about how/what freetype/stb_truetype need to work.

@david-vanderson
Copy link
Copy Markdown
Owner

Currently I'm confused, so this is confused feedback. I thought the idea was to separate Font from styling, but FontStyle seems to smoosh them together?

The current state of my draft is also making me question if there is any reason for Font and Font.Source to be different things.

This is something we need to nail down. The reason I separated them is that a single Font.Source can back multiple Fonts. Example is font size - each size uses the same underlying Font.Source, but has to rasterize separately so we need extra machinery. Unlike line_height_factor which we can on-the-fly adjust for any Font.

So the idea is that Font.Source roughly corresponds to a font file. Font is the way code asks for a particular instance. In the future with glyph fallback rendering a Font might pull from multiple Font.Source.

Given that, I thought text styling would be things that can apply to any font, like underline, strikethrough, and (in the future) shadow. Is that what you are thinking?

I think we need a few concrete usecases for me to understand the intention. I'm imagining something like:

  • app allows the user to change the font/size
  • app controls a style that is added to the user's choice for a particular situation

Is that the primary way you see this working?

* Due to how `Options.override` works its impossible to only partially override its fields (like `FontStyle.fill`)

Yes good point, will think about this.

* Setting the opacity to `.65` seems to be a very very common case, maybe this could be worth a `dimmed` color inside `FontStyle`, that way users could also have different colors on dimmed text or just as a way to "stop" internals from dimming the text (debatable how good of an idea that is)

I'm unsure if messing with opacity makes sense (by default). Maybe we should do more color mixing?

* `Debug` does some very unique things that need complete rewrites.

Yeah - don't worry about this yet.

@Didas-git
Copy link
Copy Markdown
Collaborator Author

Didas-git commented May 22, 2026

So the idea is that Font.Source roughly corresponds to a font file. Font is the way code asks for a particular instance. In the future with glyph fallback rendering a Font might pull from multiple Font.Source.

This does make more sense, given .ttc files can be a source in the future.

I think this distinction makes sense; and the glaring problem i see in my draft is that due to the size "issue" you mentioned (that only applies to freetype)

The solution i see for it is to keep font as a way to get an instance of a font with certain properties, however we can change the api to be easier to use (like no more .array and .string) as FontStyle would be the only thing interacting with it (and limiting font family names can be an issue)

So FontStyle would ask for a font matching the family and properties (this would include getting ascender values and what not, so somewhat merging current Font with Entry here) which would allow font fallback to be defined on the style itself like in CSS you can pass multiple families and making styles inherently more reusable than the current Font.

This changes would also means that my proposal would turn into recoding and renaming Font to make it more clear, costumizable, and resuable, with - hopefuly - an easier structure to implement new features and accomodate more use cases.

I thought text styling would be things that can apply to any font, like underline, strikethrough, and (in the future) shadow. Is that what you are thinking?

Coloring (fills, borders, etc) are also part of styling and, as it stands right now, there is no easy way to customize things like select colors (text and backgroud) on a per-text basis without making a copy of the theme, modifying it and using that which is very confusing to the user as its not very clear you can do that, in my opinion a Theme is what defines the defaults, if the only way to achieve some specific constumization is to modify specific theme colors at runtime it means there are some holes to fill.

Even something like text outline/border i think would be very weird to be implemented on the current Font api.

I think we need a few concrete usecases for me to understand the intention.

To put it in a very simple form, the idea is to have a construct that is reusable, easy to use/understand, and can define/alter any property related to text.

As currently the only way to do something like this is to keep entire dvui.Options "instances" around and use override everywhere which can turn into a mess very quickly.

@david-vanderson
Copy link
Copy Markdown
Owner

I'm somewhat following.

To put it in a very simple form, the idea is to have a construct that is reusable, easy to use/understand, and can define/alter any property related to text.

It's hard to get details right unless we can describe in detail the usecases you need.

I suspect most of this is driven by the markdown rendering right? My guess is that the main problem there is how to combine information from the theme (font family name and base size?) with info coming from markdown (bold, italic, underline, how much bigger/smaller than base etc.). Is that in the right direction?

@Didas-git
Copy link
Copy Markdown
Collaborator Author

Didas-git commented May 23, 2026

It's hard to get details right unless we can describe in detail the usecases you need.

For example, TexyLayout.addText; you might want to define a style that can be used on multiple calls across your entire app.
Currently the only way to partially do this is to have a dvui.Options and using override for the specific properties you might want to change outside of text styling (like enabling background and changing its color), i say partially because if you change the background color you might want to change the select color but there is no way to do that besides the theme duplication i have mentioned, this from my point of few adds to many "glue points" and make a complex app hard to maintain.

I suspect most of this is driven by the markdown rendering right?

Partially yes, i had some problems before that could be adressed with hacks like duplicating the theme and modifying it but they always felt very ugly and not very easy to maintain.

As i have mentioned before; in the app im working on i want to allow users to create their own themes, the problem with that is that due to the hacks required there is no viable way to do that besides having my own theme on top of dvui's theme which cannot be used internally by dvui and would require a bunch of workarounds and wasted memory to work as one would expect as a user.


One other thing that is a problem is font fallback (which dvui doesnt support yet) in the current system i find it very hard to see a user friendly way to implement such for the reason that the user might (and most likely will) want different fallbacks for different parts of the application, one simple example being emojis, you might want one part of the app to use colored emojis and another to use monochrome emojis, and complexity can spiral from there. If this was to be done via Theme is just yet more glue for the developer to maintain and way harder to support user-provided fallbacks.

@david-vanderson
Copy link
Copy Markdown
Owner

For example, TexyLayout.addText; you might want to define a style that can be used on multiple calls across your entire app.

Okay this is starting to make sense to me. So you want to define a style like "second-level heading" or "hyperlink" that can be applied to any addText call?

Then style modifies the font (default) you get from the theme (or callsite) by adjusting:

  • italic/bold/underline/strike (overrides the default)
  • size, but specified as a change to the default (bigger or smaller)
  • color, unsure if overriding the default or as a change (lighter or darker)
  • line_height_factor, unsure if override or as change

If the user changes the theme, that would change the underlying font (and default size), but the "second-level heading" style would still adjust things?

Sounds like we might have to duplicate some features across Font and FontStyle. For example the theme font might be bold, but the given font_style might be regular.

@Didas-git
Copy link
Copy Markdown
Collaborator Author

Ideally, FontStyle would only care about a font family and not singular fonts like it is right now.

This is why i think Entry requires some changes, ideally one would store a font entry as part of a family and then possibly cache the results of a query using the size, the current system somewhat does this but seems to merge both on the same Entry result (its a bit confusing the way it is right now, i honestly need to read the code some more)

The only fonts defined in the Theme would be embedded_fonts (fonts to automatically create an Entry for), fonts would not have a concept of "default size", having a default line height seems like it could be useful when dealing with multiple font families but its also something im wondering if should actually be included or leave it fully for style just like size.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants