[egg-list-box/row-widget: 5/7] listbox: Move state changes and drawing to Row
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [egg-list-box/row-widget: 5/7] listbox: Move state changes and drawing to Row
- Date: Mon, 10 Jun 2013 08:43:40 +0000 (UTC)
commit 25bd7cc274b975b683cc808be5e818960dd6cffe
Author: Alexander Larsson <alexl redhat com>
Date: Fri Jun 7 15:21:01 2013 +0200
listbox: Move state changes and drawing to Row
Also we add support for borders.
egg-list-box.c | 344 +++++++++++++++++++++++++++++++++++++-------------------
test-list.vala | 9 +-
2 files changed, 233 insertions(+), 120 deletions(-)
---
diff --git a/egg-list-box.c b/egg-list-box.c
index d2504be..e85e852 100644
--- a/egg-list-box.c
+++ b/egg-list-box.c
@@ -818,7 +818,14 @@ egg_list_box_update_selected (EggListBox *list_box,
if (row != priv->selected_row &&
(row == NULL || priv->selection_mode != GTK_SELECTION_NONE))
{
+ if (priv->selected_row)
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->selected_row),
+ GTK_STATE_FLAG_SELECTED);
priv->selected_row = row;
+ if (priv->selected_row)
+ gtk_widget_set_state_flags (GTK_WIDGET (priv->selected_row),
+ GTK_STATE_FLAG_SELECTED,
+ FALSE);
g_signal_emit (list_box, signals[ROW_SELECTED], 0,
priv->selected_row);
gtk_widget_queue_draw (GTK_WIDGET (list_box));
@@ -844,7 +851,14 @@ egg_list_box_update_prelight (EggListBox *list_box, EggListBoxRow *row)
if (row != priv->prelight_row)
{
+ if (priv->prelight_row)
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->prelight_row),
+ GTK_STATE_FLAG_PRELIGHT);
priv->prelight_row = row;
+ if (priv->prelight_row)
+ gtk_widget_set_state_flags (GTK_WIDGET (priv->prelight_row),
+ GTK_STATE_FLAG_PRELIGHT,
+ FALSE);
gtk_widget_queue_draw (GTK_WIDGET (list_box));
}
}
@@ -860,6 +874,13 @@ egg_list_box_update_active (EggListBox *list_box, EggListBoxRow *row)
val != priv->active_row_active)
{
priv->active_row_active = val;
+ if (priv->active_row_active)
+ gtk_widget_set_state_flags (GTK_WIDGET (priv->active_row),
+ GTK_STATE_FLAG_ACTIVE,
+ FALSE);
+ else
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->active_row),
+ GTK_STATE_FLAG_ACTIVE);
gtk_widget_queue_draw (GTK_WIDGET (list_box));
}
}
@@ -943,19 +964,22 @@ egg_list_box_real_button_press_event (GtkWidget *widget,
EggListBoxRow *row;
row = egg_list_box_get_row_at_y (list_box, event->y);
if (row != NULL)
- {
- priv->active_row = row;
- priv->active_row_active = TRUE;
- gtk_widget_queue_draw (GTK_WIDGET (list_box));
- if (event->type == GDK_2BUTTON_PRESS &&
- !priv->activate_single_click)
- g_signal_emit (list_box, signals[ROW_ACTIVATED], 0,
- row);
+ {
+ priv->active_row = row;
+ priv->active_row_active = TRUE;
+ gtk_widget_set_state_flags (GTK_WIDGET (priv->active_row),
+ GTK_STATE_FLAG_ACTIVE,
+ FALSE);
+ gtk_widget_queue_draw (GTK_WIDGET (list_box));
+ if (event->type == GDK_2BUTTON_PRESS &&
+ !priv->activate_single_click)
+ g_signal_emit (list_box, signals[ROW_ACTIVATED], 0,
+ row);
- }
+ }
/* TODO:
- Should mark as active while down,
- and handle grab breaks */
+ Should mark as active while down,
+ and handle grab breaks */
}
return FALSE;
@@ -978,6 +1002,9 @@ egg_list_box_real_button_release_event (GtkWidget *widget,
else
egg_list_box_update_selected (list_box, priv->active_row);
}
+ if (priv->active_row_active)
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->active_row),
+ GTK_STATE_FLAG_ACTIVE);
priv->active_row = NULL;
priv->active_row_active = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (list_box));
@@ -1133,91 +1160,21 @@ egg_list_box_real_focus (GtkWidget* widget, GtkDirectionType direction)
return TRUE;
}
-typedef struct {
- EggListBoxRow *row;
- GtkStateFlags state;
-} RowFlags;
-
-static RowFlags*
-row_flags_find_or_add (RowFlags *array,
- int *array_length,
- EggListBoxRow *to_find)
-{
- gint i;
-
- for (i = 0; i < *array_length; i++)
- {
- if (array[i].row == to_find)
- return &array[i];
- }
-
- *array_length = *array_length + 1;
- array[*array_length - 1].row = to_find;
- array[*array_length - 1].state = 0;
- return &array[*array_length - 1];
-}
-
static gboolean
egg_list_box_real_draw (GtkWidget* widget, cairo_t* cr)
{
- EggListBox * list_box = EGG_LIST_BOX (widget);
- EggListBoxPrivate *priv = list_box->priv;
- GtkAllocation allocation = {0};
- GtkStyleContext* context;
- GtkStateFlags state;
- RowFlags flags[3], *found;
- gint flags_length;
- gint focus_pad;
- int i;
-
- gtk_widget_get_allocation (GTK_WIDGET (list_box), &allocation);
- context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
- state = gtk_widget_get_state_flags (widget);
- gtk_render_background (context, cr, (gdouble) 0, (gdouble) 0, (gdouble) allocation.width, (gdouble)
allocation.height);
- flags_length = 0;
-
- if (priv->selected_row != NULL)
- {
- found = row_flags_find_or_add (flags, &flags_length, priv->selected_row);
- found->state |= (state | GTK_STATE_FLAG_SELECTED);
- }
-
- if (priv->prelight_row != NULL)
- {
- found = row_flags_find_or_add (flags, &flags_length, priv->prelight_row);
- found->state |= (state | GTK_STATE_FLAG_PRELIGHT);
- }
-
- if (priv->active_row != NULL && priv->active_row_active)
- {
- found = row_flags_find_or_add (flags, &flags_length, priv->active_row);
- found->state |= (state | GTK_STATE_FLAG_ACTIVE);
- }
-
- for (i = 0; i < flags_length; i++)
- {
- RowFlags *flag = &flags[i];
- gtk_style_context_save (context);
- gtk_style_context_set_state (context, flag->state);
- gtk_render_background (context, cr, 0, flag->row->priv->y, allocation.width, flag->row->priv->height);
- gtk_style_context_restore (context);
- }
+ GtkAllocation allocation;
+ GtkStyleContext *context;
- if (gtk_widget_has_visible_focus (GTK_WIDGET (list_box)) && priv->cursor_row != NULL)
- {
- gtk_style_context_get_style (context,
- "focus-padding", &focus_pad,
- NULL);
- gtk_render_focus (context, cr, focus_pad, priv->cursor_row->priv->y + focus_pad,
- allocation.width - 2 * focus_pad, priv->cursor_row->priv->height - 2 * focus_pad);
- }
+ gtk_widget_get_allocation (widget, &allocation);
+ context = gtk_widget_get_style_context (widget);
+ gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
- GTK_WIDGET_CLASS (egg_list_box_parent_class)->draw ((GtkWidget*) G_TYPE_CHECK_INSTANCE_CAST (list_box,
GTK_TYPE_CONTAINER, GtkContainer), cr);
+ GTK_WIDGET_CLASS (egg_list_box_parent_class)->draw (widget, cr);
return TRUE;
}
-
static void
egg_list_box_real_realize (GtkWidget* widget)
{
@@ -1521,12 +1478,19 @@ egg_list_box_real_remove (GtkContainer* container, GtkWidget* child)
if (row == priv->selected_row)
egg_list_box_update_selected (list_box, NULL);
- if (row == priv->prelight_row)
+ if (row == priv->prelight_row) {
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->prelight_row),
+ GTK_STATE_FLAG_PRELIGHT);
priv->prelight_row = NULL;
+ }
if (row == priv->cursor_row)
priv->cursor_row = NULL;
- if (row == priv->active_row)
+ if (row == priv->active_row) {
+ if (priv->active_row_active)
+ gtk_widget_unset_state_flags (GTK_WIDGET (priv->active_row),
+ GTK_STATE_FLAG_ACTIVE);
priv->active_row = NULL;
+ }
next = egg_list_box_get_next_visible (list_box, row->priv->iter);
gtk_widget_unparent (child);
@@ -1609,17 +1573,9 @@ egg_list_box_real_get_preferred_height_for_width (GtkWidget* widget, gint width,
GSequenceIter *iter;
gint minimum_height;
gint natural_height;
- GtkStyleContext *context;
- gint focus_width;
- gint focus_pad;
minimum_height = 0;
- context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
- gtk_style_context_get_style (context,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad, NULL);
-
for (iter = g_sequence_get_begin_iter (priv->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
@@ -1636,9 +1592,9 @@ egg_list_box_real_get_preferred_height_for_width (GtkWidget* widget, gint width,
gtk_widget_get_preferred_height_for_width (row->priv->separator, width, &row_min, NULL);
minimum_height += row_min;
}
- gtk_widget_get_preferred_height_for_width (GTK_WIDGET (row), width - 2 * (focus_width + focus_pad),
+ gtk_widget_get_preferred_height_for_width (GTK_WIDGET (row), width,
&row_min, NULL);
- minimum_height += row_min + 2 * (focus_width + focus_pad);
+ minimum_height += row_min;
}
/* We always allocate the minimum height, since handling
@@ -1660,17 +1616,11 @@ egg_list_box_real_get_preferred_width (GtkWidget* widget, gint* minimum_width_ou
EggListBoxPrivate *priv = list_box->priv;
gint minimum_width;
gint natural_width;
- GtkStyleContext *context;
- gint focus_width;
- gint focus_pad;
GSequenceIter *iter;
EggListBoxRow *row;
gint row_min;
gint row_nat;
- context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
- gtk_style_context_get_style (context, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL);
-
minimum_width = 0;
natural_width = 0;
@@ -1683,8 +1633,8 @@ egg_list_box_real_get_preferred_width (GtkWidget* widget, gint* minimum_width_ou
continue;
gtk_widget_get_preferred_width (GTK_WIDGET (row), &row_min, &row_nat);
- minimum_width = MAX (minimum_width, row_min + 2 * (focus_width + focus_pad));
- natural_width = MAX (natural_width, row_nat + 2 * (focus_width + focus_pad));
+ minimum_width = MAX (minimum_width, row_min);
+ natural_width = MAX (natural_width, row_nat);
if (row->priv->separator != NULL)
{
@@ -1720,8 +1670,6 @@ egg_list_box_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
GtkWidget *child;
GSequenceIter *iter;
GtkStyleContext *context;
- gint focus_width;
- gint focus_pad;
int child_min;
@@ -1743,13 +1691,9 @@ egg_list_box_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
allocation->width, allocation->height);
context = gtk_widget_get_style_context (GTK_WIDGET (list_box));
- gtk_style_context_get_style (context,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- NULL);
- child_allocation.x = 0 + focus_width + focus_pad;
+ child_allocation.x = 0;
child_allocation.y = 0;
- child_allocation.width = allocation->width - 2 * (focus_width + focus_pad);
+ child_allocation.width = allocation->width;
separator_allocation.x = 0;
separator_allocation.width = allocation->width;
@@ -1777,15 +1721,14 @@ egg_list_box_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
}
row->priv->y = child_allocation.y;
- child_allocation.y += focus_width + focus_pad;
gtk_widget_get_preferred_height_for_width (GTK_WIDGET (row), child_allocation.width, &child_min, NULL);
child_allocation.height = child_min;
- row->priv->height = child_allocation.height + 2 * (focus_width + focus_pad);
+ row->priv->height = child_allocation.height;
gtk_widget_size_allocate (GTK_WIDGET (row), &child_allocation);
- child_allocation.y += child_min + focus_width + focus_pad;
+ child_allocation.y += child_min;
}
}
@@ -2157,6 +2100,165 @@ egg_list_box_row_real_hide (GtkWidget *widget)
egg_list_box_row_visibility_changed (list_box, row);
}
+static gboolean
+egg_list_box_row_real_draw (GtkWidget* widget, cairo_t* cr)
+{
+ EggListBoxRow *row = EGG_LIST_BOX_ROW (widget);
+ EggListBox *list_box;
+ GtkAllocation allocation = {0};
+ GtkStyleContext* context;
+ GtkStateFlags state;
+ GtkBorder border;
+ gint focus_pad;
+ int i;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ context = gtk_widget_get_style_context (widget);
+ state = gtk_widget_get_state_flags (widget);
+
+ gtk_render_background (context, cr, (gdouble) 0, (gdouble) 0, (gdouble) allocation.width, (gdouble)
allocation.height);
+ gtk_render_frame (context, cr, (gdouble) 0, (gdouble) 0, (gdouble) allocation.width, (gdouble)
allocation.height);
+
+ list_box = egg_list_box_row_get_box (row);
+ if (list_box && gtk_widget_has_visible_focus (GTK_WIDGET (list_box)) &&
+ row == list_box->priv->cursor_row)
+ {
+ gtk_style_context_get_border (context, state, &border);
+
+ gtk_style_context_get_style (context,
+ "focus-padding", &focus_pad,
+ NULL);
+ gtk_render_focus (context, cr, border.left + focus_pad, border.top + focus_pad,
+ allocation.width - 2 * focus_pad - border.left - border.right,
+ allocation.height - 2 * focus_pad - border.top - border.bottom);
+ }
+
+ GTK_WIDGET_CLASS (egg_list_box_row_parent_class)->draw (widget, cr);
+
+ return TRUE;
+}
+
+static void
+egg_list_box_row_get_full_border (EggListBoxRow *row,
+ GtkBorder *full_border)
+{
+ GtkWidget *widget = GTK_WIDGET (row);
+ GtkStyleContext *context;
+ GtkStateFlags state;
+ GtkBorder default_border, padding, border;
+ int focus_width, focus_pad;
+
+ context = gtk_widget_get_style_context (widget);
+ state = gtk_style_context_get_state (context);
+
+ gtk_style_context_get_padding (context, state, &padding);
+ gtk_style_context_get_border (context, state, &border);
+ gtk_style_context_get_style (context,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ full_border->left = padding.left + border.left + focus_width + focus_pad;
+ full_border->right = padding.right + border.right + focus_width + focus_pad;
+ full_border->top = padding.top + border.top + focus_width + focus_pad;
+ full_border->bottom = padding.bottom + border.bottom + focus_width + focus_pad;
+}
+
+static void egg_list_box_row_real_get_preferred_height_for_width (GtkWidget* widget, gint width,
+ gint* minimum_height_out, gint*
natural_height_out);
+static void egg_list_box_row_real_get_preferred_width (GtkWidget* widget,
+ gint* minimum_width_out, gint* natural_width_out);
+
+static void
+egg_list_box_row_real_get_preferred_height (GtkWidget* widget,
+ gint* minimum_height,
+ gint* natural_height)
+{
+ gint natural_width;
+ egg_list_box_row_real_get_preferred_width (widget, NULL, &natural_width);
+ egg_list_box_row_real_get_preferred_height_for_width (widget, natural_width,
+ minimum_height, natural_height);
+}
+
+static void
+egg_list_box_row_real_get_preferred_height_for_width (GtkWidget* widget, gint width,
+ gint* minimum_height_out, gint* natural_height_out)
+{
+ EggListBoxRow *row = EGG_LIST_BOX_ROW (widget);
+ GtkWidget *child;
+ gint child_min = 0, child_natural = 0;
+ GtkBorder full_border;
+
+ egg_list_box_row_get_full_border (row, &full_border);
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ if (child && gtk_widget_get_visible (child))
+ gtk_widget_get_preferred_height_for_width (child, width - full_border.left - full_border.right,
+ &child_min, &child_natural);
+
+ if (minimum_height_out)
+ *minimum_height_out = full_border.top + child_min + full_border.bottom;
+ if (natural_height_out)
+ *natural_height_out = full_border.top + child_natural + full_border.bottom;
+}
+
+static void
+egg_list_box_row_real_get_preferred_width (GtkWidget* widget, gint* minimum_width_out, gint*
natural_width_out)
+{
+ EggListBoxRow *row = EGG_LIST_BOX_ROW (widget);
+ GtkWidget *child;
+ gint child_min = 0, child_natural = 0;
+ GtkBorder full_border;
+
+ egg_list_box_row_get_full_border (row, &full_border);
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ if (child && gtk_widget_get_visible (child))
+ gtk_widget_get_preferred_width (child,
+ &child_min, &child_natural);
+
+ if (minimum_width_out)
+ *minimum_width_out = full_border.left + child_min + full_border.right;
+ if (natural_width_out)
+ *natural_width_out = full_border.left + child_natural + full_border.bottom;
+}
+
+static void
+egg_list_box_row_real_get_preferred_width_for_height (GtkWidget *widget, gint height,
+ gint *minimum_width, gint *natural_width)
+{
+ egg_list_box_row_real_get_preferred_width (widget, minimum_width, natural_width);
+}
+
+static void
+egg_list_box_row_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ EggListBoxRow *row = EGG_LIST_BOX_ROW (widget);
+ GtkWidget *child;
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ if (child && gtk_widget_get_visible (child))
+ {
+ GtkAllocation child_allocation;
+ GtkBorder border;
+ gint baseline;
+
+ egg_list_box_row_get_full_border (row, &border);
+
+ child_allocation.x = allocation->x + border.left;
+ child_allocation.y = allocation->y + border.top;
+ child_allocation.width = allocation->width - border.left - border.right;
+ child_allocation.height = allocation->height - border.top - border.bottom;
+
+ child_allocation.width = MAX (1, child_allocation.width);
+ child_allocation.height = MAX (1, child_allocation.height);
+
+ gtk_widget_size_allocate (child, &child_allocation);
+ }
+}
+
void
egg_list_box_row_changed (EggListBoxRow *row)
{
@@ -2221,4 +2323,10 @@ egg_list_box_row_class_init (EggListBoxRowClass *klass)
widget_class->show = egg_list_box_row_real_show;
widget_class->hide = egg_list_box_row_real_hide;
+ widget_class->draw = egg_list_box_row_real_draw;
+ widget_class->get_preferred_height = egg_list_box_row_real_get_preferred_height;
+ widget_class->get_preferred_height_for_width = egg_list_box_row_real_get_preferred_height_for_width;
+ widget_class->get_preferred_width = egg_list_box_row_real_get_preferred_width;
+ widget_class->get_preferred_width_for_height = egg_list_box_row_real_get_preferred_width_for_height;
+ widget_class->size_allocate = egg_list_box_row_real_size_allocate;
}
diff --git a/test-list.vala b/test-list.vala
index 2c8291f..b121822 100644
--- a/test-list.vala
+++ b/test-list.vala
@@ -208,10 +208,15 @@ main (string[] args) {
var provider = new Gtk.CssProvider ();
provider.load_from_data (
"""
-EggListBox:prelight {
+EggListBoxRow {
+ border-width: 1px;
+ border-style: solid;
+ border-color: blue;
+}
+EggListBoxRow:prelight {
background-color: green;
}
-EggListBox:active {
+EggListBoxRow:active {
background-color: red;
}
""", -1);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]