forked from AuroraMiddleware/gtk
Merge branch 'wip/otte/listview-colors' into 'master'
Improve listview-colors demo See merge request GNOME/gtk!2123
This commit is contained in:
commit
7d409dd2e0
@ -23,7 +23,7 @@ struct _GtkColor
|
|||||||
GObject parent_instance;
|
GObject parent_instance;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
GdkRGBA *color;
|
GdkRGBA color;
|
||||||
int h, s, v;
|
int h, s, v;
|
||||||
gboolean selected;
|
gboolean selected;
|
||||||
};
|
};
|
||||||
@ -40,7 +40,7 @@ enum {
|
|||||||
PROP_VALUE,
|
PROP_VALUE,
|
||||||
PROP_SELECTED,
|
PROP_SELECTED,
|
||||||
|
|
||||||
N_PROPS
|
N_COLOR_PROPS
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -51,7 +51,7 @@ gtk_color_snapshot (GdkPaintable *paintable,
|
|||||||
{
|
{
|
||||||
GtkColor *self = GTK_COLOR (paintable);
|
GtkColor *self = GTK_COLOR (paintable);
|
||||||
|
|
||||||
gtk_snapshot_append_color (snapshot, self->color, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
gtk_snapshot_append_color (snapshot, &self->color, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -82,7 +82,82 @@ G_DEFINE_TYPE_WITH_CODE (GtkColor, gtk_color, G_TYPE_OBJECT,
|
|||||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||||
gtk_color_paintable_init))
|
gtk_color_paintable_init))
|
||||||
|
|
||||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
static GParamSpec *color_properties[N_COLOR_PROPS] = { NULL, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
rgb_to_hsv (GdkRGBA *rgba,
|
||||||
|
gdouble *h_out,
|
||||||
|
gdouble *s_out,
|
||||||
|
gdouble *v_out)
|
||||||
|
{
|
||||||
|
gdouble red, green, blue;
|
||||||
|
gdouble h, s, v;
|
||||||
|
gdouble min, max;
|
||||||
|
gdouble delta;
|
||||||
|
|
||||||
|
red = rgba->red;
|
||||||
|
green = rgba->green;
|
||||||
|
blue = rgba->blue;
|
||||||
|
|
||||||
|
h = 0.0;
|
||||||
|
|
||||||
|
if (red > green)
|
||||||
|
{
|
||||||
|
if (red > blue)
|
||||||
|
max = red;
|
||||||
|
else
|
||||||
|
max = blue;
|
||||||
|
|
||||||
|
if (green < blue)
|
||||||
|
min = green;
|
||||||
|
else
|
||||||
|
min = blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (green > blue)
|
||||||
|
max = green;
|
||||||
|
else
|
||||||
|
max = blue;
|
||||||
|
|
||||||
|
if (red < blue)
|
||||||
|
min = red;
|
||||||
|
else
|
||||||
|
min = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = max;
|
||||||
|
|
||||||
|
if (max != 0.0)
|
||||||
|
s = (max - min) / max;
|
||||||
|
else
|
||||||
|
s = 0.0;
|
||||||
|
|
||||||
|
if (s == 0.0)
|
||||||
|
h = 0.0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delta = max - min;
|
||||||
|
|
||||||
|
if (red == max)
|
||||||
|
h = (green - blue) / delta;
|
||||||
|
else if (green == max)
|
||||||
|
h = 2 + (blue - red) / delta;
|
||||||
|
else if (blue == max)
|
||||||
|
h = 4 + (red - green) / delta;
|
||||||
|
|
||||||
|
h /= 6.0;
|
||||||
|
|
||||||
|
if (h < 0.0)
|
||||||
|
h += 1.0;
|
||||||
|
else if (h > 1.0)
|
||||||
|
h -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*h_out = h;
|
||||||
|
*s_out = s;
|
||||||
|
*v_out = v;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_color_get_property (GObject *object,
|
gtk_color_get_property (GObject *object,
|
||||||
@ -99,19 +174,19 @@ gtk_color_get_property (GObject *object,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_COLOR:
|
case PROP_COLOR:
|
||||||
g_value_set_boxed (value, self->color);
|
g_value_set_boxed (value, &self->color);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_RED:
|
case PROP_RED:
|
||||||
g_value_set_float (value, self->color->red);
|
g_value_set_float (value, self->color.red);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_GREEN:
|
case PROP_GREEN:
|
||||||
g_value_set_float (value, self->color->green);
|
g_value_set_float (value, self->color.green);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_BLUE:
|
case PROP_BLUE:
|
||||||
g_value_set_float (value, self->color->blue);
|
g_value_set_float (value, self->color.blue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_HUE:
|
case PROP_HUE:
|
||||||
@ -143,6 +218,7 @@ gtk_color_set_property (GObject *object,
|
|||||||
GParamSpec *pspec)
|
GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
GtkColor *self = GTK_COLOR (object);
|
GtkColor *self = GTK_COLOR (object);
|
||||||
|
double h, s, v;
|
||||||
|
|
||||||
switch (property_id)
|
switch (property_id)
|
||||||
{
|
{
|
||||||
@ -151,19 +227,11 @@ gtk_color_set_property (GObject *object,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_COLOR:
|
case PROP_COLOR:
|
||||||
self->color = g_value_dup_boxed (value);
|
self->color = *(GdkRGBA *) g_value_dup_boxed (value);
|
||||||
break;
|
rgb_to_hsv (&self->color, &h, &s, &v);
|
||||||
|
self->h = round (360 * h);
|
||||||
case PROP_HUE:
|
self->s = round (100 * s);
|
||||||
self->h = g_value_get_int (value);
|
self->v = round (100 * v);
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_SATURATION:
|
|
||||||
self->s = g_value_get_int (value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PROP_VALUE:
|
|
||||||
self->v = g_value_get_int (value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_SELECTED:
|
case PROP_SELECTED:
|
||||||
@ -182,7 +250,6 @@ gtk_color_finalize (GObject *object)
|
|||||||
GtkColor *self = GTK_COLOR (object);
|
GtkColor *self = GTK_COLOR (object);
|
||||||
|
|
||||||
g_free (self->name);
|
g_free (self->name);
|
||||||
g_clear_pointer (&self->color, gdk_rgba_free);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_color_parent_class)->finalize (object);
|
G_OBJECT_CLASS (gtk_color_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@ -196,26 +263,26 @@ gtk_color_class_init (GtkColorClass *klass)
|
|||||||
gobject_class->set_property = gtk_color_set_property;
|
gobject_class->set_property = gtk_color_set_property;
|
||||||
gobject_class->finalize = gtk_color_finalize;
|
gobject_class->finalize = gtk_color_finalize;
|
||||||
|
|
||||||
properties[PROP_NAME] =
|
color_properties[PROP_NAME] =
|
||||||
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
properties[PROP_COLOR] =
|
color_properties[PROP_COLOR] =
|
||||||
g_param_spec_boxed ("color", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
g_param_spec_boxed ("color", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
properties[PROP_RED] =
|
color_properties[PROP_RED] =
|
||||||
g_param_spec_float ("red", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
g_param_spec_float ("red", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_GREEN] =
|
color_properties[PROP_GREEN] =
|
||||||
g_param_spec_float ("green", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
g_param_spec_float ("green", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_BLUE] =
|
color_properties[PROP_BLUE] =
|
||||||
g_param_spec_float ("blue", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
g_param_spec_float ("blue", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_HUE] =
|
color_properties[PROP_HUE] =
|
||||||
g_param_spec_int ("hue", NULL, NULL, 0, 360, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
g_param_spec_int ("hue", NULL, NULL, 0, 360, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_SATURATION] =
|
color_properties[PROP_SATURATION] =
|
||||||
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_VALUE] =
|
color_properties[PROP_VALUE] =
|
||||||
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READABLE);
|
||||||
properties[PROP_SELECTED] =
|
color_properties[PROP_SELECTED] =
|
||||||
g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE);
|
g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE);
|
||||||
|
|
||||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
g_object_class_install_properties (gobject_class, N_COLOR_PROPS, color_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -225,8 +292,7 @@ gtk_color_init (GtkColor *self)
|
|||||||
|
|
||||||
static GtkColor *
|
static GtkColor *
|
||||||
gtk_color_new (const char *name,
|
gtk_color_new (const char *name,
|
||||||
float r, float g, float b,
|
float r, float g, float b)
|
||||||
int h, int s, int v)
|
|
||||||
{
|
{
|
||||||
GtkColor *result;
|
GtkColor *result;
|
||||||
GdkRGBA color = { r, g, b, 1.0 };
|
GdkRGBA color = { r, g, b, 1.0 };
|
||||||
@ -234,132 +300,242 @@ gtk_color_new (const char *name,
|
|||||||
result = g_object_new (GTK_TYPE_COLOR,
|
result = g_object_new (GTK_TYPE_COLOR,
|
||||||
"name", name,
|
"name", name,
|
||||||
"color", &color,
|
"color", &color,
|
||||||
"hue", h,
|
|
||||||
"saturation", s,
|
|
||||||
"value", v,
|
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
#define N_COLORS (256 * 256 * 256)
|
||||||
{
|
|
||||||
GtkWidget *widget;
|
|
||||||
GBytes *data;
|
|
||||||
GListStore *store;
|
|
||||||
char **lines;
|
|
||||||
guint n;
|
|
||||||
guint i;
|
|
||||||
} ColorData;
|
|
||||||
|
|
||||||
static void
|
#define GTK_TYPE_COLOR_LIST (gtk_color_list_get_type ())
|
||||||
free_color_data (gpointer data)
|
G_DECLARE_FINAL_TYPE (GtkColorList, gtk_color_list, GTK, COLOR_LIST, GObject)
|
||||||
{
|
|
||||||
ColorData *cd = data;
|
|
||||||
|
|
||||||
if (cd->widget)
|
enum {
|
||||||
gtk_widget_set_sensitive (cd->widget, TRUE);
|
LIST_PROP_0,
|
||||||
g_bytes_unref (cd->data);
|
LIST_PROP_SIZE,
|
||||||
g_object_unref (cd->store);
|
|
||||||
g_strfreev (cd->lines);
|
N_LIST_PROPS
|
||||||
g_free (cd);
|
};
|
||||||
|
|
||||||
|
typedef struct _GtkColorList GtkColorList;
|
||||||
|
struct _GtkColorList
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
GtkColor **colors; /* Always N_COLORS */
|
||||||
|
|
||||||
|
guint size; /* How many colors we allow */
|
||||||
|
};
|
||||||
|
|
||||||
|
static GType
|
||||||
|
gtk_color_list_get_item_type (GListModel *list)
|
||||||
|
{
|
||||||
|
return GTK_TYPE_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static guint
|
||||||
add_color (GtkWidget *widget,
|
gtk_color_list_get_n_items (GListModel *list)
|
||||||
GdkFrameClock *clock,
|
|
||||||
gpointer data)
|
|
||||||
{
|
{
|
||||||
ColorData *cd = data;
|
GtkColorList *self = GTK_COLOR_LIST (list);
|
||||||
const char *name;
|
|
||||||
char **fields;
|
|
||||||
int red, green, blue;
|
|
||||||
int h, s, v;
|
|
||||||
GtkColor *color;
|
|
||||||
guint64 start, now;
|
|
||||||
|
|
||||||
start = g_get_monotonic_time ();
|
return self->size;
|
||||||
|
}
|
||||||
|
|
||||||
while (cd->i < cd->n)
|
static guint
|
||||||
|
position_to_color (guint position)
|
||||||
|
{
|
||||||
|
static guint map[] = {
|
||||||
|
0xFF0000, 0x00FF00, 0x0000FF,
|
||||||
|
0x7F0000, 0x007F00, 0x00007F,
|
||||||
|
0x3F0000, 0x003F00, 0x00003F,
|
||||||
|
0x1F0000, 0x001F00, 0x00001F,
|
||||||
|
0x0F0000, 0x000F00, 0x00000F,
|
||||||
|
0x070000, 0x000700, 0x000007,
|
||||||
|
0x030000, 0x000300, 0x000003,
|
||||||
|
0x010000, 0x000100, 0x000001
|
||||||
|
};
|
||||||
|
guint result, i;
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (map); i++)
|
||||||
{
|
{
|
||||||
const char *line = cd->lines[cd->i];
|
if (position & (1 << i))
|
||||||
|
result ^= map[i];
|
||||||
|
}
|
||||||
|
|
||||||
cd->i++;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (line[0] == '#' || line[0] == '\0')
|
static gpointer
|
||||||
|
gtk_color_list_get_item (GListModel *list,
|
||||||
|
guint position)
|
||||||
|
{
|
||||||
|
GtkColorList *self = GTK_COLOR_LIST (list);
|
||||||
|
|
||||||
|
if (position >= self->size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
position = position_to_color (position);
|
||||||
|
|
||||||
|
if (self->colors[position] == NULL)
|
||||||
|
{
|
||||||
|
guint red, green, blue;
|
||||||
|
|
||||||
|
red = (position >> 16) & 0xFF;
|
||||||
|
green = (position >> 8) & 0xFF;
|
||||||
|
blue = position & 0xFF;
|
||||||
|
|
||||||
|
self->colors[position] = gtk_color_new ("", red / 255., green / 255., blue / 255.);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_object_ref (self->colors[position]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_model_init (GListModelInterface *iface)
|
||||||
|
{
|
||||||
|
iface->get_item_type = gtk_color_list_get_item_type;
|
||||||
|
iface->get_n_items = gtk_color_list_get_n_items;
|
||||||
|
iface->get_item = gtk_color_list_get_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (GtkColorList, gtk_color_list, G_TYPE_OBJECT,
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||||
|
gtk_color_list_model_init))
|
||||||
|
|
||||||
|
static GParamSpec *list_properties[N_LIST_PROPS] = { NULL, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkColorList *self = GTK_COLOR_LIST (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case LIST_PROP_SIZE:
|
||||||
|
g_value_set_uint (value, self->size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_set_size (GtkColorList *self,
|
||||||
|
guint size)
|
||||||
|
{
|
||||||
|
guint old_size = self->size;
|
||||||
|
|
||||||
|
self->size = size;
|
||||||
|
if (self->size > old_size)
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), old_size, 0, self->size - old_size);
|
||||||
|
else if (old_size > self->size)
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), self->size, old_size - self->size, 0);
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), list_properties[LIST_PROP_SIZE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkColorList *self = GTK_COLOR_LIST (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case LIST_PROP_SIZE:
|
||||||
|
gtk_color_list_set_size (self, g_value_get_uint (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GtkColorList *self = GTK_COLOR_LIST (object);
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < N_COLORS; i++)
|
||||||
|
{
|
||||||
|
g_clear_object (&self->colors[i]);
|
||||||
|
}
|
||||||
|
g_free (self->colors);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (gtk_color_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_class_init (GtkColorListClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->get_property = gtk_color_list_get_property;
|
||||||
|
gobject_class->set_property = gtk_color_list_set_property;
|
||||||
|
gobject_class->dispose = gtk_color_list_dispose;
|
||||||
|
|
||||||
|
list_properties[LIST_PROP_SIZE] =
|
||||||
|
g_param_spec_uint ("size", NULL, NULL, 0, N_COLORS, 0, G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_properties (gobject_class, N_LIST_PROPS, list_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_color_list_init (GtkColorList *self)
|
||||||
|
{
|
||||||
|
GBytes *data;
|
||||||
|
char **lines;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
self->colors = g_new0 (GtkColor *, N_COLORS);
|
||||||
|
|
||||||
|
data = g_resources_lookup_data ("/listview_colors/color.names.txt", 0, NULL);
|
||||||
|
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
|
||||||
|
|
||||||
|
for (i = 0; lines[i]; i++)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
char **fields;
|
||||||
|
int red, green, blue;
|
||||||
|
guint pos;
|
||||||
|
|
||||||
|
if (lines[i][0] == '#' || lines[i][0] == '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fields = g_strsplit (line, " ", 0);
|
fields = g_strsplit (lines[i], " ", 0);
|
||||||
name = fields[1];
|
name = fields[1];
|
||||||
red = atoi (fields[3]);
|
red = atoi (fields[3]);
|
||||||
green = atoi (fields[4]);
|
green = atoi (fields[4]);
|
||||||
blue = atoi (fields[5]);
|
blue = atoi (fields[5]);
|
||||||
h = atoi (fields[9]);
|
|
||||||
s = atoi (fields[10]);
|
|
||||||
v = atoi (fields[11]);
|
|
||||||
|
|
||||||
color = gtk_color_new (name, red / 255., green / 255., blue / 255., h, s, v);
|
pos = ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | blue;
|
||||||
g_list_store_append (cd->store, color);
|
if (self->colors[pos] == NULL)
|
||||||
g_object_unref (color);
|
self->colors[pos] = gtk_color_new (name, red / 255., green / 255., blue / 255.);
|
||||||
|
|
||||||
g_strfreev (fields);
|
g_strfreev (fields);
|
||||||
|
|
||||||
now = g_get_monotonic_time ();
|
|
||||||
if (now > start + 4000)
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
g_strfreev (lines);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
g_bytes_unref (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GListModel *
|
||||||
populate_colors_model (GtkWidget *widget,
|
gtk_color_list_new (guint size)
|
||||||
GListStore *store)
|
|
||||||
{
|
{
|
||||||
ColorData *cd;
|
return g_object_new (GTK_TYPE_COLOR_LIST,
|
||||||
|
"size", size,
|
||||||
cd = g_new (ColorData, 1);
|
NULL);
|
||||||
|
|
||||||
gtk_widget_set_sensitive (widget, FALSE);
|
|
||||||
|
|
||||||
cd->widget = widget;
|
|
||||||
cd->store = g_object_ref (store);
|
|
||||||
cd->data = g_resources_lookup_data ("/listview_colors/color.names.txt", 0, NULL);
|
|
||||||
cd->lines = g_strsplit (g_bytes_get_data (cd->data, NULL), "\n", 0);
|
|
||||||
cd->n = g_strv_length (cd->lines);
|
|
||||||
cd->i = 0;
|
|
||||||
|
|
||||||
gtk_widget_add_tick_callback (widget, add_color, cd, free_color_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fill (GtkWidget *view,
|
|
||||||
GListStore *store)
|
|
||||||
{
|
|
||||||
ColorData *cd;
|
|
||||||
gboolean res;
|
|
||||||
|
|
||||||
cd = g_new (ColorData, 1);
|
|
||||||
|
|
||||||
cd->widget = NULL;
|
|
||||||
cd->store = g_object_ref (store);
|
|
||||||
cd->data = g_resources_lookup_data ("/listview_colors/color.names.txt", 0, NULL);
|
|
||||||
cd->lines = g_strsplit (g_bytes_get_data (cd->data, NULL), "\n", 0);
|
|
||||||
cd->n = g_strv_length (cd->lines);
|
|
||||||
cd->i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
res = add_color (view, NULL, cd);
|
|
||||||
} while (res == G_SOURCE_CONTINUE);
|
|
||||||
free_color_data (cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
refill (GtkWidget *button,
|
|
||||||
GListStore *store)
|
|
||||||
{
|
|
||||||
g_list_store_remove_all (store);
|
|
||||||
populate_colors_model (button, store);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -370,9 +546,9 @@ get_rgb_markup (gpointer this,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return g_strdup_printf ("<b>R:</b> %d <b>G:</b> %d <b>B:</b> %d",
|
return g_strdup_printf ("<b>R:</b> %d <b>G:</b> %d <b>B:</b> %d",
|
||||||
(int)(color->color->red * 255),
|
(int)(color->color.red * 255),
|
||||||
(int)(color->color->green * 255),
|
(int)(color->color.green * 255),
|
||||||
(int)(color->color->blue * 255));
|
(int)(color->color.blue * 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -477,7 +653,6 @@ create_color_grid (void)
|
|||||||
GtkWidget *gridview;
|
GtkWidget *gridview;
|
||||||
GtkListItemFactory *factory;
|
GtkListItemFactory *factory;
|
||||||
GListModel *model, *selection;
|
GListModel *model, *selection;
|
||||||
GListStore *store;
|
|
||||||
|
|
||||||
gridview = gtk_grid_view_new ();
|
gridview = gtk_grid_view_new ();
|
||||||
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
||||||
@ -491,19 +666,74 @@ create_color_grid (void)
|
|||||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
|
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
|
||||||
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
|
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
|
||||||
|
|
||||||
store = g_list_store_new (GTK_TYPE_COLOR);
|
model = G_LIST_MODEL (gtk_sort_list_model_new (gtk_color_list_new (0), NULL));
|
||||||
fill (gridview, store);
|
|
||||||
|
|
||||||
model = G_LIST_MODEL (gtk_sort_list_model_new (G_LIST_MODEL (store), NULL));
|
|
||||||
selection = G_LIST_MODEL (gtk_property_selection_new (model, "selected"));
|
selection = G_LIST_MODEL (gtk_property_selection_new (model, "selected"));
|
||||||
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
|
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
|
||||||
g_object_unref (selection);
|
g_object_unref (selection);
|
||||||
g_object_unref (model);
|
g_object_unref (model);
|
||||||
g_object_unref (store);
|
|
||||||
|
|
||||||
return gridview;
|
return gridview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
add_colors (GtkWidget *widget,
|
||||||
|
GdkFrameClock *clock,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GtkColorList *colors = data;
|
||||||
|
guint limit;
|
||||||
|
|
||||||
|
limit = GPOINTER_TO_UINT (g_object_get_data (data, "limit"));
|
||||||
|
gtk_color_list_set_size (colors, MIN (limit, colors->size + MAX (1, limit / 4096)));
|
||||||
|
|
||||||
|
if (colors->size >= limit)
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
else
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
refill (GtkWidget *button,
|
||||||
|
GtkColorList *colors)
|
||||||
|
{
|
||||||
|
gtk_color_list_set_size (colors, 0);
|
||||||
|
gtk_widget_add_tick_callback (button, add_colors, g_object_ref (colors), g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
limit_changed_cb (GtkDropDown *dropdown,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
GtkColorList *colors)
|
||||||
|
{
|
||||||
|
guint new_limit, old_limit;
|
||||||
|
|
||||||
|
old_limit = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (colors), "limit"));
|
||||||
|
new_limit = 1 << (3 * (gtk_drop_down_get_selected (dropdown) + 1));
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (colors), "limit", GUINT_TO_POINTER (new_limit));
|
||||||
|
|
||||||
|
if (old_limit == colors->size)
|
||||||
|
gtk_color_list_set_size (colors, new_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
limit_changed_cb2 (GtkDropDown *dropdown,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
GtkLabel *label)
|
||||||
|
{
|
||||||
|
gpointer item;
|
||||||
|
char *string;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
item = gtk_drop_down_get_selected_item (dropdown);
|
||||||
|
g_object_get (item, "string", &string, NULL);
|
||||||
|
len = g_utf8_strlen (string, -1);
|
||||||
|
g_free (string);
|
||||||
|
|
||||||
|
gtk_label_set_max_width_chars (label, len + 2); /* for " /" */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
items_changed_cb (GListModel *model,
|
items_changed_cb (GListModel *model,
|
||||||
guint position,
|
guint position,
|
||||||
@ -514,11 +744,12 @@ items_changed_cb (GListModel *model,
|
|||||||
guint n = g_list_model_get_n_items (model);
|
guint n = g_list_model_get_n_items (model);
|
||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
text = g_strdup_printf ("%u items", n);
|
text = g_strdup_printf ("%u /", n);
|
||||||
gtk_label_set_label (GTK_LABEL (label), text);
|
gtk_label_set_label (GTK_LABEL (label), text);
|
||||||
g_free (text);
|
g_free (text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static GtkWidget *window = NULL;
|
static GtkWidget *window = NULL;
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
@ -536,6 +767,7 @@ do_listview_colors (GtkWidget *do_widget)
|
|||||||
GtkExpression *expression;
|
GtkExpression *expression;
|
||||||
GtkWidget *button;
|
GtkWidget *button;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
|
PangoAttrList *attrs;
|
||||||
|
|
||||||
window = gtk_window_new ();
|
window = gtk_window_new ();
|
||||||
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
||||||
@ -563,13 +795,38 @@ do_listview_colors (GtkWidget *do_widget)
|
|||||||
|
|
||||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
||||||
|
|
||||||
label = gtk_label_new ("0 items");
|
label = gtk_label_new ("0 /");
|
||||||
|
attrs = pango_attr_list_new ();
|
||||||
|
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum"));
|
||||||
|
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
||||||
|
pango_attr_list_unref (attrs);
|
||||||
|
gtk_label_set_width_chars (GTK_LABEL (label), 6);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 1);
|
||||||
g_signal_connect (gtk_grid_view_get_model (GTK_GRID_VIEW (gridview)),
|
g_signal_connect (gtk_grid_view_get_model (GTK_GRID_VIEW (gridview)),
|
||||||
"items-changed", G_CALLBACK (items_changed_cb), label);
|
"items-changed", G_CALLBACK (items_changed_cb), label);
|
||||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), label);
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), label);
|
||||||
|
|
||||||
|
dropdown = gtk_drop_down_new ();
|
||||||
|
gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), (const char *[]) { "8", "64", "512", "4096", "32768", "262144", "2097152", "16777216", NULL });
|
||||||
|
g_signal_connect (dropdown, "notify::selected",
|
||||||
|
G_CALLBACK (limit_changed_cb),
|
||||||
|
gtk_sort_list_model_get_model (GTK_SORT_LIST_MODEL (model)));
|
||||||
|
g_signal_connect (dropdown, "notify::selected",
|
||||||
|
G_CALLBACK (limit_changed_cb2),
|
||||||
|
label);
|
||||||
|
gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), 3); /* 4096 */
|
||||||
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), dropdown);
|
||||||
|
|
||||||
sorters = g_list_store_new (GTK_TYPE_SORTER);
|
sorters = g_list_store_new (GTK_TYPE_SORTER);
|
||||||
|
|
||||||
|
/* An empty multisorter doesn't do any sorting and the sortmodel is
|
||||||
|
* smart enough to know that.
|
||||||
|
*/
|
||||||
|
sorter = gtk_multi_sorter_new ();
|
||||||
|
set_title (sorter, "Unsorted");
|
||||||
|
g_list_store_append (sorters, sorter);
|
||||||
|
g_object_unref (sorter);
|
||||||
|
|
||||||
sorter = gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name"));
|
sorter = gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name"));
|
||||||
set_title (sorter, "Name");
|
set_title (sorter, "Name");
|
||||||
g_list_store_append (sorters, sorter);
|
g_list_store_append (sorters, sorter);
|
||||||
|
@ -308,6 +308,30 @@ gtk_sort_list_model_get_property (GObject *object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_sort_list_model_clear_sequences (GtkSortListModel *self)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&self->unsorted, g_sequence_free);
|
||||||
|
g_clear_pointer (&self->sorted, g_sequence_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_sort_list_model_create_sequences (GtkSortListModel *self)
|
||||||
|
{
|
||||||
|
if (self->sorted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (self->sorter == NULL ||
|
||||||
|
self->model == NULL ||
|
||||||
|
gtk_sorter_get_order (self->sorter) == GTK_SORTER_ORDER_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self->sorted = g_sequence_new (gtk_sort_list_entry_free);
|
||||||
|
self->unsorted = g_sequence_new (NULL);
|
||||||
|
|
||||||
|
gtk_sort_list_model_add_items (self, 0, g_list_model_get_n_items (self->model), NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void gtk_sort_list_model_resort (GtkSortListModel *self);
|
static void gtk_sort_list_model_resort (GtkSortListModel *self);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -315,7 +339,16 @@ gtk_sort_list_model_sorter_changed_cb (GtkSorter *sorter,
|
|||||||
int change,
|
int change,
|
||||||
GtkSortListModel *self)
|
GtkSortListModel *self)
|
||||||
{
|
{
|
||||||
gtk_sort_list_model_resort (self);
|
if (gtk_sorter_get_order (sorter) == GTK_SORTER_ORDER_NONE)
|
||||||
|
gtk_sort_list_model_clear_sequences (self);
|
||||||
|
else if (self->sorted == NULL)
|
||||||
|
{
|
||||||
|
guint n_items = g_list_model_get_n_items (self->model);
|
||||||
|
gtk_sort_list_model_create_sequences (self);
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gtk_sort_list_model_resort (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -326,8 +359,7 @@ gtk_sort_list_model_clear_model (GtkSortListModel *self)
|
|||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (self->model, gtk_sort_list_model_items_changed_cb, self);
|
g_signal_handlers_disconnect_by_func (self->model, gtk_sort_list_model_items_changed_cb, self);
|
||||||
g_clear_object (&self->model);
|
g_clear_object (&self->model);
|
||||||
g_clear_pointer (&self->sorted, g_sequence_free);
|
gtk_sort_list_model_clear_sequences (self);
|
||||||
g_clear_pointer (&self->unsorted, g_sequence_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -338,6 +370,7 @@ gtk_sort_list_model_clear_sorter (GtkSortListModel *self)
|
|||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (self->sorter, gtk_sort_list_model_sorter_changed_cb, self);
|
g_signal_handlers_disconnect_by_func (self->sorter, gtk_sort_list_model_sorter_changed_cb, self);
|
||||||
g_clear_object (&self->sorter);
|
g_clear_object (&self->sorter);
|
||||||
|
gtk_sort_list_model_clear_sequences (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -451,18 +484,6 @@ gtk_sort_list_model_new_for_type (GType item_type)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_sort_list_model_create_sequences (GtkSortListModel *self)
|
|
||||||
{
|
|
||||||
if (self->sorter == NULL || self->model == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self->sorted = g_sequence_new (gtk_sort_list_entry_free);
|
|
||||||
self->unsorted = g_sequence_new (NULL);
|
|
||||||
|
|
||||||
gtk_sort_list_model_add_items (self, 0, g_list_model_get_n_items (self->model), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_sort_list_model_set_model:
|
* gtk_sort_list_model_set_model:
|
||||||
* @self: a #GtkSortListModel
|
* @self: a #GtkSortListModel
|
||||||
@ -566,9 +587,6 @@ gtk_sort_list_model_set_sorter (GtkSortListModel *self,
|
|||||||
g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sort_list_model_sorter_changed_cb), self);
|
g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sort_list_model_sorter_changed_cb), self);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_pointer (&self->unsorted, g_sequence_free);
|
|
||||||
g_clear_pointer (&self->sorted, g_sequence_free);
|
|
||||||
|
|
||||||
gtk_sort_list_model_create_sequences (self);
|
gtk_sort_list_model_create_sequences (self);
|
||||||
|
|
||||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||||
|
Loading…
Reference in New Issue
Block a user