/* LIBGIMP - The GIMP Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * gimpscaleentry.c * Copyright (C) 2000 Michael Natterer * * 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 * Library 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 "libgimpcolor/gimpcolor.h" #include "libgimpmath/gimpmath.h" #include "libgimpbase/gimpbase.h" #include "gimpwidgets.h" static void gimp_scale_entry_unconstrained_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj); static void gimp_scale_entry_exp_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj); static void gimp_scale_entry_log_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj); static GtkObject * gimp_scale_entry_new_internal (gboolean color_scale, GtkTable *table, gint column, gint row, const gchar *text, gint scale_width, gint spinbutton_width, gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, guint digits, gboolean constrain, gdouble unconstrained_lower, gdouble unconstrained_upper, const gchar *tooltip, const gchar *help_id); static void gimp_scale_entry_unconstrained_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj) { g_signal_handlers_block_by_func (other_adj, gimp_scale_entry_unconstrained_adjustment_callback, adjustment); gtk_adjustment_set_value (other_adj, gtk_adjustment_get_value (adjustment)); g_signal_handlers_unblock_by_func (other_adj, gimp_scale_entry_unconstrained_adjustment_callback, adjustment); } static void gimp_scale_entry_log_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj) { gdouble value; g_signal_handlers_block_by_func (other_adj, gimp_scale_entry_exp_adjustment_callback, adjustment); if (gtk_adjustment_get_lower (adjustment) <= 0.0) value = log (gtk_adjustment_get_value (adjustment) - gtk_adjustment_get_lower (adjustment) + 0.1); else value = log (gtk_adjustment_get_value (adjustment)); gtk_adjustment_set_value (other_adj, value); g_signal_handlers_unblock_by_func (other_adj, gimp_scale_entry_exp_adjustment_callback, adjustment); } static void gimp_scale_entry_exp_adjustment_callback (GtkAdjustment *adjustment, GtkAdjustment *other_adj) { gdouble value; g_signal_handlers_block_by_func (other_adj, gimp_scale_entry_log_adjustment_callback, adjustment); value = exp (gtk_adjustment_get_value (adjustment)); if (gtk_adjustment_get_lower (other_adj) <= 0.0) value += gtk_adjustment_get_lower (other_adj) - 0.1; gtk_adjustment_set_value (other_adj, value); g_signal_handlers_unblock_by_func (other_adj, gimp_scale_entry_log_adjustment_callback, adjustment); } static GtkObject * gimp_scale_entry_new_internal (gboolean color_scale, GtkTable *table, gint column, gint row, const gchar *text, gint scale_width, gint spinbutton_width, gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, guint digits, gboolean constrain, gdouble unconstrained_lower, gdouble unconstrained_upper, const gchar *tooltip, const gchar *help_id) { GtkWidget *label; GtkWidget *ebox; GtkWidget *scale; GtkWidget *spinbutton; GtkObject *adjustment; GtkObject *return_adj; label = gtk_label_new_with_mnemonic (text); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); if (tooltip) { ebox = g_object_new (GTK_TYPE_EVENT_BOX, "visible-window", FALSE, NULL); gtk_table_attach (GTK_TABLE (table), ebox, column, column + 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (ebox); gtk_container_add (GTK_CONTAINER (ebox), label); } else { ebox = NULL; gtk_table_attach (GTK_TABLE (table), label, column, column + 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); } gtk_widget_show (label); if (! constrain && unconstrained_lower <= lower && unconstrained_upper >= upper) { GtkObject *constrained_adj; constrained_adj = gtk_adjustment_new (value, lower, upper, step_increment, page_increment, 0.0); spinbutton = gimp_spin_button_new (&adjustment, value, unconstrained_lower, unconstrained_upper, step_increment, page_increment, 0.0, 1.0, digits); g_signal_connect (G_OBJECT (constrained_adj), "value-changed", G_CALLBACK (gimp_scale_entry_unconstrained_adjustment_callback), adjustment); g_signal_connect (G_OBJECT (adjustment), "value-changed", G_CALLBACK (gimp_scale_entry_unconstrained_adjustment_callback), constrained_adj); return_adj = adjustment; adjustment = constrained_adj; } else { spinbutton = gimp_spin_button_new (&adjustment, value, lower, upper, step_increment, page_increment, 0.0, 1.0, digits); return_adj = adjustment; } gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton); if (spinbutton_width > 0) { if (spinbutton_width < 17) gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), spinbutton_width); else gtk_widget_set_size_request (spinbutton, spinbutton_width, -1); } if (color_scale) { scale = gimp_color_scale_new (GTK_ORIENTATION_HORIZONTAL, GIMP_COLOR_SELECTOR_VALUE); gtk_range_set_adjustment (GTK_RANGE (scale), GTK_ADJUSTMENT (adjustment)); } else { scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment)); } if (scale_width > 0) gtk_widget_set_size_request (scale, scale_width, -1); gtk_scale_set_digits (GTK_SCALE (scale), digits); gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); gtk_table_attach (GTK_TABLE (table), scale, column + 1, column + 2, row, row + 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_widget_show (scale); gtk_table_attach (GTK_TABLE (table), spinbutton, column + 2, column + 3, row, row + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); gtk_widget_show (spinbutton); if (tooltip || help_id) { if (ebox) gimp_help_set_help_data (ebox, tooltip, help_id); gimp_help_set_help_data (scale, tooltip, help_id); gimp_help_set_help_data (spinbutton, tooltip, help_id); } g_object_set_data (G_OBJECT (return_adj), "label", label); g_object_set_data (G_OBJECT (return_adj), "scale", scale); g_object_set_data (G_OBJECT (return_adj), "spinbutton", spinbutton); return return_adj; } /** * gimp_scale_entry_new: * @table: The #GtkTable the widgets will be attached to. * @column: The column to start with. * @row: The row to attach the widgets. * @text: The text for the #GtkLabel which will appear * left of the #GtkHScale. * @scale_width: The minimum horizontal size of the #GtkHScale. * @spinbutton_width: The minimum horizontal size of the #GtkSpinButton. * @value: The initial value. * @lower: The lower boundary. * @upper: The upper boundary. * @step_increment: The step increment. * @page_increment: The page increment. * @digits: The number of decimal digits. * @constrain: %TRUE if the range of possible values of the * #GtkSpinButton should be the same as of the #GtkHScale. * @unconstrained_lower: The spinbutton's lower boundary * if @constrain == %FALSE. * @unconstrained_upper: The spinbutton's upper boundary * if @constrain == %FALSE. * @tooltip: A tooltip message for the scale and the spinbutton. * @help_id: The widgets' help_id (see gimp_help_set_help_data()). * * This function creates a #GtkLabel, a #GtkHScale and a #GtkSpinButton and * attaches them to a 3-column #GtkTable. * * Returns: The #GtkSpinButton's #GtkAdjustment. **/ GtkObject * gimp_scale_entry_new (GtkTable *table, gint column, gint row, const gchar *text, gint scale_width, gint spinbutton_width, gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, guint digits, gboolean constrain, gdouble unconstrained_lower, gdouble unconstrained_upper, const gchar *tooltip, const gchar *help_id) { return gimp_scale_entry_new_internal (FALSE, table, column, row, text, scale_width, spinbutton_width, value, lower, upper, step_increment, page_increment, digits, constrain, unconstrained_lower, unconstrained_upper, tooltip, help_id); } /** * gimp_color_scale_entry_new: * @table: The #GtkTable the widgets will be attached to. * @column: The column to start with. * @row: The row to attach the widgets. * @text: The text for the #GtkLabel which will appear * left of the #GtkHScale. * @scale_width: The minimum horizontal size of the #GtkHScale. * @spinbutton_width: The minimum horizontal size of the #GtkSpinButton. * @value: The initial value. * @lower: The lower boundary. * @upper: The upper boundary. * @step_increment: The step increment. * @page_increment: The page increment. * @digits: The number of decimal digits. * @tooltip: A tooltip message for the scale and the spinbutton. * @help_id: The widgets' help_id (see gimp_help_set_help_data()). * * This function creates a #GtkLabel, a #GimpColorScale and a * #GtkSpinButton and attaches them to a 3-column #GtkTable. * * Returns: The #GtkSpinButton's #GtkAdjustment. **/ GtkObject * gimp_color_scale_entry_new (GtkTable *table, gint column, gint row, const gchar *text, gint scale_width, gint spinbutton_width, gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, guint digits, const gchar *tooltip, const gchar *help_id) { return gimp_scale_entry_new_internal (TRUE, table, column, row, text, scale_width, spinbutton_width, value, lower, upper, step_increment, page_increment, digits, TRUE, 0.0, 0.0, tooltip, help_id); } /** * gimp_scale_entry_set_logarithmic: * @adjustment: a #GtkAdjustment as returned by gimp_scale_entry_new() * @logarithmic: a boolean value to set or reset logarithmic behaviour * of the scale widget * * Sets whether the scale_entry's scale widget will behave in a linear * or logharithmic fashion. Useful when an entry has to attend large * ranges, but smaller selections on that range require a finer * adjustment. * * Since: GIMP 2.2 **/ void gimp_scale_entry_set_logarithmic (GtkObject *adjustment, gboolean logarithmic) { GtkAdjustment *adj; GtkAdjustment *scale_adj; g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); adj = GTK_ADJUSTMENT (adjustment); scale_adj = GIMP_SCALE_ENTRY_SCALE_ADJ (adjustment); if (logarithmic == gimp_scale_entry_get_logarithmic (adjustment)) return; if (logarithmic) { gdouble correction; gdouble log_value, log_lower, log_upper; gdouble log_step_increment, log_page_increment; correction = (gtk_adjustment_get_lower (scale_adj) > 0 ? 0 : 0.1 + - gtk_adjustment_get_lower (scale_adj)); log_value = log (gtk_adjustment_get_value (scale_adj) + correction); log_lower = log (gtk_adjustment_get_lower (scale_adj) + correction); log_upper = log (gtk_adjustment_get_upper (scale_adj) + correction); log_step_increment = (log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) - gtk_adjustment_get_lower (scale_adj)) / gtk_adjustment_get_step_increment (scale_adj)); log_page_increment = (log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) - gtk_adjustment_get_lower (scale_adj)) / gtk_adjustment_get_page_increment (scale_adj)); if (scale_adj == adj) { GtkObject *new_adj; new_adj = gtk_adjustment_new (gtk_adjustment_get_value (scale_adj), gtk_adjustment_get_lower (scale_adj), gtk_adjustment_get_upper (scale_adj), gtk_adjustment_get_step_increment (scale_adj), gtk_adjustment_get_page_increment (scale_adj), 0.0); gtk_range_set_adjustment (GTK_RANGE (GIMP_SCALE_ENTRY_SCALE (adj)), GTK_ADJUSTMENT (new_adj)); scale_adj = (GtkAdjustment *) new_adj; } else { g_signal_handlers_disconnect_by_func (adj, gimp_scale_entry_unconstrained_adjustment_callback, scale_adj); g_signal_handlers_disconnect_by_func (scale_adj, gimp_scale_entry_unconstrained_adjustment_callback, adj); } gtk_adjustment_configure (scale_adj, log_value, log_lower, log_upper, log_step_increment, log_page_increment, 0.0); g_signal_connect (scale_adj, "value-changed", G_CALLBACK (gimp_scale_entry_exp_adjustment_callback), adj); g_signal_connect (adj, "value-changed", G_CALLBACK (gimp_scale_entry_log_adjustment_callback), scale_adj); g_object_set_data (G_OBJECT (adjustment), "logarithmic", GINT_TO_POINTER (TRUE)); } else { gdouble lower, upper; g_signal_handlers_disconnect_by_func (adj, gimp_scale_entry_log_adjustment_callback, scale_adj); g_signal_handlers_disconnect_by_func (scale_adj, gimp_scale_entry_exp_adjustment_callback, adj); lower = exp (gtk_adjustment_get_lower (scale_adj)); upper = exp (gtk_adjustment_get_upper (scale_adj)); if (gtk_adjustment_get_lower (adj) <= 0.0) { lower += - 0.1 + gtk_adjustment_get_lower (adj); upper += - 0.1 + gtk_adjustment_get_lower (adj); } gtk_adjustment_configure (scale_adj, gtk_adjustment_get_value (adj), lower, upper, gtk_adjustment_get_step_increment (adj), gtk_adjustment_get_page_increment (adj), 0.0); g_signal_connect (scale_adj, "value-changed", G_CALLBACK (gimp_scale_entry_unconstrained_adjustment_callback), adj); g_signal_connect (adj, "value-changed", G_CALLBACK (gimp_scale_entry_unconstrained_adjustment_callback), scale_adj); g_object_set_data (G_OBJECT (adjustment), "logarithmic", GINT_TO_POINTER (FALSE)); } } /** * gimp_scale_entry_get_logarithmic: * @adjustment: a #GtkAdjustment as returned by gimp_scale_entry_new() * * Return value: %TRUE if the the entry's scale widget will behave in * logharithmic fashion, %FALSE for linear behaviour. * * Since: GIMP 2.2 **/ gboolean gimp_scale_entry_get_logarithmic (GtkObject *adjustment) { return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (adjustment), "logarithmic")); } /** * gimp_scale_entry_set_sensitive: * @adjustment: a #GtkAdjustment returned by gimp_scale_entry_new() * @sensitive: a boolean value with the same semantics as the @sensitive * parameter of gtk_widget_set_sensitive() * * Sets the sensitivity of the scale_entry's #GtkLabel, #GtkHScale and * #GtkSpinButton. **/ void gimp_scale_entry_set_sensitive (GtkObject *adjustment, gboolean sensitive) { GtkWidget *widget; g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); widget = GIMP_SCALE_ENTRY_LABEL (adjustment); if (widget) gtk_widget_set_sensitive (widget, sensitive); widget = GIMP_SCALE_ENTRY_SCALE (adjustment); if (widget) gtk_widget_set_sensitive (widget, sensitive); widget = GIMP_SCALE_ENTRY_SPINBUTTON (adjustment); if (widget) gtk_widget_set_sensitive (widget, sensitive); }