diff --git a/libgimpbase/gimpbase.def b/libgimpbase/gimpbase.def
index 7c01ca46c3..5f05604cf4 100644
--- a/libgimpbase/gimpbase.def
+++ b/libgimpbase/gimpbase.def
@@ -17,6 +17,16 @@ EXPORTS
gimp_check_size_get_type
gimp_check_type_get_type
gimp_checks_get_colors
+ gimp_choice_add
+ gimp_choice_get_documentation
+ gimp_choice_get_help
+ gimp_choice_get_id
+ gimp_choice_get_label
+ gimp_choice_get_type
+ gimp_choice_is_valid
+ gimp_choice_list_nicks
+ gimp_choice_new
+ gimp_choice_new_with_values
gimp_clone_type_get_type
gimp_color_tag_get_type
gimp_component_type_get_type
diff --git a/libgimpbase/gimpchoice.c b/libgimpbase/gimpchoice.c
new file mode 100644
index 0000000000..92a59ee2f6
--- /dev/null
+++ b/libgimpbase/gimpchoice.c
@@ -0,0 +1,340 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
+ *
+ * gimpchoice.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include "config.h"
+
+#include
+
+#include "gimpbasetypes.h"
+
+#include "gimpchoice.h"
+#include "gimpparamspecs.h"
+
+
+typedef struct _GimpChoiceDesc
+{
+ gchar *label;
+ gchar *help;
+ gint id;
+} GimpChoiceDesc;
+
+struct _GimpChoice
+{
+ GObject parent_instance;
+
+ GHashTable *choices;
+ GList *keys;
+};
+
+
+static void gimp_choice_finalize (GObject *object);
+
+static void gimp_choice_desc_free (GimpChoiceDesc *desc);
+
+
+G_DEFINE_TYPE (GimpChoice, gimp_choice, G_TYPE_OBJECT)
+
+#define parent_class gimp_choice_parent_class
+
+static void
+gimp_choice_class_init (GimpChoiceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_choice_finalize;
+}
+
+static void
+gimp_choice_init (GimpChoice *choice)
+{
+ choice->choices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) gimp_choice_desc_free);
+}
+
+static void
+gimp_choice_finalize (GObject *object)
+{
+ GimpChoice *choice = GIMP_CHOICE (object);
+
+ g_hash_table_unref (choice->choices);
+ g_list_free_full (choice->keys, (GDestroyNotify) g_free);
+}
+
+/* Public API */
+
+/**
+ * gimp_choice_new:
+ *
+ * Returns: (transfer full): a #GimpChoice.
+ *
+ * Since: 3.0
+ **/
+GimpChoice *
+gimp_choice_new (void)
+{
+ GimpChoice *choice;
+
+ choice = g_object_new (GIMP_TYPE_CHOICE, NULL);
+
+ return choice;
+}
+
+/**
+ * gimp_choice_new_with_values:
+ * @nick: the first value.
+ * @id: integer ID for @nick.
+ * @label: the label of @nick.
+ * @help: longer help text for @nick.
+ * ...: more triplets of string to pre-fill the created %GimpChoice.
+ *
+ * Returns: (transfer full): a #GimpChoice.
+ *
+ * Since: 3.0
+ **/
+GimpChoice *
+gimp_choice_new_with_values (const gchar *nick,
+ gint id,
+ const gchar *label,
+ const gchar *help,
+ ...)
+{
+ GimpChoice *choice;
+ va_list va_args;
+
+ g_return_val_if_fail (nick != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ choice = gimp_choice_new ();
+
+ va_start (va_args, help);
+
+ do
+ {
+ gimp_choice_add (choice, nick, id, label, help);
+ nick = va_arg (va_args, const gchar *);
+ if (nick == NULL)
+ break;
+ id = va_arg (va_args, gint);
+ label = va_arg (va_args, const gchar *);
+ if (label == NULL)
+ {
+ g_critical ("%s: nick '%s' cannot have a NULL label.", G_STRFUNC, nick);
+ break;
+ }
+ help = va_arg (va_args, const gchar *);
+ }
+ while (TRUE);
+
+ va_end (va_args);
+
+ return choice;
+}
+
+/**
+ * gimp_choice_add:
+ * @choice: the %GimpChoice.
+ * @nick: the nick of @choice.
+ * @id: optional integer ID for @nick.
+ * @label: the label of @choice.
+ * @help: optional longer help text for @nick.
+ *
+ * This procedure adds a new possible value to @choice list of values.
+ * The @id is an optional integer identifier. This can be useful for instance
+ * when you want to work with different enum values mapped to each @nick.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_choice_add (GimpChoice *choice,
+ const gchar *nick,
+ gint id,
+ const gchar *label,
+ const gchar *help)
+{
+ GimpChoiceDesc *desc;
+ GList *duplicate;
+
+ g_return_if_fail (label != NULL);
+
+ desc = g_new0 (GimpChoiceDesc, 1);
+ desc->id = id;
+ desc->label = g_strdup (label);
+ desc->help = help != NULL ? g_strdup (help) : NULL;
+ g_hash_table_insert (choice->choices, g_strdup (nick), desc);
+
+ duplicate = g_list_find_custom (choice->keys, nick, (GCompareFunc) g_strcmp0);
+ if (duplicate != NULL)
+ {
+ choice->keys = g_list_remove_link (choice->keys, duplicate);
+ gimp_choice_desc_free (duplicate->data);
+ g_list_free (duplicate);
+ }
+ choice->keys = g_list_append (choice->keys, g_strdup (nick));
+}
+
+/**
+ * gimp_choice_is_valid:
+ * @choice: a %GimpChoice.
+ * @nick: the nick to check.
+ *
+ * This procedure checks if the given @nick is valid and refers to
+ * an existing choice.
+ *
+ * Returns: Whether the choice is valid.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gimp_choice_is_valid (GimpChoice *choice,
+ const gchar *nick)
+{
+ return (g_hash_table_lookup (choice->choices, nick) != NULL);
+}
+
+/**
+ * gimp_choice_list_nicks:
+ * @choice: a %GimpChoice.
+ * @nick: the nick to check.
+ *
+ * This procedure returns the list of nicks allowed for @choice.
+ *
+ * Returns: (element-type gchar*) (transfer none): The list of @choice's nicks.
+ *
+ * Since: 3.0
+ **/
+GList *
+gimp_choice_list_nicks (GimpChoice *choice)
+{
+ /* I don't use g_hash_table_get_keys() on purpose, because I want to retain
+ * the adding-time order.
+ */
+ return choice->keys;
+}
+
+/**
+ * gimp_choice_get_id:
+ * @choice: a %GimpChoice.
+ * @nick: the nick to lookup.
+ *
+ * Returns: the ID of @nick.
+ *
+ * Since: 3.0
+ **/
+gint
+gimp_choice_get_id (GimpChoice *choice,
+ const gchar *nick)
+{
+ GimpChoiceDesc *desc;
+
+ desc = g_hash_table_lookup (choice->choices, nick);
+ if (desc)
+ return desc->id;
+ else
+ return 0;
+}
+
+/**
+ * gimp_choice_get_label:
+ * @choice: a %GimpChoice.
+ * @nick: the nick to lookup.
+ *
+ * Returns: (transfer none): the label of @nick.
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_choice_get_label (GimpChoice *choice,
+ const gchar *nick)
+{
+ GimpChoiceDesc *desc;
+
+ desc = g_hash_table_lookup (choice->choices, nick);
+ if (desc)
+ return desc->label;
+ else
+ return NULL;
+}
+
+/**
+ * gimp_choice_get_help:
+ * @choice: a %GimpChoice.
+ * @nick: the nick to lookup.
+ *
+ * Returns the longer documentation for @nick.
+ *
+ * Returns: (transfer none): the help text of @nick.
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_choice_get_help (GimpChoice *choice,
+ const gchar *nick)
+{
+ GimpChoiceDesc *desc;
+
+ desc = g_hash_table_lookup (choice->choices, nick);
+ if (desc)
+ return desc->help;
+ else
+ return NULL;
+}
+
+/**
+ * gimp_choice_get_documentation:
+ * @choice: the %GimpChoice.
+ * @nick: the possible value's nick you need documentation for.
+ * @label: (transfer none): the label of @nick.
+ * @help: (transfer none): the help text of @nick.
+ *
+ * Returns the documentation strings for @nick.
+ *
+ * Returns: %TRUE if @nick is found, %FALSE otherwise.
+ *
+ * Since: 3.0
+ **/
+gboolean
+gimp_choice_get_documentation (GimpChoice *choice,
+ const gchar *nick,
+ const gchar **label,
+ const gchar **help)
+{
+ GimpChoiceDesc *desc;
+
+ desc = g_hash_table_lookup (choice->choices, nick);
+ if (desc)
+ {
+ *label = desc->label;
+ *help = desc->help;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Private functions */
+
+static void
+gimp_choice_desc_free (GimpChoiceDesc *desc)
+{
+ g_free (desc->label);
+ g_free (desc->help);
+ g_free (desc);
+}
diff --git a/libgimpbase/gimpchoice.h b/libgimpbase/gimpchoice.h
new file mode 100644
index 0000000000..783efca9f1
--- /dev/null
+++ b/libgimpbase/gimpchoice.h
@@ -0,0 +1,69 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
+ *
+ * gimpchoice.h
+ * Copyright (C) 2023 Jehan
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#if !defined (__GIMP_BASE_H_INSIDE__) && !defined (GIMP_BASE_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+
+#ifndef __GIMP_CHOICE_H__
+#define __GIMP_CHOICE_H__
+
+G_BEGIN_DECLS
+
+
+/* For information look into the C source or the html documentation */
+
+
+#define GIMP_TYPE_CHOICE (gimp_choice_get_type ())
+G_DECLARE_FINAL_TYPE (GimpChoice, gimp_choice, GIMP, CHOICE, GObject)
+
+
+GimpChoice * gimp_choice_new (void);
+GimpChoice * gimp_choice_new_with_values (const gchar *nick,
+ gint id,
+ const gchar *label,
+ const gchar *help,
+ ...) G_GNUC_NULL_TERMINATED;
+void gimp_choice_add (GimpChoice *choice,
+ const gchar *nick,
+ gint id,
+ const gchar *label,
+ const gchar *help);
+
+gboolean gimp_choice_is_valid (GimpChoice *choice,
+ const gchar *nick);
+GList * gimp_choice_list_nicks (GimpChoice *choice);
+gint gimp_choice_get_id (GimpChoice *choice,
+ const gchar *nick);
+const gchar * gimp_choice_get_label (GimpChoice *choice,
+ const gchar *nick);
+const gchar * gimp_choice_get_help (GimpChoice *choice,
+ const gchar *nick);
+gboolean gimp_choice_get_documentation (GimpChoice *choice,
+ const gchar *nick,
+ const gchar **label,
+ const gchar **help);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_CHOICE_H__ */
diff --git a/libgimpbase/meson.build b/libgimpbase/meson.build
index 5f90556d72..2fbd6710b1 100644
--- a/libgimpbase/meson.build
+++ b/libgimpbase/meson.build
@@ -51,6 +51,7 @@ stamp_compat_enums = custom_target('stamp-gimpcompatenums.h',
libgimpbase_sources_introspectable = files(
'gimpbasetypes.c',
'gimpchecks.c',
+ 'gimpchoice.c',
'gimpcpuaccel.c',
'gimpenv.c',
'gimpmemsize.c',