[gnome-builder/wip/slaf/colorpicker] gstyle: eyedropper zoom and swatch box
- From: Sébastien Lafargue <slafargue src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/slaf/colorpicker] gstyle: eyedropper zoom and swatch box
- Date: Sun, 17 Jul 2016 09:40:14 +0000 (UTC)
commit b119bb5bbaff0bd77afeedd3358834e347a500a6
Author: Sebastien Lafargue <slafargue gnome org>
Date: Sun Jul 17 11:36:08 2016 +0200
gstyle: eyedropper zoom and swatch box
The zoom factor can be control by the mouse wheel
contrib/gstyle/gstyle-eyedropper.c | 373 +++++++++++++++++++++++++++++++-----
contrib/gstyle/theme/gstyle.css | 8 +
2 files changed, 328 insertions(+), 53 deletions(-)
---
diff --git a/contrib/gstyle/gstyle-eyedropper.c b/contrib/gstyle/gstyle-eyedropper.c
index d3ee4b3..fba0da8 100644
--- a/contrib/gstyle/gstyle-eyedropper.c
+++ b/contrib/gstyle/gstyle-eyedropper.c
@@ -24,24 +24,55 @@
#define G_LOG_DOMAIN "gstyle-eyedropper"
#include <gdk/gdk.h>
+#include <math.h>
#include "gstyle-color.h"
+#include "gstyle-color-widget.h"
+#include "gstyle-css-provider.h"
+
#include "gstyle-eyedropper.h"
+#define ZOOM_AREA_WIDTH 100
+#define ZOOM_AREA_HEIGHT 100
+
+/* The spot coords is the oriented distance between the window and the cursor
+ * that mean the cursor is never inside the window, this also mean that the cursor
+ * can only be in one of the four window corners area.
+ */
+#define ZOOM_AREA_SPOT_X -20
+#define ZOOM_AREA_SPOT_Y -20
+
+#define DEFAULT_ZOOM_FACTOR 2
+#define MIN_ZOOM_FACTOR 1
+#define MAX_ZOOM_FACTOR 20
+
struct _GstyleEyedropper
{
- GtkWindow parent_instance;
-
- GtkWidget *source;
- GtkWidget *window;
- GdkCursor *cursor;
- GdkSeat *seat;
-
- gulong key_handler_id;
- gulong grab_broken_handler_id;
- gulong motion_notify_handler_id;
- gulong pointer_pressed_handler_id;
- gulong pointer_released_handler_id;
+ GtkWindow parent_instance;
+
+ GstyleCssProvider *default_provider;
+ GtkWidget *source;
+ GtkWidget *window;
+ GdkScreen *screen;
+ GtkWidget *zoom_area;
+ GdkCursor *cursor;
+ GdkSeat *seat;
+ GdkPixbuf *pixbuf;
+ GstyleColor *color;
+
+ gulong key_handler_id;
+ gulong grab_broken_handler_id;
+ gulong motion_notify_handler_id;
+ gulong pointer_pressed_handler_id;
+ gulong pointer_released_handler_id;
+ gulong pointer_wheel_handler_id;
+ gulong screen_size_changed_handler_id;
+
+ gdouble zoom_factor;
+ gint screen_width;
+ gint screen_height;
+
+ guint button_pressed : 1;
};
G_DEFINE_TYPE (GstyleEyedropper, gstyle_eyedropper, GTK_TYPE_WINDOW)
@@ -97,6 +128,7 @@ get_rgba_at_cursor (GstyleEyedropper *self,
rgba->red = pixels[0] / 255.0;
rgba->green = pixels[1] / 255.0;
rgba->blue = pixels[2] /255.0;
+ rgba->alpha = 1.0;
g_object_unref (pixbuf);
}
@@ -104,6 +136,8 @@ get_rgba_at_cursor (GstyleEyedropper *self,
static void
release_grab (GstyleEyedropper *self)
{
+ gboolean has_grab = FALSE;
+
g_assert (GSTYLE_IS_EYEDROPPER (self));
if (self->key_handler_id)
@@ -124,16 +158,130 @@ release_grab (GstyleEyedropper *self)
self->motion_notify_handler_id = 0;
}
+ if (self->pointer_pressed_handler_id)
+ {
+ g_signal_handler_disconnect (self->window, self->pointer_pressed_handler_id);
+ self->pointer_pressed_handler_id = 0;
+ }
+
if (self->pointer_released_handler_id)
{
g_signal_handler_disconnect (self->window, self->pointer_released_handler_id);
self->pointer_released_handler_id = 0;
}
- gtk_grab_remove (self->window);
- gdk_seat_ungrab (self->seat);
+ if (self->screen_size_changed_handler_id)
+ {
+ g_signal_handler_disconnect (self->screen, self->screen_size_changed_handler_id);
+ self->screen_size_changed_handler_id = 0;
+ }
+
+ if (self->window != NULL)
+ if (gtk_widget_has_grab (self->window))
+ {
+ has_grab = TRUE;
+ gtk_grab_remove (self->window);
+ }
- g_signal_emit (self, signals [GRAB_RELEASED], 0);
+ if (self->seat != NULL)
+ gdk_seat_ungrab (self->seat);
+
+ g_clear_object (&self->default_provider);
+ g_clear_object (&self->seat);
+ g_clear_object (&self->cursor);
+
+ if (self->window != NULL)
+ {
+ gtk_widget_destroy (self->window);
+ self->window = NULL;
+ }
+
+ if (has_grab)
+ g_signal_emit (self, signals [GRAB_RELEASED], 0);
+}
+
+static void
+gstyle_eyedropper_event_get_root_coords (GstyleEyedropper *self,
+ GdkEvent *event,
+ gint *x_root,
+ gint *y_root)
+{
+ GdkSeat *seat;
+ GdkDevice *pointer;
+
+ seat = gdk_event_get_seat (event);
+ pointer = gdk_seat_get_pointer (seat);
+ gdk_device_get_position (pointer, NULL, x_root, y_root);
+}
+
+static void
+gstyle_eyedropper_calculate_window_position (GstyleEyedropper *self,
+ GtkWindow *window,
+ gint cursor_root_x,
+ gint cursor_root_y,
+ gint *x,
+ gint *y)
+{
+ GtkAllocation alloc;
+ gint spot_x = ZOOM_AREA_SPOT_X;
+ gint spot_y = ZOOM_AREA_SPOT_Y;
+
+ g_assert (GSTYLE_IS_EYEDROPPER (self));
+ g_assert (GTK_IS_WINDOW (window));
+
+ gtk_widget_get_allocated_size (GTK_WIDGET (window), &alloc, NULL);
+
+ if ((spot_x < 0 && cursor_root_x > self->screen_width - alloc.width + spot_x * 2) ||
+ (spot_x > 0 && cursor_root_x < alloc.width + spot_x * 2))
+ spot_x = -spot_x;
+
+ if (spot_x > 0)
+ *x = cursor_root_x - alloc.width - spot_x;
+ else
+ *x = cursor_root_x - spot_x;
+
+ if ((spot_y < 0 && cursor_root_y > self->screen_height - alloc.height + spot_y * 2) ||
+ (spot_y > 0 && cursor_root_y < alloc.height + spot_y + 2))
+ spot_y = -spot_y;
+
+ if (spot_y > 0)
+ *y = cursor_root_y - alloc.height - spot_y;
+ else
+ *y = cursor_root_y - spot_y;
+}
+
+static void
+gstyle_eyedropper_draw_zoom_area (GstyleEyedropper *self,
+ gint cursor_x,
+ gint cursor_y)
+{
+ GdkWindow *window;
+ GdkPixbuf *root_pixbuf;
+ gint src_width;
+ gint src_height;
+ gint start_x;
+ gint start_y;
+
+ g_assert (GSTYLE_IS_EYEDROPPER (self));
+
+ src_width = ZOOM_AREA_WIDTH / self->zoom_factor;
+ src_height = ZOOM_AREA_HEIGHT / self->zoom_factor;
+ window = gdk_screen_get_root_window (self->screen);
+
+ start_x = MAX (cursor_x - src_width / 2, 0);
+ if (start_x + src_width > self->screen_width)
+ start_x = self->screen_width - src_width;
+
+ start_y = MAX (cursor_y - src_height / 2, 0);
+ if (start_y + src_height > self->screen_height)
+ start_y = self->screen_height - src_height;
+
+ root_pixbuf = gdk_pixbuf_get_from_window (window, start_x, start_y, src_width, src_height);
+ g_clear_object (&self->pixbuf);
+ self->pixbuf = gdk_pixbuf_scale_simple (root_pixbuf, ZOOM_AREA_WIDTH, ZOOM_AREA_HEIGHT,
GDK_INTERP_NEAREST);
+ g_object_unref (root_pixbuf);
+
+ gtk_widget_queue_draw (self->zoom_area);
}
static void
@@ -142,17 +290,27 @@ gstyle_eyedropper_pointer_motion_notify_cb (GstyleEyedropper *self,
GtkWindow *window)
{
GdkRGBA rgba;
+ gint x_root, y_root;
+ gint x, y;
g_assert (GSTYLE_IS_EYEDROPPER (self));
- g_assert (event != NULL);
g_assert (GTK_IS_WINDOW (window));
+ g_assert (event != NULL);
+ g_assert (self->screen == gdk_event_get_screen ((GdkEvent *) event));
+
+ gstyle_eyedropper_event_get_root_coords (self, (GdkEvent *)event, &x_root, &y_root);
+ gstyle_eyedropper_calculate_window_position (self, GTK_WINDOW (self->window), event->x_root,
event->y_root, &x, &y);
+ gtk_window_move (GTK_WINDOW (self->window), x, y);
+ gstyle_eyedropper_draw_zoom_area (self, event->x_root, event->y_root);
get_rgba_at_cursor (self,
- gdk_event_get_screen ((GdkEvent *) event),
+ self->screen,
gdk_event_get_device ((GdkEvent *) event),
event->x_root, event->y_root, &rgba);
- g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
+ gstyle_color_set_rgba (self->color, &rgba);
+ if (self->button_pressed)
+ g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
}
static gboolean
@@ -160,11 +318,23 @@ gstyle_eyedropper_pointer_released_cb (GstyleEyedropper *self,
GdkEventButton *event,
GtkWindow *window)
{
+ GdkRGBA rgba;
+
g_assert (GSTYLE_IS_EYEDROPPER (self));
g_assert (event != NULL);
g_assert (GTK_IS_WINDOW (window));
+ g_assert (self->screen == gdk_event_get_screen ((GdkEvent *) event));
+
+ get_rgba_at_cursor (self,
+ self->screen,
+ gdk_event_get_device ((GdkEvent *) event),
+ event->x_root, event->y_root, &rgba);
+
+ gstyle_color_set_rgba (self->color, &rgba);
+ g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
release_grab (self);
+ self->button_pressed = FALSE;
return GDK_EVENT_STOP;
}
@@ -174,36 +344,52 @@ gstyle_eyedropper_pointer_pressed_cb (GstyleEyedropper *self,
GdkEventButton *event,
GtkWindow *window)
{
- GdkRGBA rgba;
-
g_assert (GSTYLE_IS_EYEDROPPER (self));
g_assert (event != NULL);
g_assert (GTK_IS_WINDOW (window));
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY)
+ if (event->type == GDK_BUTTON_PRESS)
{
- self->motion_notify_handler_id =
- g_signal_connect_swapped (window, "motion-notify-event",
- G_CALLBACK (gstyle_eyedropper_pointer_motion_notify_cb), self);
-
- self->pointer_released_handler_id =
- g_signal_connect_swapped (window, "button-release-event",
- G_CALLBACK (gstyle_eyedropper_pointer_released_cb), self);
-
- g_signal_handler_disconnect (self->window, self->pointer_pressed_handler_id);
- self->pointer_pressed_handler_id = 0;
+ if (!self->button_pressed && event->button == GDK_BUTTON_PRIMARY)
+ {
+ self->button_pressed = TRUE;
+ self->pointer_released_handler_id =
+ g_signal_connect_object (window, "button-release-event",
+ G_CALLBACK (gstyle_eyedropper_pointer_released_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ return GDK_EVENT_STOP;
+ }
+ }
- get_rgba_at_cursor (self,
- gdk_event_get_screen ((GdkEvent *) event),
- gdk_event_get_device ((GdkEvent *) event),
- event->x_root, event->y_root, &rgba);
+ return GDK_EVENT_PROPAGATE;
+}
- g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
+static gboolean
+gstyle_eyedropper_pointer_wheel_cb (GstyleEyedropper *self,
+ GdkEventScroll *event,
+ GtkWindow *window)
+{
+ g_assert (GSTYLE_IS_EYEDROPPER (self));
+ g_assert (event != NULL);
+ g_assert (GTK_IS_WINDOW (window));
+ g_assert (self->screen == gdk_event_get_screen ((GdkEvent *) event));
- return GDK_EVENT_STOP;
+ if (event->type == GDK_SCROLL)
+ {
+ if (event->direction == GDK_SCROLL_UP)
+ self->zoom_factor = CLAMP (self->zoom_factor + 0.5, MIN_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
+ else if (event->direction == GDK_SCROLL_DOWN)
+ self->zoom_factor = CLAMP (self->zoom_factor - 0.5, MIN_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
+ else
+ return GDK_EVENT_PROPAGATE;
}
+ else
+ return GDK_EVENT_PROPAGATE;
- return GDK_EVENT_PROPAGATE;
+ gstyle_eyedropper_draw_zoom_area (self, event->x_root, event->y_root);
+ return GDK_EVENT_STOP;
}
static gboolean
@@ -243,34 +429,101 @@ gstyle_eyedropper_grab_broken_cb (GstyleEyedropper *self,
return GDK_EVENT_STOP;
}
+static void
+gstyle_eyedropper_screen_size_changed_cb (GstyleEyedropper *self,
+ GdkScreen *screen)
+{
+ GdkDevice *pointer;
+ gint x;
+ gint y;
+
+ g_assert (GSTYLE_IS_EYEDROPPER (self));
+ g_assert (GDK_IS_SCREEN (screen));
+
+ self->screen_width = gdk_screen_get_width (screen);
+ self->screen_height = gdk_screen_get_height (screen);
+
+ pointer = gdk_seat_get_pointer (self->seat);
+ gdk_device_get_position (pointer, NULL, &x, &y);
+ gstyle_eyedropper_draw_zoom_area (self, x, y);
+}
+
+static gint
+gstyle_eyedropper_zoom_area_draw_cb (GstyleEyedropper *self,
+ cairo_t *cr,
+ GtkWidget *widget)
+{
+ g_assert (GSTYLE_IS_EYEDROPPER (self));
+
+ if (self->pixbuf != NULL)
+ {
+ gdk_cairo_set_source_pixbuf (cr, self->pixbuf, 0, 0);
+ cairo_paint (cr);
+ }
+
+ return TRUE;
+}
+
void
gstyle_eyedropper_set_source_event (GstyleEyedropper *self,
GdkEvent *event)
{
- GdkScreen *screen;
GtkWidget *source;
+ GtkStyleContext *context;
+ GtkWidget *box;
+ GtkWidget *swatch;
GdkGrabStatus status;
+ gint x_root, y_root;
+ gint x, y;
g_return_if_fail (GSTYLE_IS_EYEDROPPER (self));
g_return_if_fail (event != NULL);
self->seat = g_object_ref (gdk_event_get_seat (event));
source = gtk_get_event_widget (event);
- screen = gdk_event_get_screen (event);
-
- g_clear_object (&self->window);
- g_clear_object (&self->cursor);
-
- self->window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_window_set_screen (GTK_WINDOW (self->window), screen);
- gtk_window_resize (GTK_WINDOW (self->window), 1, 1);
- gtk_window_move (GTK_WINDOW (self->window), -1, -1);
- gtk_widget_show (self->window);
+ self->screen = gdk_event_get_screen (event);
+ g_signal_connect_swapped (self->screen,
+ "size-changed",
+ G_CALLBACK (gstyle_eyedropper_screen_size_changed_cb),
+ self);
+
+ self->window = g_object_ref_sink (gtk_window_new (GTK_WINDOW_POPUP));
+ gtk_window_set_screen (GTK_WINDOW (self->window),self->screen);
+ gtk_widget_set_name (self->window, "gstyleeyedropper");
+ context = gtk_widget_get_style_context (self->window);
+ self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_add (GTK_CONTAINER (self->window), box);
+
+ self->zoom_area = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (self->zoom_area, ZOOM_AREA_WIDTH, ZOOM_AREA_HEIGHT);
+ gtk_container_add (GTK_CONTAINER (box), self->zoom_area);
+
+ swatch = g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+ "fallback-name-kind", GSTYLE_COLOR_KIND_RGB_HEX6,
+ "fallback-name-visible", TRUE,
+ "color", self->color,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (box), swatch);
+
+ g_signal_connect_object (self->zoom_area,
+ "draw",
+ G_CALLBACK (gstyle_eyedropper_zoom_area_draw_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->screen_width = gdk_screen_get_width (self->screen);
+ self->screen_height = gdk_screen_get_height (self->screen);
+ gstyle_eyedropper_event_get_root_coords (self, event, &x_root, &y_root);
+ gstyle_eyedropper_calculate_window_position (self, GTK_WINDOW (self->window), x_root, y_root, &x, &y);
+ gtk_window_move (GTK_WINDOW (self->window), x, y);
+ gtk_widget_show_all (self->window);
gtk_widget_add_events (self->window,
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
- self->cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen), "cell");
+ self->cursor = gdk_cursor_new_from_name (gdk_screen_get_display (self->screen), "cell");
gtk_grab_add (self->window);
status = gdk_seat_grab (self->seat,
gtk_widget_get_window (source),
@@ -286,12 +539,23 @@ gstyle_eyedropper_set_source_event (GstyleEyedropper *self,
return;
}
+ self->motion_notify_handler_id =
+ g_signal_connect_swapped (self->window, "motion-notify-event",
+ G_CALLBACK (gstyle_eyedropper_pointer_motion_notify_cb),
+ self);
+
self->pointer_pressed_handler_id =
g_signal_connect_swapped (self->window,
"button-press-event",
G_CALLBACK (gstyle_eyedropper_pointer_pressed_cb),
self);
+ self->pointer_wheel_handler_id =
+ g_signal_connect_swapped (self->window,
+ "scroll-event",
+ G_CALLBACK (gstyle_eyedropper_pointer_wheel_cb),
+ self);
+
self->key_handler_id =
g_signal_connect_swapped (self->window,
"key-press-event",
@@ -318,9 +582,8 @@ gstyle_eyedropper_finalize (GObject *object)
{
GstyleEyedropper *self = GSTYLE_EYEDROPPER (object);
- g_clear_object (&self->window);
- g_clear_object (&self->cursor);
- gdk_seat_ungrab (self->seat);
+ release_grab (self);
+ g_clear_object (&self->color);
G_OBJECT_CLASS (gstyle_eyedropper_parent_class)->finalize (object);
}
@@ -350,6 +613,7 @@ static void
gstyle_eyedropper_class_init (GstyleEyedropperClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gstyle_eyedropper_finalize;
object_class->set_property = gstyle_eyedropper_set_property;
@@ -392,9 +656,12 @@ gstyle_eyedropper_class_init (GstyleEyedropperClass *klass)
(G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
+ gtk_widget_class_set_css_name (widget_class, "gstyleeyedropper");
}
static void
gstyle_eyedropper_init (GstyleEyedropper *self)
{
+ self->zoom_factor = DEFAULT_ZOOM_FACTOR;
+ self->color = gstyle_color_new ("", GSTYLE_COLOR_KIND_RGB_HEX6, 0.0, 0.0, 0.0, 1.0);
}
diff --git a/contrib/gstyle/theme/gstyle.css b/contrib/gstyle/theme/gstyle.css
index d3fa24d..25cc859 100644
--- a/contrib/gstyle/theme/gstyle.css
+++ b/contrib/gstyle/theme/gstyle.css
@@ -118,3 +118,11 @@ gstylecolorpanel revealer button.toggle {
gstyleslidein.shade {
color: rgba(77, 78, 83, 0.8);
}
+
+#gstyleeyedropper {
+ border: solid alpha(@borders, 0.75) 1px;
+}
+
+#gstyleeyedropper > box {
+ margin: 6px;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]