Skip to content

Add an initial version of a preferences dialog - #2261

Merged
cameronwhite merged 1 commit into
masterfrom
feature/prefs-dialog
Aug 29, 2026
Merged

Add an initial version of a preferences dialog#2261
cameronwhite merged 1 commit into
masterfrom
feature/prefs-dialog

Conversation

@cameronwhite

@cameronwhite cameronwhite commented Aug 21, 2026

Copy link
Copy Markdown
Member

Description of Changes

  • Use the libadwaita preferences dialog, and define the layout using a .ui file to test out this process for the first time (works quite well!).

  • Move the color scheme preference into the dialog as a test. By adding an event when settings are modified, changes to the settings can be decoupled from the dialog itself

  • Add a Preferences menu item. Depending on the platform, this is in the application menu on macOS, or in the Edit menu for a menubar layout on other platforms, or in the main menu when using a headerbar layout.

    • Also simplified logic around how the macOS app menu commands are registered, and adjusted the keyboard shortcut dialog to use different shortcuts from the prefs dialog
  • TODO: figure out how to translate the .ui file. If we used the native gettext library for our translations this would just work automatically, so perhaps we should attempt to do this? Otherwise we need to implement a custom loader which translates the xml file using our Translations.GetString() function

prefs

Checklist

@badcel

badcel commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Great that you like the UI files 👍

If your solution for translations can be supported by GirCore we can try to upstream it or parts of it. There is already a ticket to improve the UI file translation situation but without any concrete idea yet: gircore/gir.core#1482

@cameronwhite

Copy link
Copy Markdown
Member Author

One option would be to extend the AssemblyResource loader with an additional step that parses the xml file and replaces any translatable strings (probably fairly similar to what the Parabolic app is doing already). The parsing code could be upstream, and then users would just need a way to provide their translation function (e.g. subclassing the default implementation, or implementing some interface that's provided to the loader, etc)
That's probably the most generic way to handle it, especially for apps like Parabolic which have multiple frontends and might want to use some other library for translations

The other approach I've been looking at is just having Pinta use the native gettext functions for its translations, instead of the managed library we've been using - PR #2263. We used to do this back in the GTK2 days, where gtk-sharp had a wrapper Mono.Unix.Catalog

We already bundle libintl since it's used by GTK, libadwaita, etc, so using this is pretty reasonable and just requires a few bindings for the native functions. The .ui translations then just work without any extra steps since GTK translates them using the native gettext library when loading the files

@badcel

badcel commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

I think you can already provide custom resource loaders so influencing the xml is already possible. Adding another configuration point inside it feels a little much to me.

It sounds pretty great to use the gettext package. One idea which came to my mind is to just let the user use an attribute on assembly level like SetupGettextAttribute(...) which then generates the code inside GirCore.Integration.Initialize();.

In this way if you call it everything gets setup automatically including language and subclass registration.

@cameronwhite

Copy link
Copy Markdown
Member Author

Agreed, I think it should be doable as-is to provide a custom resource loader - it's just more work to implement the parsing. But IMO using the native gettext will probably be the easiest avenue for most users.

Initializing gettext can involve some runtime configuration (e.g. to come up with the folder path that gettext should load from, or possibly changing the language-related env vars to override the default language selection), so my initial thinking was to just start with some straightforward bindings that mirror the C api before trying to come up with a higher-level utility?

@badcel

badcel commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Yes this would be possible too. I suggested the attribute instead of an API because:

  • it's not clear were to put the API, inside a new Nuget?
  • it's not a GObject based library

If I use an attribute and generate the code in the user project I don't need a new Nuget and it's more like a configuration. I don't know if there are lots of possibilities to use gettext? I thought it's always the same 3 calls in order and that's it. Do you know otherwise?

@cameronwhite

Copy link
Copy Markdown
Member Author

Yeah it's a bit different not being a gobject-based library, although it's maybe not too different from the Cairo bindings which are mostly manual

The initialization is pretty much always the same AFAIK, although for a library you would skip calling textdomain() which sets the global default
There are lots of other functions for the different variants of getting a translated string like dgettext(), ngettext() etc, but in the PR I was using Glib's wrappers around those for convenience

@badcel

badcel commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Yeah you are right. I think having a new Nuget is probably the way to go.

cameronwhite added a commit that referenced this pull request Aug 29, 2026
- Related to PR #2261, using the native gettext library is the simplest way to also support translations for .ui files - no additional work is needed since GTK already calls dgettext() for any translatable strings when loading the xml file

- We already bundle libintl with Pinta (since it's required by GTK, libadwaita etc) so this doesn't require any additional packaging. I think the original motivation for using the managed Ngettext library was because we no longer had any bindings to gettext when porting to GTK3 - for GTK2 we used the Mono.Unix.Catalog wrapper for the native library

- Several of the native methods are already wrapped via GLib and have bindings available (e.g. GLib.Functions.Dgettext()) so this just requires a couple custom bindings for functions like textdomain(). We previously already had one binding for bindtextdomain() to configure libadwaita's translation directory for the macOS app bundle
- Use the libadwaita preferences dialog, and define the layout using an xml .ui file to test out this process for the first time.

- Move the color scheme preference into the dialog as a test. By adding an event when settings are modified, changes to the settings can be decoupled from the dialog itself

- Add a Preferences menu item. Depending on the platform, this is in the application menu on macOS, or in the Edit menu for a menubar layout, or in the main menu when using a headerbar layout.

  - Also simplified logic around how the macOS app menu commands are registered, and fixed the keyboard shortcut dialog to use different shortcuts from the prefs dialog
@cameronwhite
cameronwhite marked this pull request as ready for review August 29, 2026 03:39
@cameronwhite
cameronwhite merged commit cfe8e44 into master Aug 29, 2026
11 checks passed
@cameronwhite
cameronwhite deleted the feature/prefs-dialog branch August 29, 2026 23:06
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.

2 participants