3596 lines
111 KiB
Diff
3596 lines
111 KiB
Diff
|
--- 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)
|