* 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
-#include "gtkcolorswatch.h"
+#include "gtkcolorswatchprivate.h"
+#include "gtkcolorchooserprivate.h"
#include "gtkroundedboxprivate.h"
#include "gtkthemingbackgroundprivate.h"
#include "gtkdnd.h"
#include "gtkmenu.h"
#include "gtkmenuitem.h"
#include "gtkmenushell.h"
+#include "gtkpressandholdprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
+#include "a11y/gtkcolorswatchaccessibleprivate.h"
struct _GtkColorSwatchPrivate
GdkRGBA color;
gdouble radius[4];
gchar *icon;
- guint selected : 1;
guint has_color : 1;
- guint can_drop : 1;
guint contains_pointer : 1;
guint use_alpha : 1;
+ guint selectable : 1;
+
+ GdkWindow *event_window;
+
+ GtkPressAndHold *press_and_hold;
};
enum
{
PROP_ZERO,
PROP_RGBA,
- PROP_SELECTED
+ PROP_SELECTABLE
};
enum
static guint signals[LAST_SIGNAL];
-G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_DRAWING_AREA)
+G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
static void
gtk_color_swatch_init (GtkColorSwatch *swatch)
GtkColorSwatchPrivate);
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
- gtk_widget_set_events (GTK_WIDGET (swatch), GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_EXPOSURE_MASK
- | GDK_ENTER_NOTIFY_MASK
- | GDK_LEAVE_NOTIFY_MASK);
+ gtk_widget_set_has_window (GTK_WIDGET (swatch), FALSE);
+
swatch->priv->use_alpha = TRUE;
+ swatch->priv->selectable = TRUE;
}
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
-
-static cairo_pattern_t *
-get_checkered_pattern (void)
-{
- /* 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);
-
- return pattern;
-}
+#define ACTIVE_BADGE_RADIUS 10
static gboolean
swatch_draw (GtkWidget *widget,
{
GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
GtkThemingBackground background;
- GtkRoundedBox box;
- gint i;
gdouble width, height;
GtkStyleContext *context;
GtkStateFlags state;
{
cairo_save (cr);
- _gtk_rounded_box_path (&background.clip_box, cr);
+ _gtk_rounded_box_path (&background.padding_box, cr);
cairo_clip_preserve (cr);
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
cairo_fill_preserve (cr);
- pattern = get_checkered_pattern ();
+ pattern = _gtk_color_chooser_get_checkered_pattern ();
cairo_matrix_init_scale (&matrix, 0.125, 0.125);
cairo_pattern_set_matrix (pattern, &matrix);
_gtk_theming_background_render (&background, cr);
}
+ else
+ _gtk_theming_background_render (&background, cr);
gtk_render_frame (context, cr,
0, 0, width, height);
cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
else
cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
- _gtk_rounded_box_shrink (&background.clip_box, 3, 3, 3, 3);
- _gtk_rounded_box_path (&background.clip_box, cr);
- cairo_stroke (cr);
+ _gtk_rounded_box_shrink (&background.padding_box, 3, 3, 3, 3);
+ _gtk_rounded_box_path (&background.padding_box, cr);
+ cairo_stroke (cr);
}
if (swatch->priv->icon)
{
- icon_info = gtk_icon_theme_lookup_icon (theme, "list-add-symbolic", 16,
+ icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
GTK_ICON_LOOKUP_GENERIC_FALLBACK
| GTK_ICON_LOOKUP_USE_BUILTIN);
}
- else if (swatch->priv->selected)
+ else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
{
GdkRGBA bg, border;
GtkBorder border_width;
GIcon *gicon;
gtk_style_context_add_class (context, "color-active-badge");
- gtk_style_context_get_background_color (context, state, &bg);
- gtk_style_context_get_border_color (context, state, &border);
- gtk_style_context_get_border (context, state, &border_width);
-
- cairo_new_sub_path (cr);
- cairo_arc (cr, width / 2, height / 2, 10, 0, 2 * G_PI);
- cairo_close_path (cr);
- gdk_cairo_set_source_rgba (cr, &bg);
- cairo_fill_preserve (cr);
-
- gdk_cairo_set_source_rgba (cr, &border);
- cairo_set_line_width (cr, border_width.left);
- cairo_stroke (cr);
-
- gicon = g_themed_icon_new ("object-select-symbolic");
- /* fallback for themes that don't have object-select-symbolic */
- g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");
-
- icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
- GTK_ICON_LOOKUP_GENERIC_FALLBACK
- | GTK_ICON_LOOKUP_USE_BUILTIN);
- g_object_unref (gicon);
+ _gtk_theming_background_init_from_context (&background, context,
+ (width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2,
+ 2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS,
+ GTK_JUNCTION_NONE);
+
+ if (_gtk_theming_background_has_background_image (&background))
+ {
+ _gtk_theming_background_render (&background, cr);
+ }
+ else
+ {
+ gtk_style_context_get_background_color (context, state, &bg);
+ gtk_style_context_get_border_color (context, state, &border);
+ gtk_style_context_get_border (context, state, &border_width);
+
+ cairo_new_sub_path (cr);
+ cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI);
+ cairo_close_path (cr);
+ gdk_cairo_set_source_rgba (cr, &bg);
+ cairo_fill_preserve (cr);
+
+ gdk_cairo_set_source_rgba (cr, &border);
+ cairo_set_line_width (cr, border_width.left);
+ cairo_stroke (cr);
+
+ gicon = g_themed_icon_new ("object-select-symbolic");
+ /* fallback for themes that don't have object-select-symbolic */
+ g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");
+
+ icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
+ GTK_ICON_LOOKUP_GENERIC_FALLBACK
+ | GTK_ICON_LOOKUP_USE_BUILTIN);
+ g_object_unref (gicon);
+ }
}
if (icon_info != NULL)
g_object_unref (pixbuf);
}
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
cairo_restore (cr);
event->keyval == GDK_KEY_KP_Enter ||
event->keyval == GDK_KEY_KP_Space)
{
- if (swatch->priv->has_color && !swatch->priv->selected)
- gtk_color_swatch_set_selected (swatch, TRUE);
+ if (swatch->priv->has_color &&
+ swatch->priv->selectable &&
+ (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
else
g_signal_emit (swatch, signals[ACTIVATE], 0);
return TRUE;
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
swatch->priv->contains_pointer = TRUE;
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
+
return FALSE;
}
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
swatch->priv->contains_pointer = FALSE;
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT);
+
return FALSE;
}
return FALSE;
}
+static gboolean
+swatch_primary_action (GtkColorSwatch *swatch)
+{
+ GtkWidget *widget = (GtkWidget *)swatch;
+ GtkStateFlags flags;
+
+ flags = gtk_widget_get_state_flags (widget);
+ if (!swatch->priv->has_color)
+ {
+ g_signal_emit (swatch, signals[ACTIVATE], 0);
+ return TRUE;
+ }
+ else if (swatch->priv->selectable &&
+ (flags & GTK_STATE_FLAG_SELECTED) == 0)
+ {
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static gboolean
swatch_button_release (GtkWidget *widget,
GdkEventButton *event)
if (event->button == GDK_BUTTON_PRIMARY &&
swatch->priv->contains_pointer)
+ return swatch_primary_action (swatch);
+
+ return FALSE;
+}
+
+static void
+hold_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorSwatch *swatch)
+{
+ emit_customize (swatch);
+}
+
+static void
+tap_action (GtkPressAndHold *pah,
+ gint x,
+ gint y,
+ GtkColorSwatch *swatch)
+{
+ swatch_primary_action (swatch);
+}
+
+static gboolean
+swatch_touch (GtkWidget *widget,
+ GdkEventTouch *event)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+
+ if (!swatch->priv->press_and_hold)
{
- if (!swatch->priv->has_color)
- {
- g_signal_emit (swatch, signals[ACTIVATE], 0);
- return TRUE;
- }
- else if (!swatch->priv->selected)
- {
- gtk_color_swatch_set_selected (swatch, TRUE);
- return TRUE;
- }
+ gint drag_threshold;
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-dnd-drag-threshold", &drag_threshold,
+ NULL);
+
+ swatch->priv->press_and_hold = gtk_press_and_hold_new ();
+
+ g_object_set (swatch->priv->press_and_hold,
+ "drag-threshold", drag_threshold,
+ "hold-time", 1000,
+ NULL);
+
+ g_signal_connect (swatch->priv->press_and_hold, "hold",
+ G_CALLBACK (hold_action), swatch);
+ g_signal_connect (swatch->priv->press_and_hold, "tap",
+ G_CALLBACK (tap_action), swatch);
}
- return FALSE;
+ gtk_press_and_hold_process_event (swatch->priv->press_and_hold, (GdkEvent *)event);
+
+ return TRUE;
+}
+
+static void
+swatch_map (GtkWidget *widget)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+
+ GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->map (widget);
+
+ if (swatch->priv->event_window)
+ gdk_window_show (swatch->priv->event_window);
+}
+
+static void
+swatch_unmap (GtkWidget *widget)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+
+ if (swatch->priv->event_window)
+ gdk_window_hide (swatch->priv->event_window);
+
+ GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unmap (widget);
+}
+
+static void
+swatch_realize (GtkWidget *widget)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+ GtkAllocation allocation;
+ GdkWindow *window;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gtk_widget_set_realized (widget, TRUE);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_TOUCH_MASK;
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ window = gtk_widget_get_parent_window (widget);
+ gtk_widget_set_window (widget, window);
+ g_object_ref (window);
+
+ swatch->priv->event_window =
+ gdk_window_new (window,
+ &attributes, attributes_mask);
+ gtk_widget_register_window (widget, swatch->priv->event_window);
+}
+
+static void
+swatch_unrealize (GtkWidget *widget)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+
+ if (swatch->priv->event_window)
+ {
+ gtk_widget_unregister_window (widget, swatch->priv->event_window);
+ gdk_window_destroy (swatch->priv->event_window);
+ swatch->priv->event_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unrealize (widget);
+}
+
+static void
+swatch_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (swatch->priv->event_window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
}
static gboolean
gtk_color_swatch_get_rgba (swatch, &color);
g_value_set_boxed (value, &color);
break;
- case PROP_SELECTED:
- g_value_set_boolean (value, swatch->priv->selected);
+ case PROP_SELECTABLE:
+ g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case PROP_RGBA:
gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
break;
- case PROP_SELECTED:
- gtk_color_swatch_set_selected (swatch, g_value_get_boolean (value));
+ case PROP_SELECTABLE:
+ gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
g_free (swatch->priv->icon);
+ g_clear_object (&swatch->priv->press_and_hold);
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
widget_class->button_release_event = swatch_button_release;
widget_class->enter_notify_event = swatch_enter_notify;
widget_class->leave_notify_event = swatch_leave_notify;
+ widget_class->realize = swatch_realize;
+ widget_class->unrealize = swatch_unrealize;
+ widget_class->map = swatch_map;
+ widget_class->unmap = swatch_unmap;
+ widget_class->size_allocate = swatch_size_allocate;
+ widget_class->touch_event = swatch_touch;
signals[ACTIVATE] =
g_signal_new ("activate",
g_object_class_install_property (object_class, PROP_RGBA,
g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class, PROP_SELECTED,
- g_param_spec_boolean ("selected", P_("Selected"), P_("Selected"),
- FALSE, GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class, PROP_SELECTABLE,
+ g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the swatch is selectable"),
+ TRUE, GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate));
+
+ gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE);
}
/* Public API {{{1 */
}
void
-gtk_color_swatch_set_corner_radii (GtkColorSwatch *swatch,
- gdouble top_left,
- gdouble top_right,
- gdouble bottom_right,
- gdouble bottom_left)
+gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
+ const gchar *icon)
{
- swatch->priv->radius[0] = top_left;
- swatch->priv->radius[1] = top_right;
- swatch->priv->radius[2] = bottom_right;
- swatch->priv->radius[3] = bottom_left;
-
+ swatch->priv->icon = g_strdup (icon);
gtk_widget_queue_draw (GTK_WIDGET (swatch));
}
void
-gtk_color_swatch_set_selected (GtkColorSwatch *swatch,
- gboolean selected)
+gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
+ gboolean can_drop)
{
- if (swatch->priv->selected != selected)
+ if (can_drop)
+ {
+ gtk_drag_dest_set (GTK_WIDGET (swatch),
+ GTK_DEST_DEFAULT_HIGHLIGHT |
+ GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_DROP,
+ dnd_targets, G_N_ELEMENTS (dnd_targets),
+ GDK_ACTION_COPY);
+ }
+ else
{
- swatch->priv->selected = selected;
- gtk_widget_queue_draw (GTK_WIDGET (swatch));
- g_object_notify (G_OBJECT (swatch), "selected");
+ gtk_drag_dest_unset (GTK_WIDGET (swatch));
}
}
void
-gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
- const gchar *icon)
+gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
+ gboolean use_alpha)
{
- swatch->priv->icon = g_strdup (icon);
+ swatch->priv->use_alpha = use_alpha;
gtk_widget_queue_draw (GTK_WIDGET (swatch));
}
void
-gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
- gboolean can_drop)
+gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
+ gboolean selectable)
{
- if (!swatch->priv->can_drop)
- gtk_drag_dest_set (GTK_WIDGET (swatch),
- GTK_DEST_DEFAULT_HIGHLIGHT |
- GTK_DEST_DEFAULT_MOTION |
- GTK_DEST_DEFAULT_DROP,
- dnd_targets, G_N_ELEMENTS (dnd_targets),
- GDK_ACTION_COPY);
+ if (selectable == swatch->priv->selectable)
+ return;
- swatch->priv->can_drop = can_drop;
+ swatch->priv->selectable = selectable;
+ g_object_notify (G_OBJECT (swatch), "selectable");
}
-void
-gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
- gboolean use_alpha)
+gboolean
+gtk_color_swatch_get_selectable (GtkColorSwatch *swatch)
{
- swatch->priv->use_alpha = use_alpha;
- gtk_widget_queue_draw (GTK_WIDGET (swatch));
+ return swatch->priv->selectable;
}
/* vim:set foldmethod=marker: */