pmaports/maemo/gtk+2.0-maemo/hildonize-gtk-treeview.diff
NotKit 13465a27c6 Initial packaging for Maemo UI (#461)
* Initial packaging for Maemo UI from https://github.com/fremantle-gtk2/

gtk+2.0-maemo package is based on https://pkgs.alpinelinux.org/package/edge/main/x86/gtk+2.0 by Natanael Copa

* Include git revision in tarball filename
2017-09-04 17:09:53 +00:00

3595 lines
111 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -43,6 +43,8 @@
#include "gtkframe.h"
#include "gtktreemodelsort.h"
#include "gtktooltip.h"
+#include "gtkicontheme.h"
+#include "gtkeventbox.h"
#include "gtkprivate.h"
#include "gtkalias.h"
@@ -54,6 +56,9 @@
#define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
#define AUTO_EXPAND_TIMEOUT 500
+#define HILDON_TICK_MARK_SIZE 48
+#define HILDON_ROW_HEADER_HEIGHT 35
+
/* The "background" areas of all rows/cells add up to cover the entire tree.
* The background includes all inter-row and inter-cell spacing.
* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
@@ -120,6 +125,8 @@
EXPAND_COLLAPSE_CURSOR_ROW,
SELECT_CURSOR_PARENT,
START_INTERACTIVE_SEARCH,
+ ROW_INSENSITIVE,
+ HILDON_ROW_TAPPED,
LAST_SIGNAL
};
@@ -144,7 +151,10 @@
PROP_RUBBER_BANDING,
PROP_ENABLE_GRID_LINES,
PROP_ENABLE_TREE_LINES,
- PROP_TOOLTIP_COLUMN
+ PROP_TOOLTIP_COLUMN,
+ PROP_HILDON_UI_MODE,
+ PROP_ACTION_AREA_VISIBLE,
+ PROP_ACTION_AREA_ORIENTATION
};
/* object signals */
@@ -478,9 +488,16 @@
static void add_scroll_timeout (GtkTreeView *tree_view);
static void remove_scroll_timeout (GtkTreeView *tree_view);
-static guint tree_view_signals [LAST_SIGNAL] = { 0 };
+static gboolean gtk_tree_view_tap_and_hold_query (GtkWidget *widget,
+ GdkEvent *event);
+static void free_queued_select_row (GtkTreeView *tree_view);
+static void free_queued_activate_row (GtkTreeView *tree_view);
+static void free_queued_actions (GtkTreeView *tree_view);
-
+static void hildon_tree_view_set_action_area_height (GtkTreeView *tree_view);
+static void hildon_tree_view_setup_row_header_layout (GtkTreeView *tree_view);
+
+static guint tree_view_signals [LAST_SIGNAL] = { 0 };
/* GType Methods
*/
@@ -544,6 +561,12 @@
widget_class->grab_notify = gtk_tree_view_grab_notify;
widget_class->state_changed = gtk_tree_view_state_changed;
+ g_signal_override_class_closure (g_signal_lookup ("tap-and-hold-query",
+ GTK_TYPE_WIDGET),
+ GTK_TYPE_TREE_VIEW,
+ g_cclosure_new (G_CALLBACK (gtk_tree_view_tap_and_hold_query),
+ NULL, NULL));
+
/* GtkContainer signals */
container_class->remove = gtk_tree_view_remove;
container_class->forall = gtk_tree_view_forall;
@@ -715,7 +738,7 @@
g_param_spec_boolean ("show-expanders",
P_("Show Expanders"),
P_("View has expanders"),
- TRUE,
+ FALSE,
GTK_PARAM_READWRITE));
/**
@@ -732,7 +755,7 @@
P_("Extra indentation for each level"),
0,
G_MAXINT,
- 0,
+ 10,
GTK_PARAM_READWRITE));
g_object_class_install_property (o_class,
@@ -740,7 +763,7 @@
g_param_spec_boolean ("rubber-banding",
P_("Rubber Banding"),
P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
- FALSE,
+ TRUE,
GTK_PARAM_READWRITE));
g_object_class_install_property (o_class,
@@ -770,10 +793,73 @@
-1,
GTK_PARAM_READWRITE));
+ /**
+ * GtkTreeView:hildon-ui-mode:
+ *
+ * Specifies which UI mode to use. A setting of #HILDON_UI_MODE_NORMAL
+ * will cause the tree view to disable selections and emit row-activated
+ * as soon as a row is pressed. When #HILDON_UI_MODE_EDIT is set,
+ * selections can be made according to the setting of the mode on
+ * GtkTreeSelection.
+ *
+ * Toggling this property will cause the tree view to select an
+ * appropriate selection mode if not already done.
+ *
+ * Since: maemo 5.0
+ * Stability: unstable
+ */
+ g_object_class_install_property (o_class,
+ PROP_HILDON_UI_MODE,
+ g_param_spec_enum ("hildon-ui-mode",
+ P_("Hildon UI Mode"),
+ P_("The Hildon UI mode according to which the tree view should behave"),
+ HILDON_TYPE_UI_MODE,
+ HILDON_UI_MODE_NORMAL,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkTreeView:action-area-visible:
+ *
+ * Makes the action area of the GtkTreeView visible or invisible.
+ * Based on the value of the GtkTreeView:action-area-orientation
+ * property a certain height will be allocated above the first row
+ * for the action area.
+ *
+ * Since: maemo 5.0
+ * Stability: unstable
+ */
+ g_object_class_install_property (o_class,
+ PROP_ACTION_AREA_VISIBLE,
+ g_param_spec_boolean ("action-area-visible",
+ P_("Action Area Visible"),
+ P_("Whether the action area above the first row is visible"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkTreeView:action-area-orientation:
+ *
+ * Sets the orientation of the action area. This is either
+ * horizontal (landscape) or vertical (portrait). The height of
+ * the action area depends on this setting.
+ *
+ * Since: maemo 5.0
+ * Stability: unstable
+ */
+ g_object_class_install_property (o_class,
+ PROP_ACTION_AREA_ORIENTATION,
+ g_param_spec_enum ("action-area-orientation",
+ P_("Action Area Orientation"),
+ P_("Determines the orientation of the action area."),
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_HORIZONTAL,
+ GTK_PARAM_READWRITE));
+
/* Style properties */
#define _TREE_VIEW_EXPANDER_SIZE 12
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
#define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
+#define _TREE_VIEW_SEPARATOR_HEIGHT 2
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("expander-size",
@@ -872,6 +958,43 @@
"\1\1",
GTK_PARAM_READABLE));
+ /**
+ * GtkTreeView:separator-height:
+ *
+ * Height in pixels of a separator.
+ *
+ * Since: maemo 3.0
+ * Stability: Unstable
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("separator-height",
+ P_("Separator height"),
+ P_("Height of the separator"),
+ 0,
+ G_MAXINT,
+ _TREE_VIEW_SEPARATOR_HEIGHT,
+ GTK_PARAM_READABLE));
+
+ /**
+ * GtkTreeView:row-height:
+ *
+ * Height in pixels of a row. When set, all rows will use this height,
+ * except for row separators and row headers. A value of -1 means this
+ * value is unset. Setting this property does not imply fixed height
+ * mode will be turned on, so columns are still properly autosized.
+ *
+ * Since: maemo 5.0
+ * Stability: Unstable
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("row-height",
+ P_("Row height"),
+ P_("Height of a row"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READABLE));
+
/* Signals */
/**
* GtkTreeView::set-scroll-adjustments
@@ -1109,6 +1232,36 @@
_gtk_marshal_BOOLEAN__VOID,
G_TYPE_BOOLEAN, 0);
+ /**
+ * GtkTreeView::row-insensitive:
+ * @tree_view: the object which received the signal.
+ * @path: the path where the cursor is tried to be moved.
+ *
+ * Emitted when the user tries to move cursor to an insesitive row.
+ *
+ * Since: maemo 1.0
+ * Stability: Unstable
+ */
+ tree_view_signals[ROW_INSENSITIVE] =
+ g_signal_new ("row_insensitive",
+ G_TYPE_FROM_CLASS (o_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkTreeViewClass, row_insensitive),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TREE_PATH);
+
+ tree_view_signals[HILDON_ROW_TAPPED] =
+ g_signal_new ("hildon_row_tapped",
+ G_TYPE_FROM_CLASS (o_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL, NULL,
+ _gtk_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TREE_PATH);
+
/* Key bindings */
gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
GTK_MOVEMENT_DISPLAY_LINES, -1);
@@ -1333,9 +1486,7 @@
gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
- tree_view->priv->flags = GTK_TREE_VIEW_SHOW_EXPANDERS
- | GTK_TREE_VIEW_DRAW_KEYFOCUS
- | GTK_TREE_VIEW_HEADERS_VISIBLE;
+ tree_view->priv->flags = GTK_TREE_VIEW_DRAW_KEYFOCUS;
/* We need some padding */
tree_view->priv->dy = 0;
@@ -1368,9 +1519,27 @@
tree_view->priv->hover_selection = FALSE;
tree_view->priv->hover_expand = FALSE;
- tree_view->priv->level_indentation = 0;
+ tree_view->priv->level_indentation = 10;
+
+ tree_view->priv->queued_select_row = NULL;
+ tree_view->priv->queued_expand_row = NULL;
+ tree_view->priv->queued_activate_row = NULL;
+ tree_view->priv->queued_tapped_row = NULL;
+
+ tree_view->priv->highlighted_node = NULL;
+ tree_view->priv->highlighted_tree = NULL;
+
+ tree_view->priv->queued_ctrl_pressed = FALSE;
+ tree_view->priv->queued_shift_pressed = FALSE;
+
+ tree_view->priv->hildon_ui_mode = HILDON_UI_MODE_NORMAL;
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "hildon-mode", &tree_view->priv->hildon_mode,
+ NULL);
- tree_view->priv->rubber_banding_enable = FALSE;
+ tree_view->priv->level_indentation = 10;
+
+ tree_view->priv->rubber_banding_enable = TRUE;
tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
tree_view->priv->tree_lines_enabled = FALSE;
@@ -1384,9 +1553,13 @@
tree_view->priv->event_last_x = -10000;
tree_view->priv->event_last_y = -10000;
-}
-
+ tree_view->priv->rows_offset = 0;
+ tree_view->priv->action_area_visible = FALSE;
+ tree_view->priv->action_area_orientation = GTK_ORIENTATION_HORIZONTAL;
+ tree_view->priv->action_area_event_box = NULL;
+ tree_view->priv->action_area_box = NULL;
+}
/* GObject Methods
*/
@@ -1460,6 +1633,15 @@
case PROP_TOOLTIP_COLUMN:
gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
break;
+ case PROP_HILDON_UI_MODE:
+ hildon_tree_view_set_hildon_ui_mode (tree_view, g_value_get_enum (value));
+ break;
+ case PROP_ACTION_AREA_VISIBLE:
+ hildon_tree_view_set_action_area_visible (tree_view, g_value_get_boolean (value));
+ break;
+ case PROP_ACTION_AREA_ORIENTATION:
+ hildon_tree_view_set_action_area_orientation (tree_view, g_value_get_enum (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1535,6 +1717,15 @@
case PROP_TOOLTIP_COLUMN:
g_value_set_int (value, tree_view->priv->tooltip_column);
break;
+ case PROP_HILDON_UI_MODE:
+ g_value_set_enum (value, tree_view->priv->hildon_ui_mode);
+ break;
+ case PROP_ACTION_AREA_VISIBLE:
+ g_value_set_boolean (value, tree_view->priv->action_area_visible);
+ break;
+ case PROP_ACTION_AREA_ORIENTATION:
+ g_value_set_enum (value, tree_view->priv->action_area_orientation);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1595,6 +1786,8 @@
tree_view->priv->prelight_node = NULL;
tree_view->priv->expanded_collapsed_node = NULL;
tree_view->priv->expanded_collapsed_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+ tree_view->priv->highlighted_tree = NULL;
}
static void
@@ -1650,6 +1843,30 @@
tree_view->priv->top_row = NULL;
}
+ if (tree_view->priv->queued_select_row != NULL)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_select_row);
+ tree_view->priv->queued_select_row = NULL;
+ }
+
+ if (tree_view->priv->queued_expand_row != NULL)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row);
+ tree_view->priv->queued_expand_row = NULL;
+ }
+
+ if (tree_view->priv->queued_activate_row != NULL)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_activate_row);
+ tree_view->priv->queued_activate_row = NULL;
+ }
+
+ if (tree_view->priv->queued_tapped_row != NULL)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row = NULL;
+ }
+
if (tree_view->priv->column_drop_func_data &&
tree_view->priv->column_drop_func_data_destroy)
{
@@ -1701,6 +1918,24 @@
tree_view->priv->row_separator_data = NULL;
}
+ if (tree_view->priv->row_header_destroy && tree_view->priv->row_header_data)
+ {
+ (* tree_view->priv->row_header_destroy) (tree_view->priv->row_header_data);
+ tree_view->priv->row_header_data = NULL;
+ }
+
+ if (tree_view->priv->row_header_layout)
+ {
+ g_object_unref (tree_view->priv->row_header_layout);
+ tree_view->priv->row_header_layout = NULL;
+ }
+
+ if (tree_view->priv->tickmark_icon)
+ {
+ g_object_unref (tree_view->priv->tickmark_icon);
+ tree_view->priv->tickmark_icon = NULL;
+ }
+
gtk_tree_view_set_model (tree_view, NULL);
if (tree_view->priv->hadjustment)
@@ -2036,7 +2271,7 @@
if (tree_view->priv->tree == NULL)
tree_view->priv->height = 0;
else
- tree_view->priv->height = tree_view->priv->tree->root->offset;
+ tree_view->priv->height = tree_view->priv->tree->root->offset + tree_view->priv->rows_offset;
}
static void
@@ -2228,6 +2463,13 @@
number_of_expand_columns++;
}
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ {
+ full_requested_width += HILDON_TICK_MARK_SIZE;
+ }
+
/* Only update the expand value if the width of the widget has changed,
* or the number of expand columns has changed, or if there are no expand
* columns, or if we didn't have an size-allocation yet after the
@@ -2381,6 +2623,17 @@
allocation.y = child->y;
allocation.width = child->width;
allocation.height = child->height;
+
+ if (tree_view->priv->rows_offset != 0
+ && tree_view->priv->action_area_event_box == child->widget)
+ {
+ /* Set the child's location to be the area above the first row */
+ allocation.x = 0;
+ allocation.y = -tree_view->priv->dy;
+ allocation.width = MAX (widget->allocation.width, tree_view->priv->width);
+ allocation.height = tree_view->priv->rows_offset;
+ }
+
gtk_widget_size_allocate (child->widget, &allocation);
}
@@ -2521,25 +2774,41 @@
static inline gboolean
row_is_separator (GtkTreeView *tree_view,
GtkTreeIter *iter,
+ gboolean *is_header,
GtkTreePath *path)
{
gboolean is_separator = FALSE;
+ GtkTreeIter tmpiter;
- if (tree_view->priv->row_separator_func)
+ if (tree_view->priv->row_separator_func
+ || tree_view->priv->row_header_func)
{
- GtkTreeIter tmpiter;
-
if (iter)
- tmpiter = *iter;
+ tmpiter = *iter;
else
- {
- if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
- return FALSE;
- }
+ gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
+ }
- is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
- &tmpiter,
- tree_view->priv->row_separator_data);
+ if (tree_view->priv->row_separator_func)
+ {
+ is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model,
+ &tmpiter,
+ tree_view->priv->row_separator_data);
+ }
+
+ if (tree_view->priv->row_header_func)
+ {
+ gboolean tmp;
+
+ tmp = (* tree_view->priv->row_header_func) (tree_view->priv->model,
+ &tmpiter,
+ NULL,
+ tree_view->priv->row_header_data);
+
+ is_separator |= tmp;
+
+ if (is_header)
+ *is_header = tmp;
}
return is_separator;
@@ -2589,6 +2858,7 @@
gboolean row_double_click = FALSE;
gboolean rtl;
gboolean node_selected;
+ gboolean node_is_selectable;
/* Empty tree? */
if (tree_view->priv->tree == NULL)
@@ -2633,7 +2903,7 @@
/* Get the path and the node */
path = _gtk_tree_view_find_path (tree_view, tree, node);
- path_is_selectable = !row_is_separator (tree_view, NULL, path);
+ path_is_selectable = !row_is_separator (tree_view, NULL, NULL, path);
if (!path_is_selectable)
{
@@ -2689,6 +2959,17 @@
break;
}
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE
+ && (gint)event->x < background_area.x + HILDON_TICK_MARK_SIZE)
+ {
+ GList *list;
+
+ list = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
+ column = list->data;
+ }
+
if (column == NULL)
{
gtk_tree_path_free (path);
@@ -2765,6 +3046,39 @@
gtk_tree_path_free (anchor);
}
+ node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
+ node_is_selectable =
+ _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+ node, path);
+
+ /* Save press to possibly begin a drag
+ */
+ if (!column_handled_click &&
+ !tree_view->priv->in_grab &&
+ tree_view->priv->pressed_button < 0)
+ {
+ tree_view->priv->pressed_button = event->button;
+ tree_view->priv->press_start_x = event->x;
+ tree_view->priv->press_start_y = event->y;
+
+ if (tree_view->priv->hildon_mode == HILDON_DIABLO
+ && tree_view->priv->rubber_banding_enable
+ && node_is_selectable
+ && !node_selected
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ {
+ tree_view->priv->press_start_y += tree_view->priv->dy;
+ tree_view->priv->rubber_band_x = event->x;
+ tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
+ tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
+
+ if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ tree_view->priv->rubber_band_modify = TRUE;
+ if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+ tree_view->priv->rubber_band_extend = TRUE;
+ }
+ }
+
/* select */
node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
pre_val = tree_view->priv->vadjustment->value;
@@ -2782,7 +3096,106 @@
if (focus_cell)
gtk_tree_view_column_focus_cell (column, focus_cell);
- if (event->state & GTK_MODIFY_SELECTION_MOD_MASK)
+ /* The most reliable way is to use another row reference,
+ * instead of trying to get it done with the intricate
+ * logic below.
+ */
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row =
+ gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ {
+ /* This row should be activated on button-release */
+ gtk_tree_row_reference_free (tree_view->priv->queued_activate_row);
+ tree_view->priv->queued_activate_row = gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ /* Mark the node as selected to create a highlight effect */
+ tree_view->priv->highlighted_tree = tree;
+ tree_view->priv->highlighted_node = node;
+ gtk_tree_view_queue_draw_path (tree_view, path, NULL);
+ }
+ else if (tree_view->priv->hildon_mode == HILDON_DIABLO
+ && node_selected
+ && !column_handled_click
+ && gtk_tree_row_reference_valid (tree_view->priv->cursor))
+ {
+ GtkTreePath *cursor_path;
+
+ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+ if (!gtk_tree_path_compare (cursor_path, path))
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_activate_row);
+ tree_view->priv->queued_activate_row = gtk_tree_row_reference_new (tree_view->priv->model, path);
+ }
+
+ gtk_tree_path_free (cursor_path);
+ }
+
+ if (node_is_selectable
+ && tree_view->priv->hildon_mode == HILDON_DIABLO
+ && !column_handled_click
+ && !tree_view->priv->queued_activate_row
+ && tree_view->priv->rubber_band_status == RUBBER_BAND_OFF
+ && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
+ {
+ GtkTreePath *old_cursor_path = NULL;
+
+ /* We do not know at this stage if a user is going to do
+ * a DnD or tap and hold operation, so avoid clearing
+ * the current selection.
+ */
+ if (tree_view->priv->queued_select_row)
+ gtk_tree_row_reference_free (tree_view->priv->queued_select_row);
+ tree_view->priv->queued_select_row = NULL;
+
+ /* Do move the focus */
+ if (tree_view->priv->cursor)
+ {
+ old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+ gtk_tree_row_reference_free (tree_view->priv->cursor);
+ }
+
+ tree_view->priv->cursor = gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ if (old_cursor_path)
+ {
+ gtk_tree_view_queue_draw_path (tree_view,
+ old_cursor_path, NULL);
+ gtk_tree_path_free (old_cursor_path);
+ }
+
+ tree_view->priv->queued_ctrl_pressed = tree_view->priv->modify_selection_pressed;
+ tree_view->priv->queued_shift_pressed = tree_view->priv->extend_selection_pressed;
+ tree_view->priv->queued_select_row =
+ gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ gtk_tree_view_queue_draw_path (tree_view, path, NULL);
+ }
+ else if (node_is_selectable
+ && tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && !column_handled_click
+ && !tree_view->priv->queued_activate_row)
+ {
+ /* In new-style we do not want to set cursor,
+ * instead we highlight the node.
+ */
+ if (tree_view->priv->queued_select_row)
+ gtk_tree_row_reference_free (tree_view->priv->queued_select_row);
+ tree_view->priv->queued_select_row = NULL;
+
+ tree_view->priv->highlighted_node = node;
+ tree_view->priv->highlighted_tree = tree;
+
+ tree_view->priv->queued_select_row =
+ gtk_tree_row_reference_new (tree_view->priv->model, path);
+
+ gtk_tree_view_queue_draw_path (tree_view, path, NULL);
+ }
+ /* Else, set the cursor as usual */
+ else if (event->state & GTK_MODIFY_SELECTION_MOD_MASK)
{
gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
gtk_tree_view_real_toggle_cursor_row (tree_view);
@@ -2794,7 +3207,10 @@
}
else
{
- gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+ if (tree_view->priv->queued_activate_row)
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ else
+ gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
}
tree_view->priv->modify_selection_pressed = FALSE;
@@ -2811,74 +3227,24 @@
cell_area.y += dval;
background_area.y += dval;
- /* Save press to possibly begin a drag
- */
- if (!column_handled_click &&
- !tree_view->priv->in_grab &&
- tree_view->priv->pressed_button < 0)
- {
- tree_view->priv->pressed_button = event->button;
- tree_view->priv->press_start_x = event->x;
- tree_view->priv->press_start_y = event->y;
-
- if (tree_view->priv->rubber_banding_enable
- && !node_selected
- && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ if (event->button == 1)
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
{
- tree_view->priv->press_start_y += tree_view->priv->dy;
- tree_view->priv->rubber_band_x = event->x;
- tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
- tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
-
- if ((event->state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
- tree_view->priv->rubber_band_modify = TRUE;
- if ((event->state & GTK_EXTEND_SELECTION_MOD_MASK) == GTK_EXTEND_SELECTION_MOD_MASK)
- tree_view->priv->rubber_band_extend = TRUE;
+ /* The behavior is as follows:
+ * - For a tap on a collapsed node: always expand (and the
+ * cursor moves to it.
+ * - For a tap on an expxanded node: collapse if and only
+ * if the node is currently the cursor node.
+ */
+ if (!node->children
+ || (node_selected && node->children))
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row);
+ tree_view->priv->queued_expand_row =
+ gtk_tree_row_reference_new (tree_view->priv->model, path);
+ }
}
- }
-
- /* Test if a double click happened on the same row. */
- if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
- {
- int double_click_time, double_click_distance;
-
- g_object_get (gtk_settings_get_default (),
- "gtk-double-click-time", &double_click_time,
- "gtk-double-click-distance", &double_click_distance,
- NULL);
-
- /* Same conditions as _gdk_event_button_generate */
- if (tree_view->priv->last_button_x != -1 &&
- (event->time < tree_view->priv->last_button_time + double_click_time) &&
- (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
- (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
- {
- /* We do no longer compare paths of this row and the
- * row clicked previously. We use the double click
- * distance to decide whether this is a valid click,
- * allowing the mouse to slightly move over another row.
- */
- row_double_click = TRUE;
-
- tree_view->priv->last_button_time = 0;
- tree_view->priv->last_button_x = -1;
- tree_view->priv->last_button_y = -1;
- }
- else
- {
- tree_view->priv->last_button_time = event->time;
- tree_view->priv->last_button_x = event->x;
- tree_view->priv->last_button_y = event->y;
- }
- }
-
- if (row_double_click)
- {
- gtk_grab_remove (widget);
- gtk_tree_view_row_activated (tree_view, path, column);
-
- if (tree_view->priv->pressed_button == event->button)
- tree_view->priv->pressed_button = -1;
}
gtk_tree_path_free (path);
@@ -3039,6 +3405,9 @@
GdkEventButton *event)
{
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ gint new_y;
+ GtkRBTree *tree;
+ GtkRBNode *node;
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
return gtk_tree_view_button_release_drag_column (widget, event);
@@ -3052,6 +3421,171 @@
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
return gtk_tree_view_button_release_column_resize (widget, event);
+ if (tree_view->priv->tree)
+ {
+ /* Get the node where the mouse was released */
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->y);
+ if (new_y < 0)
+ new_y = 0;
+ _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+ }
+ else
+ {
+ /* We just set tree and node to NULL otherwise. We still want
+ * to run through below's logic to free row references where needed.
+ */
+ tree = NULL;
+ node = NULL;
+ }
+
+ if (gtk_tree_row_reference_valid (tree_view->priv->queued_select_row))
+ {
+ GtkTreePath *path;
+ GtkRBTree *select_tree;
+ GtkRBNode *select_node;
+
+ path = gtk_tree_row_reference_get_path (tree_view->priv->queued_select_row);
+ _gtk_tree_view_find_node (tree_view, path,
+ &select_tree, &select_node);
+
+ if (tree == select_tree && node == select_node)
+ {
+ if (tree_view->priv->queued_ctrl_pressed)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ gtk_tree_view_real_toggle_cursor_row (tree_view);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ }
+ else if (tree_view->priv->queued_shift_pressed)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ }
+ else
+ gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+ }
+
+ free_queued_select_row (tree_view);
+ gtk_tree_path_free (path);
+ tree_view->priv->queued_ctrl_pressed = FALSE;
+ tree_view->priv->queued_shift_pressed = FALSE;
+ }
+
+ if (gtk_tree_row_reference_valid (tree_view->priv->queued_activate_row))
+ {
+ GtkTreePath *path;
+ GtkRBTree *activate_tree;
+ GtkRBNode *activate_node;
+
+ path = gtk_tree_row_reference_get_path (tree_view->priv->queued_activate_row);
+
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ {
+ if (tree_view->priv->highlighted_node)
+ {
+ _gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->highlighted_tree,
+ tree_view->priv->highlighted_node,
+ NULL);
+
+ tree_view->priv->highlighted_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+ }
+ }
+
+ _gtk_tree_view_find_node (tree_view, path,
+ &activate_tree, &activate_node);
+
+ /* Only emit activated if the mouse was released from the
+ * same row where the mouse was pressed.
+ */
+ if (tree == activate_tree && node == activate_node)
+ {
+ gtk_tree_view_row_activated (tree_view, path,
+ tree_view->priv->focus_column);
+ }
+
+ gtk_tree_path_free (path);
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_activate_row);
+ tree_view->priv->queued_activate_row = NULL;
+ }
+
+ if (gtk_tree_row_reference_valid (tree_view->priv->queued_expand_row))
+ {
+ GtkTreePath *path;
+ GtkRBTree *expand_tree;
+ GtkRBNode *expand_node = NULL;
+
+ path = gtk_tree_row_reference_get_path (tree_view->priv->queued_expand_row);
+
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE)
+ {
+ /* We should not take the cursor into accont. We do check
+ * with the node where the mouse was released.
+ */
+ _gtk_tree_view_find_node (tree_view, path,
+ &expand_tree, &expand_node);
+
+ if (tree != expand_tree || node != expand_node)
+ expand_node = NULL;
+ }
+ else
+ {
+ GtkTreePath *cursor_path;
+
+ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
+ if (!gtk_tree_path_compare (cursor_path, path))
+ _gtk_tree_view_find_node (tree_view, path,
+ &expand_tree, &expand_node);
+
+ gtk_tree_path_free (cursor_path);
+ }
+
+ if (expand_node)
+ {
+ if (!expand_node->children)
+ gtk_tree_view_real_expand_row (tree_view, path,
+ expand_tree, expand_node,
+ FALSE, TRUE);
+ else
+ gtk_tree_view_real_collapse_row (tree_view, path,
+ expand_tree, expand_node, TRUE);
+ }
+
+ gtk_tree_path_free (path);
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row);
+ tree_view->priv->queued_expand_row = NULL;
+ }
+
+ /* The hildon-row-tapped signal is executed as the last, so that
+ * any action (selection change, activation, expansion/collapse)
+ * has already been processed.
+ */
+ if (gtk_tree_row_reference_valid (tree_view->priv->queued_tapped_row))
+ {
+ GtkTreePath *path;
+ GtkRBTree *tapped_tree;
+ GtkRBNode *tapped_node;
+
+ path = gtk_tree_row_reference_get_path (tree_view->priv->queued_tapped_row);
+ _gtk_tree_view_find_node (tree_view, path,
+ &tapped_tree, &tapped_node);
+
+ if (tree == tapped_tree && node == tapped_node)
+ g_signal_emit (tree_view, tree_view_signals[HILDON_ROW_TAPPED],
+ 0, path);
+
+ gtk_tree_path_free (path);
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row = NULL;
+ }
+
if (tree_view->priv->button_pressed_node == NULL)
return FALSE;
@@ -3331,6 +3865,22 @@
}
static void
+ensure_unhighlighted (GtkTreeView *tree_view)
+{
+ /* Unconditionally unhighlight */
+ if (tree_view->priv->highlighted_node)
+ {
+ _gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->highlighted_tree,
+ tree_view->priv->highlighted_node,
+ NULL);
+
+ tree_view->priv->highlighted_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+ }
+}
+
+static void
update_prelight (GtkTreeView *tree_view,
gint x,
gint y)
@@ -3780,13 +4330,6 @@
gtk_tree_path_free (tmp_path);
- /* ... and the cursor to the end path */
- tmp_path = _gtk_tree_view_find_path (tree_view,
- tree_view->priv->rubber_band_end_tree,
- tree_view->priv->rubber_band_end_node);
- gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
- gtk_tree_path_free (tmp_path);
-
_gtk_tree_selection_emit_changed (tree_view->priv->selection);
}
@@ -3868,6 +4411,8 @@
GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
}
+ add_scroll_timeout (tree_view);
+
_gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
node_not_selectable:
@@ -3903,6 +4448,7 @@
{
GtkRBTree *start_tree, *end_tree;
GtkRBNode *start_node, *end_node;
+ GtkTreePath *path;
_gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
_gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
@@ -4001,6 +4547,17 @@
tree_view->priv->rubber_band_end_tree = end_tree;
tree_view->priv->rubber_band_end_node = end_node;
+
+ /* In maemo the cursor needs to follow the stylus */
+ if (gtk_tree_view_get_path_at_pos (tree_view,
+ tree_view->priv->rubber_band_x,
+ RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, tree_view->priv->rubber_band_y),
+ &path,
+ NULL, NULL, NULL))
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
+ gtk_tree_path_free (path);
+ }
}
static void
@@ -4009,8 +4566,6 @@
gint x, y;
GdkRectangle old_area;
GdkRectangle new_area;
- GdkRectangle common;
- GdkRegion *invalid_region;
old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
@@ -4027,30 +4582,6 @@
new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
- invalid_region = gdk_region_rectangle (&old_area);
- gdk_region_union_with_rect (invalid_region, &new_area);
-
- gdk_rectangle_intersect (&old_area, &new_area, &common);
- if (common.width > 2 && common.height > 2)
- {
- GdkRegion *common_region;
-
- /* make sure the border is invalidated */
- common.x += 1;
- common.y += 1;
- common.width -= 2;
- common.height -= 2;
-
- common_region = gdk_region_rectangle (&common);
-
- gdk_region_subtract (invalid_region, common_region);
- gdk_region_destroy (common_region);
- }
-
- gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
-
- gdk_region_destroy (invalid_region);
-
tree_view->priv->rubber_band_x = x;
tree_view->priv->rubber_band_y = y;
@@ -4115,6 +4646,20 @@
if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
{
+ if (tree_view->priv->hildon_mode == HILDON_DIABLO
+ && gtk_tree_row_reference_valid (tree_view->priv->queued_select_row))
+ {
+ GtkTreePath *path;
+
+ /* We now know we won't rubber band -- select the row */
+ path = gtk_tree_row_reference_get_path (tree_view->priv->queued_select_row);
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
+
+ gtk_tree_path_free (path);
+ }
+
+ free_queued_actions (tree_view);
+
gtk_grab_add (GTK_WIDGET (tree_view));
gtk_tree_view_update_rubber_band (tree_view);
@@ -4127,8 +4672,27 @@
add_scroll_timeout (tree_view);
}
+ /* If the drag-threshold has been passed, the row should
+ * not be activated or selected and the highlight removed.
+ */
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && gtk_drag_check_threshold (widget,
+ tree_view->priv->press_start_x,
+ tree_view->priv->press_start_y,
+ event->x, event->y))
+ {
+ if (tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ free_queued_activate_row (tree_view);
+ else if (tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
+ free_queued_select_row (tree_view);
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row = NULL;
+ }
+
/* only check for an initiated drag when a button is pressed */
if (tree_view->priv->pressed_button >= 0
+ && tree_view->priv->hildon_mode == HILDON_DIABLO
&& !tree_view->priv->rubber_band_status)
gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
@@ -4310,6 +4874,46 @@
}
}
+static void
+gtk_tree_view_draw_row_header (GtkTreeView *tree_view,
+ GtkTreeIter *iter,
+ GdkEventExpose *event,
+ GdkRectangle *cell_area)
+{
+ gchar *label = NULL;
+ int width, height;
+ gboolean is_header;
+ GtkWidget *widget = GTK_WIDGET (tree_view);
+
+ g_return_if_fail (tree_view->priv->row_header_func != NULL);
+
+ is_header = (* tree_view->priv->row_header_func) (tree_view->priv->model,
+ iter,
+ &label,
+ tree_view->priv->row_header_data);
+
+ g_return_if_fail (is_header == TRUE);
+ g_return_if_fail (tree_view->priv->row_header_layout != NULL);
+
+ pango_layout_set_text (tree_view->priv->row_header_layout,
+ label, strlen (label));
+ pango_layout_get_pixel_size (tree_view->priv->row_header_layout,
+ &width, &height);
+
+ gtk_paint_layout (widget->style,
+ event->window,
+ widget->state,
+ TRUE,
+ &event->area,
+ widget,
+ "treeview-group-header",
+ cell_area->x + (cell_area->width - width) / 2,
+ cell_area->y + cell_area->height - height,
+ tree_view->priv->row_header_layout);
+
+ g_free (label);
+}
+
/* Warning: Very scary function.
* Modify at your own risk
*
@@ -4356,6 +4960,8 @@
gboolean got_pointer = FALSE;
gboolean row_ending_details;
gboolean draw_vgrid_lines, draw_hgrid_lines;
+ gint expose_start;
+ gboolean render_checkboxes = FALSE;
rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
@@ -4379,11 +4985,27 @@
validate_visible_area (tree_view);
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
+ if (G_UNLIKELY (tree_view->priv->rows_offset != 0)
+ && tree_view->priv->dy <= tree_view->priv->rows_offset
+ && event->area.y <= tree_view->priv->rows_offset - tree_view->priv->dy)
+ {
+ /* As long as a part of the button window is visible ... */
+ expose_start = tree_view->priv->rows_offset - tree_view->priv->dy;
+ y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
+ tree_view->priv->rows_offset,
+ &tree, &node);
+ }
+ else
+ {
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
+
+ if (new_y < 0)
+ new_y = 0;
+
+ expose_start = event->area.y;
+ y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+ }
- if (new_y < 0)
- new_y = 0;
- y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
@@ -4395,7 +5017,7 @@
GTK_SHADOW_NONE,
&event->area,
widget,
- "cell_even",
+ "cell_blank",
0, tree_view->priv->height,
bin_window_width,
bin_window_height - tree_view->priv->height);
@@ -4449,6 +5071,13 @@
n_visible_columns ++;
}
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ {
+ render_checkboxes = TRUE;
+ }
+
/* Find the last column */
for (last_column = g_list_last (tree_view->priv->columns);
last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
@@ -4472,8 +5101,9 @@
gboolean is_separator = FALSE;
gboolean is_first = FALSE;
gboolean is_last = FALSE;
+ gboolean is_header = FALSE;
- is_separator = row_is_separator (tree_view, &iter, NULL);
+ is_separator = row_is_separator (tree_view, &iter, &is_header, NULL);
max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
@@ -4481,7 +5111,7 @@
highlight_x = 0; /* should match x coord of first cell */
expander_cell_width = 0;
- background_area.y = y_offset + event->area.y;
+ background_area.y = y_offset + expose_start;
background_area.height = max_height;
flags = 0;
@@ -4489,7 +5119,8 @@
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
flags |= GTK_CELL_RENDERER_PRELIT;
- if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED)
+ || node == tree_view->priv->highlighted_node)
flags |= GTK_CELL_RENDERER_SELECTED;
parity = _gtk_rbtree_node_find_parity (tree, node);
@@ -4503,12 +5134,13 @@
list = (rtl ? list->prev : list->next))
{
GtkTreeViewColumn *column = list->data;
- gtk_tree_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter,
- GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
- node->children?TRUE:FALSE);
- }
+ gtk_tree_view_column_cell_set_cell_data_with_hint (column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
+ node->children?TRUE:FALSE,
+ GTK_TREE_CELL_DATA_HINT_KEY_FOCUS);
+ }
has_special_cell = gtk_tree_view_has_special_cell (tree_view);
@@ -4543,7 +5175,11 @@
background_area.x = cell_offset;
background_area.width = column->width;
- cell_area = background_area;
+ /* Nasty hack to get background handling for free */
+ if (render_checkboxes && column == last_column->data)
+ background_area.width += HILDON_TICK_MARK_SIZE;
+
+ cell_area = background_area;
cell_area.y += vertical_separator / 2;
cell_area.x += horizontal_separator / 2;
cell_area.height -= vertical_separator;
@@ -4682,6 +5318,93 @@
background_area.height);
}
+ /* Nasty hack to get background handling for free */
+ if (render_checkboxes && column == last_column->data)
+ {
+ background_area.width -= HILDON_TICK_MARK_SIZE;
+ cell_area.width -= HILDON_TICK_MARK_SIZE;
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ gdk_draw_pixbuf (event->window,
+ NULL,
+ tree_view->priv->tickmark_icon,
+ 0, 0,
+ background_area.x + background_area.width,
+ background_area.y + (background_area.height - HILDON_TICK_MARK_SIZE) / 2,
+ HILDON_TICK_MARK_SIZE,
+ HILDON_TICK_MARK_SIZE,
+ GDK_RGB_DITHER_MAX,
+ 0, 0);
+ }
+
+ if (node == drag_highlight)
+ {
+ /* Draw indicator for the drop
+ */
+ gint highlight_y = -1;
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+ gint width;
+
+ switch (tree_view->priv->drag_dest_pos)
+ {
+ case GTK_TREE_VIEW_DROP_BEFORE:
+ highlight_y = background_area.y - 1;
+ if (highlight_y < 0)
+ highlight_y = 0;
+ break;
+
+ case GTK_TREE_VIEW_DROP_AFTER:
+ highlight_y = background_area.y + background_area.height - 1;
+ break;
+
+ case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
+ case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
+ _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
+
+ if (tree == NULL)
+ break;
+ gdk_drawable_get_size (tree_view->priv->bin_window,
+ &width, NULL);
+
+ if (row_ending_details)
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ gtk_widget_get_state (widget),
+ &event->area,
+ widget,
+ (is_first
+ ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
+ : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
+ 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+ - focus_line_width / 2,
+ width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+ - focus_line_width + 1);
+ else
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ gtk_widget_get_state (widget),
+ &event->area,
+ widget,
+ "treeview-drop-indicator",
+ 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+ - focus_line_width / 2,
+ width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+ - focus_line_width + 1);
+ break;
+ }
+
+ if (highlight_y >= 0)
+ {
+ gdk_draw_line (event->window,
+ widget->style->fg_gc[gtk_widget_get_state (widget)],
+ rtl ? highlight_x + expander_cell_width : highlight_x,
+ highlight_y,
+ rtl ? 0 : bin_window_width,
+ highlight_y);
+ }
+ }
+
if (gtk_tree_view_is_expander_column (tree_view, column))
{
if (!rtl)
@@ -4702,7 +5425,14 @@
highlight_x = cell_area.x;
expander_cell_width = cell_area.width;
- if (is_separator)
+ if (is_header)
+ {
+ gtk_tree_view_draw_row_header (tree_view,
+ &iter,
+ event,
+ &cell_area);
+ }
+ else if (is_separator)
gtk_paint_hline (widget->style,
event->window,
state,
@@ -4737,7 +5467,14 @@
}
else
{
- if (is_separator)
+ if (is_header)
+ {
+ gtk_tree_view_draw_row_header (tree_view,
+ &iter,
+ event,
+ &cell_area);
+ }
+ else if (is_separator)
gtk_paint_hline (widget->style,
event->window,
state,
@@ -4862,73 +5599,6 @@
cell_offset += column->width;
}
- if (node == drag_highlight)
- {
- /* Draw indicator for the drop
- */
- gint highlight_y = -1;
- GtkRBTree *tree = NULL;
- GtkRBNode *node = NULL;
- gint width;
-
- switch (tree_view->priv->drag_dest_pos)
- {
- case GTK_TREE_VIEW_DROP_BEFORE:
- highlight_y = background_area.y - 1;
- if (highlight_y < 0)
- highlight_y = 0;
- break;
-
- case GTK_TREE_VIEW_DROP_AFTER:
- highlight_y = background_area.y + background_area.height - 1;
- break;
-
- case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
- case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
- _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
-
- if (tree == NULL)
- break;
- width = gdk_window_get_width (tree_view->priv->bin_window);
-
- if (row_ending_details)
- gtk_paint_focus (widget->style,
- tree_view->priv->bin_window,
- gtk_widget_get_state (widget),
- &event->area,
- widget,
- (is_first
- ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
- : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
- 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
- - focus_line_width / 2,
- width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
- - focus_line_width + 1);
- else
- gtk_paint_focus (widget->style,
- tree_view->priv->bin_window,
- gtk_widget_get_state (widget),
- &event->area,
- widget,
- "treeview-drop-indicator",
- 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
- - focus_line_width / 2,
- width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
- - focus_line_width + 1);
- break;
- }
-
- if (highlight_y >= 0)
- {
- gtk_tree_view_draw_line (tree_view, event->window,
- GTK_TREE_VIEW_FOREGROUND_LINE,
- rtl ? highlight_x + expander_cell_width : highlight_x,
- highlight_y,
- rtl ? 0 : bin_window_width,
- highlight_y);
- }
- }
-
/* draw the big row-spanning focus rectangle, if needed */
if (!has_special_cell && node == cursor &&
GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
@@ -5042,21 +5712,6 @@
done:
gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
- if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
- {
- GdkRectangle *rectangles;
- gint n_rectangles;
-
- gdk_region_get_rectangles (event->region,
- &rectangles,
- &n_rectangles);
-
- while (n_rectangles--)
- gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
-
- g_free (rectangles);
- }
-
if (cursor_path)
gtk_tree_path_free (cursor_path);
@@ -5504,6 +6159,15 @@
* the typeahead find capabilities. */
if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
&& tree_view->priv->enable_search
+ /* These are usually handled via keybindings, but these do not
+ * function in Fremantle mode. Therefore we need to explicitly
+ * check for these there.
+ */
+ && event->keyval != GDK_ISO_Enter
+ && event->keyval != GDK_KP_Enter
+ && event->keyval != GDK_Return
+ && event->keyval != GDK_space
+ && event->keyval != GDK_KP_Space
&& !tree_view->priv->search_custom_entry_set)
{
GdkEvent *new_event;
@@ -5730,13 +6394,15 @@
gint grid_line_width;
gboolean wide_separators;
gint separator_height;
+ gint row_height;
+ gboolean is_header = FALSE;
/* double check the row needs validating */
if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
return FALSE;
- is_separator = row_is_separator (tree_view, iter, NULL);
+ is_separator = row_is_separator (tree_view, iter, &is_header, NULL);
gtk_widget_style_get (GTK_WIDGET (tree_view),
"focus-padding", &focus_pad,
@@ -5746,6 +6412,7 @@
"grid-line-width", &grid_line_width,
"wide-separators", &wide_separators,
"separator-height", &separator_height,
+ "row-height", &row_height,
NULL);
draw_vgrid_lines =
@@ -5793,10 +6460,12 @@
}
else
{
- if (wide_separators)
- height = separator_height + 2 * focus_pad;
- else
- height = 2 + 2 * focus_pad;
+ if (is_header)
+ {
+ height = HILDON_ROW_HEADER_HEIGHT;
+ }
+ else
+ height = separator_height + 2 * focus_pad;
}
if (gtk_tree_view_is_expander_column (tree_view, column))
@@ -5817,6 +6486,14 @@
tmp_width += grid_line_width;
}
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ {
+ tmp_width += HILDON_TICK_MARK_SIZE;
+ height = MAX (height, HILDON_TICK_MARK_SIZE);
+ }
+
if (tmp_width > column->requested_width)
{
retval = TRUE;
@@ -5827,6 +6504,9 @@
if (draw_hgrid_lines)
height += grid_line_width;
+ if (row_height != -1 && !is_separator && !is_header)
+ height = row_height;
+
if (height != GTK_RBNODE_GET_HEIGHT (node))
{
retval = TRUE;
@@ -6180,33 +6860,166 @@
{
GtkRequisition requisition;
- /* We temporarily guess a size, under the assumption that it will be the
- * same when we get our next size_allocate. If we don't do this, we'll be
- * in an inconsistent state if we call top_row_to_dy. */
+ /* We temporarily guess a size, under the assumption that it will be the
+ * same when we get our next size_allocate. If we don't do this, we'll be
+ * in an inconsistent state if we call top_row_to_dy. */
+
+ gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
+ tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
+ tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
+ gtk_adjustment_changed (tree_view->priv->hadjustment);
+ gtk_adjustment_changed (tree_view->priv->vadjustment);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
+
+ if (tree_view->priv->scroll_to_path)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
+ tree_view->priv->scroll_to_path = NULL;
+ }
+
+ if (above_path)
+ gtk_tree_path_free (above_path);
+
+ if (tree_view->priv->scroll_to_column)
+ {
+ tree_view->priv->scroll_to_column = NULL;
+ }
+ if (need_redraw)
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/* You can pass in focus_pad, separator_height to save
+ * calls to gtk_widget_style_get() (especially for
+ * gtk_tree_view_nodes_set_fixed_height).
+ */
+static inline int
+determine_row_height (GtkTreeView *tree_view,
+ GtkTreeIter *iter,
+ int focus_pad,
+ int separator_height)
+{
+ int height;
+ gboolean is_separator, is_header = FALSE;
+
+ /* Determine the correct height for this node. This is
+ * analogous to what is found in validate_row().
+ */
+ is_separator = row_is_separator (tree_view, iter, &is_header, NULL);
+
+ if (!is_separator)
+ height = tree_view->priv->fixed_height;
+ else if (is_header)
+ height = HILDON_ROW_HEADER_HEIGHT;
+ else
+ {
+ if (focus_pad == -1 || separator_height == -1)
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "focus-padding", &focus_pad,
+ "separator-height", &separator_height,
+ NULL);
+
+ height = separator_height + 2 * focus_pad;
+ }
+
+ return height;
+}
+
+/* This function is basically an extended and non-recursive version of
+ * _gtk_rbtree_set_fixed_height() which also keeps track of the current
+ * iter. We can then pass this iter in to the row separator and
+ * row header funcs.
+ */
+static void
+gtk_tree_view_nodes_set_fixed_height (GtkTreeView *tree_view)
+{
+ int focus_pad;
+ int separator_height;
+ GtkRBTree *tree;
+ GtkRBNode *node;
+ GtkTreeIter iter;
+
+ tree = tree_view->priv->tree;
+
+ if (tree == NULL)
+ return;
+
+ node = tree->root;
+ g_assert (node);
+
+ /* Rewind tree, we start at the first node */
+ while (node->left != tree->nil)
+ node = node->left;
+
+ gtk_tree_model_get_iter_first (tree_view->priv->model, &iter);
+
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "focus-padding", &focus_pad,
+ "separator-height", &separator_height,
+ NULL);
+
+ /* This loop is equivalent to the one in bin_expose, but with
+ * the extra assertions removed.
+ */
+ do
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))
+ {
+ int height;
+
+ height = determine_row_height (tree_view, &iter,
+ focus_pad, separator_height);
+
+ _gtk_rbtree_node_set_height (tree, node, height);
+ _gtk_rbtree_node_mark_valid (tree, node);
+ }
+
+ if (node->children)
+ {
+ GtkTreeIter parent = iter;
+
+ tree = node->children;
+ node = tree->root;
+
+ g_assert (node != tree->nil);
- gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
- tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
- tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
- gtk_adjustment_changed (tree_view->priv->hadjustment);
- gtk_adjustment_changed (tree_view->priv->vadjustment);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- }
+ while (node->left != tree->nil)
+ node = node->left;
- if (tree_view->priv->scroll_to_path)
- {
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
+ gtk_tree_model_iter_children (tree_view->priv->model,
+ &iter, &parent);
+ }
+ else
+ {
+ gboolean done = FALSE;
- if (above_path)
- gtk_tree_path_free (above_path);
+ do
+ {
+ node = _gtk_rbtree_next (tree, node);
+ if (node != NULL)
+ {
+ gtk_tree_model_iter_next (tree_view->priv->model, &iter);
+ done = TRUE;
+ }
+ else
+ {
+ GtkTreeIter parent_iter = iter;
- if (tree_view->priv->scroll_to_column)
- {
- tree_view->priv->scroll_to_column = NULL;
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+
+ if (!tree)
+ /* We are done */
+ return;
+
+ gtk_tree_model_iter_parent (tree_view->priv->model,
+ &iter, &parent_iter);
+ }
+ }
+ while (!done);
+ }
}
- if (need_redraw)
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+ while (TRUE);
}
static void
@@ -6227,6 +7040,29 @@
node = tree->root;
path = _gtk_tree_view_find_path (tree_view, tree, node);
+
+ /* Search for the first regular row */
+ while (node)
+ {
+ gboolean is_header = FALSE, is_separator;
+
+ is_separator = row_is_separator (tree_view, NULL, &is_header, path);
+ if (!is_separator && !is_header)
+ break;
+
+ _gtk_rbtree_next_full (tree, node, &tree, &node);
+
+ gtk_tree_path_free (path);
+
+ if (node)
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ else
+ path = NULL;
+ }
+
+ if (!path)
+ return;
+
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
validate_row (tree_view, tree, node, &iter, path);
@@ -6236,8 +7072,16 @@
tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
}
- _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
- tree_view->priv->fixed_height, TRUE);
+ /* If a separator or row header func has been set, we cannot
+ * uniformly set the same height on all rows. We fall back to
+ * a slower alternative.
+ */
+ if (tree_view->priv->row_separator_func
+ || tree_view->priv->row_header_func)
+ gtk_tree_view_nodes_set_fixed_height (tree_view);
+ else
+ _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
+ tree_view->priv->fixed_height, TRUE);
}
/* Our strategy for finding nodes to validate is a little convoluted. We find
@@ -7206,6 +8050,9 @@
set_source_row (context, model, path);
+ /* Clear pending actions on row */
+ free_queued_actions (tree_view);
+
out:
if (path)
gtk_tree_path_free (path);
@@ -7708,12 +8555,20 @@
gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
{
GList *list;
+ guint n_specials = 0;
for (list = tree_view->priv->columns; list; list = list->next)
{
if (!((GtkTreeViewColumn *)list->data)->visible)
continue;
- if (_gtk_tree_view_column_count_special_cells (list->data))
+ /* We return true if there is more than one special cell. Since
+ * we do not want to have the per-cell focus rectangles when there
+ * is only a single activatable cell, we return FALSE for
+ * n_specials == 1
+ */
+ n_specials += _gtk_tree_view_column_count_special_cells (list->data);
+
+ if (n_specials > 1)
return TRUE;
}
@@ -7813,148 +8668,11 @@
GtkDirectionType dir,
gboolean clamp_column_visible)
{
- GtkWidget *focus_child;
-
- GList *last_column, *first_column;
- GList *tmp_list;
- gboolean rtl;
-
- if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
- return FALSE;
-
- focus_child = GTK_CONTAINER (tree_view)->focus_child;
-
- first_column = tree_view->priv->columns;
- while (first_column)
- {
- if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
- GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
- (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
- GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
- break;
- first_column = first_column->next;
- }
-
- /* No headers are visible, or are focusable. We can't focus in or out.
- */
- if (first_column == NULL)
- return FALSE;
-
- last_column = g_list_last (tree_view->priv->columns);
- while (last_column)
- {
- if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
- GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
- (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
- GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
- break;
- last_column = last_column->prev;
- }
-
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- switch (dir)
- {
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_UP:
- case GTK_DIR_DOWN:
- if (focus_child == NULL)
- {
- if (tree_view->priv->focus_column != NULL &&
- gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
- focus_child = tree_view->priv->focus_column->button;
- else
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- break;
- }
- return FALSE;
-
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- if (focus_child == NULL)
- {
- if (tree_view->priv->focus_column != NULL)
- focus_child = tree_view->priv->focus_column->button;
- else if (dir == GTK_DIR_LEFT)
- focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
- else
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- break;
- }
-
- if (gtk_widget_child_focus (focus_child, dir))
- {
- /* The focus moves inside the button. */
- /* This is probably a great example of bad UI */
- break;
- }
-
- /* We need to move the focus among the row of buttons. */
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
- break;
-
- if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
- || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
- {
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- break;
- }
-
- while (tmp_list)
- {
- GtkTreeViewColumn *column;
-
- if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
- tmp_list = tmp_list->next;
- else
- tmp_list = tmp_list->prev;
-
- if (tmp_list == NULL)
- {
- g_warning ("Internal button not found");
- break;
- }
- column = tmp_list->data;
- if (column->button &&
- column->visible &&
- gtk_widget_get_can_focus (column->button))
- {
- focus_child = column->button;
- gtk_widget_grab_focus (column->button);
- break;
- }
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- /* if focus child is non-null, we assume it's been set to the current focus child
+ /* Skip headers when acquiring focus; behave the same as the headers
+ * are invisible.
*/
- if (focus_child)
- {
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
- {
- tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
- break;
- }
-
- if (clamp_column_visible)
- {
- gtk_tree_view_clamp_column_visible (tree_view,
- tree_view->priv->focus_column,
- FALSE);
- }
- }
- return (focus_child != NULL);
+ return FALSE;
}
/* This function returns in 'path' the first focusable path, if the given path
@@ -7978,7 +8696,9 @@
if (!tree || !node)
return FALSE;
- while (node && row_is_separator (tree_view, NULL, *path))
+ while (node &&
+ !_gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+ node, *path))
{
if (search_forward)
_gtk_rbtree_next_full (tree, node, &tree, &node);
@@ -8097,6 +8817,31 @@
tree_view->priv->fixed_height = -1;
_gtk_rbtree_mark_invalid (tree_view->priv->tree);
+ /* Cache the hildon-mode because it is slow to call gtk_widget_style_get
+ * too much. */
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "hildon-mode", &tree_view->priv->hildon_mode,
+ NULL);
+
+ /* Reset the UI mode */
+ hildon_tree_view_set_hildon_ui_mode (tree_view,
+ tree_view->priv->hildon_ui_mode);
+
+ if (tree_view->priv->row_header_layout)
+ hildon_tree_view_setup_row_header_layout (tree_view);
+
+ if (tree_view->priv->tickmark_icon)
+ g_object_unref (tree_view->priv->tickmark_icon);
+
+ tree_view->priv->tickmark_icon =
+ gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ "widgets_tickmark_list",
+ HILDON_TICK_MARK_SIZE,
+ 0, NULL);
+
+ if (tree_view->priv->action_area_visible)
+ hildon_tree_view_set_action_area_height (tree_view);
+
gtk_widget_queue_resize (widget);
}
@@ -8354,10 +9099,39 @@
if (tree == NULL)
goto done;
+ /* Unselect the row if it just became insensitive */
+ if (!_gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+ node, path)
+ && gtk_tree_row_reference_valid (tree_view->priv->cursor))
+ {
+ GtkTreePath *cursor_path;
+
+ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+ if (! gtk_tree_path_compare (path, cursor_path))
+ {
+ gtk_tree_row_reference_free (tree_view->priv->cursor);
+ tree_view->priv->cursor = NULL;
+ }
+
+ gtk_tree_selection_unselect_path (tree_view->priv->selection, path);
+
+ gtk_tree_path_free (cursor_path);
+ }
+
if (tree_view->priv->fixed_height_mode
&& tree_view->priv->fixed_height >= 0)
{
- _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
+ if (tree_view->priv->row_separator_func
+ || tree_view->priv->row_header_func)
+ {
+ int height;
+
+ height = determine_row_height (tree_view, iter, -1, -1);
+ _gtk_rbtree_node_set_height (tree, node, height);
+ }
+ else
+ _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
+
if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
gtk_tree_view_node_queue_redraw (tree_view, tree, node);
}
@@ -8407,7 +9181,13 @@
if (tree_view->priv->fixed_height_mode
&& tree_view->priv->fixed_height >= 0)
- height = tree_view->priv->fixed_height;
+ {
+ if (tree_view->priv->row_separator_func
+ || tree_view->priv->row_header_func)
+ height = determine_row_height (tree_view, iter, -1, -1);
+ else
+ height = tree_view->priv->fixed_height;
+ }
else
height = 0;
@@ -8420,7 +9200,13 @@
gtk_tree_model_get_iter (model, iter, path);
if (tree_view->priv->tree == NULL)
- tree_view->priv->tree = _gtk_rbtree_new ();
+ {
+ tree_view->priv->tree = _gtk_rbtree_new ();
+
+ if (G_UNLIKELY (tree_view->priv->rows_offset != 0))
+ _gtk_rbtree_set_base_offset (tree_view->priv->tree,
+ tree_view->priv->rows_offset);
+ }
tmptree = tree = tree_view->priv->tree;
@@ -8485,6 +9271,23 @@
tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
}
+ /* If this was the first node inserted in the tree, we want to
+ * select it.
+ */
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE
+ && gtk_tree_selection_count_selected_rows (tree_view->priv->selection) < 1)
+ {
+ GtkTreePath *tmppath;
+
+ tmppath = gtk_tree_path_new_first ();
+ search_first_focusable_path (tree_view, &tmppath,
+ TRUE, NULL, NULL);
+ gtk_tree_selection_select_path (tree_view->priv->selection, tmppath);
+ gtk_tree_path_free (tmppath);
+ }
+
done:
if (height > 0)
{
@@ -8631,6 +9434,8 @@
/* Ensure we don't have a dangling pointer to a dead node */
ensure_unprelighted (tree_view);
+ free_queued_actions (tree_view);
+ ensure_unhighlighted (tree_view);
/* Cancel editting if we've started */
gtk_tree_view_stop_editing (tree_view, TRUE);
@@ -8638,6 +9443,12 @@
/* If we have a node expanded/collapsed timeout, remove it */
remove_expand_collapse_timeout (tree_view);
+ /* Stop rubber banding as row deletion invalidates the start/end
+ * rbtree/nodes. Should consider updating the pointers instead.
+ */
+ if (tree_view->priv->rubber_band_status)
+ gtk_tree_view_stop_rubber_band (tree_view);
+
if (tree_view->priv->destroy_count_func)
{
gint child_count = 0;
@@ -8666,6 +9477,24 @@
install_scroll_sync_handler (tree_view);
+ if (selection_changed
+ && tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE
+ && gtk_tree_selection_count_selected_rows (tree_view->priv->selection) < 1)
+ {
+ GtkTreePath *tmppath;
+
+ /* One item must be selected, now there is none. If iter_first
+ * does not exist, the view is empty.
+ */
+ tmppath = gtk_tree_path_new_first ();
+ search_first_focusable_path (tree_view, &tmppath,
+ TRUE, NULL, NULL);
+ gtk_tree_selection_select_path (tree_view->priv->selection, tmppath);
+ gtk_tree_path_free (tmppath);
+ }
+
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
if (selection_changed)
@@ -8714,6 +9543,8 @@
/* we need to be unprelighted */
ensure_unprelighted (tree_view);
+ free_queued_actions (tree_view);
+ ensure_unhighlighted (tree_view);
/* clear the timeout */
cancel_arrow_animation (tree_view);
@@ -9590,6 +10421,9 @@
{
GtkTreePath *cursor_path;
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE)
+ return;
+
if ((tree_view->priv->tree == NULL) ||
(! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
return;
@@ -9628,8 +10462,11 @@
if (cursor_path)
{
- if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
- gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
+ if ((tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ && tree_view->priv->hildon_mode == HILDON_DIABLO)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
+ }
else
gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
}
@@ -9833,6 +10670,8 @@
if (y >= tree_view->priv->height)
y = tree_view->priv->height - 1;
+ else if (tree_view->priv->rows_offset != 0 && y < tree_view->priv->rows_offset)
+ y = tree_view->priv->rows_offset;
tree_view->priv->cursor_offset =
_gtk_rbtree_find_offset (tree_view->priv->tree, y,
@@ -9942,11 +10781,12 @@
if (column->visible == FALSE)
goto loop_end;
- gtk_tree_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter,
- GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
- cursor_node->children?TRUE:FALSE);
+ gtk_tree_view_column_cell_set_cell_data_with_hint (column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
+ cursor_node->children?TRUE:FALSE,
+ GTK_TREE_CELL_DATA_HINT_KEY_FOCUS);
if (rtl)
{
@@ -10007,6 +10847,12 @@
gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
+ /* Immediately return when there is no cursor. (Like all other
+ * cursor movement handlers -- should prolly go upstream).
+ */
+ if (!old_path)
+ return;
+
cursor_tree = tree_view->priv->tree;
cursor_node = cursor_tree->root;
@@ -10115,6 +10961,54 @@
return FALSE;
}
+ if (start_editing)
+ {
+ GList *list;
+ gboolean rtl;
+ GtkTreeIter iter;
+
+ /* In case we have only one activatable cell in the tree view, we have
+ * a special case. We will have to set the cell data on the cursor
+ * row in order to figure out.
+ */
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
+ {
+ GtkTreeViewColumn *column = list->data;
+ gtk_tree_view_column_cell_set_cell_data_with_hint (column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
+ cursor_node->children?TRUE:FALSE,
+ GTK_TREE_CELL_DATA_HINT_KEY_FOCUS);
+ }
+
+ if (!gtk_tree_view_has_special_cell (tree_view))
+ {
+ /* We now set focus_column to the first column with an activatable
+ * cell that we can find. This is either none, or the one with
+ * the only activatable cell that is around.
+ */
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
+ {
+ GtkTreeViewColumn *column = list->data;
+
+ if (column->visible
+ && _gtk_tree_view_column_count_special_cells (column))
+ {
+ tree_view->priv->focus_column = column;
+ break;
+ }
+ }
+ }
+ }
+
if (!tree_view->priv->extend_selection_pressed && start_editing &&
tree_view->priv->focus_column)
{
@@ -10235,18 +11129,40 @@
if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
return FALSE;
- /* Don't handle the event if we aren't an expander */
- if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
- return FALSE;
-
if (!logical
&& gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
expand = !expand;
if (expand)
- gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
+ {
+ gboolean expanded;
+
+ expanded = gtk_tree_view_real_expand_row (tree_view, cursor_path,
+ tree, node, open_all, TRUE);
+ if (!expanded
+ && !gtk_widget_keynav_failed (GTK_WIDGET (tree_view), GTK_DIR_RIGHT))
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+ if (toplevel)
+ gtk_widget_child_focus (toplevel, GTK_DIR_TAB_FORWARD);
+ }
+ }
else
- gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
+ {
+ gboolean collapsed;
+
+ collapsed = gtk_tree_view_real_collapse_row (tree_view, cursor_path,
+ tree, node, TRUE);
+ if (!collapsed
+ && !gtk_widget_keynav_failed (GTK_WIDGET (tree_view), GTK_DIR_LEFT))
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+ if (toplevel)
+ gtk_widget_child_focus (toplevel, GTK_DIR_TAB_BACKWARD);
+
+ gtk_tree_view_real_select_cursor_parent (tree_view);
+ }
+ }
gtk_tree_path_free (cursor_path);
@@ -10361,6 +11277,7 @@
}
tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_is_temporary (GTK_WINDOW (tree_view->priv->search_window), TRUE);
gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
if (GTK_WINDOW (toplevel)->group)
@@ -10792,6 +11709,11 @@
gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
tree_view->priv->scroll_to_path = NULL;
+ tree_view->priv->highlighted_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+
+ free_queued_actions (tree_view);
+
tree_view->priv->scroll_to_column = NULL;
g_object_unref (tree_view->priv->model);
@@ -10859,8 +11781,24 @@
if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
{
tree_view->priv->tree = _gtk_rbtree_new ();
+
+ if (G_UNLIKELY (tree_view->priv->rows_offset != 0))
+ _gtk_rbtree_set_base_offset (tree_view->priv->tree,
+ tree_view->priv->rows_offset);
+
gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
}
+
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+ {
+ /* Select the first item */
+ search_first_focusable_path (tree_view, &path,
+ TRUE, NULL, NULL);
+ gtk_tree_selection_select_path (tree_view->priv->selection, path);
+ }
+
gtk_tree_path_free (path);
/* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
@@ -12079,6 +13017,12 @@
GtkTreeIter iter;
GtkTreeIter temp;
gboolean expand;
+ gint dy;
+ GtkTreeIter tmpiter;
+ GtkTreePath *tmppath;
+ GtkRBTree *tmptree;
+ GtkRBNode *tmpnode;
+ gint branch_height;
if (animate)
g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
@@ -12147,12 +13091,54 @@
gtk_tree_path_get_depth (path) + 1,
open_all);
- remove_expand_collapse_timeout (tree_view);
+ remove_expand_collapse_timeout (tree_view);
+
+ if (animate)
+ add_expand_collapse_timeout (tree_view, tree, node, TRUE);
+
+ /* We do validate new nodes ourselves below, but we still need
+ * somebody to take care of the actual resizing.
+ */
+ if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+
+ install_presize_handler (tree_view);
+
+ gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
+ _gtk_tree_view_find_node (tree_view, path, &tmptree, &tmpnode);
+
+ validate_row (tree_view, tmptree, tmpnode, &tmpiter, path);
+ branch_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (tmpnode));
+ dy = _gtk_rbtree_node_find_offset (tmptree, tmpnode);
+
+ tmppath = gtk_tree_path_copy (path);
+ gtk_tree_path_down (tmppath);
+ gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
+
+ do
+ {
+ _gtk_tree_view_find_node (tree_view, tmppath, &tmptree, &tmpnode);
+
+ validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath);
+ branch_height += ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (tmpnode));
+
+ gtk_tree_path_next (tmppath);
+ }
+ while (gtk_tree_model_iter_next (tree_view->priv->model, &tmpiter));
+
+ gtk_tree_path_prev (tmppath);
- if (animate)
- add_expand_collapse_timeout (tree_view, tree, node, TRUE);
+ /* We scroll to the just expanded row if the expanding row and its children
+ * do not fit in the view.
+ * Otherwise, if the last child is not visible, we scroll to it to make
+ * sure all children are visible.
+ */
+ if (branch_height > GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view))
+ gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.0, 0.0);
+ else if (dy + branch_height > tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
+ gtk_tree_view_scroll_to_cell (tree_view, tmppath, NULL, TRUE, 1.0, 0.0);
- install_presize_handler (tree_view);
+ gtk_tree_path_free (tmppath);
g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
if (open_all && node->children)
@@ -12556,6 +13542,20 @@
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
+ _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+
+ /* If we are in legacy or in (new-style) edit mode, row-insensitive
+ * can be emitted.
+ */
+ if ((tree_view->priv->hildon_mode == HILDON_DIABLO
+ || tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
+ && !_gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+ node, path))
+ {
+ g_signal_emit (tree_view, tree_view_signals[ROW_INSENSITIVE], 0, path);
+ return;
+ }
+
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
{
GtkTreePath *cursor_path;
@@ -12573,18 +13573,21 @@
* path maps to a non-existing path and we will silently bail out.
* We unset tree and node to avoid further processing.
*/
- if (!row_is_separator (tree_view, NULL, path)
- && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
+ if (tree_view->priv->hildon_mode == HILDON_DIABLO)
{
- tree_view->priv->cursor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
- tree_view->priv->model,
- path);
- }
- else
- {
- tree = NULL;
- node = NULL;
+ if (!row_is_separator (tree_view, NULL, NULL, path)
+ && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
+ {
+ tree_view->priv->cursor =
+ gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+ tree_view->priv->model,
+ path);
+ }
+ else
+ {
+ tree = NULL;
+ node = NULL;
+ }
}
if (tree != NULL)
@@ -12596,8 +13599,13 @@
{
GtkTreeSelectMode mode = 0;
- if (tree_view->priv->modify_selection_pressed)
- mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+ if (tree_view->priv->modify_selection_pressed ||
+ (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE))
+ {
+ mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+ }
if (tree_view->priv->extend_selection_pressed)
mode |= GTK_TREE_SELECT_MODE_EXTEND;
@@ -12622,7 +13630,9 @@
}
}
- g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
+ /* Only in the original mode we want to handle the cursor */
+ if (tree_view->priv->hildon_mode == HILDON_DIABLO)
+ g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
}
/**
@@ -13780,6 +14790,7 @@
gboolean is_separator = FALSE;
gboolean rtl;
cairo_t *cr;
+ gboolean is_header = FALSE;
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
g_return_val_if_fail (path != NULL, NULL);
@@ -13804,7 +14815,7 @@
path))
return NULL;
- is_separator = row_is_separator (tree_view, &iter, NULL);
+ is_separator = row_is_separator (tree_view, &iter, &is_header, NULL);
cell_offset = x;
@@ -13872,7 +14883,14 @@
if (gtk_tree_view_column_cell_is_visible (column))
{
- if (is_separator)
+ if (is_header)
+ {
+ gtk_tree_view_draw_row_header (tree_view,
+ &iter,
+ NULL,
+ &cell_area);
+ }
+ else if (is_separator)
gtk_paint_hline (widget->style,
drawable,
GTK_STATE_NORMAL,
@@ -15141,6 +16159,83 @@
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
+HildonTreeViewRowHeaderFunc
+hildon_tree_view_get_row_header_func (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->row_header_func;
+}
+
+static void
+hildon_tree_view_setup_row_header_layout (GtkTreeView *tree_view)
+{
+ GdkColor font_color;
+ GtkStyle *font_style;
+ GtkWidget *widget = GTK_WIDGET (tree_view);
+
+ font_style = gtk_rc_get_style_by_paths (gtk_settings_get_default (),
+ "EmpSmallSystemFont",
+ NULL, G_TYPE_NONE);
+ if (font_style)
+ {
+ pango_layout_set_font_description (tree_view->priv->row_header_layout,
+ font_style->font_desc);
+ }
+
+ if (gtk_style_lookup_color (widget->style, "SecondaryTextColor", &font_color))
+ {
+ PangoAttrList *list;
+ PangoAttribute *attr;
+
+ list = pango_attr_list_new ();
+ attr = pango_attr_foreground_new (font_color.red,
+ font_color.green,
+ font_color.blue);
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+ pango_attr_list_insert (list, attr);
+
+ pango_layout_set_attributes (tree_view->priv->row_header_layout,
+ list);
+
+ pango_attr_list_unref (list);
+ }
+}
+
+void
+hildon_tree_view_set_row_header_func (GtkTreeView *tree_view,
+ HildonTreeViewRowHeaderFunc func,
+ gpointer data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->row_header_destroy)
+ (* tree_view->priv->row_header_destroy) (tree_view->priv->row_header_data);
+
+ tree_view->priv->row_header_func = func;
+ tree_view->priv->row_header_data = data;
+ tree_view->priv->row_header_destroy = destroy;
+
+ if (func && !tree_view->priv->row_header_layout)
+ {
+ tree_view->priv->row_header_layout =
+ gtk_widget_create_pango_layout (GTK_WIDGET (tree_view), "");
+
+ hildon_tree_view_setup_row_header_layout (tree_view);
+ }
+ else if (!func && tree_view->priv->row_header_layout)
+ {
+ g_object_unref (tree_view->priv->row_header_layout);
+ tree_view->priv->row_header_layout = NULL;
+ }
+
+ /* Have the tree recalculate heights */
+ _gtk_rbtree_mark_invalid (tree_view->priv->tree);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+}
+
static void
gtk_tree_view_grab_notify (GtkWidget *widget,
@@ -15156,6 +16251,21 @@
if (tree_view->priv->rubber_band_status)
gtk_tree_view_stop_rubber_band (tree_view);
+
+ if (tree_view->priv->queued_expand_row)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row);
+ tree_view->priv->queued_expand_row = NULL;
+ }
+
+ if (tree_view->priv->queued_tapped_row)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row = NULL;
+ }
+
+ free_queued_select_row (tree_view);
+ free_queued_activate_row (tree_view);
}
}
@@ -15755,5 +16865,373 @@
return tree_view->priv->tooltip_column;
}
+static gboolean
+gtk_tree_view_tap_and_hold_query (GtkWidget *widget,
+ GdkEvent *event)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GtkTreePath *path;
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+ gdouble x, y;
+ gint new_y;
+ gboolean sensitive;
+
+ if (!tree_view->priv->tree)
+ return FALSE;
+
+ if (!gdk_event_get_coords (event, &x, &y))
+ return FALSE;
+
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
+ if (new_y < 0)
+ new_y = 0;
+ _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+ if (node == NULL)
+ return TRUE;
+
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ {
+ /* The normal mode has no notion of selection, so we special-case
+ * it here.
+ */
+ sensitive = !row_is_separator (tree_view, NULL, NULL, path);
+ }
+ else
+ {
+ sensitive = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
+ node, path);
+ }
+
+ gtk_tree_path_free (path);
+
+ return !sensitive;
+}
+
+static void
+free_queued_select_row (GtkTreeView *tree_view)
+{
+ /* We only clear the selected flag (used for highlight) if the node
+ * was previously *not* selected.
+ */
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && gtk_tree_row_reference_valid (tree_view->priv->queued_select_row))
+ {
+ if (tree_view->priv->highlighted_node)
+ {
+ _gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->highlighted_tree,
+ tree_view->priv->highlighted_node,
+ NULL);
+
+ tree_view->priv->highlighted_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+ }
+ }
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_select_row);
+ tree_view->priv->queued_select_row = NULL;
+}
+
+static void
+free_queued_activate_row (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->hildon_mode == HILDON_FREMANTLE
+ && tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL
+ && gtk_tree_row_reference_valid (tree_view->priv->queued_activate_row))
+ {
+ if (tree_view->priv->highlighted_node)
+ {
+ _gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->highlighted_tree,
+ tree_view->priv->highlighted_node,
+ NULL);
+
+ tree_view->priv->highlighted_tree = NULL;
+ tree_view->priv->highlighted_node = NULL;
+ }
+ }
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_activate_row);
+ tree_view->priv->queued_activate_row = NULL;
+}
+
+static void
+free_queued_actions (GtkTreeView *tree_view)
+{
+ free_queued_activate_row (tree_view);
+ free_queued_select_row (tree_view);
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_expand_row);
+ tree_view->priv->queued_expand_row = NULL;
+
+ gtk_tree_row_reference_free (tree_view->priv->queued_tapped_row);
+ tree_view->priv->queued_tapped_row = NULL;
+}
+
+HildonUIMode
+hildon_tree_view_get_hildon_ui_mode (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return tree_view->priv->hildon_ui_mode;
+}
+
+void
+hildon_tree_view_set_hildon_ui_mode (GtkTreeView *tree_view,
+ HildonUIMode hildon_ui_mode)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ /* Don't check if the new mode matches the old mode; always continue
+ * so that the selection corrections below always happen.
+ */
+ tree_view->priv->hildon_ui_mode = hildon_ui_mode;
+
+ if (tree_view->priv->hildon_mode == HILDON_DIABLO)
+ return;
+
+ /* For both normal and edit mode a couple of things are disabled. */
+
+ /* Mode-specific settings */
+ if (hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ {
+ gtk_tree_selection_set_mode (tree_view->priv->selection,
+ GTK_SELECTION_NONE);
+ }
+ else if (hildon_ui_mode == HILDON_UI_MODE_EDIT)
+ {
+ if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_NONE)
+ {
+ gtk_tree_selection_set_mode (tree_view->priv->selection,
+ GTK_SELECTION_SINGLE);
+ }
+
+ if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE
+ && gtk_tree_selection_count_selected_rows (tree_view->priv->selection) < 1)
+ {
+ GtkTreePath *path;
+
+ /* Select the first item */
+ path = gtk_tree_path_new_first ();
+ search_first_focusable_path (tree_view, &path,
+ TRUE, NULL, NULL);
+ gtk_tree_selection_select_path (tree_view->priv->selection, path);
+ gtk_tree_path_free (path);
+ }
+ }
+ else
+ g_assert_not_reached ();
+}
+
+static void
+hildon_tree_view_set_rows_offset (GtkTreeView *tree_view,
+ int rows_offset)
+{
+ if (tree_view->priv->rows_offset == rows_offset)
+ return;
+
+ tree_view->priv->rows_offset = rows_offset;
+ if (tree_view->priv->tree)
+ _gtk_rbtree_set_base_offset (tree_view->priv->tree, rows_offset);
+
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+}
+
+static void
+hildon_tree_view_create_action_area (GtkTreeView *tree_view)
+{
+ /* gtk_tree_view_put() takes over ownership and so we do not
+ * have to unref these values in gtk_tree_view_destroy().
+ */
+ tree_view->priv->action_area_event_box = gtk_event_box_new ();
+ gtk_tree_view_put (tree_view, tree_view->priv->action_area_event_box,
+ 0, 0, 0, 0);
+
+ if (tree_view->priv->action_area_orientation == GTK_ORIENTATION_HORIZONTAL)
+ tree_view->priv->action_area_box = gtk_hbox_new (TRUE, 0);
+ else if (tree_view->priv->action_area_orientation == GTK_ORIENTATION_VERTICAL)
+ tree_view->priv->action_area_box = gtk_vbox_new (TRUE, 0);
+
+ gtk_container_add (GTK_CONTAINER (tree_view->priv->action_area_event_box),
+ tree_view->priv->action_area_box);
+}
+
+static void
+hildon_tree_view_set_action_area_height (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->action_area_orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ int row_height;
+
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "row-height", &row_height,
+ NULL);
+ hildon_tree_view_set_rows_offset (tree_view, row_height);
+ }
+ else if (tree_view->priv->action_area_orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ GList *children;
+
+ /* The height in portrait mode is currently hardcoded to 90px per
+ * button.
+ */
+ children = gtk_container_get_children (GTK_CONTAINER (tree_view->priv->action_area_box));
+ hildon_tree_view_set_rows_offset (tree_view,
+ g_list_length (children) * 90);
+ g_list_free (children);
+ }
+}
+
+void
+hildon_tree_view_set_action_area_visible (GtkTreeView *tree_view,
+ gboolean visible)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->action_area_visible == !!visible)
+ return;
+
+ tree_view->priv->action_area_visible = visible;
+
+ if (visible)
+ {
+ hildon_tree_view_set_action_area_height (tree_view);
+
+ if (!tree_view->priv->action_area_event_box)
+ hildon_tree_view_create_action_area (tree_view);
+
+ gtk_widget_show (tree_view->priv->action_area_box);
+ gtk_widget_show (tree_view->priv->action_area_event_box);
+ }
+ else
+ {
+ gtk_widget_hide (tree_view->priv->action_area_event_box);
+
+ hildon_tree_view_set_rows_offset (tree_view, 0);
+ }
+}
+
+gboolean
+hildon_tree_view_get_action_area_visible (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ return tree_view->priv->action_area_visible;
+}
+
+static void
+hildon_tree_view_rotate_action_area_box (GtkBox *old_box,
+ GtkBox *new_box)
+{
+ int spacing, border_width;
+ GList *children, *child;
+ gboolean homogeneous;
+
+ g_object_get (old_box,
+ "homogeneous", &homogeneous,
+ "spacing", &spacing,
+ "border-width", &border_width,
+ NULL);
+
+ g_object_set (new_box,
+ "homogeneous", homogeneous,
+ "spacing", spacing,
+ "border-width", border_width,
+ NULL);
+
+ children = gtk_container_get_children (GTK_CONTAINER (old_box));
+ for (child = children; child; child = child->next)
+ {
+ guint padding;
+ gboolean expand, fill;
+ GtkPackType type;
+ GtkWidget *widget = child->data;
+
+ g_object_ref (widget);
+ gtk_box_query_child_packing (old_box, widget,
+ &expand, &fill, &padding, &type);
+ gtk_container_remove (GTK_CONTAINER (old_box), widget);
+ gtk_container_add (GTK_CONTAINER (new_box), widget);
+ gtk_box_set_child_packing (new_box, widget,
+ expand, fill, padding, type);
+ g_object_unref (widget);
+ }
+
+ g_list_free (children);
+
+ if (gtk_widget_get_visible (GTK_WIDGET (old_box)))
+ gtk_widget_show (GTK_WIDGET (new_box));
+}
+
+void
+hildon_tree_view_set_action_area_orientation (GtkTreeView *tree_view,
+ GtkOrientation orientation)
+{
+ GtkWidget *old_box;
+ GtkWidget *new_box;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->action_area_orientation == orientation)
+ return;
+
+ tree_view->priv->action_area_orientation = orientation;
+
+ old_box = tree_view->priv->action_area_box;
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ new_box = gtk_hbox_new (TRUE, 0);
+ else if (orientation == GTK_ORIENTATION_VERTICAL)
+ new_box = gtk_vbox_new (TRUE, 0);
+
+ if (tree_view->priv->action_area_visible)
+ hildon_tree_view_set_action_area_height (tree_view);
+
+ hildon_tree_view_rotate_action_area_box (GTK_BOX (old_box),
+ GTK_BOX (new_box));
+
+ gtk_widget_destroy (old_box);
+
+ tree_view->priv->action_area_box = new_box;
+ gtk_container_add (GTK_CONTAINER (tree_view->priv->action_area_event_box),
+ tree_view->priv->action_area_box);
+}
+
+GtkOrientation
+hildon_tree_view_get_action_area_orientation (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return tree_view->priv->action_area_orientation;
+}
+
+/**
+ * hildon_tree_view_get_action_area_box:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns the GtkBox is embedded in GtkTreeView's action area. Depending
+ * on the setting of the GtkTreeView:action-area-orientation property
+ * this is either a GtkHBox or GtkVBox. You do not own a reference to
+ * the returned widget and thus this value should not be unreferenced.
+ *
+ * Returns: a pointer to a GtkBox. This pointer should not be unreferenced.
+ *
+ * Since: maemo 5.0
+ * Stability: unstable
+ */
+GtkWidget *
+hildon_tree_view_get_action_area_box (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ if (!tree_view->priv->action_area_event_box)
+ hildon_tree_view_create_action_area (tree_view);
+
+ return tree_view->priv->action_area_box;
+}
+
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"
--- a/gtk/gtktreeview.h
+++ b/gtk/gtktreeview.h
@@ -111,7 +111,8 @@
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
+ void (* row_insensitive) (GtkTreeView *tree_view,
+ GtkTreePath *path);
};
@@ -134,7 +135,10 @@
typedef void (*GtkTreeViewSearchPositionFunc) (GtkTreeView *tree_view,
GtkWidget *search_dialog,
gpointer user_data);
-
+typedef gboolean (*HildonTreeViewRowHeaderFunc) (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gchar **header_text,
+ gpointer data);
/* Creators */
GType gtk_tree_view_get_type (void) G_GNUC_CONST;
@@ -392,6 +396,27 @@
gpointer data,
GDestroyNotify destroy);
+HildonTreeViewRowHeaderFunc hildon_tree_view_get_row_header_func (GtkTreeView *tree_view);
+void hildon_tree_view_set_row_header_func (GtkTreeView *tree_view,
+ HildonTreeViewRowHeaderFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+
+HildonUIMode hildon_tree_view_get_hildon_ui_mode (GtkTreeView *tree_view);
+void hildon_tree_view_set_hildon_ui_mode (GtkTreeView *tree_view,
+ HildonUIMode mode);
+
+
+void hildon_tree_view_set_action_area_visible (GtkTreeView *tree_view,
+ gboolean visible);
+gboolean hildon_tree_view_get_action_area_visible (GtkTreeView *tree_view);
+
+void hildon_tree_view_set_action_area_orientation (GtkTreeView *tree_view,
+ GtkOrientation orientation);
+GtkOrientation hildon_tree_view_get_action_area_orientation (GtkTreeView *tree_view);
+
+GtkWidget *hildon_tree_view_get_action_area_box (GtkTreeView *tree_view);
+
GtkTreeViewGridLines gtk_tree_view_get_grid_lines (GtkTreeView *tree_view);
void gtk_tree_view_set_grid_lines (GtkTreeView *tree_view,
GtkTreeViewGridLines grid_lines);
--- a/gtk/gtktreeprivate.h
+++ b/gtk/gtktreeprivate.h
@@ -28,7 +28,7 @@
#include <gtk/gtktreeselection.h>
#include <gtk/gtkrbtree.h>
-#define TREE_VIEW_DRAG_WIDTH 6
+#define TREE_VIEW_DRAG_WIDTH 28
typedef enum
{
@@ -300,6 +300,37 @@
/* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
guint search_entry_avoid_unhandled_binding : 1;
+
+ /* Fields for Maemo specific functionality */
+ GtkTreeRowReference *queued_select_row;
+ GtkTreeRowReference *queued_expand_row;
+ GtkTreeRowReference *queued_activate_row;
+ GtkTreeRowReference *queued_tapped_row;
+
+ GtkRBNode *highlighted_node;
+ GtkRBTree *highlighted_tree;
+
+ GtkTreeCellDataHint cell_data_hint;
+
+ HildonUIMode hildon_ui_mode;
+ HildonMode hildon_mode;
+
+ GdkPixbuf *tickmark_icon;
+
+ HildonTreeViewRowHeaderFunc row_header_func;
+ gpointer row_header_data;
+ GDestroyNotify row_header_destroy;
+ PangoLayout *row_header_layout;
+
+ gint rows_offset;
+ GtkOrientation action_area_orientation;
+ GtkWidget *action_area_event_box;
+ GtkWidget *action_area_box;
+
+ guint queued_shift_pressed : 1;
+ guint queued_ctrl_pressed : 1;
+
+ guint action_area_visible : 1;
};
#ifdef __GNUC__
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -851,7 +851,7 @@
G_CALLBACK (gtk_tree_view_column_button_clicked),
tree_column);
- tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
+ tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 1.0, 1.0);
hbox = gtk_hbox_new (FALSE, 2);
tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
@@ -916,7 +916,7 @@
/* Set up the actual button */
gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
- 0.5, 0.0, 0.0);
+ 0.5, 1.0, 1.0);
if (tree_column->child)
{
@@ -926,6 +926,7 @@
current_child);
gtk_container_add (GTK_CONTAINER (alignment),
tree_column->child);
+ current_child = tree_column->child;
}
}
else
@@ -948,6 +949,14 @@
"");
}
+ if (GTK_IS_MISC (current_child))
+ {
+ gfloat yalign;
+
+ gtk_misc_get_alignment (GTK_MISC (current_child), NULL, &yalign);
+ gtk_misc_set_alignment (GTK_MISC (current_child), tree_column->xalign, yalign);
+ }
+
if (GTK_IS_TREE_SORTABLE (model))
gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
&sort_column_id,
@@ -2536,6 +2545,100 @@
}
/**
+ * gtk_tree_view_column_cell_set_cell_data_with_hint:
+ * @tree_column: A #GtkTreeViewColumn.
+ * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
+ * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
+ * @is_expander: %TRUE, if the row has children
+ * @is_expanded: %TRUE, if the row has visible children
+ * @hint: A #GtkTreeCellDataHint for the #GtkTreeCellDataFunc.
+ *
+ * Sets the cell renderer based on the @tree_model and @iter. That is, for
+ * every attribute mapping in @tree_column, it will get a value from the set
+ * column on the @iter, and use that value to set the attribute on the cell
+ * renderer. The @hint is a hint for the #GtkTreeCellDataFunc so that it does not
+ * have to set all cell renderer properties, possible leading to some
+ * optimizations. This is used primarily by the #GtkTreeView.
+ *
+ * Since: maemo 4.0
+ * Stability: Unstable
+ **/
+void
+gtk_tree_view_column_cell_set_cell_data_with_hint (GtkTreeViewColumn *tree_column,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gboolean is_expander,
+ gboolean is_expanded,
+ GtkTreeCellDataHint hint)
+{
+ GSList *list;
+ GValue value = { 0, };
+ GList *cell_list;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+
+ if (tree_model == NULL)
+ return;
+
+ GTK_TREE_VIEW (tree_column->tree_view)->priv->cell_data_hint = hint;
+
+ for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
+ GObject *cell = (GObject *) info->cell;
+
+ list = info->attributes;
+
+ g_object_freeze_notify (cell);
+
+ if (info->cell->is_expander != is_expander)
+ g_object_set (cell, "is-expander", is_expander, NULL);
+
+ if (info->cell->is_expanded != is_expanded)
+ g_object_set (cell, "is-expanded", is_expanded, NULL);
+
+ while (list && list->next)
+ {
+ gtk_tree_model_get_value (tree_model, iter,
+ GPOINTER_TO_INT (list->next->data),
+ &value);
+ g_object_set_property (cell, (gchar *) list->data, &value);
+ g_value_unset (&value);
+ list = list->next->next;
+ }
+
+ if (info->func)
+ (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
+ g_object_thaw_notify (G_OBJECT (info->cell));
+ }
+}
+
+/**
+ * gtk_tree_view_column_get_cell_data_hint:
+ * @tree_column: A #GtkTreeViewColumn.
+ *
+ * Returns the current value of the cell data hint as a
+ * #GtkTreeCellDataHint. Note that the value returned is only
+ * valid when called from a #GtkTreeCellDataFunc. The value of the hint
+ * tells you why the #GtkTreeView is calling the #GtkTreeCellDataFunc.
+ * Based on this hint, you can omit to generate the data and set certain
+ * cell renderer properties to improve performance.
+ *
+ * Return value: A #GtkTreeCellDataHint with the hint.
+ *
+ * Since: maemo 4.0
+ * Stability: Unstable
+ */
+GtkTreeCellDataHint
+gtk_tree_view_column_get_cell_data_hint (GtkTreeViewColumn *tree_column)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_column->tree_view), 0);
+
+ return GTK_TREE_VIEW (tree_column->tree_view)->priv->cell_data_hint;
+}
+
+/**
* gtk_tree_view_column_cell_set_cell_data:
* @tree_column: A #GtkTreeViewColumn.
* @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
@@ -2564,6 +2667,8 @@
if (tree_model == NULL)
return;
+ GTK_TREE_VIEW (tree_column->tree_view)->priv->cell_data_hint = GTK_TREE_CELL_DATA_HINT_ALL;
+
for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
--- a/gtk/gtktreeviewcolumn.h
+++ b/gtk/gtktreeviewcolumn.h
@@ -238,6 +238,25 @@
void gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column);
GtkWidget *gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column);
+/**
+ * GtkTreeCellDataHint:
+ *
+ * See gtk_tree_view_column_get_cell_data_hint().
+ **/
+typedef enum
+{
+ GTK_TREE_CELL_DATA_HINT_ALL,
+ GTK_TREE_CELL_DATA_HINT_KEY_FOCUS,
+ GTK_TREE_CELL_DATA_HINT_SENSITIVITY
+} GtkTreeCellDataHint;
+
+void gtk_tree_view_column_cell_set_cell_data_with_hint (GtkTreeViewColumn *tree_column,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gboolean is_expander,
+ gboolean is_expanded,
+ GtkTreeCellDataHint hint);
+GtkTreeCellDataHint gtk_tree_view_column_get_cell_data_hint (GtkTreeViewColumn *tree_column);
G_END_DECLS
--- a/gtk/gtktreeselection.c
+++ b/gtk/gtktreeselection.c
@@ -25,6 +25,7 @@
#include "gtkmarshalers.h"
#include "gtkintl.h"
#include "gtkalias.h"
+#include "gtkcelllayout.h"
static void gtk_tree_selection_finalize (GObject *object);
static gint gtk_tree_selection_real_select_all (GtkTreeSelection *selection);
@@ -160,12 +161,24 @@
GtkSelectionMode type)
{
GtkTreeSelectionFunc tmp_func;
+ HildonMode mode;
g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
if (selection->type == type)
return;
-
+ gtk_widget_style_get (GTK_WIDGET (selection->tree_view),
+ "hildon-mode", &mode,
+ NULL);
+
+ if (mode == HILDON_FREMANTLE
+ && selection->tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL
+ && type != GTK_SELECTION_NONE)
+ {
+ g_warning ("Cannot change the selection mode to anything other than GTK_SELECTION_NONE if hildon-ui-mode is GTK_HILDON_UI_MODE_NORMAL.\n");
+ return;
+ }
+
if (type == GTK_SELECTION_NONE)
{
/* We do this so that we unconditionally unset all rows
@@ -202,6 +215,47 @@
}
}
+ if (!selected
+ && mode == HILDON_FREMANTLE
+ && selection->tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
+ {
+ GList *rows;
+
+ /* One item must stay selected; we look for the first selected
+ * item we can find, that one becomes the anchor. We silently
+ * assume here that there is at least *one* selected row,
+ * as mandated by any new-style edit mode. When switching
+ * from SELECTION_NONE there is no selected row, and the
+ * tree view will be responsible for selecting a node.
+ */
+
+ if (anchor_path)
+ gtk_tree_path_free (anchor_path);
+
+ /* FIXME: this can be obviously optimized by walking
+ * the selection tree ourselves; or probably having a _real
+ * variant of _get_selected_rows() that we can tell to stop
+ * as soon as a selected node is found.
+ */
+ rows = gtk_tree_selection_get_selected_rows (selection, NULL);
+ if (rows)
+ {
+ anchor_path = gtk_tree_path_copy (rows->data);
+ g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (rows);
+
+ _gtk_tree_view_find_node (selection->tree_view,
+ anchor_path,
+ &tree,
+ &node);
+
+ if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ selected = TRUE;
+
+ g_return_if_fail (selected == TRUE);
+ }
+ }
+
/* We do this so that we unconditionally unset all rows
*/
tmp_func = selection->user_func;
@@ -221,6 +275,23 @@
}
selection->type = type;
+
+ if (type == GTK_SELECTION_SINGLE
+ || type == GTK_SELECTION_BROWSE)
+ {
+ GtkTreeIter iter;
+
+ /* Make sure the cursor is on a selected node */
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (selection->tree_view->priv->model,
+ &iter);
+ gtk_tree_view_set_cursor (selection->tree_view, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+ }
}
/**
@@ -1249,6 +1320,39 @@
g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
}
+static gboolean
+tree_column_is_sensitive (GtkTreeViewColumn *column,
+ GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ GList *cells, *list;
+ gboolean sensitive = TRUE;
+ gboolean visible;
+
+ gtk_tree_view_column_cell_set_cell_data_with_hint (column, model,
+ iter, FALSE, FALSE,
+ GTK_TREE_CELL_DATA_HINT_SENSITIVITY);
+
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+
+ list = cells;
+ while (list)
+ {
+ g_object_get (list->data,
+ "sensitive", &sensitive,
+ "visible", &visible,
+ NULL);
+
+ if (visible && sensitive)
+ break;
+
+ list = list->next;
+ }
+ g_list_free (cells);
+
+ return sensitive;
+}
+
gboolean
_gtk_tree_selection_row_is_selectable (GtkTreeSelection *selection,
GtkRBNode *node,
@@ -1256,6 +1360,17 @@
{
GtkTreeIter iter;
gboolean sensitive = FALSE;
+ GList *list;
+ HildonMode mode;
+
+ gtk_widget_style_get (GTK_WIDGET (selection->tree_view),
+ "hildon-mode", &mode,
+ NULL);
+
+ /* normal-mode does not support selections */
+ if (mode == HILDON_FREMANTLE
+ && selection->tree_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ return FALSE;
if (!gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path))
sensitive = TRUE;
@@ -1269,6 +1384,29 @@
return FALSE;
}
+ if (!sensitive && selection->tree_view->priv->row_header_func)
+ {
+ /* never allow separators to be selected */
+ if ((* selection->tree_view->priv->row_header_func) (selection->tree_view->priv->model,
+ &iter,
+ NULL,
+ selection->tree_view->priv->row_header_data))
+ return FALSE;
+ }
+
+ for (list = selection->tree_view->priv->columns; list && !sensitive; list = list->next)
+ {
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
+
+ if (!column->visible)
+ continue;
+
+ sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter);
+ }
+
+ if (!sensitive)
+ return FALSE;
+
if (selection->user_func)
return (*selection->user_func) (selection, selection->tree_view->priv->model, path,
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED),
@@ -1453,6 +1591,11 @@
path = _gtk_tree_view_find_path (selection->tree_view, tree, node);
toggle = _gtk_tree_selection_row_is_selectable (selection, node, path);
gtk_tree_path_free (path);
+
+ /* Allow unselecting an insensitive row */
+ if (!toggle && !select
+ && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
+ toggle = TRUE;
}
if (toggle)