Compare commits
3 Commits
shader-too
...
wip/gbsnet
Author | SHA1 | Date | |
---|---|---|---|
|
347841504c | ||
|
8994607f99 | ||
|
507d45c2d4 |
@@ -14,6 +14,7 @@ demos_base = \
|
||||
combobox.c \
|
||||
css_accordion.c \
|
||||
css_basics.c \
|
||||
css_blendmodes.c \
|
||||
css_multiplebgs.c \
|
||||
css_pixbufs.c \
|
||||
css_shadows.c \
|
||||
|
391
demos/gtk-demo/blendmodes.ui
Normal file
391
demos/gtk-demo/blendmodes.ui
Normal file
@@ -0,0 +1,391 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">CSS Blend Modes</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="default_height">300</property>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Blend mode:</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="min_content_width">150</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackSwitcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hhomogeneous">False</property>
|
||||
<property name="vhomogeneous">False</property>
|
||||
<property name="transition_type">crossfade</property>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">False</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Duck</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Background</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="duck"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="gradient"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">
|
||||
Blended picture</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<style>
|
||||
<class name="blend0"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">page0</property>
|
||||
<property name="title" translatable="yes">Ducky</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">False</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Red</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Blue</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="red"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="blue"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">
|
||||
Blended picture</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<style>
|
||||
<class name="blend1"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">page1</property>
|
||||
<property name="title" translatable="yes">Blends</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="cyan"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="magenta"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="yellow"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<style>
|
||||
<class name="blend2"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Cyan</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Magenta</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Yellow</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Blended picture</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">page2</property>
|
||||
<property name="title" translatable="yes">CMYK</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
BIN
demos/gtk-demo/blends.png
Normal file
BIN
demos/gtk-demo/blends.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 788 B |
BIN
demos/gtk-demo/cmy.jpg
Normal file
BIN
demos/gtk-demo/cmy.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
178
demos/gtk-demo/css_blendmodes.c
Normal file
178
demos/gtk-demo/css_blendmodes.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* Theming/CSS Blend Modes
|
||||
*
|
||||
* You can blend multiple backgrounds using the CSS blend modes available.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define WID(x) ((GtkWidget*) gtk_builder_get_object (builder, x))
|
||||
|
||||
/*
|
||||
* These are the available blend modes.
|
||||
*/
|
||||
struct {
|
||||
gchar *name;
|
||||
gchar *id;
|
||||
} blend_modes[] =
|
||||
{
|
||||
{ "Color", "color" },
|
||||
{ "Color (burn)", "color-burn" },
|
||||
{ "Color (dodge)", "color-dodge" },
|
||||
{ "Darken", "darken" },
|
||||
{ "Difference", "difference" },
|
||||
{ "Exclusion", "exclusion" },
|
||||
{ "Hard Light", "hard-light" },
|
||||
{ "Hue", "hue" },
|
||||
{ "Lighten", "lighten" },
|
||||
{ "Luminosity", "luminosity" },
|
||||
{ "Multiply", "multiply" },
|
||||
{ "Normal", "normal" },
|
||||
{ "Overlay", "overlay" },
|
||||
{ "Saturate", "saturate" },
|
||||
{ "Screen", "screen" },
|
||||
{ "Soft Light", "soft-light" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* The CSS class to be applied in the blended image. Notice that the first %s
|
||||
* is replaced by the content of css_blendmodes.css and the second %s is
|
||||
* replaced by the blend mode.
|
||||
*/
|
||||
static const gchar *CSS_TEMPLATE =
|
||||
"%s\n"
|
||||
"\n"
|
||||
"image.blend0 {\n"
|
||||
" background-image: url('resource://css_blendmodes/ducky.png'),\n"
|
||||
" linear-gradient(to right, red 0%, green 50%, blue 100%);\n"
|
||||
" background-size: cover;\n"
|
||||
" background-blend-mode: %s;\n"
|
||||
" min-width: 200px;\n"
|
||||
" min-height: 200px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"image.blend1 {\n"
|
||||
" background: url('resource://css_blendmodes/blends.png') top center,\n"
|
||||
" url('resource://css_blendmodes/blends.png') bottom center;\n"
|
||||
" background-blend-mode: %s;\n"
|
||||
" min-width: 200px;\n"
|
||||
" min-height: 200px;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"image.blend2 {\n"
|
||||
" background: url('resource://css_blendmodes/cmy.jpg') top center,\n"
|
||||
" url('resource://css_blendmodes/cmy.jpg') center center,\n"
|
||||
" url('resource://css_blendmodes/cmy.jpg') bottom center;\n"
|
||||
" background-blend-mode: %s;\n"
|
||||
" min-width: 200px;\n"
|
||||
" min-height: 200px;\n"
|
||||
"}\n";
|
||||
|
||||
static void
|
||||
update_css_for_blend_mode (GtkCssProvider *provider,
|
||||
const gchar *blend_mode)
|
||||
{
|
||||
GBytes *bytes;
|
||||
gchar *css;
|
||||
|
||||
bytes = g_resources_lookup_data ("/css_blendmodes/css_blendmodes.css", 0, NULL);
|
||||
|
||||
css = g_strdup_printf (CSS_TEMPLATE,
|
||||
(gchar*) g_bytes_get_data (bytes, NULL),
|
||||
blend_mode,
|
||||
blend_mode,
|
||||
blend_mode);
|
||||
|
||||
gtk_css_provider_load_from_data (provider, css, -1, NULL);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_free (css);
|
||||
}
|
||||
|
||||
static void
|
||||
row_activated (GtkListBox *listbox,
|
||||
GtkListBoxRow *row,
|
||||
GtkCssProvider *provider)
|
||||
{
|
||||
const gchar *blend_mode;
|
||||
|
||||
blend_mode = blend_modes[gtk_list_box_row_get_index (row)].id;
|
||||
|
||||
update_css_for_blend_mode (provider, blend_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_listbox (GtkBuilder *builder,
|
||||
GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *normal_row;
|
||||
GtkWidget *listbox;
|
||||
gint i;
|
||||
|
||||
normal_row = NULL;
|
||||
listbox = gtk_list_box_new ();
|
||||
gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
|
||||
|
||||
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
|
||||
|
||||
/* Add a row for each blend mode available */
|
||||
for (i = 0; blend_modes[i].name != NULL; i++)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *row;
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
label = g_object_new (GTK_TYPE_LABEL,
|
||||
"label", blend_modes[i].name,
|
||||
"xalign", 0.0,
|
||||
NULL);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (row), label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (listbox), row);
|
||||
|
||||
/* The first selected row is "normal" */
|
||||
if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
|
||||
normal_row = row;
|
||||
}
|
||||
|
||||
/* Select the "normal" row */
|
||||
gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (normal_row));
|
||||
g_signal_emit_by_name (G_OBJECT (normal_row), "activate");
|
||||
|
||||
gtk_widget_grab_focus (normal_row);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_css_blendmodes (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkStyleProvider *provider;
|
||||
GtkBuilder *builder;
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/css_blendmodes/blendmodes.ui");
|
||||
|
||||
window = WID ("window");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
/* Setup the CSS provider for window */
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
|
||||
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
|
||||
provider,
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
setup_listbox (builder, provider);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show_all (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
51
demos/gtk-demo/css_blendmodes.css
Normal file
51
demos/gtk-demo/css_blendmodes.css
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* First page.
|
||||
*/
|
||||
image.duck {
|
||||
background-image: url('resource://css_blendmodes/ducky.png');
|
||||
background-size: cover;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
image.gradient {
|
||||
background-image: linear-gradient(to right, red 0%, green 50%, blue 100%);
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Second page.
|
||||
*/
|
||||
image.red {
|
||||
background: url('resource://css_blendmodes/blends.png') top center;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
image.blue {
|
||||
background: url('resource://css_blendmodes/blends.png') bottom center;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Third page.
|
||||
*/
|
||||
image.cyan {
|
||||
background: url('resource://css_blendmodes/cmy.jpg') top center;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
image.magenta {
|
||||
background: url('resource://css_blendmodes/cmy.jpg') center center;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
image.yellow {
|
||||
background: url('resource://css_blendmodes/cmy.jpg') bottom center;
|
||||
min-width: 200px;
|
||||
min-height: 200px;
|
||||
}
|
@@ -20,6 +20,13 @@
|
||||
<file>css_basics.css</file>
|
||||
<file>reset.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/css_blendmodes">
|
||||
<file>css_blendmodes.css</file>
|
||||
<file>blendmodes.ui</file>
|
||||
<file>blends.png</file>
|
||||
<file>ducky.png</file>
|
||||
<file>cmy.jpg</file>
|
||||
</gresource>
|
||||
<gresource prefix="/css_multiplebgs">
|
||||
<file>css_multiplebgs.css</file>
|
||||
<file>brick.png</file>
|
||||
@@ -130,6 +137,7 @@
|
||||
<file>combobox.c</file>
|
||||
<file>css_accordion.c</file>
|
||||
<file>css_basics.c</file>
|
||||
<file>css_blendmodes.c</file>
|
||||
<file>css_multiplebgs.c</file>
|
||||
<file>css_pixbufs.c</file>
|
||||
<file>css_shadows.c</file>
|
||||
|
BIN
demos/gtk-demo/ducky.png
Normal file
BIN
demos/gtk-demo/ducky.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 243 KiB |
@@ -1109,6 +1109,15 @@ We use <literallayout> for syntax productions, and each line is put in a <code>
|
||||
<ulink url="http://www.w3.org/TR/css3-background/#background-image">CSS3</ulink></entry>
|
||||
<entry>not supported: urls without quotes, CSS radial gradients, colors in crossfades</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>background-blend-mode</entry>
|
||||
<entry><code>〈blend-mode〉 [ , 〈blend-mode〉 ]*</code></entry>
|
||||
<entry><code>normal</code></entry>
|
||||
<entry></entry>
|
||||
<entry></entry>
|
||||
<entry></entry>
|
||||
<entry>only affects multiple backgrounds</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>box‑shadow</entry>
|
||||
<entry><code>none | 〈box shadow〉 [ , 〈box shadow〉 ]*</code></entry>
|
||||
@@ -1144,6 +1153,7 @@ We use <literallayout> for syntax productions, and each line is put in a <code>
|
||||
<code>〈bg-image〉 = 〈image〉 | none</code>
|
||||
<code>〈bg-layer〉 = 〈bg-image〉 || 〈position〉 [ / 〈bg-size〉 ]? || 〈bg-repeat〉 || 〈box〉 || 〈box〉</code>
|
||||
<code>〈final-bg-layer〉 = 〈bg-image〉 || 〈position〉 [ / 〈bg-size〉 ]? || 〈bg-repeat〉 || 〈box〉 || 〈box〉|| 〈color〉</code>
|
||||
<code>〈blend-mode〉 = color || color-burn || color-dodge || darken || difference || exclusion || hard-light || hue || lighten || luminosity || multiply || normal || overlay || saturate || screen || soft-light</code>
|
||||
<code>〈box shadow〉 = inset? && 〈length〉{2,4}? && 〈color〉?</code>
|
||||
</literallayout>
|
||||
|
||||
@@ -1152,6 +1162,10 @@ We use <literallayout> for syntax productions, and each line is put in a <code>
|
||||
background images are absent or have transparency.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Alternatively, multiple backgrounds can be blended using the <code>background-blend-mode</code> property.
|
||||
</para>
|
||||
|
||||
<table pgwide="1">
|
||||
<title>Transition properties</title>
|
||||
<tgroup cols="7">
|
||||
|
@@ -126,6 +126,67 @@ _gtk_css_border_style_value_get (const GtkCssValue *value)
|
||||
return value->value;
|
||||
}
|
||||
|
||||
/* GtkCssBlendMode */
|
||||
|
||||
static const GtkCssValueClass GTK_CSS_VALUE_BLEND_MODE = {
|
||||
gtk_css_value_enum_free,
|
||||
gtk_css_value_enum_compute,
|
||||
gtk_css_value_enum_equal,
|
||||
gtk_css_value_enum_transition,
|
||||
gtk_css_value_enum_print
|
||||
};
|
||||
|
||||
static GtkCssValue blend_mode_values[] = {
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_COLOR, "color" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_COLOR_BURN, "color-burn" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_COLOR_DODGE, "color-dodge" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_DARKEN, "darken" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_DIFFERENCE, "difference" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_EXCLUSION, "exclusion" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_HARD_LIGHT, "hard-light" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_HUE, "hue" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_LIGHTEN, "lighten" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_LUMINOSITY, "luminosity" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_MULTIPLY, "multiply" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_NORMAL, "normal" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_OVERLAY, "overlay" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_SATURATE, "saturate" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_SCREEN, "screen" },
|
||||
{ >K_CSS_VALUE_BLEND_MODE, 1, GTK_CSS_BLEND_MODE_SOFT_LIGHT, "soft-light" }
|
||||
};
|
||||
|
||||
GtkCssValue *
|
||||
_gtk_css_blend_mode_value_new (GtkCssBlendMode blend_mode)
|
||||
{
|
||||
g_return_val_if_fail (blend_mode < G_N_ELEMENTS (blend_mode_values), NULL);
|
||||
|
||||
return _gtk_css_value_ref (&blend_mode_values[blend_mode]);
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
_gtk_css_blend_mode_value_try_parse (GtkCssParser *parser)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (parser != NULL, NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (blend_mode_values); i++)
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, blend_mode_values[i].name, TRUE))
|
||||
return _gtk_css_value_ref (&blend_mode_values[i]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkCssBlendMode
|
||||
_gtk_css_blend_mode_value_get (const GtkCssValue *value)
|
||||
{
|
||||
g_return_val_if_fail (value->class == >K_CSS_VALUE_BLEND_MODE, GTK_CSS_BLEND_MODE_NORMAL);
|
||||
|
||||
return value->value;
|
||||
}
|
||||
|
||||
/* GtkCssFontSize */
|
||||
|
||||
static double
|
||||
|
@@ -27,6 +27,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkCssValue * _gtk_css_blend_mode_value_new (GtkCssBlendMode blend_mode);
|
||||
GtkCssValue * _gtk_css_blend_mode_value_try_parse (GtkCssParser *parser);
|
||||
GtkCssBlendMode _gtk_css_blend_mode_value_get (const GtkCssValue *value);
|
||||
|
||||
GtkCssValue * _gtk_css_border_style_value_new (GtkBorderStyle border_style);
|
||||
GtkCssValue * _gtk_css_border_style_value_try_parse (GtkCssParser *parser);
|
||||
GtkBorderStyle _gtk_css_border_style_value_get (const GtkCssValue *value);
|
||||
|
@@ -985,6 +985,24 @@ parse_border_width (GtkCssStyleProperty *property,
|
||||
| GTK_CSS_PARSE_LENGTH);
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
blend_mode_value_parse_one (GtkCssParser *parser)
|
||||
{
|
||||
GtkCssValue *value = _gtk_css_blend_mode_value_try_parse (parser);
|
||||
|
||||
if (value == NULL)
|
||||
_gtk_css_parser_error (parser, "unknown value for property");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
blend_mode_value_parse (GtkCssStyleProperty *property,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
return _gtk_css_array_value_parse (parser, blend_mode_value_parse_one);
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
background_repeat_value_parse_one (GtkCssParser *parser)
|
||||
{
|
||||
@@ -1565,6 +1583,16 @@ _gtk_css_style_property_init_properties (void)
|
||||
background_image_value_assign,
|
||||
_gtk_css_array_value_new (_gtk_css_image_value_new (NULL)));
|
||||
|
||||
gtk_css_style_property_register ("background-blend-mode",
|
||||
GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE,
|
||||
G_TYPE_NONE,
|
||||
0,
|
||||
GTK_CSS_AFFECTS_BACKGROUND,
|
||||
blend_mode_value_parse,
|
||||
NULL,
|
||||
NULL,
|
||||
_gtk_css_array_value_new (_gtk_css_blend_mode_value_new (GTK_CSS_BLEND_MODE_NORMAL)));
|
||||
|
||||
gtk_css_style_property_register ("border-image-source",
|
||||
GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE,
|
||||
CAIRO_GOBJECT_TYPE_PATTERN,
|
||||
|
@@ -22,6 +22,46 @@
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
|
||||
cairo_operator_t
|
||||
_gtk_css_blend_mode_get_operator (GtkCssBlendMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case GTK_CSS_BLEND_MODE_COLOR:
|
||||
return CAIRO_OPERATOR_HSL_COLOR;
|
||||
case GTK_CSS_BLEND_MODE_COLOR_BURN:
|
||||
return CAIRO_OPERATOR_COLOR_BURN;
|
||||
case GTK_CSS_BLEND_MODE_COLOR_DODGE:
|
||||
return CAIRO_OPERATOR_COLOR_DODGE;
|
||||
case GTK_CSS_BLEND_MODE_DARKEN:
|
||||
return CAIRO_OPERATOR_DARKEN;
|
||||
case GTK_CSS_BLEND_MODE_DIFFERENCE:
|
||||
return CAIRO_OPERATOR_DIFFERENCE;
|
||||
case GTK_CSS_BLEND_MODE_EXCLUSION:
|
||||
return CAIRO_OPERATOR_EXCLUSION;
|
||||
case GTK_CSS_BLEND_MODE_HARD_LIGHT:
|
||||
return CAIRO_OPERATOR_HARD_LIGHT;
|
||||
case GTK_CSS_BLEND_MODE_HUE:
|
||||
return CAIRO_OPERATOR_HSL_HUE;
|
||||
case GTK_CSS_BLEND_MODE_LIGHTEN:
|
||||
return CAIRO_OPERATOR_LIGHTEN;
|
||||
case GTK_CSS_BLEND_MODE_LUMINOSITY:
|
||||
return CAIRO_OPERATOR_HSL_LUMINOSITY;
|
||||
case GTK_CSS_BLEND_MODE_MULTIPLY:
|
||||
return CAIRO_OPERATOR_MULTIPLY;
|
||||
case GTK_CSS_BLEND_MODE_OVERLAY:
|
||||
return CAIRO_OPERATOR_OVERLAY;
|
||||
case GTK_CSS_BLEND_MODE_SATURATE:
|
||||
return CAIRO_OPERATOR_SATURATE;
|
||||
case GTK_CSS_BLEND_MODE_SCREEN:
|
||||
return CAIRO_OPERATOR_SCREEN;
|
||||
|
||||
case GTK_CSS_BLEND_MODE_NORMAL:
|
||||
default:
|
||||
return CAIRO_OPERATOR_OVER;
|
||||
}
|
||||
}
|
||||
|
||||
GtkCssChange
|
||||
_gtk_css_change_for_sibling (GtkCssChange match)
|
||||
{
|
||||
|
@@ -198,6 +198,7 @@ enum { /*< skip >*/
|
||||
GTK_CSS_PROPERTY_OUTLINE_COLOR,
|
||||
GTK_CSS_PROPERTY_BACKGROUND_REPEAT,
|
||||
GTK_CSS_PROPERTY_BACKGROUND_IMAGE,
|
||||
GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE,
|
||||
GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE,
|
||||
GTK_CSS_PROPERTY_BORDER_IMAGE_REPEAT,
|
||||
GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE,
|
||||
@@ -230,6 +231,25 @@ enum { /*< skip >*/
|
||||
GTK_CSS_PROPERTY_N_PROPERTIES
|
||||
};
|
||||
|
||||
typedef enum /*< skip >*/ {
|
||||
GTK_CSS_BLEND_MODE_COLOR,
|
||||
GTK_CSS_BLEND_MODE_COLOR_BURN,
|
||||
GTK_CSS_BLEND_MODE_COLOR_DODGE,
|
||||
GTK_CSS_BLEND_MODE_DARKEN,
|
||||
GTK_CSS_BLEND_MODE_DIFFERENCE,
|
||||
GTK_CSS_BLEND_MODE_EXCLUSION,
|
||||
GTK_CSS_BLEND_MODE_HARD_LIGHT,
|
||||
GTK_CSS_BLEND_MODE_HUE,
|
||||
GTK_CSS_BLEND_MODE_LIGHTEN,
|
||||
GTK_CSS_BLEND_MODE_LUMINOSITY,
|
||||
GTK_CSS_BLEND_MODE_MULTIPLY,
|
||||
GTK_CSS_BLEND_MODE_NORMAL,
|
||||
GTK_CSS_BLEND_MODE_OVERLAY,
|
||||
GTK_CSS_BLEND_MODE_SATURATE,
|
||||
GTK_CSS_BLEND_MODE_SCREEN,
|
||||
GTK_CSS_BLEND_MODE_SOFT_LIGHT
|
||||
} GtkCssBlendMode;
|
||||
|
||||
typedef enum /*< skip >*/ {
|
||||
GTK_CSS_IMAGE_BUILTIN_NONE,
|
||||
GTK_CSS_IMAGE_BUILTIN_CHECK,
|
||||
@@ -372,6 +392,8 @@ typedef enum /*< skip >*/ {
|
||||
GTK_CSS_MS,
|
||||
} GtkCssUnit;
|
||||
|
||||
cairo_operator_t _gtk_css_blend_mode_get_operator (GtkCssBlendMode mode);
|
||||
|
||||
GtkCssChange _gtk_css_change_for_sibling (GtkCssChange match);
|
||||
GtkCssChange _gtk_css_change_for_child (GtkCssChange match);
|
||||
|
||||
|
@@ -72,10 +72,45 @@ _gtk_theming_background_paint_color (GtkThemingBackground *bg,
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gtk_theming_background_needs_push_group (GtkCssStyle *style)
|
||||
{
|
||||
const GdkRGBA *bg_color;
|
||||
GtkCssValue *background_color;
|
||||
GtkCssValue *blend_modes;
|
||||
gint i;
|
||||
|
||||
background_color = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR);
|
||||
bg_color = _gtk_css_rgba_value_get_rgba (background_color);
|
||||
|
||||
/* An opaque background-color means we don't need to push the group */
|
||||
if (bg_color->alpha == 1)
|
||||
return FALSE;
|
||||
|
||||
blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
|
||||
|
||||
/*
|
||||
* If we have any blend mode different than NORMAL, we'll need to
|
||||
* push a group in order to correctly apply the blend modes.
|
||||
*/
|
||||
for (i = _gtk_css_array_value_get_n_values (blend_modes); i > 0; i--)
|
||||
{
|
||||
GtkCssBlendMode blend_mode;
|
||||
|
||||
blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, i - 1));
|
||||
|
||||
if (blend_mode != GTK_CSS_BLEND_MODE_NORMAL)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gtk_theming_background_paint_layer (GtkThemingBackground *bg,
|
||||
guint idx,
|
||||
cairo_t *cr)
|
||||
cairo_t *cr,
|
||||
GtkCssBlendMode blend_mode)
|
||||
{
|
||||
GtkCssRepeatStyle hrepeat, vrepeat;
|
||||
const GtkCssValue *pos, *repeat;
|
||||
@@ -134,6 +169,13 @@ _gtk_theming_background_paint_layer (GtkThemingBackground *bg,
|
||||
|
||||
cairo_translate (cr, origin->box.x, origin->box.y);
|
||||
|
||||
/*
|
||||
* Apply the blend mode, if any.
|
||||
*/
|
||||
if (G_UNLIKELY (_gtk_css_blend_mode_get_operator (blend_mode) != cairo_get_operator (cr)))
|
||||
cairo_set_operator (cr, _gtk_css_blend_mode_get_operator (blend_mode));
|
||||
|
||||
|
||||
if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT && vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
|
||||
{
|
||||
cairo_translate (cr,
|
||||
@@ -249,6 +291,12 @@ _gtk_theming_background_paint_layer (GtkThemingBackground *bg,
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this cairo_t can be shared with other widgets,
|
||||
* we must reset the operator after all the backgrounds
|
||||
* are properly rendered.
|
||||
*/
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
@@ -304,10 +352,14 @@ gtk_css_style_render_background (GtkCssStyle *style,
|
||||
GtkThemingBackground bg;
|
||||
gint idx;
|
||||
GtkCssValue *background_image;
|
||||
GtkCssValue *blend_modes;
|
||||
GtkCssValue *box_shadow;
|
||||
const GdkRGBA *bg_color;
|
||||
gboolean needs_push_group;
|
||||
gint number_of_layers;
|
||||
|
||||
background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE);
|
||||
blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE);
|
||||
bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
|
||||
box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW);
|
||||
|
||||
@@ -324,6 +376,22 @@ gtk_css_style_render_background (GtkCssStyle *style,
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
/*
|
||||
* When we have a blend mode set for the background, we cannot blend the current
|
||||
* widget's drawing with whatever the content that the Cairo context may have.
|
||||
* Because of that, push the drawing to a new group before drawing the background
|
||||
* layers, and paint the resulting image back after.
|
||||
*/
|
||||
needs_push_group = _gtk_theming_background_needs_push_group (style);
|
||||
|
||||
if (needs_push_group)
|
||||
{
|
||||
cairo_save (cr);
|
||||
cairo_rectangle (cr, x, y, width, height);
|
||||
cairo_clip (cr);
|
||||
cairo_push_group (cr);
|
||||
}
|
||||
|
||||
/* Outset shadows */
|
||||
_gtk_css_shadows_value_paint_box (box_shadow,
|
||||
cr,
|
||||
@@ -332,9 +400,15 @@ gtk_css_style_render_background (GtkCssStyle *style,
|
||||
|
||||
_gtk_theming_background_paint_color (&bg, cr, bg_color, background_image);
|
||||
|
||||
for (idx = _gtk_css_array_value_get_n_values (background_image) - 1; idx >= 0; idx--)
|
||||
number_of_layers = _gtk_css_array_value_get_n_values (background_image);
|
||||
|
||||
for (idx = number_of_layers - 1; idx >= 0; idx--)
|
||||
{
|
||||
_gtk_theming_background_paint_layer (&bg, idx, cr);
|
||||
GtkCssBlendMode blend_mode;
|
||||
|
||||
blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx));
|
||||
|
||||
_gtk_theming_background_paint_layer (&bg, idx, cr, blend_mode);
|
||||
}
|
||||
|
||||
/* Inset shadows */
|
||||
@@ -343,6 +417,14 @@ gtk_css_style_render_background (GtkCssStyle *style,
|
||||
&bg.boxes[GTK_CSS_AREA_PADDING_BOX],
|
||||
TRUE);
|
||||
|
||||
/* Paint back the resulting surface */
|
||||
if (needs_push_group)
|
||||
{
|
||||
cairo_pop_group_to_source (cr);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user