[gnome-builder] layout: add support for specifying foreground color
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] layout: add support for specifying foreground color
- Date: Wed, 19 Jul 2017 11:10:39 +0000 (UTC)
commit b356492c84f53e289aa78b345dd6f3813e1aee5e
Author: Christian Hergert <chergert redhat com>
Date: Wed Jul 5 17:13:28 2017 -0700
layout: add support for specifying foreground color
This allows us to get a better set of colors for the layout
stack based on the document content.
There are a few tricks in here. We generate a unique CSS
identifier for the layout stack so that we can select on it.
It is just a monotonic number that is incremented for each
instance of layout stack that is loaded.
Because we need to inform our children widgets, the CSS is
connected globally, not to the layoutstack itself.
libide/editor/ide-editor-view.c | 17 +++-
libide/layout/ide-layout-private.h | 2 +
libide/layout/ide-layout-stack-header.c | 132 ++++++++++++++++++++++---
libide/layout/ide-layout-stack.c | 7 +-
libide/layout/ide-layout-view.c | 159 ++++++++++++++++++++++++-------
libide/layout/ide-layout-view.h | 9 +-
6 files changed, 270 insertions(+), 56 deletions(-)
---
diff --git a/libide/editor/ide-editor-view.c b/libide/editor/ide-editor-view.c
index 5d9bf6e..624ec1f 100644
--- a/libide/editor/ide-editor-view.c
+++ b/libide/editor/ide-editor-view.c
@@ -240,9 +240,11 @@ ide_editor_view_buffer_notify_style_scheme (IdeEditorView *self,
IdeBuffer *buffer)
{
g_autofree gchar *background = NULL;
+ g_autofree gchar *foreground = NULL;
GtkSourceStyleScheme *scheme;
GtkSourceStyle *style;
gboolean background_set = FALSE;
+ gboolean foreground_set = FALSE;
GdkRGBA rgba;
g_assert (IDE_IS_EDITOR_VIEW (self));
@@ -255,17 +257,28 @@ ide_editor_view_buffer_notify_style_scheme (IdeEditorView *self,
g_object_get (style,
"background-set", &background_set,
"background", &background,
+ "foreground-set", &foreground_set,
+ "foreground", &foreground,
NULL);
if (!background_set || background == NULL || !gdk_rgba_parse (&rgba, background))
goto unset_primary_color;
- ide_layout_view_set_primary_color (IDE_LAYOUT_VIEW (self), &rgba);
+ if (background_set && background != NULL && gdk_rgba_parse (&rgba, background))
+ ide_layout_view_set_primary_color_bg (IDE_LAYOUT_VIEW (self), &rgba);
+ else
+ goto unset_primary_color;
+
+ if (foreground_set && foreground != NULL && gdk_rgba_parse (&rgba, foreground))
+ ide_layout_view_set_primary_color_fg (IDE_LAYOUT_VIEW (self), &rgba);
+ else
+ ide_layout_view_set_primary_color_fg (IDE_LAYOUT_VIEW (self), NULL);
return;
unset_primary_color:
- ide_layout_view_set_primary_color (IDE_LAYOUT_VIEW (self), NULL);
+ ide_layout_view_set_primary_color_bg (IDE_LAYOUT_VIEW (self), NULL);
+ ide_layout_view_set_primary_color_fg (IDE_LAYOUT_VIEW (self), NULL);
}
static gboolean
diff --git a/libide/layout/ide-layout-private.h b/libide/layout/ide-layout-private.h
index 343ac51..173dd13 100644
--- a/libide/layout/ide-layout-private.h
+++ b/libide/layout/ide-layout-private.h
@@ -61,5 +61,7 @@ void _ide_layout_stack_header_set_modified (IdeLayoutStackHead
gboolean modified);
void _ide_layout_stack_header_set_background_rgba (IdeLayoutStackHeader *self,
const GdkRGBA *background_rgba);
+void _ide_layout_stack_header_set_foreground_rgba (IdeLayoutStackHeader *self,
+ const GdkRGBA *foreground_rgba);
G_END_DECLS
diff --git a/libide/layout/ide-layout-stack-header.c b/libide/layout/ide-layout-stack-header.c
index ee1487d..a4d5a50 100644
--- a/libide/layout/ide-layout-stack-header.c
+++ b/libide/layout/ide-layout-stack-header.c
@@ -28,6 +28,13 @@ struct _IdeLayoutStackHeader
DzlPriorityBox parent_instance;
GtkCssProvider *background_css;
+ gchar *css_identifier;
+
+ GdkRGBA background_rgba;
+ GdkRGBA foreground_rgba;
+
+ guint background_rgba_set : 1;
+ guint foreground_rgba_set : 1;
GtkButton *close_button;
GtkMenuButton *document_button;
@@ -46,6 +53,7 @@ struct _IdeLayoutStackHeader
enum {
PROP_0,
PROP_BACKGROUND_RGBA,
+ PROP_FOREGROUND_RGBA,
PROP_MODIFIED,
PROP_SHOW_CLOSE_BUTTON,
PROP_TITLE,
@@ -263,41 +271,96 @@ ide_layout_stack_header_view_row_activated (GtkListBox *list_box,
IDE_LAYOUT_VIEW (view));
}
-void
-_ide_layout_stack_header_set_background_rgba (IdeLayoutStackHeader *self,
- const GdkRGBA *background_rgba)
+static void
+ide_layout_stack_header_update_css (IdeLayoutStackHeader *self)
{
- GtkStyleContext *style_context;
g_autoptr(GString) str = NULL;
g_autoptr(GError) error = NULL;
g_assert (IDE_IS_LAYOUT_STACK_HEADER (self));
- style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
-
if (self->background_css == NULL)
{
self->background_css = gtk_css_provider_new ();
- gtk_style_context_add_provider (style_context,
- GTK_STYLE_PROVIDER (self->background_css),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (self->background_css),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 100);
}
str = g_string_new (NULL);
- if (background_rgba != NULL)
+ if (self->background_rgba_set)
{
- g_autofree gchar *rgbastr = gdk_rgba_to_string (background_rgba);
-
- if (rgbastr != NULL)
- g_string_append_printf (str, "idelayoutstackheader { background: %s; }", rgbastr);
+ g_autofree gchar *bgstr = gdk_rgba_to_string (&self->background_rgba);
+
+ if (bgstr != NULL)
+ g_string_append_printf (str,
+ "%s { background: none; background-color: %s }\n"
+ "%s button:checked,\n"
+ "%s button:hover { background: none; background-color: shade(%s,.85); }\n",
+ self->css_identifier, bgstr,
+ self->css_identifier,
+ self->css_identifier, bgstr);
+
+ /* only use foreground when background is set */
+ if (self->foreground_rgba_set)
+ {
+ g_autofree gchar *fgstr = gdk_rgba_to_string (&self->foreground_rgba);
+
+ if (fgstr != NULL)
+ g_string_append_printf (str,
+ "%s button image,\n"
+ "%s button label {\n"
+ " -gtk-icon-shadow: 0 -1px alpha(%s,0.543529);\n"
+ " text-shadow: none;\n"
+ " text-shadow: 0 -1px alpha(%s,0.05);\n"
+ " color: %s;\n"
+ "}",
+ self->css_identifier,
+ self->css_identifier,
+ fgstr, fgstr, fgstr);
+ }
}
if (!gtk_css_provider_load_from_data (self->background_css, str->str, str->len, &error))
- g_warning ("Failed to load background-rgba CSS: %s: %s",
+ g_warning ("Failed to load CSS: '%s': %s",
str->str, error->message);
}
+void
+_ide_layout_stack_header_set_background_rgba (IdeLayoutStackHeader *self,
+ const GdkRGBA *background_rgba)
+{
+ g_assert (IDE_IS_LAYOUT_STACK_HEADER (self));
+
+ self->background_rgba_set = FALSE;
+
+ if (background_rgba)
+ {
+ self->background_rgba = *background_rgba;
+ self->background_rgba_set = TRUE;
+ }
+
+ ide_layout_stack_header_update_css (self);
+}
+
+void
+_ide_layout_stack_header_set_foreground_rgba (IdeLayoutStackHeader *self,
+ const GdkRGBA *foreground_rgba)
+{
+ g_assert (IDE_IS_LAYOUT_STACK_HEADER (self));
+
+ self->foreground_rgba_set = FALSE;
+
+ if (foreground_rgba)
+ {
+ self->foreground_rgba = *foreground_rgba;
+ self->foreground_rgba_set = TRUE;
+ }
+
+ ide_layout_stack_header_update_css (self);
+}
+
static void
ide_layout_stack_header_destroy (GtkWidget *widget)
{
@@ -305,11 +368,17 @@ ide_layout_stack_header_destroy (GtkWidget *widget)
g_assert (IDE_IS_LAYOUT_STACK_HEADER (self));
+ if (self->background_css != NULL)
+ {
+ gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (self->background_css));
+ g_clear_object (&self->background_css);
+ }
+
if (self->title_list_box != NULL)
gtk_list_box_bind_model (self->title_list_box, NULL, NULL, NULL, NULL);
g_clear_object (&self->menu);
- g_clear_object (&self->background_css);
GTK_WIDGET_CLASS (ide_layout_stack_header_parent_class)->destroy (widget);
}
@@ -355,6 +424,10 @@ ide_layout_stack_header_set_property (GObject *object,
_ide_layout_stack_header_set_background_rgba (self, g_value_get_boxed (value));
break;
+ case PROP_FOREGROUND_RGBA:
+ _ide_layout_stack_header_set_foreground_rgba (self, g_value_get_boxed (value));
+ break;
+
case PROP_MODIFIED:
_ide_layout_stack_header_set_modified (self, g_value_get_boolean (value));
break;
@@ -401,6 +474,21 @@ ide_layout_stack_header_class_init (IdeLayoutStackHeaderClass *klass)
GDK_TYPE_RGBA,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * IdeLayoutStackHeader:foreground-rgba:
+ *
+ * Sets the foreground color to use when
+ * #IdeLayoutStackHeader:background-rgba is used for the background.
+ *
+ * Since: 3.26
+ */
+ properties [PROP_FOREGROUND_RGBA] =
+ g_param_spec_boxed ("foreground-rgba",
+ "Foreground RGBA",
+ "The foreground color to use with background-rgba",
+ GDK_TYPE_RGBA,
+ (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
properties [PROP_SHOW_CLOSE_BUTTON] =
g_param_spec_boolean ("show-close-button",
"Show Close Button",
@@ -441,11 +529,23 @@ ide_layout_stack_header_class_init (IdeLayoutStackHeaderClass *klass)
static void
ide_layout_stack_header_init (IdeLayoutStackHeader *self)
{
+ g_autofree gchar *class_name = NULL;
+ static guint sequence;
GMenu *frame_section;
+
gtk_widget_init_template (GTK_WIDGET (self));
/*
+ * So that we can use global CSS styling but apply to a single stack,
+ * we generate a unique sequence number to this header. We then use
+ * that from the CSS generation to attach to this instance.
+ */
+ class_name = g_strdup_printf ("stack-header-%u", ++sequence);
+ self->css_identifier = g_strdup_printf ("idelayoutstackheader.%s", class_name);
+ dzl_gtk_widget_add_style_class (GTK_WIDGET (self), class_name);
+
+ /*
* Create our menu for the document controls popover. It has two sections.
* The top section is based on the document and is updated whenever the
* visible child is changed. The bottom, are the frame controls are and
diff --git a/libide/layout/ide-layout-stack.c b/libide/layout/ide-layout-stack.c
index 619a8e2..647f87a 100644
--- a/libide/layout/ide-layout-stack.c
+++ b/libide/layout/ide-layout-stack.c
@@ -124,6 +124,7 @@ ide_layout_stack_bindings_notify_source (IdeLayoutStack *self,
_ide_layout_stack_header_set_title (priv->header, _("No Open Pages"));
_ide_layout_stack_header_set_modified (priv->header, FALSE);
_ide_layout_stack_header_set_background_rgba (priv->header, NULL);
+ _ide_layout_stack_header_set_foreground_rgba (priv->header, NULL);
}
}
@@ -568,10 +569,14 @@ ide_layout_stack_init (IdeLayoutStack *self)
priv->header, "modified",
G_BINDING_SYNC_CREATE);
- dzl_binding_group_bind (priv->bindings, "primary-color",
+ dzl_binding_group_bind (priv->bindings, "primary-color-bg",
priv->header, "background-rgba",
G_BINDING_SYNC_CREATE);
+ dzl_binding_group_bind (priv->bindings, "primary-color-fg",
+ priv->header, "foreground-rgba",
+ G_BINDING_SYNC_CREATE);
+
g_signal_connect_object (priv->stack,
"notify::visible-child",
G_CALLBACK (ide_layout_stack_notify_visible_child),
diff --git a/libide/layout/ide-layout-view.c b/libide/layout/ide-layout-view.c
index dd2b165..7e1e320 100644
--- a/libide/layout/ide-layout-view.c
+++ b/libide/layout/ide-layout-view.c
@@ -28,12 +28,14 @@ typedef struct
const gchar *icon_name;
gchar *title;
- GdkRGBA primary_color;
+ GdkRGBA primary_color_bg;
+ GdkRGBA primary_color_fg;
guint failed : 1;
guint modified : 1;
guint can_split : 1;
- guint primary_color_set : 1;
+ guint primary_color_bg_set : 1;
+ guint primary_color_fg_set : 1;
} IdeLayoutViewPrivate;
enum {
@@ -43,7 +45,8 @@ enum {
PROP_ICON_NAME,
PROP_MENU_ID,
PROP_MODIFIED,
- PROP_PRIMARY_COLOR,
+ PROP_PRIMARY_COLOR_BG,
+ PROP_PRIMARY_COLOR_FG,
PROP_TITLE,
N_PROPS
};
@@ -141,8 +144,12 @@ ide_layout_view_get_property (GObject *object,
g_value_set_boolean (value, ide_layout_view_get_modified (self));
break;
- case PROP_PRIMARY_COLOR:
- g_value_set_boxed (value, ide_layout_view_get_primary_color (self));
+ case PROP_PRIMARY_COLOR_BG:
+ g_value_set_boxed (value, ide_layout_view_get_primary_color_bg (self));
+ break;
+
+ case PROP_PRIMARY_COLOR_FG:
+ g_value_set_boxed (value, ide_layout_view_get_primary_color_fg (self));
break;
case PROP_TITLE:
@@ -184,8 +191,12 @@ ide_layout_view_set_property (GObject *object,
ide_layout_view_set_modified (self, g_value_get_boolean (value));
break;
- case PROP_PRIMARY_COLOR:
- ide_layout_view_set_primary_color (self, g_value_get_boxed (value));
+ case PROP_PRIMARY_COLOR_BG:
+ ide_layout_view_set_primary_color_bg (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_PRIMARY_COLOR_FG:
+ ide_layout_view_set_primary_color_fg (self, g_value_get_boxed (value));
break;
case PROP_TITLE:
@@ -247,9 +258,9 @@ ide_layout_view_class_init (IdeLayoutViewClass *klass)
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
/**
- * IdeLayoutView:primary-color:
+ * IdeLayoutView:primary-color-bg:
*
- * The "primary-color" property should describe the primary color
+ * The "primary-color-bg" property should describe the primary color
* of the content of the view (if any).
*
* This can be used by the layout stack to alter the color of the
@@ -257,10 +268,28 @@ ide_layout_view_class_init (IdeLayoutViewClass *klass)
*
* Since: 3.26
*/
- properties [PROP_PRIMARY_COLOR] =
- g_param_spec_boxed ("primary-color",
- "Primary Color",
- "The primary color of the content",
+ properties [PROP_PRIMARY_COLOR_BG] =
+ g_param_spec_boxed ("primary-color-bg",
+ "Primary Color Background",
+ "The primary foreground color of the content",
+ GDK_TYPE_RGBA,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * IdeLayoutView:primary-color-fg:
+ *
+ * The "primary-color-fg" property should describe the foreground
+ * to use for content above primary-color-bg.
+ *
+ * This can be used by the layout stack to alter the color of the
+ * foreground to match that of the content.
+ *
+ * Since: 3.26
+ */
+ properties [PROP_PRIMARY_COLOR_FG] =
+ g_param_spec_boxed ("primary-color-fg",
+ "Primary Color Foreground",
+ "The primary foreground color of the content",
GDK_TYPE_RGBA,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
@@ -531,12 +560,74 @@ ide_layout_view_create_split_view (IdeLayoutView *self)
}
/**
- * ide_layout_view_get_primary_color:
+ * ide_layout_view_get_primary_color_bg:
+ * @self: a #IdeLayoutView
+ *
+ * Gets the #IdeLayoutView:primary-color-bg property if it has been set.
+ *
+ * The primary-color-bg can be used to alter the color of the layout
+ * stack header to match the document contents.
+ *
+ * Returns: (transfer none) (nullable): A #GdkRGBA or %NULL.
+ *
+ * Since: 3.26
+ */
+const GdkRGBA *
+ide_layout_view_get_primary_color_bg (IdeLayoutView *self)
+{
+ IdeLayoutViewPrivate *priv = ide_layout_view_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_LAYOUT_VIEW (self), NULL);
+
+ return priv->primary_color_bg_set ? &priv->primary_color_bg : NULL;
+}
+
+/**
+ * ide_layout_view_set_primary_color_bg:
+ * @self: a #IdeLayoutView
+ * @primary_color_bg: (nullable): A #GdkRGBA or %NULL
+ *
+ * Sets the #IdeLayoutView:primary-color-bg property.
+ * If @primary_color_bg is %NULL, the property is unset.
+ *
+ * Since: 3.26
+ */
+void
+ide_layout_view_set_primary_color_bg (IdeLayoutView *self,
+ const GdkRGBA *primary_color_bg)
+{
+ IdeLayoutViewPrivate *priv = ide_layout_view_get_instance_private (self);
+ gboolean old_set;
+ GdkRGBA old;
+
+ g_return_if_fail (IDE_IS_LAYOUT_VIEW (self));
+
+ old_set = priv->primary_color_bg_set;
+ old = priv->primary_color_bg;
+
+ if (primary_color_bg != NULL)
+ {
+ priv->primary_color_bg = *primary_color_bg;
+ priv->primary_color_bg_set = TRUE;
+ }
+ else
+ {
+ memset (&priv->primary_color_bg, 0, sizeof priv->primary_color_bg);
+ priv->primary_color_bg_set = FALSE;
+ }
+
+ if (old_set != priv->primary_color_bg_set ||
+ !gdk_rgba_equal (&old, &priv->primary_color_bg))
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIMARY_COLOR_BG]);
+}
+
+/**
+ * ide_layout_view_get_primary_color_fg:
* @self: a #IdeLayoutView
*
- * Gets the #IdeLayoutView:primary-color property if it has been set.
+ * Gets the #IdeLayoutView:primary-color-fg property if it has been set.
*
- * The primary-color can be used to alter the color of the layout
+ * The primary-color-fg can be used to alter the foreground color of the layout
* stack header to match the document contents.
*
* Returns: (transfer none) (nullable): A #GdkRGBA or %NULL.
@@ -544,28 +635,28 @@ ide_layout_view_create_split_view (IdeLayoutView *self)
* Since: 3.26
*/
const GdkRGBA *
-ide_layout_view_get_primary_color (IdeLayoutView *self)
+ide_layout_view_get_primary_color_fg (IdeLayoutView *self)
{
IdeLayoutViewPrivate *priv = ide_layout_view_get_instance_private (self);
g_return_val_if_fail (IDE_IS_LAYOUT_VIEW (self), NULL);
- return priv->primary_color_set ? &priv->primary_color : NULL;
+ return priv->primary_color_fg_set ? &priv->primary_color_fg : NULL;
}
/**
- * ide_layout_view_set_primary_color:
+ * ide_layout_view_set_primary_color_fg:
* @self: a #IdeLayoutView
- * @primary_color: (nullable): A #GdkRGBA or %NULL
+ * @primary_color_fg: (nullable): A #GdkRGBA or %NULL
*
- * Sets the #IdeLayoutView:primary-color property.
- * If @primary_color is %NULL, the property is unset.
+ * Sets the #IdeLayoutView:primary-color-fg property.
+ * If @primary_color_fg is %NULL, the property is unset.
*
* Since: 3.26
*/
void
-ide_layout_view_set_primary_color (IdeLayoutView *self,
- const GdkRGBA *primary_color)
+ide_layout_view_set_primary_color_fg (IdeLayoutView *self,
+ const GdkRGBA *primary_color_fg)
{
IdeLayoutViewPrivate *priv = ide_layout_view_get_instance_private (self);
gboolean old_set;
@@ -573,21 +664,21 @@ ide_layout_view_set_primary_color (IdeLayoutView *self,
g_return_if_fail (IDE_IS_LAYOUT_VIEW (self));
- old_set = priv->primary_color_set;
- old = priv->primary_color;
+ old_set = priv->primary_color_fg_set;
+ old = priv->primary_color_fg;
- if (primary_color != NULL)
+ if (primary_color_fg != NULL)
{
- priv->primary_color = *primary_color;
- priv->primary_color_set = TRUE;
+ priv->primary_color_fg = *primary_color_fg;
+ priv->primary_color_fg_set = TRUE;
}
else
{
- memset (&priv->primary_color, 0, sizeof priv->primary_color);
- priv->primary_color_set = FALSE;
+ memset (&priv->primary_color_fg, 0, sizeof priv->primary_color_fg);
+ priv->primary_color_fg_set = FALSE;
}
- if (old_set != priv->primary_color_set ||
- !gdk_rgba_equal (&old, &priv->primary_color))
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIMARY_COLOR]);
+ if (old_set != priv->primary_color_fg_set ||
+ !gdk_rgba_equal (&old, &priv->primary_color_fg))
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIMARY_COLOR_FG]);
}
diff --git a/libide/layout/ide-layout-view.h b/libide/layout/ide-layout-view.h
index f0e254f..67bfe99 100644
--- a/libide/layout/ide-layout-view.h
+++ b/libide/layout/ide-layout-view.h
@@ -73,9 +73,12 @@ void ide_layout_view_set_modified (IdeLayoutView *self
const gchar *ide_layout_view_get_title (IdeLayoutView *self);
void ide_layout_view_set_title (IdeLayoutView *self,
const gchar *title);
-const GdkRGBA *ide_layout_view_get_primary_color (IdeLayoutView *self);
-void ide_layout_view_set_primary_color (IdeLayoutView *self,
- const GdkRGBA *primary_color);
+const GdkRGBA *ide_layout_view_get_primary_color_bg (IdeLayoutView *self);
+void ide_layout_view_set_primary_color_bg (IdeLayoutView *self,
+ const GdkRGBA *primary_color_bg);
+const GdkRGBA *ide_layout_view_get_primary_color_fg (IdeLayoutView *self);
+void ide_layout_view_set_primary_color_fg (IdeLayoutView *self,
+ const GdkRGBA *primary_color_fg);
void ide_layout_view_agree_to_close_async (IdeLayoutView *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]