diff --git a/devel-docs/libgimpwidgets/libgimpwidgets-docs.sgml b/devel-docs/libgimpwidgets/libgimpwidgets-docs.sgml
index 16f49ffbe8..f00ff333ec 100644
--- a/devel-docs/libgimpwidgets/libgimpwidgets-docs.sgml
+++ b/devel-docs/libgimpwidgets/libgimpwidgets-docs.sgml
@@ -136,6 +136,10 @@
Index of new symbols in GIMP 2.10.4
+
+ Index of new symbols in GIMP 2.10.10
+
+
Index of deprecated symbols
diff --git a/devel-docs/libgimpwidgets/libgimpwidgets-sections.txt b/devel-docs/libgimpwidgets/libgimpwidgets-sections.txt
index 3336d92496..3b0b6767d1 100644
--- a/devel-docs/libgimpwidgets/libgimpwidgets-sections.txt
+++ b/devel-docs/libgimpwidgets/libgimpwidgets-sections.txt
@@ -530,6 +530,23 @@ GIMP_TYPE_INT_COMBO_BOX_LAYOUT
gimp_int_combo_box_layout_get_type
+
+gimpspinbutton
+GimpSpinButton
+GimpSpinButton
+gimp_spin_button_new
+gimp_spin_button_new_with_range
+
+GIMP_SPIN_BUTTON
+GIMP_IS_SPIN_BUTTON
+GIMP_TYPE_SPIN_BUTTON
+gimp_spin_button_get_type
+GimpSpinButtonClass
+GIMP_SPIN_BUTTON_CLASS
+GIMP_IS_SPIN_BUTTON_CLASS
+GIMP_SPIN_BUTTON_GET_CLASS
+
+
gimpstringcombobox
GimpStringComboBox
diff --git a/devel-docs/libgimpwidgets/libgimpwidgets.types b/devel-docs/libgimpwidgets/libgimpwidgets.types
index 3ce98519aa..abd39f26a1 100644
--- a/devel-docs/libgimpwidgets/libgimpwidgets.types
+++ b/devel-docs/libgimpwidgets/libgimpwidgets.types
@@ -46,6 +46,7 @@ gimp_preview_get_type
gimp_ruler_get_type
gimp_scrolled_preview_get_type
gimp_size_entry_get_type
+gimp_spin_button_get_type
gimp_string_combo_box_get_type
gimp_unit_combo_box_get_type
gimp_unit_menu_get_type
diff --git a/libgimpwidgets/Makefile.am b/libgimpwidgets/Makefile.am
index e9b0cacde2..4daca1789e 100644
--- a/libgimpwidgets/Makefile.am
+++ b/libgimpwidgets/Makefile.am
@@ -179,6 +179,8 @@ libgimpwidgets_sources = \
gimpscrolledpreview.h \
gimpsizeentry.c \
gimpsizeentry.h \
+ gimpspinbutton.c \
+ gimpspinbutton.h \
gimpstringcombobox.c \
gimpstringcombobox.h \
gimpunitcombobox.c \
diff --git a/libgimpwidgets/gimpspinbutton.c b/libgimpwidgets/gimpspinbutton.c
new file mode 100644
index 0000000000..de69fcd4bb
--- /dev/null
+++ b/libgimpwidgets/gimpspinbutton.c
@@ -0,0 +1,226 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpspinbutton.c
+ * Copyright (C) 2018 Ell
+ *
+ * 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
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpwidgetstypes.h"
+
+#include "gimp3migration.h"
+#include "gimpspinbutton.h"
+
+
+/**
+ * SECTION: gimpspinbutton
+ * @title: GimpSpinButton
+ * @short_description: A #GtkSpinButton with a some tweaked functionality.
+ *
+ * #GimpSpinButton modifies the behavior of #GtkSpinButton, so that
+ * when the spin-button loses focus, its adjustment value is only
+ * updated if the entry text has been changed.
+ **/
+
+
+#define MAX_DIGITS 20
+
+
+struct _GimpSpinButtonPrivate
+{
+ gboolean changed;
+};
+
+
+/* local function prototypes */
+
+static gboolean gimp_spin_button_focus_in (GtkWidget *widget,
+ GdkEventFocus *event);
+static gboolean gimp_spin_button_focus_out (GtkWidget *widget,
+ GdkEventFocus *event);
+
+static void gimp_spin_button_changed (GtkEditable *editable,
+ gpointer data);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpSpinButton, gimp_spin_button,
+ GTK_TYPE_SPIN_BUTTON)
+
+#define parent_class gimp_spin_button_parent_class
+
+
+/* private functions */
+
+
+static void
+gimp_spin_button_class_init (GimpSpinButtonClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ widget_class->focus_in_event = gimp_spin_button_focus_in;
+ widget_class->focus_out_event = gimp_spin_button_focus_out;
+}
+
+static void
+gimp_spin_button_init (GimpSpinButton *spin_button)
+{
+ spin_button->priv = gimp_spin_button_get_instance_private (spin_button);
+
+ g_signal_connect (spin_button, "changed",
+ G_CALLBACK (gimp_spin_button_changed),
+ NULL);
+}
+
+static gboolean
+gimp_spin_button_focus_in (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ GimpSpinButton *spin_button = GIMP_SPIN_BUTTON (widget);
+
+ spin_button->priv->changed = FALSE;
+
+ return GTK_WIDGET_CLASS (parent_class)->focus_in_event (widget, event);
+}
+
+static gboolean
+gimp_spin_button_focus_out (GtkWidget *widget,
+ GdkEventFocus *event)
+{
+ GimpSpinButton *spin_button = GIMP_SPIN_BUTTON (widget);
+ gboolean editable;
+ gboolean result;
+
+ editable = gtk_editable_get_editable (GTK_EDITABLE (widget));
+
+ if (! spin_button->priv->changed)
+ gtk_editable_set_editable (GTK_EDITABLE (widget), FALSE);
+
+ result = GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
+
+ if (! spin_button->priv->changed)
+ gtk_editable_set_editable (GTK_EDITABLE (widget), editable);
+
+ return result;
+}
+
+static void
+gimp_spin_button_changed (GtkEditable *editable,
+ gpointer data)
+{
+ GimpSpinButton *spin_button = GIMP_SPIN_BUTTON (editable);
+
+ spin_button->priv->changed = TRUE;
+}
+
+
+/* public functions */
+
+
+/**
+ * gimp_spin_button_new:
+ * @adjustment: (allow-none): the #GtkAdjustment object that this spin
+ * button should use, or %NULL
+ * @climb_rate: specifies by how much the rate of change in the
+ * value will accelerate if you continue to hold
+ * down an up/down button or arrow key
+ * @digits: the number of decimal places to display
+ *
+ * Creates a new #GimpSpinButton.
+ *
+ * Returns: The new spin button as a #GtkWidget
+ *
+ * Since: 2.10.10
+ */
+GtkWidget *
+gimp_spin_button_new_ (GtkAdjustment *adjustment,
+ gdouble climb_rate,
+ guint digits)
+{
+ GtkWidget *spin_button;
+
+ g_return_val_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment),
+ NULL);
+
+ spin_button = g_object_new (GIMP_TYPE_SPIN_BUTTON, NULL);
+
+ gtk_spin_button_configure (GTK_SPIN_BUTTON (spin_button),
+ adjustment, climb_rate, digits);
+
+ return spin_button;
+}
+
+/**
+ * gimp_spin_button_new_with_range:
+ * @min: Minimum allowable value
+ * @max: Maximum allowable value
+ * @step: Increment added or subtracted by spinning the widget
+ *
+ * This is a convenience constructor that allows creation of a numeric
+ * #GimpSpinButton without manually creating an adjustment. The value is
+ * initially set to the minimum value and a page increment of 10 * @step
+ * is the default. The precision of the spin button is equivalent to the
+ * precision of @step.
+ *
+ * Note that the way in which the precision is derived works best if @step
+ * is a power of ten. If the resulting precision is not suitable for your
+ * needs, use gtk_spin_button_set_digits() to correct it.
+ *
+ * Returns: The new spin button as a #GtkWidget
+ *
+ * Since: 2.10.10
+ */
+GtkWidget *
+gimp_spin_button_new_with_range (gdouble min,
+ gdouble max,
+ gdouble step)
+{
+ GtkAdjustment *adjustment;
+ GtkWidget *spin_button;
+ gint digits;
+
+ g_return_val_if_fail (min <= max, NULL);
+ g_return_val_if_fail (step != 0.0, NULL);
+
+ spin_button = g_object_new (GTK_TYPE_SPIN_BUTTON, NULL);
+
+ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (min, min, max,
+ step, 10.0 * step, 0.0));
+
+ if (fabs (step) >= 1.0 || step == 0.0)
+ {
+ digits = 0;
+ }
+ else
+ {
+ digits = abs ((gint) floor (log10 (fabs (step))));
+
+ if (digits > MAX_DIGITS)
+ digits = MAX_DIGITS;
+ }
+
+ gtk_spin_button_configure (GTK_SPIN_BUTTON (spin_button),
+ adjustment, step, digits);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin_button), TRUE);
+
+ return spin_button;
+}
diff --git a/libgimpwidgets/gimpspinbutton.h b/libgimpwidgets/gimpspinbutton.h
new file mode 100644
index 0000000000..ea77cd6d99
--- /dev/null
+++ b/libgimpwidgets/gimpspinbutton.h
@@ -0,0 +1,90 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpspinbutton.h
+ * Copyright (C) 2018 Ell
+ *
+ * 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_WIDGETS_H_INSIDE__) && !defined (GIMP_WIDGETS_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __GIMP_SPIN_BUTTON_H__
+#define __GIMP_SPIN_BUTTON_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+#define GIMP_TYPE_SPIN_BUTTON (gimp_spin_button_get_type ())
+#define GIMP_SPIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SPIN_BUTTON, GimpSpinButton))
+#define GIMP_SPIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SPIN_BUTTON, GimpSpinButtonClass))
+#define GIMP_IS_SPIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SPIN_BUTTON))
+#define GIMP_IS_SPIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SPIN_BUTTON))
+#define GIMP_SPIN_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SPIN_BUTTON, GimpSpinButtonClass))
+
+
+typedef struct _GimpSpinButtonPrivate GimpSpinButtonPrivate;
+typedef struct _GimpSpinButtonClass GimpSpinButtonClass;
+
+struct _GimpSpinButton
+{
+ GtkSpinButton parent_instance;
+
+ GimpSpinButtonPrivate *priv;
+};
+
+struct _GimpSpinButtonClass
+{
+ GtkSpinButtonClass parent_class;
+
+ /* Padding for future expansion */
+ void (* _gimp_reserved1) (void);
+ void (* _gimp_reserved2) (void);
+ void (* _gimp_reserved3) (void);
+ void (* _gimp_reserved4) (void);
+};
+
+
+GType gimp_spin_button_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_spin_button_new_ (GtkAdjustment *adjustment,
+ gdouble climb_rate,
+ guint digits);
+GtkWidget * gimp_spin_button_new_with_range (gdouble min,
+ gdouble max,
+ gdouble step);
+
+
+/* compatibility magic, expanding to either the old (deprecated)
+ * gimp_spin_button_new(), defined in gimpwidgets.h, or the new
+ * gimp_spin_button_new(), defined here, based on the number of arguments.
+ */
+#define gimp_spin_button_new(...) gimp_spin_button_new_I (__VA_ARGS__, \
+ 9, , , , , , 3)
+#define gimp_spin_button_new_I(_1, _2, _3, _4, _5, _6, _7, _8, _9, n, ...) \
+ gimp_spin_button_new_I_##n (_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define gimp_spin_button_new_I_3(_1, _2, _3, _4, _5, _6, _7, _8, _9) \
+ gimp_spin_button_new_ (_1, _2, _3)
+#define gimp_spin_button_new_I_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) \
+ gimp_spin_button_new (_1, _2, _3, _4, _5, _6, _7, _8, _9)
+
+
+G_END_DECLS
+
+#endif /* __GIMP_SPIN_BUTTON_H__ */
diff --git a/libgimpwidgets/gimpwidgets.def b/libgimpwidgets/gimpwidgets.def
index ed52b18b2c..134123a2a5 100644
--- a/libgimpwidgets/gimpwidgets.def
+++ b/libgimpwidgets/gimpwidgets.def
@@ -402,7 +402,10 @@ EXPORTS
gimp_size_entry_set_value_boundaries
gimp_size_entry_show_unit_menu
gimp_size_entry_update_policy_get_type
+ gimp_spin_button_get_type
gimp_spin_button_new
+ gimp_spin_button_new_
+ gimp_spin_button_new_with_range
gimp_standard_help_func
gimp_stock_init
gimp_string_combo_box_get_active
diff --git a/libgimpwidgets/gimpwidgets.h b/libgimpwidgets/gimpwidgets.h
index b6367bfdf6..f3d8b773e4 100644
--- a/libgimpwidgets/gimpwidgets.h
+++ b/libgimpwidgets/gimpwidgets.h
@@ -75,6 +75,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libgimpwidgets/gimpwidgetstypes.h b/libgimpwidgets/gimpwidgetstypes.h
index 839d17b32b..3dfec172d9 100644
--- a/libgimpwidgets/gimpwidgetstypes.h
+++ b/libgimpwidgets/gimpwidgetstypes.h
@@ -72,6 +72,7 @@ typedef struct _GimpPixmap GimpPixmap;
typedef struct _GimpRuler GimpRuler;
typedef struct _GimpScrolledPreview GimpScrolledPreview;
typedef struct _GimpSizeEntry GimpSizeEntry;
+typedef struct _GimpSpinButton GimpSpinButton;
typedef struct _GimpStringComboBox GimpStringComboBox;
typedef struct _GimpUnitComboBox GimpUnitComboBox;
typedef struct _GimpUnitMenu GimpUnitMenu;