X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcolorscale.c;h=88e4459b59441b8886d0cb51f86ec27670d5d674;hb=cf216d780cb2c889a3bcb5faa825fc1b21af8896;hp=f520cf203b6f6b6f92373fdd90f84ef4ff5aa485;hpb=dbbe4c12fa659992a09fd7b43ec7016cb0145b9d;p=~andy%2Fgtk diff --git a/gtk/gtkcolorscale.c b/gtk/gtkcolorscale.c index f520cf203..88e4459b5 100644 --- a/gtk/gtkcolorscale.c +++ b/gtk/gtkcolorscale.c @@ -12,136 +12,106 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" -#include "gtkcolorscale.h" -#include "gtkhsv.h" +#include "gtkcolorscaleprivate.h" + +#include "gtkcolorchooserprivate.h" +#include "gtkcolorutils.h" #include "gtkorientable.h" #include "gtkstylecontext.h" +#include "gtkaccessible.h" +#include "gtkpressandholdprivate.h" +#include "gtkprivate.h" #include "gtkintl.h" +#include + struct _GtkColorScalePrivate { cairo_surface_t *surface; gint width, height; GdkRGBA color; GtkColorScaleType type; -}; -G_DEFINE_TYPE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE) + GtkPressAndHold *press_and_hold; +}; -static cairo_pattern_t * -get_checkered_pattern (void) +enum { - /* need to respect pixman's stride being a multiple of 4 */ - static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00 }; - static cairo_surface_t *checkered = NULL; - cairo_pattern_t *pattern; - - if (checkered == NULL) - checkered = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_A8, - 2, 2, 4); - - pattern = cairo_pattern_create_for_surface (checkered); - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); - cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + PROP_ZERO, + PROP_SCALE_TYPE +}; - return pattern; -} +G_DEFINE_TYPE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE) static void -create_h_surface (GtkColorScale *scale) +gtk_color_scale_get_trough_size (GtkColorScale *scale, + gint *x_offset_out, + gint *y_offset_out, + gint *width_out, + gint *height_out) { GtkWidget *widget = GTK_WIDGET (scale); - cairo_t *cr; - cairo_surface_t *surface; - gint width, height, stride; - cairo_surface_t *tmp; - guint red, green, blue; - guint32 *data, *p; - gdouble h; - gdouble r, g, b; - gdouble f; - gint x, y; - - if (!gtk_widget_get_realized (widget)) - return; - - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); - - if (width != scale->priv->width || - height != scale->priv->height) - { - surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), - CAIRO_CONTENT_COLOR, - width, height); - if (scale->priv->surface) - cairo_surface_destroy (scale->priv->surface); - scale->priv->surface = surface; - scale->priv->width = width; - scale->priv->height= height; - } - else - surface = scale->priv->surface; + gint width, height, focus_line_width, focus_padding; + gint x_offset, y_offset; + gint slider_width, slider_height; - if (width == 1 || height == 1) - return; + gtk_widget_style_get (widget, + "focus-line-width", &focus_line_width, + "focus-padding", &focus_padding, + "slider-width", &slider_width, + "slider-length", &slider_height, + NULL); - stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); + width = gtk_widget_get_allocated_width (widget) - 2 * (focus_line_width + focus_padding); + height = gtk_widget_get_allocated_height (widget) - 2 * (focus_line_width + focus_padding); - data = g_malloc (height * stride); + x_offset = focus_line_width + focus_padding; + y_offset = focus_line_width + focus_padding; - f = 1.0 / (height - 1); - for (y = 0; y < height; y++) + /* if the slider has a vertical shape, draw the trough asymmetric */ + if (slider_width > slider_height) { - h = CLAMP (y * f, 0.0, 1.0); - p = data + y * (stride / 4); - for (x = 0; x < width; x++) + if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL) + { + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + x_offset += (gint) floor (slider_width / 2.0); + + width = (gint) floor (slider_width / 2.0); + } + else { - gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b); - red = CLAMP (r * 255, 0, 255); - green = CLAMP (g * 255, 0, 255); - blue = CLAMP (b * 255, 0, 255); - p[x] = (red << 16) | (green << 8) | blue; + height = (gint) floor (slider_width / 2.0); } } - tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24, - width, height, stride); - cr = cairo_create (surface); - - cairo_set_source_surface (cr, tmp, 0, 0); - cairo_paint (cr); - - cairo_destroy (cr); - cairo_surface_destroy (tmp); - g_free (data); + if (width_out) + *width_out = width; + if (height_out) + *height_out = height; + if (x_offset_out) + *x_offset_out = x_offset; + if (y_offset_out) + *y_offset_out = y_offset; } static void -create_a_surface (GtkColorScale *scale) +create_surface (GtkColorScale *scale) { GtkWidget *widget = GTK_WIDGET (scale); - cairo_t *cr; cairo_surface_t *surface; - cairo_pattern_t *pattern; - cairo_matrix_t matrix; - GdkRGBA *color; gint width, height; if (!gtk_widget_get_realized (widget)) return; - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); + gtk_color_scale_get_trough_size (scale, + NULL, NULL, + &width, &height); if (!scale->priv->surface || width != scale->priv->width || @@ -154,65 +124,86 @@ create_a_surface (GtkColorScale *scale) cairo_surface_destroy (scale->priv->surface); scale->priv->surface = surface; scale->priv->width = width; - scale->priv->height = height; + scale->priv->height= height; } else - return; + surface = scale->priv->surface; if (width == 1 || height == 1) return; - cr = cairo_create (surface); + if (scale->priv->type == GTK_COLOR_SCALE_HUE) + { + cairo_t *cr; + gint stride; + cairo_surface_t *tmp; + guint red, green, blue; + guint32 *data, *p; + gdouble h; + gdouble r, g, b; + gdouble f; + gint x, y; + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width); + + data = g_malloc (height * stride); + + f = 1.0 / (height - 1); + for (y = 0; y < height; y++) + { + h = CLAMP (y * f, 0.0, 1.0); + p = data + y * (stride / 4); + for (x = 0; x < width; x++) + { + gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b); + red = CLAMP (r * 255, 0, 255); + green = CLAMP (g * 255, 0, 255); + blue = CLAMP (b * 255, 0, 255); + p[x] = (red << 16) | (green << 8) | blue; + } + } - cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); - cairo_paint (cr); - cairo_set_source_rgb (cr, 0.66, 0.66, 0.66); + tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24, + width, height, stride); + cr = cairo_create (surface); - pattern = get_checkered_pattern (); - cairo_matrix_init_scale (&matrix, 0.125, 0.125); - cairo_pattern_set_matrix (pattern, &matrix); - cairo_mask (cr, pattern); - cairo_pattern_destroy (pattern); + cairo_set_source_surface (cr, tmp, 0, 0); + cairo_paint (cr); - color = &scale->priv->color; + cairo_destroy (cr); + cairo_surface_destroy (tmp); + g_free (data); + } + else if (scale->priv->type == GTK_COLOR_SCALE_ALPHA) + { + cairo_t *cr; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + GdkRGBA *color; - pattern = cairo_pattern_create_linear (0, 0, width, 0); - cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0); - cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1); - cairo_set_source (cr, pattern); - cairo_paint (cr); - cairo_pattern_destroy (pattern); + cr = cairo_create (surface); - cairo_destroy (cr); -} + cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.66, 0.66, 0.66); -static void -create_surface (GtkColorScale *scale) -{ - switch (scale->priv->type) - { - case GTK_COLOR_SCALE_HUE: - create_h_surface (scale); - break; - case GTK_COLOR_SCALE_ALPHA: - create_a_surface (scale); - break; - } -} + pattern = _gtk_color_chooser_get_checkered_pattern (); + cairo_matrix_init_scale (&matrix, 0.125, 0.125); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_mask (cr, pattern); + cairo_pattern_destroy (pattern); -static gboolean -scale_has_asymmetric_thumb (GtkWidget *widget) -{ - gchar *theme; - gboolean res; + color = &scale->priv->color; - g_object_get (gtk_widget_get_settings (widget), - "gtk-theme-name", &theme, - NULL); - res = strcmp ("Adwaita", theme) == 0; - g_free (theme); + pattern = cairo_pattern_create_linear (0, 0, width, 0); + cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0); + cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1); + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); - return res; + cairo_destroy (cr); + } } static gboolean @@ -220,28 +211,32 @@ scale_draw (GtkWidget *widget, cairo_t *cr) { GtkColorScale *scale = GTK_COLOR_SCALE (widget); - gint width, height; - - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); + gint width, height, x_offset, y_offset; + cairo_pattern_t *pattern; create_surface (scale); + gtk_color_scale_get_trough_size (scale, + &x_offset, &y_offset, + &width, &height); cairo_save (cr); + cairo_translate (cr, x_offset, y_offset); + cairo_rectangle (cr, 0, 0, width, height); - if (scale_has_asymmetric_thumb (widget)) + pattern = cairo_pattern_create_for_surface (scale->priv->surface); + if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL && + gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) { - if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL) - cairo_rectangle (cr, width / 2, 1, width / 2 - 1, height - 2); - else - cairo_rectangle (cr, 1, 1, width - 2, height / 2); + cairo_matrix_t matrix; + + cairo_matrix_init_scale (&matrix, -1, 1); + cairo_matrix_translate (&matrix, -width, 0); + cairo_pattern_set_matrix (pattern, &matrix); } - else - cairo_rectangle (cr, 1, 1, width - 2, height - 2); + cairo_set_source (cr, pattern); + cairo_fill (cr); - cairo_clip (cr); - cairo_set_source_surface (cr, scale->priv->surface, 0, 0); - cairo_paint (cr); + cairo_pattern_destroy (pattern); cairo_restore (cr); @@ -256,8 +251,7 @@ gtk_color_scale_init (GtkColorScale *scale) scale->priv = G_TYPE_INSTANCE_GET_PRIVATE (scale, GTK_TYPE_COLOR_SCALE, GtkColorScalePrivate); - - scale->priv->type = GTK_COLOR_SCALE_HUE; + gtk_widget_add_events (GTK_WIDGET (scale), GDK_TOUCH_MASK); } static void @@ -268,9 +262,110 @@ scale_finalize (GObject *object) if (scale->priv->surface) cairo_surface_destroy (scale->priv->surface); + g_clear_object (&scale->priv->press_and_hold); + G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object); } +static void +scale_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkColorScale *scale = GTK_COLOR_SCALE (object); + + switch (prop_id) + { + case PROP_SCALE_TYPE: + g_value_set_int (value, scale->priv->type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +scale_set_type (GtkColorScale *scale, + GtkColorScaleType type) +{ + AtkObject *atk_obj; + + scale->priv->type = type; + + atk_obj = gtk_widget_get_accessible (GTK_WIDGET (scale)); + if (GTK_IS_ACCESSIBLE (atk_obj)) + { + if (type == GTK_COLOR_SCALE_HUE) + atk_object_set_name (atk_obj, C_("Color channel", "Hue")); + else if (type == GTK_COLOR_SCALE_ALPHA) + atk_object_set_name (atk_obj, C_("Color channel", "Alpha")); + atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (scale)), ATK_ROLE_COLOR_CHOOSER); + } +} + +static void +scale_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkColorScale *scale = GTK_COLOR_SCALE (object); + + switch (prop_id) + { + case PROP_SCALE_TYPE: + scale_set_type (scale, (GtkColorScaleType)g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +hold_action (GtkPressAndHold *pah, + gint x, + gint y, + GtkColorScale *scale) +{ + gboolean handled; + + g_signal_emit_by_name (scale, "popup-menu", &handled); +} + +static gboolean +scale_touch (GtkWidget *widget, + GdkEventTouch *event) +{ + GtkColorScale *scale = GTK_COLOR_SCALE (widget); + + if (!scale->priv->press_and_hold) + { + gint drag_threshold; + + g_object_get (gtk_widget_get_settings (widget), + "gtk-dnd-drag-threshold", &drag_threshold, + NULL); + + scale->priv->press_and_hold = gtk_press_and_hold_new (); + + g_object_set (scale->priv->press_and_hold, + "drag-threshold", drag_threshold, + "hold-time", 1000, + NULL); + + g_signal_connect (scale->priv->press_and_hold, "hold", + G_CALLBACK (hold_action), scale); + } + + gtk_press_and_hold_process_event (scale->priv->press_and_hold, (GdkEvent *)event); + + return GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->touch_event (widget, event); +} + + static void gtk_color_scale_class_init (GtkColorScaleClass *class) { @@ -278,45 +373,37 @@ gtk_color_scale_class_init (GtkColorScaleClass *class) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); object_class->finalize = scale_finalize; + object_class->get_property = scale_get_property; + object_class->set_property = scale_set_property; widget_class->draw = scale_draw; + widget_class->touch_event = scale_touch; - g_type_class_add_private (class, sizeof (GtkColorScalePrivate)); -} + g_object_class_install_property (object_class, PROP_SCALE_TYPE, + g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"), + 0, 1, 0, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -void -gtk_color_scale_set_color (GtkColorScale *scale, - const GdkRGBA *color) -{ - scale->priv->color.red = color->red; - scale->priv->color.green = color->green; - scale->priv->color.blue = color->blue; - scale->priv->color.alpha = color->alpha; - if (scale->priv->surface) - { - cairo_surface_destroy (scale->priv->surface); - scale->priv->surface = NULL; - } - create_surface (scale); - gtk_widget_queue_draw (GTK_WIDGET (scale)); + g_type_class_add_private (class, sizeof (GtkColorScalePrivate)); } void -gtk_color_scale_set_type (GtkColorScale *scale, - GtkColorScaleType type) +gtk_color_scale_set_rgba (GtkColorScale *scale, + const GdkRGBA *color) { - scale->priv->type = type; - cairo_surface_destroy (scale->priv->surface); - scale->priv->surface = NULL; + scale->priv->color = *color; + scale->priv->width = -1; /* force surface refresh */ create_surface (scale); gtk_widget_queue_draw (GTK_WIDGET (scale)); } GtkWidget * -gtk_color_scale_new (void) +gtk_color_scale_new (GtkAdjustment *adjustment, + GtkColorScaleType type) { return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SCALE, - "adjustment", gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0), + "adjustment", adjustment, "draw-value", FALSE, + "scale-type", type, NULL); }