GdkEventButton *event);
static gboolean pspp_sheet_view_grab_broken (GtkWidget *widget,
GdkEventGrabBroken *event);
-#if 0
-static gboolean pspp_sheet_view_configure (GtkWidget *widget,
- GdkEventConfigure *event);
-#endif
static void pspp_sheet_view_set_focus_child (GtkContainer *container,
GtkWidget *child);
gint height);
static gboolean pspp_sheet_view_start_editing (PsppSheetView *tree_view,
GtkTreePath *cursor_path);
+static gboolean pspp_sheet_view_editable_button_press_event (GtkWidget *,
+ GdkEventButton *,
+ PsppSheetView *);
+static void pspp_sheet_view_editable_clicked (GtkButton *, PsppSheetView *);
static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view,
PsppSheetViewColumn *column,
GtkTreePath *path,
static PsppSheetViewColumn *pspp_sheet_view_get_drop_column (PsppSheetView *tree_view,
PsppSheetViewColumn *column,
gint drop_position);
+static void
+pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view,
+ PsppSheetViewColumn *column,
+ const GdkRectangle *background_area,
+ gboolean subtract_focus_rect,
+ GdkRectangle *cell_area);
static gint pspp_sheet_view_find_offset (PsppSheetView *tree_view,
gint height,
int *new_node);
* Enables of disables the hover selection mode of @tree_view.
* Hover selection makes the selected row follow the pointer.
* Currently, this works only for the selection modes
- * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
+ * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
*
* This mode is primarily intended for treeviews in popups, e.g.
* in #GtkComboBox or #GtkEntryCompletion.
0, G_MAXINT, 1,
GTK_PARAM_READABLE));
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_string ("grid-line-pattern",
- P_("Grid line pattern"),
- P_("Dash pattern used to draw the tree view grid lines"),
- "\1\1",
- GTK_PARAM_READABLE));
-
gtk_widget_class_install_style_property (widget_class,
g_param_spec_string ("tree-line-pattern",
P_("Tree line pattern"),
tree_view->priv->prelight_node = -1;
tree_view->priv->rubber_band_start_node = -1;
tree_view->priv->rubber_band_end_node = -1;
+
+ tree_view->priv->anchor_column = NULL;
}
\f
return node > 0 ? node - 1 : -1;
}
+static gboolean
+all_columns_selected (PsppSheetView *tree_view)
+{
+ GList *list;
+
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ PsppSheetViewColumn *column = list->data;
+ if (column->selectable && !column->selected)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+pspp_sheet_view_row_head_clicked (PsppSheetView *tree_view,
+ gint node,
+ PsppSheetViewColumn *column,
+ GdkEventButton *event)
+{
+ PsppSheetSelection *selection;
+ PsppSheetSelectionMode mode;
+ GtkTreePath *path;
+ gboolean update_anchor;
+ gboolean handled;
+ guint modifiers;
+
+ g_return_val_if_fail (tree_view != NULL, FALSE);
+ g_return_val_if_fail (column != NULL, FALSE);
+
+ selection = tree_view->priv->selection;
+ mode = pspp_sheet_selection_get_mode (selection);
+ if (mode != PSPP_SHEET_SELECTION_RECTANGLE)
+ return FALSE;
+
+ if (!column->row_head)
+ return FALSE;
+
+ if (event)
+ {
+ modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+ if (event->type != GDK_BUTTON_PRESS
+ || (modifiers != GDK_CONTROL_MASK && modifiers != GDK_SHIFT_MASK))
+ return FALSE;
+ }
+ else
+ modifiers = 0;
+
+ path = gtk_tree_path_new_from_indices (node, -1);
+ if (event == NULL)
+ {
+ pspp_sheet_selection_unselect_all (selection);
+ pspp_sheet_selection_select_path (selection, path);
+ pspp_sheet_selection_select_all_columns (selection);
+ update_anchor = TRUE;
+ handled = TRUE;
+ }
+ else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+ {
+ if (pspp_sheet_selection_count_selected_rows (selection) <= 1
+ || !all_columns_selected (tree_view))
+ {
+ pspp_sheet_selection_unselect_all (selection);
+ pspp_sheet_selection_select_path (selection, path);
+ pspp_sheet_selection_select_all_columns (selection);
+ update_anchor = TRUE;
+ handled = FALSE;
+ }
+ else
+ update_anchor = handled = FALSE;
+ }
+ else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+ && modifiers == GDK_CONTROL_MASK)
+ {
+ if (!all_columns_selected (tree_view))
+ {
+ pspp_sheet_selection_unselect_all (selection);
+ pspp_sheet_selection_select_all_columns (selection);
+ }
+
+ if (pspp_sheet_selection_path_is_selected (selection, path))
+ pspp_sheet_selection_unselect_path (selection, path);
+ else
+ pspp_sheet_selection_select_path (selection, path);
+ update_anchor = TRUE;
+ handled = TRUE;
+ }
+ else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+ && modifiers == GDK_SHIFT_MASK)
+ {
+ GtkTreeRowReference *anchor = tree_view->priv->anchor;
+ GtkTreePath *anchor_path;
+
+ if (all_columns_selected (tree_view)
+ && gtk_tree_row_reference_valid (anchor))
+ {
+ update_anchor = FALSE;
+ anchor_path = gtk_tree_row_reference_get_path (anchor);
+ }
+ else
+ {
+ update_anchor = TRUE;
+ anchor_path = gtk_tree_path_copy (path);
+ }
+
+ pspp_sheet_selection_unselect_all (selection);
+ pspp_sheet_selection_select_range (selection, anchor_path, path);
+ pspp_sheet_selection_select_all_columns (selection);
+
+ gtk_tree_path_free (anchor_path);
+
+ handled = TRUE;
+ }
+ else
+ update_anchor = handled = FALSE;
+
+ if (update_anchor)
+ {
+ if (tree_view->priv->anchor)
+ gtk_tree_row_reference_free (tree_view->priv->anchor);
+ tree_view->priv->anchor =
+ gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+ tree_view->priv->model,
+ path);
+ }
+
+ gtk_tree_path_free (path);
+ return handled;
+}
+
+static gboolean
+find_click (PsppSheetView *tree_view,
+ gint x, gint y,
+ gint *node,
+ PsppSheetViewColumn **column,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area)
+{
+ gint y_offset;
+ gboolean rtl;
+ GList *list;
+ gint new_y;
+
+ /* find the node that was clicked */
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, y);
+ if (new_y < 0)
+ new_y = 0;
+ y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, node);
+
+ if (*node < 0)
+ return FALSE;
+
+ background_area->y = y_offset + y;
+ background_area->height = ROW_HEIGHT (tree_view);
+ background_area->x = 0;
+
+ /* Let the column have a chance at selecting it. */
+ 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))
+ {
+ PsppSheetViewColumn *candidate = list->data;
+
+ if (!candidate->visible)
+ continue;
+
+ background_area->width = candidate->width;
+ if ((background_area->x > x) ||
+ (background_area->x + background_area->width <= x))
+ {
+ background_area->x += background_area->width;
+ continue;
+ }
+
+ /* we found the focus column */
+
+ pspp_sheet_view_adjust_cell_area (tree_view, candidate, background_area,
+ TRUE, cell_area);
+ *column = candidate;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static gboolean
pspp_sheet_view_button_press (GtkWidget *widget,
GdkEventButton *event)
gint i;
GdkRectangle background_area;
GdkRectangle cell_area;
- gint vertical_separator;
- gint horizontal_separator;
gboolean rtl;
rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
pspp_sheet_view_stop_editing (tree_view, FALSE);
- gtk_widget_style_get (widget,
- "vertical-separator", &vertical_separator,
- "horizontal-separator", &horizontal_separator,
- NULL);
/* Because grab_focus can cause reentrancy, we delay grab_focus until after
{
int node;
GtkTreePath *path;
- gchar *path_string;
- gint depth;
- gint new_y;
- gint y_offset;
gint dval;
gint pre_val, aft_val;
PsppSheetViewColumn *column = NULL;
GtkCellRenderer *focus_cell = NULL;
- gint column_handled_click = FALSE;
gboolean row_double_click = FALSE;
- gboolean rtl;
gboolean node_selected;
/* Empty tree? */
return TRUE;
}
- /* find the node that was clicked */
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
- if (new_y < 0)
- new_y = 0;
- y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
- if (node < 0)
- {
- /* We clicked in dead space */
- grab_focus_and_unset_draw_keyfocus (tree_view);
- return TRUE;
- }
-
- /* Get the path and the node */
- path = _pspp_sheet_view_find_path (tree_view, node);
-
- depth = gtk_tree_path_get_depth (path);
- background_area.y = y_offset + event->y;
- background_area.height = ROW_HEIGHT (tree_view);
- background_area.x = 0;
-
-
- /* Let the column have a chance at selecting it. */
- 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))
- {
- PsppSheetViewColumn *candidate = list->data;
-
- if (!candidate->visible)
- continue;
-
- background_area.width = candidate->width;
- if ((background_area.x > (gint) event->x) ||
- (background_area.x + background_area.width <= (gint) event->x))
- {
- background_area.x += background_area.width;
- continue;
- }
-
- /* we found the focus column */
- column = candidate;
- cell_area = background_area;
- cell_area.width -= horizontal_separator;
- cell_area.height -= vertical_separator;
- cell_area.x += horizontal_separator/2;
- cell_area.y += vertical_separator/2;
- break;
- }
-
- if (column == NULL)
- {
- gtk_tree_path_free (path);
+ if (!find_click (tree_view, event->x, event->y, &node, &column,
+ &background_area, &cell_area))
+ {
grab_focus_and_unset_draw_keyfocus (tree_view);
- return FALSE;
- }
+ return FALSE;
+ }
tree_view->priv->focus_column = column;
- /* decide if we edit */
- if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
- !(event->state & gtk_accelerator_get_default_mod_mask ()))
- {
- GtkTreePath *anchor;
- GtkTreeIter iter;
-
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- if (tree_view->priv->anchor)
- anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
- else
- anchor = NULL;
-
- if ((anchor && !gtk_tree_path_compare (anchor, path))
- || !_pspp_sheet_view_column_has_editable_cell (column))
- {
- GtkCellEditable *cell_editable = NULL;
-
- /* FIXME: get the right flags */
- guint flags = 0;
-
- path_string = gtk_tree_path_to_string (path);
-
- if (_pspp_sheet_view_column_cell_event (column,
- &cell_editable,
- (GdkEvent *)event,
- path_string,
- &background_area,
- &cell_area, flags))
- {
- if (cell_editable != NULL)
- {
- gint left, right;
- GdkRectangle area;
-
- area = cell_area;
- _pspp_sheet_view_column_get_neighbor_sizes (column, _pspp_sheet_view_column_get_edited_cell (column), &left, &right);
-
- area.x += left;
- area.width -= right + left;
-
- pspp_sheet_view_real_start_editing (tree_view,
- column,
- path,
- cell_editable,
- &area,
- (GdkEvent *)event,
- flags);
- g_free (path_string);
- gtk_tree_path_free (path);
- gtk_tree_path_free (anchor);
- return TRUE;
- }
- column_handled_click = TRUE;
- }
- g_free (path_string);
- }
- if (anchor)
- gtk_tree_path_free (anchor);
- }
+ if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event))
+ return TRUE;
/* select */
node_selected = pspp_sheet_view_node_is_selected (tree_view, node);
pre_val = tree_view->priv->vadjustment->value;
+ path = _pspp_sheet_view_find_path (tree_view, node);
+
/* we only handle selection modifications on the first button press
*/
if (event->type == GDK_BUTTON_PRESS)
}
else if (event->state & GDK_SHIFT_MASK)
{
- pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE);
pspp_sheet_view_real_select_cursor_row (tree_view, FALSE);
}
else
pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE);
}
+ if (tree_view->priv->anchor_column == NULL ||
+ !(event->state & GDK_SHIFT_MASK))
+ tree_view->priv->anchor_column = column;
+ pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+ pspp_sheet_selection_select_column_range (tree_view->priv->selection,
+ tree_view->priv->anchor_column,
+ column);
+
tree_view->priv->ctrl_pressed = FALSE;
tree_view->priv->shift_pressed = FALSE;
}
/* Save press to possibly begin a drag
*/
- if (!column_handled_click &&
- !tree_view->priv->in_grab &&
+ if (!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;
+ tree_view->priv->press_start_node = node;
if (tree_view->priv->rubber_banding_enable
- && !node_selected
- && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ //&& !node_selected
+ && (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+ tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE))
{
tree_view->priv->press_start_y += tree_view->priv->dy;
tree_view->priv->rubber_band_x = event->x;
tree_view->priv->rubber_band_ctrl = TRUE;
if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
tree_view->priv->rubber_band_shift = TRUE;
+
}
}
return TRUE;
}
+static gboolean
+pspp_sheet_view_button_release_edit (PsppSheetView *tree_view,
+ GdkEventButton *event)
+{
+ GtkCellEditable *cell_editable;
+ gchar *path_string;
+ GtkTreePath *path;
+ gint left, right;
+ GtkTreeIter iter;
+ PsppSheetViewColumn *column;
+ GdkRectangle background_area;
+ GdkRectangle cell_area;
+ GdkRectangle area;
+ guint modifiers;
+ guint flags;
+ int node;
+
+ if (event->window != tree_view->priv->bin_window)
+ return FALSE;
+
+ if (!find_click (tree_view, event->x, event->y, &node, &column, &background_area,
+ &cell_area))
+ return FALSE;
+
+ /* decide if we edit */
+ path = _pspp_sheet_view_find_path (tree_view, node);
+ modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+ if (event->button != 1 || modifiers)
+ return FALSE;
+
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+ pspp_sheet_view_column_cell_set_cell_data (column,
+ tree_view->priv->model,
+ &iter);
+
+ if (!pspp_sheet_view_column_get_quick_edit (column)
+ && _pspp_sheet_view_column_has_editable_cell (column))
+ return FALSE;
+
+ flags = 0; /* FIXME: get the right flags */
+ path_string = gtk_tree_path_to_string (path);
+
+ if (!_pspp_sheet_view_column_cell_event (column,
+ &cell_editable,
+ (GdkEvent *)event,
+ path_string,
+ &background_area,
+ &cell_area, flags))
+ return FALSE;
+
+ if (cell_editable == NULL)
+ return FALSE;
+
+ pspp_sheet_view_real_set_cursor (tree_view, path,
+ TRUE, TRUE);
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
+ area = cell_area;
+ _pspp_sheet_view_column_get_neighbor_sizes (
+ column, _pspp_sheet_view_column_get_edited_cell (column), &left, &right);
+
+ area.x += left;
+ area.width -= right + left;
+
+ pspp_sheet_view_real_start_editing (tree_view,
+ column,
+ path,
+ cell_editable,
+ &area,
+ (GdkEvent *)event,
+ flags);
+ g_free (path_string);
+ gtk_tree_path_free (path);
+ return TRUE;
+}
+
static gboolean
pspp_sheet_view_button_release (GtkWidget *widget,
GdkEventButton *event)
{
PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
+ pspp_sheet_view_stop_editing (tree_view, FALSE);
+ if (tree_view->priv->rubber_band_status != RUBBER_BAND_ACTIVE
+ && pspp_sheet_view_button_release_edit (tree_view, event))
+ {
+ if (tree_view->priv->pressed_button == event->button)
+ tree_view->priv->pressed_button = -1;
+
+ tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
+ return TRUE;
+ }
+
if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
return pspp_sheet_view_button_release_drag_column (widget, event);
return TRUE;
}
-#if 0
-static gboolean
-pspp_sheet_view_configure (GtkWidget *widget,
- GdkEventConfigure *event)
-{
- PsppSheetView *tree_view;
-
- tree_view = PSPP_SHEET_VIEW (widget);
- tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
-
- return FALSE;
-}
-#endif
-
/* GtkWidget::motion_event function set.
*/
gint x,
gint y)
{
- GtkSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
+ PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
if (tree_view->priv->hover_selection &&
- (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
+ (mode == PSPP_SHEET_SELECTION_SINGLE || mode == PSPP_SHEET_SELECTION_BROWSE) &&
!(tree_view->priv->edited_column &&
tree_view->priv->edited_column->editable_widget))
{
}
}
- else if (mode == GTK_SELECTION_SINGLE)
+ else if (mode == PSPP_SHEET_SELECTION_SINGLE)
pspp_sheet_selection_unselect_all (tree_view->priv->selection);
}
GdkRectangle new_area;
GdkRectangle common;
GdkRegion *invalid_region;
+ PsppSheetViewColumn *column;
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;
tree_view->priv->rubber_band_x = x;
tree_view->priv->rubber_band_y = y;
+ pspp_sheet_view_get_path_at_pos (tree_view, x, y, NULL, &column, NULL, NULL);
+
+ pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+ pspp_sheet_selection_select_column_range (tree_view->priv->selection,
+ tree_view->priv->anchor_column,
+ column);
+
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
pspp_sheet_view_update_rubber_band_selection (tree_view);
}
GdkRectangle rect;
GdkRectangle rubber_rect;
+ return;
rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
{
+ GdkRectangle background_area, cell_area;
+ PsppSheetViewColumn *column;
+
+ if (find_click (tree_view, event->x, event->y, &node, &column,
+ &background_area, &cell_area)
+ && tree_view->priv->focus_column == column
+ && tree_view->priv->press_start_node == node)
+ return FALSE;
+
gtk_grab_add (GTK_WIDGET (tree_view));
pspp_sheet_view_update_rubber_band (tree_view);
GList *list = tree_view->priv->columns;
gint i = 0;
gint current_x = 0;
+ gint height;
if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
&& tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_BOTH)
return;
+ gdk_drawable_get_size (event->window, NULL, &height);
+
/* Only draw the lines for visible rows and columns */
for (list = tree_view->priv->columns; list; list = list->next, i++)
{
current_x += column->width;
- gdk_draw_line (event->window,
- tree_view->priv->grid_line_gc,
- current_x - 1, 0,
- current_x - 1, tree_view->priv->height);
+ if (current_x - 1 >= event->area.x
+ && current_x - 1 < event->area.x + event->area.width)
+ gdk_draw_line (event->window,
+ tree_view->priv->grid_line_gc,
+ current_x - 1, 0,
+ current_x - 1, height);
}
}
gboolean is_first = FALSE;
gboolean is_last = FALSE;
gboolean done = FALSE;
+ gboolean selected;
max_height = ROW_HEIGHT (tree_view);
if (node == tree_view->priv->prelight_node)
flags |= GTK_CELL_RENDERER_PRELIT;
- if (pspp_sheet_view_node_is_selected (tree_view, node))
- flags |= GTK_CELL_RENDERER_SELECTED;
+ selected = pspp_sheet_view_node_is_selected (tree_view, node);
parity = node % 2;
{
PsppSheetViewColumn *column = list->data;
const gchar *detail = NULL;
+ gboolean selected_column;
GtkStateType state;
if (!column->visible)
continue;
+ if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
+ selected_column = column->selected && column->selectable;
+ else
+ selected_column = TRUE;
+
if (cell_offset > event->area.x + event->area.width ||
cell_offset + column->width < event->area.x)
{
continue;
}
+ if (selected && selected_column)
+ flags |= GTK_CELL_RENDERER_SELECTED;
+ else
+ flags &= ~GTK_CELL_RENDERER_SELECTED;
+
if (column->show_sort_indicator)
flags |= GTK_CELL_RENDERER_SORTED;
else
{
PsppSheetView *tree_view = data;
+ pspp_sheet_view_horizontal_autoscroll (tree_view);
pspp_sheet_view_vertical_autoscroll (tree_view);
if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
/* This function returns in 'path' the first focusable path, if the given path
* is already focusable, it's the returned one.
+ *
*/
static gboolean
search_first_focusable_path (PsppSheetView *tree_view,
gboolean search_forward,
int *new_node)
{
+ /* XXX this function is trivial given that the sheetview doesn't support
+ separator rows */
int node = -1;
if (!path || !*path)
if (cursor_path == NULL)
{
- /* Consult the selection before defaulting to the
- * first focusable element
+ /* There's no cursor. Move the cursor to the first selected row, if any
+ * are selected, otherwise to the first row in the sheetview.
*/
GList *selected_rows;
GtkTreeModel *model;
if (selected_rows)
{
+ /* XXX we could avoid doing O(n) work to get this result */
cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
g_list_free (selected_rows);
if (cursor_path)
{
- if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+ tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
else
pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
if (cursor_path)
{
+ /* Now find a column for the cursor. */
PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
if (PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
{
tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (list->data);
+ pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+ pspp_sheet_selection_select_column (tree_view->priv->selection, tree_view->priv->focus_column);
break;
}
}
+
}
}
}
selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection);
if (selection_count == 0
- && tree_view->priv->selection->type != GTK_SELECTION_NONE
+ && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE
&& !tree_view->priv->ctrl_pressed)
{
/* Don't move the cursor, but just select the current node */
* If the list has only one item and multi-selection is set then select
* the row (if not yet selected).
*/
- if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
+ if ((tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+ tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) &&
new_cursor_node < 0)
{
if (count == -1)
if (found_column)
{
- if (!pspp_sheet_view_has_special_cell (tree_view))
- _pspp_sheet_view_queue_draw_node (tree_view,
- cursor_node,
- NULL);
+ _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
return FALSE;
- if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+ if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+ tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
return FALSE;
pspp_sheet_selection_select_all (tree_view->priv->selection);
if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
return FALSE;
- if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+ if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+ tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
return FALSE;
pspp_sheet_selection_unselect_all (tree_view->priv->selection);
g_object_notify (G_OBJECT (tree_view), "reorderable");
}
+/* If CLEAR_AND_SELECT is true, then the row will be selected and, unless Shift
+ is pressed, other rows will be unselected.
+
+ If CLAMP_NODE is true, then the sheetview will scroll to make the row
+ visible. */
static void
pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view,
GtkTreePath *path,
pspp_sheet_view_column_focus_cell (focus_column, focus_cell);
if (start_editing)
pspp_sheet_view_start_editing (tree_view, path);
+
+ pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+ pspp_sheet_selection_select_column (tree_view->priv->selection, focus_column);
+
}
}
return TRUE;
}
+/* Computes 'cell_area' from 'background_area', which must be the background
+ area for a cell. Set 'subtract_focus_rect' to TRUE to compute the cell area
+ as passed to a GtkCellRenderer's "render" function, or to FALSE to compute
+ the cell area as passed to _pspp_sheet_view_column_cell_render().
+
+ 'column' is required to properly adjust 'cell_area->x' and
+ 'cell_area->width'. It may be set to NULL if these values are not of
+ interest. In this case 'cell_area->x' and 'cell_area->width' will be
+ returned as 0. */
+static void
+pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view,
+ PsppSheetViewColumn *column,
+ const GdkRectangle *background_area,
+ gboolean subtract_focus_rect,
+ GdkRectangle *cell_area)
+{
+ gint vertical_separator;
+ gint horizontal_separator;
+
+ *cell_area = *background_area;
+
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "vertical-separator", &vertical_separator,
+ "horizontal-separator", &horizontal_separator,
+ NULL);
+ cell_area->x += horizontal_separator / 2;
+ cell_area->y += vertical_separator / 2;
+ cell_area->width -= horizontal_separator;
+ cell_area->height -= vertical_separator;
+
+ if (subtract_focus_rect)
+ {
+ int focus_line_width;
+
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "focus-line-width", &focus_line_width,
+ NULL);
+ cell_area->x += focus_line_width;
+ cell_area->y += focus_line_width;
+ cell_area->width -= 2 * focus_line_width;
+ cell_area->height -= 2 * focus_line_width;
+ }
+
+ if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE)
+ {
+ gint grid_line_width;
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "grid-line-width", &grid_line_width,
+ NULL);
+
+ if ((tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
+ || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
+ && column != NULL)
+ {
+ PsppSheetViewColumn *first_column, *last_column;
+ GList *list;
+
+ /* Find the last visible column. */
+ last_column = NULL;
+ for (list = g_list_last (tree_view->priv->columns);
+ list;
+ list = list->prev)
+ {
+ PsppSheetViewColumn *c = list->data;
+ if (c->visible)
+ {
+ last_column = c;
+ break;
+ }
+ }
+
+ /* Find the first visible column. */
+ first_column = NULL;
+ for (list = g_list_first (tree_view->priv->columns);
+ list;
+ list = list->next)
+ {
+ PsppSheetViewColumn *c = list->data;
+ if (c->visible)
+ {
+ first_column = c;
+ break;
+ }
+ }
+
+ if (column == first_column)
+ {
+ cell_area->width -= grid_line_width / 2;
+ }
+ else if (column == last_column)
+ {
+ cell_area->x += grid_line_width / 2;
+ cell_area->width -= grid_line_width / 2;
+ }
+ else
+ {
+ cell_area->x += grid_line_width / 2;
+ cell_area->width -= grid_line_width;
+ }
+ }
+
+ if (tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
+ || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
+ {
+ cell_area->y += grid_line_width / 2;
+ cell_area->height -= grid_line_width;
+ }
+ }
+
+ if (column == NULL)
+ {
+ cell_area->x = 0;
+ cell_area->width = 0;
+ }
+}
/**
* pspp_sheet_view_get_cell_area:
PsppSheetViewColumn *column,
GdkRectangle *rect)
{
- int node = -1;
- gint vertical_separator;
- gint horizontal_separator;
+ GdkRectangle background_area;
g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "vertical-separator", &vertical_separator,
- "horizontal-separator", &horizontal_separator,
- NULL);
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 0;
- rect->height = 0;
-
- if (column)
- {
- rect->x = column->button->allocation.x + horizontal_separator/2;
- rect->width = column->button->allocation.width - horizontal_separator;
- }
-
- if (path)
- {
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- /* Get vertical coords */
- if (node < 0)
- return;
-
- rect->y = CELL_FIRST_PIXEL (tree_view, node, vertical_separator);
- rect->height = MAX (CELL_HEIGHT (tree_view, vertical_separator), tree_view->priv->expander_size - vertical_separator);
- }
+ pspp_sheet_view_get_background_area (tree_view, path, column,
+ &background_area);
+ pspp_sheet_view_adjust_cell_area (tree_view, column, &background_area,
+ FALSE, rect);
}
/**
g_signal_handlers_disconnect_by_func (cell_editable,
pspp_sheet_view_remove_widget,
tree_view);
+ g_signal_handlers_disconnect_by_func (cell_editable,
+ pspp_sheet_view_editable_button_press_event,
+ tree_view);
+ g_signal_handlers_disconnect_by_func (cell_editable,
+ pspp_sheet_view_editable_clicked,
+ tree_view);
gtk_container_remove (GTK_CONTAINER (tree_view),
GTK_WIDGET (cell_editable));
return retval;
}
+static gboolean
+pspp_sheet_view_editable_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ PsppSheetView *sheet_view)
+{
+ gint node;
+
+ node = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
+ "pspp-sheet-view-node"));
+ return pspp_sheet_view_row_head_clicked (sheet_view,
+ node,
+ sheet_view->priv->edited_column,
+ event);
+}
+
+static void
+pspp_sheet_view_editable_clicked (GtkButton *button,
+ PsppSheetView *sheet_view)
+{
+ pspp_sheet_view_editable_button_press_event (GTK_WIDGET (button), NULL,
+ sheet_view);
+}
+
static void
pspp_sheet_view_real_start_editing (PsppSheetView *tree_view,
PsppSheetViewColumn *column,
GdkEvent *event,
guint flags)
{
+ PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
gint pre_val = tree_view->priv->vadjustment->value;
GtkRequisition requisition;
pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE);
cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
+ pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+ pspp_sheet_selection_select_column (tree_view->priv->selection, column);
+ tree_view->priv->anchor_column = column;
+
gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
g_signal_connect (cell_editable, "remove-widget",
G_CALLBACK (pspp_sheet_view_remove_widget), tree_view);
+ if (mode == PSPP_SHEET_SELECTION_RECTANGLE && column->row_head &&
+ GTK_IS_BUTTON (cell_editable))
+ {
+ g_signal_connect (cell_editable, "button-press-event",
+ G_CALLBACK (pspp_sheet_view_editable_button_press_event),
+ tree_view);
+ g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node",
+ GINT_TO_POINTER (gtk_tree_path_get_indices (path)[0]));
+ g_signal_connect (cell_editable, "clicked",
+ G_CALLBACK (pspp_sheet_view_editable_clicked),
+ tree_view);
+ }
}
static void
* Enables of disables the hover selection mode of @tree_view.
* Hover selection makes the selected row follow the pointer.
* Currently, this works only for the selection modes
- * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
+ * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
*
* Since: 2.6
**/
* @tree_view: a #PsppSheetView
* @enable: %TRUE to enable rubber banding
*
- * Enables or disables rubber banding in @tree_view. If the selection mode
- * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
- * multiple rows by dragging the mouse.
+ * Enables or disables rubber banding in @tree_view. If the selection mode is
+ * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, rubber
+ * banding will allow the user to select multiple rows by dragging the mouse.
*
* Since: 2.10
**/
* @tree_view: a #PsppSheetView
*
* Returns whether rubber banding is turned on for @tree_view. If the
- * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
- * user to select multiple rows by dragging the mouse.
+ * selection mode is #PSPP_SHEET_SELECTION_MULTIPLE or
+ * #PSPP_SHEET_SELECTION_RECTANGLE, rubber banding will allow the user to
+ * select multiple rows by dragging the mouse.
*
* Return value: %TRUE if rubber banding in @tree_view is enabled.
*
!priv->grid_line_gc)
{
gint line_width;
- gint8 *dash_list;
gtk_widget_style_get (widget,
"grid-line-width", &line_width,
- "grid-line-pattern", (gchar *)&dash_list,
NULL);
priv->grid_line_gc = gdk_gc_new (widget->window);
gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
-
- gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
- GDK_LINE_ON_OFF_DASH,
- GDK_CAP_BUTT, GDK_JOIN_MITER);
- gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
-
- g_free (dash_list);
}
}