X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fgtk-contrib%2Fpsppire-sheet.c;fp=lib%2Fgtk-contrib%2Fpsppire-sheet.c;h=0000000000000000000000000000000000000000;hb=83d072f018123f29af27a730a9ac2653ca67eea8;hp=ecadf742cbb9e0b874bf207ecaeae832072e17b9;hpb=0fe886a656b0ee57b4d542b7c16b3c56288b6fc6;p=pspp diff --git a/lib/gtk-contrib/psppire-sheet.c b/lib/gtk-contrib/psppire-sheet.c deleted file mode 100644 index ecadf742cb..0000000000 --- a/lib/gtk-contrib/psppire-sheet.c +++ /dev/null @@ -1,4882 +0,0 @@ -/* - Copyright (C) 2006, 2008, 2009, 2011 Free Software Foundation - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - - This file is derived from the gtksheet.c and extensively modified for the - requirements of PSPPIRE. The changes are copyright by the - Free Software Foundation. The copyright notice for the original work is - below. -*/ - -/* GtkSheet widget for Gtk+. - * Copyright (C) 1999-2001 Adrian E. Feiguin - * - * Based on GtkClist widget by Jay Painter, but major changes. - * Memory allocation routines inspired on SC (Spreadsheet Calculator) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * SECTION:psppiresheet - * @short_description: spreadsheet widget for gtk2 - * - * PsppireSheet is a matrix widget for GTK+. It consists of an scrollable grid of - * cells where you can allocate text. Cell contents can be edited interactively - * through a specially designed entry, GtkItemEntry. - * - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "psppire-sheet.h" -#include -#include -#include -#include - -/* sheet flags */ -enum - { - PSPPIRE_SHEET_IN_XDRAG = 1 << 1, - PSPPIRE_SHEET_IN_YDRAG = 1 << 2, - PSPPIRE_SHEET_IN_DRAG = 1 << 3, - - /* This flag is set when the user is actually in the process - of making a selection - ie while the mouse button is - depressed. - */ - PSPPIRE_SHEET_IN_SELECTION = 1 << 4 - }; - -#define PSPPIRE_SHEET_FLAGS(sheet) (PSPPIRE_SHEET (sheet)->flags) -#define PSPPIRE_SHEET_SET_FLAGS(sheet,flag) (PSPPIRE_SHEET_FLAGS (sheet) |= (flag)) -#define PSPPIRE_SHEET_UNSET_FLAGS(sheet,flag) (PSPPIRE_SHEET_FLAGS (sheet) &= ~ (flag)) - -#define PSPPIRE_SHEET_IN_XDRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_XDRAG) -#define PSPPIRE_SHEET_IN_YDRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_YDRAG) -#define PSPPIRE_SHEET_IN_DRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_DRAG) -#define PSPPIRE_SHEET_IN_SELECTION(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_SELECTION) - -#define CELL_SPACING 1 - -#define TIMEOUT_HOVER 300 -#define COLUMN_MIN_WIDTH 10 -#define COLUMN_TITLES_HEIGHT 4 -#define DEFAULT_COLUMN_WIDTH 80 -#define DEFAULT_ROW_HEIGHT 25 - -static void set_entry_widget_font (PsppireSheet *sheet); - -static void psppire_sheet_update_primary_selection (PsppireSheet *sheet); -static void draw_column_title_buttons_range (PsppireSheet *sheet, gint first, gint n); -static void draw_row_title_buttons_range (PsppireSheet *sheet, gint first, gint n); -static void redraw_range (PsppireSheet *sheet, PsppireSheetRange *range); - - -static void set_row_height (PsppireSheet *sheet, - gint row, - gint height); - -static void destroy_hover_window (PsppireSheetHoverTitle *); -static PsppireSheetHoverTitle *create_hover_window (void); - -static inline void -dispose_string (const PsppireSheet *sheet, gchar *text) -{ - PsppireSheetModel *model = psppire_sheet_get_model (sheet); - - if ( ! model ) - return; - - if (psppire_sheet_model_free_strings (model)) - g_free (text); -} - - -/* FIXME: Why bother with these two ? */ - -/* returns the column index from a pixel location */ -static inline gint -column_from_xpixel (const PsppireSheet *sheet, gint pixel) -{ - return psppire_axis_unit_at_pixel (sheet->haxis, pixel); -} - -static inline gint -row_from_ypixel (const PsppireSheet *sheet, gint pixel) -{ - return psppire_axis_unit_at_pixel (sheet->vaxis, pixel); -} - - -/* Return the lowest row number which is wholly or partially on - the visible range of the sheet */ -static inline glong -min_visible_row (const PsppireSheet *sheet) -{ - return row_from_ypixel (sheet, sheet->vadjustment->value); -} - -static inline glong -min_fully_visible_row (const PsppireSheet *sheet) -{ - glong row = min_visible_row (sheet); - - if ( psppire_axis_start_pixel (sheet->vaxis, row) < sheet->vadjustment->value) - row++; - - return row; -} - -static inline glong -max_visible_row (const PsppireSheet *sheet) -{ - return row_from_ypixel (sheet, sheet->vadjustment->value + sheet->vadjustment->page_size); -} - - -static inline glong -max_fully_visible_row (const PsppireSheet *sheet) -{ - glong row = max_visible_row (sheet); - - if ( psppire_axis_start_pixel (sheet->vaxis, row) - + - psppire_axis_unit_size (sheet->vaxis, row) - > sheet->vadjustment->value) - row--; - - return row; -} - - -/* Returns the lowest column number which is wholly or partially - on the sheet */ -static inline glong -min_visible_column (const PsppireSheet *sheet) -{ - return column_from_xpixel (sheet, sheet->hadjustment->value); -} - -static inline glong -min_fully_visible_column (const PsppireSheet *sheet) -{ - glong col = min_visible_column (sheet); - - if ( psppire_axis_start_pixel (sheet->haxis, col) < sheet->hadjustment->value) - col++; - - return col; -} - - -/* Returns the highest column number which is wholly or partially - on the sheet */ -static inline glong -max_visible_column (const PsppireSheet *sheet) -{ - return column_from_xpixel (sheet, sheet->hadjustment->value + sheet->hadjustment->page_size); -} - -static inline glong -max_fully_visible_column (const PsppireSheet *sheet) -{ - glong col = max_visible_column (sheet); - - if ( psppire_axis_start_pixel (sheet->haxis, col) - + - psppire_axis_unit_size (sheet->haxis, col) - > sheet->hadjustment->value) - col--; - - return col; -} - - - -/* The size of the region (in pixels) around the row/column boundaries - where the height/width may be grabbed to change size */ -#define DRAG_WIDTH 6 - -static gboolean -on_column_boundary (const PsppireSheet *sheet, gint x, gint *column) -{ - gint col; - gint pixel; - - x += sheet->hadjustment->value; - - if ( x < 0) - return FALSE; - - col = column_from_xpixel (sheet, x); - - pixel = x - DRAG_WIDTH / 2; - if (pixel < 0) - pixel = 0; - - if ( column_from_xpixel (sheet, pixel) < col ) - { - *column = col - 1; - return TRUE; - } - - if ( column_from_xpixel (sheet, x + DRAG_WIDTH / 2) > col ) - { - *column = col; - return TRUE; - } - - return FALSE; -} - -static gboolean -on_row_boundary (const PsppireSheet *sheet, gint y, gint *row) -{ - gint r; - gint pixel; - - y += sheet->vadjustment->value; - - if ( y < 0) - return FALSE; - - r = row_from_ypixel (sheet, y); - - pixel = y - DRAG_WIDTH / 2; - if (pixel < 0) - pixel = 0; - - if ( row_from_ypixel (sheet, pixel) < r ) - { - *row = r - 1; - return TRUE; - } - - if ( row_from_ypixel (sheet, y + DRAG_WIDTH / 2) > r ) - { - *row = r; - return TRUE; - } - - return FALSE; -} - - -static inline gboolean -POSSIBLE_DRAG (const PsppireSheet *sheet, gint x, gint y, - gint *drag_row, gint *drag_column) -{ - gint ydrag, xdrag; - - /* Can't drag if nothing is selected */ - if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 || - sheet->range.col0 < 0 || sheet->range.coli < 0 ) - return FALSE; - - *drag_column = column_from_xpixel (sheet, x); - *drag_row = row_from_ypixel (sheet, y); - - if (x >= psppire_axis_start_pixel (sheet->haxis, sheet->range.col0) - DRAG_WIDTH / 2 && - x <= psppire_axis_start_pixel (sheet->haxis, sheet->range.coli) + - psppire_axis_unit_size (sheet->haxis, sheet->range.coli) + DRAG_WIDTH / 2) - { - ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.row0); - if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) - { - *drag_row = sheet->range.row0; - return TRUE; - } - ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) + - psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi); - if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) - { - *drag_row = sheet->range.rowi; - return TRUE; - } - } - - if (y >= psppire_axis_start_pixel (sheet->vaxis, sheet->range.row0) - DRAG_WIDTH / 2 && - y <= psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) + - psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi) + DRAG_WIDTH / 2) - { - xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.col0); - if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2) - { - *drag_column = sheet->range.col0; - return TRUE; - } - xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.coli) + - psppire_axis_unit_size (sheet->haxis, sheet->range.coli); - if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2) - { - *drag_column = sheet->range.coli; - return TRUE; - } - } - - return FALSE; -} - -static inline gboolean -POSSIBLE_RESIZE (const PsppireSheet *sheet, gint x, gint y, - gint *drag_row, gint *drag_column) -{ - gint xdrag, ydrag; - - /* Can't drag if nothing is selected */ - if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 || - sheet->range.col0 < 0 || sheet->range.coli < 0 ) - return FALSE; - - xdrag = psppire_axis_start_pixel (sheet->haxis, sheet->range.coli)+ - psppire_axis_unit_size (sheet->haxis, sheet->range.coli); - - ydrag = psppire_axis_start_pixel (sheet->vaxis, sheet->range.rowi) + - psppire_axis_unit_size (sheet->vaxis, sheet->range.rowi); - - if (sheet->select_status == PSPPIRE_SHEET_COLUMN_SELECTED) - ydrag = psppire_axis_start_pixel (sheet->vaxis, min_visible_row (sheet)); - - if (sheet->select_status == PSPPIRE_SHEET_ROW_SELECTED) - xdrag = psppire_axis_start_pixel (sheet->haxis, min_visible_column (sheet)); - - *drag_column = column_from_xpixel (sheet, x); - *drag_row = row_from_ypixel (sheet, y); - - if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 && - y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE; - - return FALSE; -} - - -static void -rectangle_from_range (PsppireSheet *sheet, const PsppireSheetRange *range, - GdkRectangle *r) -{ - gint col0 = MIN (range->col0, range->coli); - gint coli = MAX (range->col0, range->coli); - gint row0 = MIN (range->row0, range->rowi); - gint rowi = MAX (range->row0, range->rowi); - - if ( row0 == -1 ) row0 = min_visible_row (sheet); - if ( rowi == -1 ) rowi = max_visible_row (sheet); - if ( col0 == -1 ) col0 = min_visible_column (sheet); - if ( coli == -1 ) coli = max_visible_column (sheet); - - r->x = psppire_axis_start_pixel (sheet->haxis, col0); - r->x -= round (sheet->hadjustment->value); - - r->y = psppire_axis_start_pixel (sheet->vaxis, row0); - r->y -= round (sheet->vadjustment->value); - - r->width = psppire_axis_start_pixel (sheet->haxis, coli) - - psppire_axis_start_pixel (sheet->haxis, col0) + - psppire_axis_unit_size (sheet->haxis, coli); - - r->height = psppire_axis_start_pixel (sheet->vaxis, rowi) - - psppire_axis_start_pixel (sheet->vaxis, row0) + - psppire_axis_unit_size (sheet->vaxis, rowi); - - if ( sheet->column_titles_visible) - { - r->y += sheet->column_title_area.height; - } - - if ( sheet->row_titles_visible) - { - r->x += sheet->row_title_area.width; - } -} - -static void -rectangle_from_cell (PsppireSheet *sheet, gint row, gint col, - GdkRectangle *r) -{ - PsppireSheetRange range; - g_return_if_fail (row >= 0); - g_return_if_fail (col >= 0); - - range.row0 = range.rowi = row; - range.col0 = range.coli = col; - - rectangle_from_range (sheet, &range, r); -} - - -static void psppire_sheet_class_init (PsppireSheetClass *klass); -static void psppire_sheet_init (PsppireSheet *sheet); -static void psppire_sheet_dispose (GObject *object); -static void psppire_sheet_finalize (GObject *object); -static void psppire_sheet_style_set (GtkWidget *widget, - GtkStyle *previous_style); -static void psppire_sheet_realize (GtkWidget *widget); -static void psppire_sheet_unrealize (GtkWidget *widget); -static void psppire_sheet_map (GtkWidget *widget); -static void psppire_sheet_unmap (GtkWidget *widget); -static gint psppire_sheet_expose (GtkWidget *widget, - GdkEventExpose *event); - -static void psppire_sheet_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); - -static gboolean psppire_sheet_set_scroll_adjustments (PsppireSheet *sheet, - GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); - -static gint psppire_sheet_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint psppire_sheet_button_release (GtkWidget *widget, - GdkEventButton *event); -static gint psppire_sheet_motion (GtkWidget *widget, - GdkEventMotion *event); -static gboolean psppire_sheet_crossing_notify (GtkWidget *widget, - GdkEventCrossing *event); -static gint psppire_sheet_entry_key_press (GtkWidget *widget, - GdkEventKey *key); -static gboolean psppire_sheet_key_press (GtkWidget *widget, - GdkEventKey *key); -static void psppire_sheet_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void psppire_sheet_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); - -static gboolean psppire_sheet_focus_in (GtkWidget *widget, - GdkEventFocus *event); - -/* Sheet queries */ - -static gboolean psppire_sheet_range_isvisible (const PsppireSheet *sheet, - const PsppireSheetRange *range); -static gboolean psppire_sheet_cell_isvisible (PsppireSheet *sheet, - gint row, gint column); -/* Drawing Routines */ - -/* draw cell */ -static void psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint column); - - -/* draw visible part of range. */ -static void draw_sheet_region (PsppireSheet *sheet, GdkRegion *region); - - -/* Selection */ -static void psppire_sheet_draw_border (PsppireSheet *sheet, - PsppireSheetRange range); - -/* Active Cell handling */ - -static void psppire_sheet_hide_entry_widget (PsppireSheet *sheet); -static void change_active_cell (PsppireSheet *sheet, gint row, gint col); -static gboolean psppire_sheet_draw_active_cell (PsppireSheet *sheet); -static void psppire_sheet_show_entry_widget (PsppireSheet *sheet); -static gboolean psppire_sheet_click_cell (PsppireSheet *sheet, - gint row, - gint column); - - -/* Scrollbars */ - -static void adjust_scrollbars (PsppireSheet *sheet); -static void vadjustment_value_changed (GtkAdjustment *adjustment, - gpointer data); -static void hadjustment_value_changed (GtkAdjustment *adjustment, - gpointer data); - - -static void draw_xor_vline (PsppireSheet *sheet); -static void draw_xor_hline (PsppireSheet *sheet); -static void draw_xor_rectangle (PsppireSheet *sheet, - PsppireSheetRange range); - -/* Sheet Button */ - -static void create_global_button (PsppireSheet *sheet); -static void global_button_clicked (GtkWidget *widget, - gpointer data); -/* Sheet Entry */ - -static void create_sheet_entry (PsppireSheet *sheet); -static void psppire_sheet_size_allocate_entry (PsppireSheet *sheet); - -/* Sheet button gadgets */ - -static void draw_column_title_buttons (PsppireSheet *sheet); -static void draw_row_title_buttons (PsppireSheet *sheet); - - -static void size_allocate_global_button (PsppireSheet *sheet); - -static void psppire_sheet_real_cell_clear (PsppireSheet *sheet, - gint row, - gint column); - - -/* Signals */ -enum - { - SELECT_ROW, - SELECT_COLUMN, - DOUBLE_CLICK_ROW, - DOUBLE_CLICK_COLUMN, - BUTTON_EVENT_ROW, - BUTTON_EVENT_COLUMN, - SELECT_RANGE, - RESIZE_RANGE, - MOVE_RANGE, - TRAVERSE, - ACTIVATE, - LAST_SIGNAL - }; - -static GtkContainerClass *parent_class = NULL; -static guint sheet_signals[LAST_SIGNAL] = { 0 }; - - -GType -psppire_sheet_get_type () -{ - static GType sheet_type = 0; - - if (!sheet_type) - { - static const GTypeInfo sheet_info = - { - sizeof (PsppireSheetClass), - NULL, - NULL, - (GClassInitFunc) psppire_sheet_class_init, - NULL, - NULL, - sizeof (PsppireSheet), - 0, - (GInstanceInitFunc) psppire_sheet_init, - NULL, - }; - - sheet_type = - g_type_register_static (GTK_TYPE_BIN, "PsppireSheet", - &sheet_info, 0); - } - return sheet_type; -} - - - -static PsppireSheetRange* -psppire_sheet_range_copy (const PsppireSheetRange *range) -{ - PsppireSheetRange *new_range; - - g_return_val_if_fail (range != NULL, NULL); - - new_range = g_new (PsppireSheetRange, 1); - - *new_range = *range; - - return new_range; -} - -static void -psppire_sheet_range_free (PsppireSheetRange *range) -{ - g_return_if_fail (range != NULL); - - g_free (range); -} - -GType -psppire_sheet_range_get_type (void) -{ - static GType sheet_range_type = 0; - - if (!sheet_range_type) - { - sheet_range_type = - g_boxed_type_register_static ("PsppireSheetRange", - (GBoxedCopyFunc) psppire_sheet_range_copy, - (GBoxedFreeFunc) psppire_sheet_range_free); - } - - return sheet_range_type; -} - -static PsppireSheetCell* -psppire_sheet_cell_copy (const PsppireSheetCell *cell) -{ - PsppireSheetCell *new_cell; - - g_return_val_if_fail (cell != NULL, NULL); - - new_cell = g_new (PsppireSheetCell, 1); - - *new_cell = *cell; - - return new_cell; -} - -static void -psppire_sheet_cell_free (PsppireSheetCell *cell) -{ - g_return_if_fail (cell != NULL); - - g_free (cell); -} - -GType -psppire_sheet_cell_get_type (void) -{ - static GType sheet_cell_type = 0; - - if (!sheet_cell_type) - { - sheet_cell_type = - g_boxed_type_register_static ("PsppireSheetCell", - (GBoxedCopyFunc) psppire_sheet_cell_copy, - (GBoxedFreeFunc) psppire_sheet_cell_free); - } - - return sheet_cell_type; -} - - -/* Properties */ -enum - { - PROP_0, - PROP_VAXIS, - PROP_HAXIS, - PROP_CELL_PADDING, - PROP_MODEL - }; - -static void -resize_column (PsppireSheet *sheet, gint unit, glong size) -{ - PsppireSheetRange range; - range.col0 = unit; - range.coli = max_visible_column (sheet); - range.row0 = min_visible_row (sheet); - range.rowi = max_visible_row (sheet); - - redraw_range (sheet, &range); - - draw_column_title_buttons_range (sheet, range.col0, range.coli); -} - - -static void -psppire_sheet_set_horizontal_axis (PsppireSheet *sheet, PsppireAxis *a) -{ - if ( sheet->haxis ) - g_object_unref (sheet->haxis); - - sheet->haxis = a; - g_signal_connect_swapped (a, "resize-unit", G_CALLBACK (resize_column), sheet); - - if ( sheet->haxis ) - g_object_ref (sheet->haxis); -} - -static void -resize_row (PsppireSheet *sheet, gint unit, glong size) -{ - PsppireSheetRange range; - range.col0 = min_visible_column (sheet); - range.coli = max_visible_column (sheet); - range.row0 = unit; - range.rowi = max_visible_row (sheet); - - redraw_range (sheet, &range); - - draw_row_title_buttons_range (sheet, range.row0, range.rowi); -} - -static void -psppire_sheet_set_vertical_axis (PsppireSheet *sheet, PsppireAxis *a) -{ - if ( sheet->vaxis ) - g_object_unref (sheet->vaxis); - - sheet->vaxis = a; - - g_signal_connect_swapped (a, "resize-unit", G_CALLBACK (resize_row), sheet); - - if ( sheet->vaxis ) - g_object_ref (sheet->vaxis); -} - -static const GtkBorder default_cell_padding = {3, 3, 3, 3}; - -static void -psppire_sheet_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) - -{ - PsppireSheet *sheet = PSPPIRE_SHEET (object); - - switch (prop_id) - { - case PROP_CELL_PADDING: - if ( sheet->cell_padding) - g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding); - - sheet->cell_padding = g_value_dup_boxed (value); - - if (NULL == sheet->cell_padding) - sheet->cell_padding = g_boxed_copy (GTK_TYPE_BORDER, - &default_cell_padding); - - if (sheet->vaxis) - g_object_set (sheet->vaxis, "padding", - sheet->cell_padding->top + sheet->cell_padding->bottom, - NULL); - - if (sheet->haxis) - g_object_set (sheet->haxis, "padding", - sheet->cell_padding->left + sheet->cell_padding->right, - NULL); - break; - case PROP_VAXIS: - psppire_sheet_set_vertical_axis (sheet, g_value_get_pointer (value)); - g_object_set (sheet->vaxis, "padding", - sheet->cell_padding->top + sheet->cell_padding->bottom, - NULL); - break; - case PROP_HAXIS: - psppire_sheet_set_horizontal_axis (sheet, g_value_get_pointer (value)); - g_object_set (sheet->haxis, "padding", - sheet->cell_padding->left + sheet->cell_padding->right, - NULL); - break; - case PROP_MODEL: - psppire_sheet_set_model (sheet, g_value_get_pointer (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - }; -} - -static void -psppire_sheet_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (object); - - switch (prop_id) - { - case PROP_CELL_PADDING: - g_value_set_boxed (value, sheet->cell_padding); - break; - case PROP_VAXIS: - g_value_set_pointer (value, sheet->vaxis); - break; - case PROP_HAXIS: - g_value_set_pointer (value, sheet->haxis); - break; - case PROP_MODEL: - g_value_set_pointer (value, sheet->model); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - }; -} - - -static void -psppire_sheet_class_init (PsppireSheetClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - GParamSpec *haxis_spec ; - GParamSpec *vaxis_spec ; - GParamSpec *model_spec ; - GParamSpec *cell_padding_spec ; - - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - /** - * PsppireSheet::select-row - * @sheet: the sheet widget that emitted the signal - * @row: the newly selected row index, or -1 if no row is selected. - * - * A row has been selected. - */ - sheet_signals[SELECT_ROW] = - g_signal_new ("select-row", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, select_row), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, - 1, - G_TYPE_INT); - - - /** - * PsppireSheet::select - column - * @sheet: the sheet widget that emitted the signal - * @column: the newly selected column index, or -1 if no column is selected. - * - * A column has been selected. - */ - sheet_signals[SELECT_COLUMN] = - g_signal_new ("select-column", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, select_column), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, - 1, - G_TYPE_INT); - - - /** - * PsppireSheet::double-click-row - * @sheet: the sheet widget that emitted the signal - * @row: the row that was double clicked. - * - * A row's title button has been double clicked - */ - sheet_signals[DOUBLE_CLICK_ROW] = - g_signal_new ("double-click-row", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, - 1, - G_TYPE_INT); - - - /** - * PsppireSheet::double-click-column - * @sheet: the sheet widget that emitted the signal - * @column: the column that was double clicked. - * - * A column's title button has been double clicked - */ - sheet_signals[DOUBLE_CLICK_COLUMN] = - g_signal_new ("double-click-column", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, - 1, - G_TYPE_INT); - - - /** - * PsppireSheet::button-event-column - * @sheet: the sheet widget that emitted the signal - * @column: the column on which the event occured. - * - * A button event occured on a column title button - */ - sheet_signals[BUTTON_EVENT_COLUMN] = - g_signal_new ("button-event-column", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - psppire_marshal_VOID__INT_POINTER, - G_TYPE_NONE, - 2, - G_TYPE_INT, - G_TYPE_POINTER - ); - - - /** - * PsppireSheet::button-event-row - * @sheet: the sheet widget that emitted the signal - * @column: the column on which the event occured. - * - * A button event occured on a row title button - */ - sheet_signals[BUTTON_EVENT_ROW] = - g_signal_new ("button-event-row", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - psppire_marshal_VOID__INT_POINTER, - G_TYPE_NONE, - 2, - G_TYPE_INT, - G_TYPE_POINTER - ); - - - sheet_signals[SELECT_RANGE] = - g_signal_new ("select-range", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, select_range), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, - 1, - PSPPIRE_TYPE_SHEET_RANGE); - - - sheet_signals[RESIZE_RANGE] = - g_signal_new ("resize-range", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, resize_range), - NULL, NULL, - psppire_marshal_VOID__BOXED_BOXED, - G_TYPE_NONE, - 2, - PSPPIRE_TYPE_SHEET_RANGE, PSPPIRE_TYPE_SHEET_RANGE - ); - - sheet_signals[MOVE_RANGE] = - g_signal_new ("move-range", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, move_range), - NULL, NULL, - psppire_marshal_VOID__BOXED_BOXED, - G_TYPE_NONE, - 2, - PSPPIRE_TYPE_SHEET_RANGE, PSPPIRE_TYPE_SHEET_RANGE - ); - - sheet_signals[TRAVERSE] = - g_signal_new ("traverse", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, traverse), - NULL, NULL, - psppire_marshal_BOOLEAN__BOXED_POINTER, - G_TYPE_BOOLEAN, 2, - PSPPIRE_TYPE_SHEET_CELL, - G_TYPE_POINTER); - - - sheet_signals[ACTIVATE] = - g_signal_new ("activate", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, activate), - NULL, NULL, - psppire_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, G_TYPE_INT, - G_TYPE_INT, G_TYPE_INT); - - widget_class->set_scroll_adjustments_signal = - g_signal_new ("set-scroll-adjustments", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - offsetof (PsppireSheetClass, set_scroll_adjustments), - NULL, NULL, - psppire_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); - - - container_class->add = NULL; - container_class->remove = NULL; - container_class->forall = psppire_sheet_forall; - container_class->set_focus_child = NULL; - - object_class->dispose = psppire_sheet_dispose; - object_class->finalize = psppire_sheet_finalize; - - cell_padding_spec = - g_param_spec_boxed ("cell-padding", - "Cell Padding", - "The space between a cell's contents and its border", - GTK_TYPE_BORDER, - G_PARAM_CONSTRUCT | G_PARAM_READABLE | G_PARAM_WRITABLE); - - vaxis_spec = - g_param_spec_pointer ("vertical-axis", - "Vertical Axis", - "A pointer to the PsppireAxis object for the rows", - G_PARAM_READABLE | G_PARAM_WRITABLE ); - - haxis_spec = - g_param_spec_pointer ("horizontal-axis", - "Horizontal Axis", - "A pointer to the PsppireAxis object for the columns", - G_PARAM_READABLE | G_PARAM_WRITABLE ); - - model_spec = - g_param_spec_pointer ("model", - "Model", - "A pointer to the data model", - G_PARAM_READABLE | G_PARAM_WRITABLE ); - - - object_class->set_property = psppire_sheet_set_property; - object_class->get_property = psppire_sheet_get_property; - - g_object_class_install_property (object_class, - PROP_VAXIS, - vaxis_spec); - - g_object_class_install_property (object_class, - PROP_HAXIS, - haxis_spec); - - g_object_class_install_property (object_class, - PROP_CELL_PADDING, - cell_padding_spec); - - g_object_class_install_property (object_class, - PROP_MODEL, - model_spec); - - - widget_class->realize = psppire_sheet_realize; - widget_class->unrealize = psppire_sheet_unrealize; - widget_class->map = psppire_sheet_map; - widget_class->unmap = psppire_sheet_unmap; - widget_class->style_set = psppire_sheet_style_set; - widget_class->button_press_event = psppire_sheet_button_press; - widget_class->button_release_event = psppire_sheet_button_release; - widget_class->motion_notify_event = psppire_sheet_motion; - widget_class->enter_notify_event = psppire_sheet_crossing_notify; - widget_class->leave_notify_event = psppire_sheet_crossing_notify; - widget_class->key_press_event = psppire_sheet_key_press; - widget_class->expose_event = psppire_sheet_expose; - widget_class->size_request = psppire_sheet_size_request; - widget_class->size_allocate = psppire_sheet_size_allocate; - widget_class->focus_in_event = psppire_sheet_focus_in; - widget_class->focus_out_event = NULL; - - klass->set_scroll_adjustments = psppire_sheet_set_scroll_adjustments; - klass->select_row = NULL; - klass->select_column = NULL; - klass->select_range = NULL; - klass->resize_range = NULL; - klass->move_range = NULL; - klass->traverse = NULL; - klass->activate = NULL; - klass->changed = NULL; -} - -static void -psppire_sheet_init (PsppireSheet *sheet) -{ - sheet->model = NULL; - sheet->haxis = NULL; - sheet->vaxis = NULL; - - sheet->flags = 0; - sheet->select_status = PSPPIRE_SHEET_NORMAL; - - GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW); - GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS); - - sheet->column_title_window = NULL; - sheet->column_title_area.x = 0; - sheet->column_title_area.y = 0; - sheet->column_title_area.width = 0; - sheet->column_title_area.height = DEFAULT_ROW_HEIGHT; - - sheet->row_title_window = NULL; - sheet->row_title_area.x = 0; - sheet->row_title_area.y = 0; - sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH; - sheet->row_title_area.height = 0; - - - sheet->active_cell.row = 0; - sheet->active_cell.col = 0; - - sheet->range.row0 = 0; - sheet->range.rowi = 0; - sheet->range.col0 = 0; - sheet->range.coli = 0; - - sheet->sheet_window = NULL; - sheet->entry_widget = NULL; - sheet->button = NULL; - - sheet->hadjustment = NULL; - sheet->vadjustment = NULL; - - sheet->cursor_drag = NULL; - - sheet->xor_gc = NULL; - sheet->fg_gc = NULL; - sheet->bg_gc = NULL; - sheet->x_drag = 0; - sheet->y_drag = 0; - sheet->show_grid = TRUE; - - sheet->motion_timer = 0; - - sheet->row_titles_visible = TRUE; - sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH; - - sheet->column_titles_visible = TRUE; - - - /* create sheet entry */ - sheet->entry_type = GTK_TYPE_ENTRY; - create_sheet_entry (sheet); - - /* create global selection button */ - create_global_button (sheet); -} - - -/* Cause RANGE to be redrawn. If RANGE is null, then the - entire visible range will be redrawn. -*/ -static void -redraw_range (PsppireSheet *sheet, PsppireSheetRange *range) -{ - GdkRectangle rect; - - if ( ! GTK_WIDGET_REALIZED (sheet)) - return; - - if ( NULL != range ) - rectangle_from_range (sheet, range, &rect); - else - { - GdkRegion *r = gdk_drawable_get_visible_region (sheet->sheet_window); - gdk_region_get_clipbox (r, &rect); - - if ( sheet->column_titles_visible) - { - rect.y += sheet->column_title_area.height; - rect.height -= sheet->column_title_area.height; - } - - if ( sheet->row_titles_visible) - { - rect.x += sheet->row_title_area.width; - rect.width -= sheet->row_title_area.width; - } - } - - gdk_window_invalidate_rect (sheet->sheet_window, &rect, FALSE); -} - - -/* Callback which occurs whenever columns are inserted / deleted in the model */ -static void -columns_inserted_deleted_callback (PsppireSheetModel *model, gint first_column, - gint n_columns, - gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - - PsppireSheetRange range; - gint model_columns = psppire_sheet_model_get_column_count (model); - - - /* Need to update all the columns starting from the first column and onwards. - * Previous column are unchanged, so don't need to be updated. - */ - range.col0 = first_column; - range.row0 = 0; - range.coli = psppire_axis_unit_count (sheet->haxis) - 1; - range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1; - - adjust_scrollbars (sheet); - - if (sheet->active_cell.col >= model_columns) - change_active_cell (sheet, sheet->active_cell.row, model_columns - 1); - - draw_column_title_buttons_range (sheet, - first_column, max_visible_column (sheet)); - - - redraw_range (sheet, &range); -} - - - - -/* Callback which occurs whenever rows are inserted / deleted in the model */ -static void -rows_inserted_deleted_callback (PsppireSheetModel *model, gint first_row, - gint n_rows, gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - - PsppireSheetRange range; - - gint model_rows = psppire_sheet_model_get_row_count (model); - - /* Need to update all the rows starting from the first row and onwards. - * Previous rows are unchanged, so don't need to be updated. - */ - range.row0 = first_row; - range.col0 = 0; - range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1; - range.coli = psppire_axis_unit_count (sheet->haxis) - 1; - - adjust_scrollbars (sheet); - - if (sheet->active_cell.row >= model_rows) - change_active_cell (sheet, model_rows - 1, sheet->active_cell.col); - - draw_row_title_buttons_range (sheet, first_row, max_visible_row (sheet)); - - redraw_range (sheet, &range); -} - -/* - If row0 or rowi are negative, then all rows will be updated. - If col0 or coli are negative, then all columns will be updated. -*/ -static void -range_update_callback (PsppireSheetModel *m, gint row0, gint col0, - gint rowi, gint coli, gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - - PsppireSheetRange range; - - range.row0 = row0; - range.col0 = col0; - range.rowi = rowi; - range.coli = coli; - - if ( !GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) ) - { - redraw_range (sheet, NULL); - adjust_scrollbars (sheet); - - draw_row_title_buttons_range (sheet, min_visible_row (sheet), - max_visible_row (sheet)); - - draw_column_title_buttons_range (sheet, min_visible_column (sheet), - max_visible_column (sheet)); - - return; - } - else if ( row0 < 0 || rowi < 0 ) - { - range.row0 = min_visible_row (sheet); - range.rowi = max_visible_row (sheet); - } - else if ( col0 < 0 || coli < 0 ) - { - range.col0 = min_visible_column (sheet); - range.coli = max_visible_column (sheet); - } - - redraw_range (sheet, &range); -} - - -/** - * psppire_sheet_new: - * @rows: initial number of rows - * @columns: initial number of columns - * @title: sheet title - * @model: the model to use for the sheet data - * - * Creates a new sheet widget with the given number of rows and columns. - * - * Returns: the new sheet widget - */ -GtkWidget * -psppire_sheet_new (PsppireSheetModel *model) -{ - GtkWidget *widget = g_object_new (PSPPIRE_TYPE_SHEET, - "model", model, - NULL); - return widget; -} - - -/** - * psppire_sheet_set_model - * @sheet: the sheet to set the model for - * @model: the model to use for the sheet data - * - * Sets the model for a PsppireSheet - * - */ -void -psppire_sheet_set_model (PsppireSheet *sheet, PsppireSheetModel *model) -{ - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (sheet->model ) g_object_unref (sheet->model); - - sheet->model = model; - - if ( model) - { - g_object_ref (model); - - sheet->update_handler_id = g_signal_connect (model, "range_changed", - G_CALLBACK (range_update_callback), - sheet); - - g_signal_connect (model, "rows_inserted", - G_CALLBACK (rows_inserted_deleted_callback), sheet); - - g_signal_connect (model, "rows_deleted", - G_CALLBACK (rows_inserted_deleted_callback), sheet); - - g_signal_connect (model, "columns_inserted", - G_CALLBACK (columns_inserted_deleted_callback), sheet); - - g_signal_connect (model, "columns_deleted", - G_CALLBACK (columns_inserted_deleted_callback), sheet); - } -} - - -void -psppire_sheet_change_entry (PsppireSheet *sheet, GType entry_type) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (sheet->select_status == PSPPIRE_SHEET_NORMAL) - psppire_sheet_hide_entry_widget (sheet); - - sheet->entry_type = entry_type; - - create_sheet_entry (sheet); - - if (sheet->select_status == PSPPIRE_SHEET_NORMAL) - psppire_sheet_show_entry_widget (sheet); -} - -void -psppire_sheet_show_grid (PsppireSheet *sheet, gboolean show) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (show == sheet->show_grid) return; - - sheet->show_grid = show; - - redraw_range (sheet, NULL); -} - -gboolean -psppire_sheet_grid_visible (PsppireSheet *sheet) -{ - g_return_val_if_fail (sheet != NULL, 0); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0); - - return sheet->show_grid; -} - -guint -psppire_sheet_get_columns_count (PsppireSheet *sheet) -{ - g_return_val_if_fail (sheet != NULL, 0); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0); - - return psppire_axis_unit_count (sheet->haxis); -} - -static void set_column_width (PsppireSheet *sheet, - gint column, - gint width); - - -void -psppire_sheet_show_column_titles (PsppireSheet *sheet) -{ - if (sheet->column_titles_visible) return; - - sheet->column_titles_visible = TRUE; - - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - gdk_window_show (sheet->column_title_window); - gdk_window_move_resize (sheet->column_title_window, - sheet->column_title_area.x, - sheet->column_title_area.y, - sheet->column_title_area.width, - sheet->column_title_area.height); - - adjust_scrollbars (sheet); - - if (sheet->vadjustment) - g_signal_emit_by_name (sheet->vadjustment, - "value_changed"); - - size_allocate_global_button (sheet); - - if ( sheet->row_titles_visible) - gtk_widget_show (sheet->button); -} - - -void -psppire_sheet_show_row_titles (PsppireSheet *sheet) -{ - if (sheet->row_titles_visible) return; - - sheet->row_titles_visible = TRUE; - - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - { - gdk_window_show (sheet->row_title_window); - gdk_window_move_resize (sheet->row_title_window, - sheet->row_title_area.x, - sheet->row_title_area.y, - sheet->row_title_area.width, - sheet->row_title_area.height); - - adjust_scrollbars (sheet); - } - - if (sheet->hadjustment) - g_signal_emit_by_name (sheet->hadjustment, - "value_changed"); - - size_allocate_global_button (sheet); - - if ( sheet->column_titles_visible) - gtk_widget_show (sheet->button); -} - -void -psppire_sheet_hide_column_titles (PsppireSheet *sheet) -{ - if (!sheet->column_titles_visible) return; - - sheet->column_titles_visible = FALSE; - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - { - if (sheet->column_title_window) - gdk_window_hide (sheet->column_title_window); - - gtk_widget_hide (sheet->button); - - adjust_scrollbars (sheet); - } - - if (sheet->vadjustment) - g_signal_emit_by_name (sheet->vadjustment, - "value_changed"); -} - -void -psppire_sheet_hide_row_titles (PsppireSheet *sheet) -{ - if (!sheet->row_titles_visible) return; - - sheet->row_titles_visible = FALSE; - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - { - if (sheet->row_title_window) - gdk_window_hide (sheet->row_title_window); - - gtk_widget_hide (sheet->button); - - adjust_scrollbars (sheet); - } - - if (sheet->hadjustment) - g_signal_emit_by_name (sheet->hadjustment, - "value_changed"); -} - - -/* Scroll the sheet so that the cell ROW, COLUMN is visible. - If {ROW,COL}_ALIGN is zero, then the cell will be placed - at the {top,left} of the sheet. If it's 1, then it'll - be placed at the {bottom,right}. - ROW or COL may be -1, in which case scrolling in that dimension - does not occur. -*/ -void -psppire_sheet_moveto (PsppireSheet *sheet, - gint row, - gint col, - gfloat row_align, - gfloat col_align) -{ - gint width, height; - - g_return_if_fail (row_align >= 0); - g_return_if_fail (col_align >= 0); - - g_return_if_fail (row_align <= 1); - g_return_if_fail (col_align <= 1); - - g_return_if_fail (col < - psppire_axis_unit_count (sheet->haxis)); - g_return_if_fail (row < - psppire_axis_unit_count (sheet->vaxis)); - - gdk_drawable_get_size (sheet->sheet_window, &width, &height); - - - if (row >= 0) - { - gint y = psppire_axis_start_pixel (sheet->vaxis, row); - - gtk_adjustment_set_value (sheet->vadjustment, y - height * row_align); - } - - - if (col >= 0) - { - gint x = psppire_axis_start_pixel (sheet->haxis, col); - - gtk_adjustment_set_value (sheet->hadjustment, x - width * col_align); - } -} - - - - -static gboolean -psppire_sheet_range_isvisible (const PsppireSheet *sheet, - const PsppireSheetRange *range) -{ - g_return_val_if_fail (sheet != NULL, FALSE); - - if (range->row0 < 0 || range->row0 >= psppire_axis_unit_count (sheet->vaxis)) - return FALSE; - - if (range->rowi < 0 || range->rowi >= psppire_axis_unit_count (sheet->vaxis)) - return FALSE; - - if (range->col0 < 0 || range->col0 >= psppire_axis_unit_count (sheet->haxis)) - return FALSE; - - if (range->coli < 0 || range->coli >= psppire_axis_unit_count (sheet->haxis)) - return FALSE; - - if (range->rowi < min_visible_row (sheet)) - return FALSE; - - if (range->row0 > max_visible_row (sheet)) - return FALSE; - - if (range->coli < min_visible_column (sheet)) - return FALSE; - - if (range->col0 > max_visible_column (sheet)) - return FALSE; - - return TRUE; -} - -static gboolean -psppire_sheet_cell_isvisible (PsppireSheet *sheet, - gint row, gint column) -{ - PsppireSheetRange range; - - range.row0 = row; - range.col0 = column; - range.rowi = row; - range.coli = column; - - return psppire_sheet_range_isvisible (sheet, &range); -} - -void -psppire_sheet_get_visible_range (PsppireSheet *sheet, PsppireSheetRange *range) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)) ; - g_return_if_fail (range != NULL); - - range->row0 = min_visible_row (sheet); - range->col0 = min_visible_column (sheet); - range->rowi = max_visible_row (sheet); - range->coli = max_visible_column (sheet); -} - - -static gboolean -psppire_sheet_set_scroll_adjustments (PsppireSheet *sheet, - GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment) -{ - if ( sheet->vadjustment != vadjustment ) - { - if (sheet->vadjustment) - g_object_unref (sheet->vadjustment); - sheet->vadjustment = vadjustment; - - if ( vadjustment) - { - g_object_ref (vadjustment); - - g_signal_connect (sheet->vadjustment, "value_changed", - G_CALLBACK (vadjustment_value_changed), - sheet); - } - } - - if ( sheet->hadjustment != hadjustment ) - { - if (sheet->hadjustment) - g_object_unref (sheet->hadjustment); - - sheet->hadjustment = hadjustment; - - if ( hadjustment) - { - g_object_ref (hadjustment); - - g_signal_connect (sheet->hadjustment, "value_changed", - G_CALLBACK (hadjustment_value_changed), - sheet); - } - } - return TRUE; -} - -static void -psppire_sheet_finalize (GObject *object) -{ - PsppireSheet *sheet; - - g_return_if_fail (object != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (object)); - - sheet = PSPPIRE_SHEET (object); - - if (G_OBJECT_CLASS (parent_class)->finalize) - (*G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -static void -psppire_sheet_dispose (GObject *object) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (object); - - g_return_if_fail (object != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (object)); - - if ( sheet->dispose_has_run ) - return ; - - sheet->dispose_has_run = TRUE; - - if ( sheet->cell_padding) - g_boxed_free (GTK_TYPE_BORDER, sheet->cell_padding); - - if (sheet->model) g_object_unref (sheet->model); - if (sheet->vaxis) g_object_unref (sheet->vaxis); - if (sheet->haxis) g_object_unref (sheet->haxis); - - g_object_unref (sheet->button); - sheet->button = NULL; - - /* unref adjustments */ - if (sheet->hadjustment) - { - g_signal_handlers_disconnect_matched (sheet->hadjustment, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - sheet); - - g_object_unref (sheet->hadjustment); - sheet->hadjustment = NULL; - } - - if (sheet->vadjustment) - { - g_signal_handlers_disconnect_matched (sheet->vadjustment, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - sheet); - - g_object_unref (sheet->vadjustment); - - sheet->vadjustment = NULL; - } - - if (G_OBJECT_CLASS (parent_class)->dispose) - (*G_OBJECT_CLASS (parent_class)->dispose) (object); -} - -static void -psppire_sheet_style_set (GtkWidget *widget, - GtkStyle *previous_style) -{ - PsppireSheet *sheet; - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - - if (GTK_WIDGET_CLASS (parent_class)->style_set) - (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style); - - sheet = PSPPIRE_SHEET (widget); - - if (GTK_WIDGET_REALIZED (widget)) - { - gtk_style_set_background (widget->style, widget->window, widget->state); - } - - set_entry_widget_font (sheet); -} - - -static void -psppire_sheet_realize (GtkWidget *widget) -{ - PsppireSheet *sheet; - GdkWindowAttr attributes; - const gint attributes_mask = - GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR; - - GdkGCValues values; - GdkColormap *colormap; - GdkDisplay *display; - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - - sheet = PSPPIRE_SHEET (widget); - - colormap = gtk_widget_get_colormap (widget); - display = gtk_widget_get_display (widget); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = colormap; - - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - attributes.cursor = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW); - - /* main window */ - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - - gdk_window_set_user_data (widget->window, sheet); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); - - gdk_color_parse ("white", &sheet->color[BG_COLOR]); - gdk_colormap_alloc_color (colormap, &sheet->color[BG_COLOR], FALSE, - TRUE); - gdk_color_parse ("gray", &sheet->color[GRID_COLOR]); - gdk_colormap_alloc_color (colormap, &sheet->color[GRID_COLOR], FALSE, - TRUE); - - attributes.x = 0; - attributes.y = 0; - attributes.width = sheet->column_title_area.width; - attributes.height = sheet->column_title_area.height; - - - /* column - title window */ - sheet->column_title_window = - gdk_window_new (widget->window, &attributes, attributes_mask); - gdk_window_set_user_data (sheet->column_title_window, sheet); - gtk_style_set_background (widget->style, sheet->column_title_window, - GTK_STATE_NORMAL); - - - attributes.x = 0; - attributes.y = 0; - attributes.width = sheet->row_title_area.width; - attributes.height = sheet->row_title_area.height; - - /* row - title window */ - sheet->row_title_window = gdk_window_new (widget->window, - &attributes, attributes_mask); - gdk_window_set_user_data (sheet->row_title_window, sheet); - gtk_style_set_background (widget->style, sheet->row_title_window, - GTK_STATE_NORMAL); - - /* sheet - window */ - attributes.cursor = gdk_cursor_new_for_display (display, GDK_PLUS); - - attributes.x = 0; - attributes.y = 0; - - sheet->sheet_window = gdk_window_new (widget->window, - &attributes, attributes_mask); - gdk_window_set_user_data (sheet->sheet_window, sheet); - - gdk_cursor_unref (attributes.cursor); - - gdk_window_set_background (sheet->sheet_window, &widget->style->white); - gdk_window_show (sheet->sheet_window); - - /* GCs */ - sheet->fg_gc = gdk_gc_new (widget->window); - sheet->bg_gc = gdk_gc_new (widget->window); - - values.foreground = widget->style->white; - values.function = GDK_INVERT; - values.subwindow_mode = GDK_INCLUDE_INFERIORS; - values.line_width = MAX (sheet->cell_padding->left, - MAX (sheet->cell_padding->right, - MAX (sheet->cell_padding->top, - sheet->cell_padding->bottom))); - - sheet->xor_gc = gdk_gc_new_with_values (widget->window, - &values, - GDK_GC_FOREGROUND | - GDK_GC_FUNCTION | - GDK_GC_SUBWINDOW | - GDK_GC_LINE_WIDTH - ); - - gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window); - gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet)); - - gtk_widget_set_parent_window (sheet->button, sheet->sheet_window); - gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet)); - - sheet->button->style = gtk_style_attach (sheet->button->style, - sheet->sheet_window); - - - sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS); - - if (sheet->column_titles_visible) - gdk_window_show (sheet->column_title_window); - if (sheet->row_titles_visible) - gdk_window_show (sheet->row_title_window); - - sheet->hover_window = create_hover_window (); - - draw_row_title_buttons (sheet); - draw_column_title_buttons (sheet); - - psppire_sheet_update_primary_selection (sheet); - - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); -} - -static void -create_global_button (PsppireSheet *sheet) -{ - sheet->button = gtk_button_new_with_label (" "); - - GTK_WIDGET_UNSET_FLAGS(sheet->button, GTK_CAN_FOCUS); - - g_object_ref_sink (sheet->button); - - g_signal_connect (sheet->button, - "pressed", - G_CALLBACK (global_button_clicked), - sheet); -} - -static void -size_allocate_global_button (PsppireSheet *sheet) -{ - GtkAllocation allocation; - - if (!sheet->column_titles_visible) return; - if (!sheet->row_titles_visible) return; - - gtk_widget_size_request (sheet->button, NULL); - - allocation.x = 0; - allocation.y = 0; - allocation.width = sheet->row_title_area.width; - allocation.height = sheet->column_title_area.height; - - gtk_widget_size_allocate (sheet->button, &allocation); -} - -static void -global_button_clicked (GtkWidget *widget, gpointer data) -{ - psppire_sheet_click_cell (PSPPIRE_SHEET (data), -1, -1); -} - - -static void -psppire_sheet_unrealize (GtkWidget *widget) -{ - PsppireSheet *sheet; - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - - sheet = PSPPIRE_SHEET (widget); - - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = NULL; - - gdk_colormap_free_colors (gtk_widget_get_colormap (widget), - sheet->color, n_COLORS); - - g_object_unref (sheet->xor_gc); - g_object_unref (sheet->fg_gc); - g_object_unref (sheet->bg_gc); - - destroy_hover_window (sheet->hover_window); - - gdk_window_destroy (sheet->sheet_window); - gdk_window_destroy (sheet->column_title_window); - gdk_window_destroy (sheet->row_title_window); - - gtk_widget_unparent (sheet->entry_widget); - if (sheet->button != NULL) - gtk_widget_unparent (sheet->button); - - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void -psppire_sheet_map (GtkWidget *widget) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - - if (!GTK_WIDGET_MAPPED (widget)) - { - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - - gdk_window_show (widget->window); - gdk_window_show (sheet->sheet_window); - - if (sheet->column_titles_visible) - { - draw_column_title_buttons (sheet); - gdk_window_show (sheet->column_title_window); - } - if (sheet->row_titles_visible) - { - draw_row_title_buttons (sheet); - gdk_window_show (sheet->row_title_window); - } - - if (!GTK_WIDGET_MAPPED (sheet->entry_widget) - && sheet->active_cell.row >= 0 - && sheet->active_cell.col >= 0 ) - { - gtk_widget_show (sheet->entry_widget); - gtk_widget_map (sheet->entry_widget); - } - - if (!GTK_WIDGET_MAPPED (sheet->button)) - { - gtk_widget_show (sheet->button); - gtk_widget_map (sheet->button); - } - - redraw_range (sheet, NULL); - change_active_cell (sheet, - sheet->active_cell.row, - sheet->active_cell.col); - } -} - -static void -psppire_sheet_unmap (GtkWidget *widget) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - if (!GTK_WIDGET_MAPPED (widget)) - return; - - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - - gdk_window_hide (sheet->sheet_window); - if (sheet->column_titles_visible) - gdk_window_hide (sheet->column_title_window); - if (sheet->row_titles_visible) - gdk_window_hide (sheet->row_title_window); - gdk_window_hide (widget->window); - - gtk_widget_unmap (sheet->entry_widget); - gtk_widget_unmap (sheet->button); - gtk_widget_unmap (sheet->hover_window->window); -} - -/* get cell attributes of the given cell */ -/* TRUE means that the cell is currently allocated */ -static gboolean psppire_sheet_get_attributes (const PsppireSheet *sheet, - gint row, gint col, - PsppireSheetCellAttr *attributes); - - - -static void -psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint col) -{ - PangoLayout *layout; - PangoRectangle text; - PangoFontDescription *font_desc = GTK_WIDGET (sheet)->style->font_desc; - gint font_height; - - gchar *label; - - PsppireSheetCellAttr attributes; - GdkRectangle area; - - g_return_if_fail (sheet != NULL); - - /* bail now if we aren't yet drawable */ - if (!GTK_WIDGET_DRAWABLE (sheet)) return; - - if (row < 0 || - row >= psppire_axis_unit_count (sheet->vaxis)) - return; - - if (col < 0 || - col >= psppire_axis_unit_count (sheet->haxis)) - return; - - psppire_sheet_get_attributes (sheet, row, col, &attributes); - - /* select GC for background rectangle */ - gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground); - gdk_gc_set_foreground (sheet->bg_gc, &attributes.background); - - rectangle_from_cell (sheet, row, col, &area); - - gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0); - - if (sheet->show_grid) - { - gdk_gc_set_foreground (sheet->bg_gc, &sheet->color[GRID_COLOR]); - - gdk_draw_rectangle (sheet->sheet_window, - sheet->bg_gc, - FALSE, - area.x, area.y, - area.width, area.height); - } - - - label = psppire_sheet_cell_get_text (sheet, row, col); - if (NULL == label) - return; - - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label); - dispose_string (sheet, label); - - - pango_layout_set_font_description (layout, font_desc); - - pango_layout_get_pixel_extents (layout, NULL, &text); - - gdk_gc_set_clip_rectangle (sheet->fg_gc, &area); - - font_height = pango_font_description_get_size (font_desc); - if ( !pango_font_description_get_size_is_absolute (font_desc)) - font_height /= PANGO_SCALE; - - - if ( sheet->cell_padding ) - { - area.x += sheet->cell_padding->left; - area.width -= sheet->cell_padding->right - + sheet->cell_padding->left; - - area.y += sheet->cell_padding->top; - area.height -= sheet->cell_padding->bottom - + - sheet->cell_padding->top; - } - - /* Centre the text vertically */ - area.y += (area.height - font_height) / 2.0; - - switch (attributes.justification) - { - case GTK_JUSTIFY_RIGHT: - area.x += area.width - text.width; - break; - case GTK_JUSTIFY_CENTER: - area.x += (area.width - text.width) / 2.0; - break; - case GTK_JUSTIFY_LEFT: - /* Do nothing */ - break; - default: - g_critical ("Unhandled justification %d in column %d\n", - attributes.justification, col); - break; - } - - gdk_draw_layout (sheet->sheet_window, sheet->fg_gc, - area.x, - area.y, - layout); - - gdk_gc_set_clip_rectangle (sheet->fg_gc, NULL); - g_object_unref (layout); -} - - -static void -draw_sheet_region (PsppireSheet *sheet, GdkRegion *region) -{ - PsppireSheetRange range; - GdkRectangle area; - gint y, x; - gint i, j; - - PsppireSheetRange drawing_range; - - gdk_region_get_clipbox (region, &area); - - y = area.y + sheet->vadjustment->value; - x = area.x + sheet->hadjustment->value; - - if ( sheet->column_titles_visible) - y -= sheet->column_title_area.height; - - if ( sheet->row_titles_visible) - x -= sheet->row_title_area.width; - - maximize_int (&x, 0); - maximize_int (&y, 0); - - range.row0 = row_from_ypixel (sheet, y); - range.rowi = row_from_ypixel (sheet, y + area.height); - - range.col0 = column_from_xpixel (sheet, x); - range.coli = column_from_xpixel (sheet, x + area.width); - - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_SHEET (sheet)); - - if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return; - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return; - if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return; - - - drawing_range.row0 = MAX (range.row0, min_visible_row (sheet)); - drawing_range.col0 = MAX (range.col0, min_visible_column (sheet)); - drawing_range.rowi = MIN (range.rowi, max_visible_row (sheet)); - drawing_range.coli = MIN (range.coli, max_visible_column (sheet)); - - g_return_if_fail (drawing_range.rowi >= drawing_range.row0); - g_return_if_fail (drawing_range.coli >= drawing_range.col0); - - for (i = drawing_range.row0; i <= drawing_range.rowi; i++) - { - for (j = drawing_range.col0; j <= drawing_range.coli; j++) - psppire_sheet_cell_draw (sheet, i, j); - } - - if (sheet->select_status == PSPPIRE_SHEET_NORMAL && - sheet->active_cell.row >= drawing_range.row0 && - sheet->active_cell.row <= drawing_range.rowi && - sheet->active_cell.col >= drawing_range.col0 && - sheet->active_cell.col <= drawing_range.coli) - psppire_sheet_show_entry_widget (sheet); -} - -static void -psppire_sheet_set_cell (PsppireSheet *sheet, gint row, gint col, - GtkJustification justification, - const gchar *text) -{ - PsppireSheetModel *model ; - gchar *old_text ; - - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (col >= psppire_axis_unit_count (sheet->haxis) - || row >= psppire_axis_unit_count (sheet->vaxis)) - return; - - if (col < 0 || row < 0) return; - - model = psppire_sheet_get_model (sheet); - - old_text = psppire_sheet_model_get_string (model, row, col); - - if (0 != g_strcmp0 (old_text, text)) - { - g_signal_handler_block (sheet->model, sheet->update_handler_id); - psppire_sheet_model_set_string (model, text, row, col); - g_signal_handler_unblock (sheet->model, sheet->update_handler_id); - } - - if ( psppire_sheet_model_free_strings (model)) - g_free (old_text); -} - - -void -psppire_sheet_cell_clear (PsppireSheet *sheet, gint row, gint column) -{ - PsppireSheetRange range; - - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - if (column >= psppire_axis_unit_count (sheet->haxis) || - row >= psppire_axis_unit_count (sheet->vaxis)) return; - - if (column < 0 || row < 0) return; - - range.row0 = row; - range.rowi = row; - range.col0 = min_visible_column (sheet); - range.coli = max_visible_column (sheet); - - psppire_sheet_real_cell_clear (sheet, row, column); - - redraw_range (sheet, &range); -} - -static void -psppire_sheet_real_cell_clear (PsppireSheet *sheet, gint row, gint column) -{ - PsppireSheetModel *model = psppire_sheet_get_model (sheet); - - gchar *old_text = psppire_sheet_cell_get_text (sheet, row, column); - - if (old_text && strlen (old_text) > 0 ) - { - psppire_sheet_model_datum_clear (model, row, column); - } - - dispose_string (sheet, old_text); -} - -gchar * -psppire_sheet_cell_get_text (const PsppireSheet *sheet, gint row, gint col) -{ - PsppireSheetModel *model; - g_return_val_if_fail (sheet != NULL, NULL); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL); - - if (col >= psppire_axis_unit_count (sheet->haxis) || row >= psppire_axis_unit_count (sheet->vaxis)) - return NULL; - if (col < 0 || row < 0) return NULL; - - model = psppire_sheet_get_model (sheet); - - if ( !model ) - return NULL; - - return psppire_sheet_model_get_string (model, row, col); -} - - -/* Convert X, Y (in pixels) to *ROW, *COLUMN - If the function returns FALSE, then the results will be unreliable. -*/ -static gboolean -psppire_sheet_get_pixel_info (PsppireSheet *sheet, - gint x, - gint y, - gint *row, - gint *column) -{ - gint trow, tcol; - *row = -G_MAXINT; - *column = -G_MAXINT; - - g_return_val_if_fail (sheet != NULL, 0); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0); - - /* bounds checking, return false if the user clicked - on a blank area */ - if (y < 0) - return FALSE; - - if (x < 0) - return FALSE; - - if ( sheet->column_titles_visible) - y -= sheet->column_title_area.height; - - y += sheet->vadjustment->value; - - if ( y < 0 && sheet->column_titles_visible) - { - trow = -1; - } - else - { - trow = row_from_ypixel (sheet, y); - if (trow > psppire_axis_unit_count (sheet->vaxis)) - return FALSE; - } - - *row = trow; - - if ( sheet->row_titles_visible) - x -= sheet->row_title_area.width; - - x += sheet->hadjustment->value; - - if ( x < 0 && sheet->row_titles_visible) - { - tcol = -1; - } - else - { - tcol = column_from_xpixel (sheet, x); - if (tcol > psppire_axis_unit_count (sheet->haxis)) - return FALSE; - } - - *column = tcol; - - return TRUE; -} - -gboolean -psppire_sheet_get_cell_area (PsppireSheet *sheet, - gint row, - gint column, - GdkRectangle *area) -{ - g_return_val_if_fail (sheet != NULL, 0); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0); - - if (row >= psppire_axis_unit_count (sheet->vaxis) || column >= psppire_axis_unit_count (sheet->haxis)) - return FALSE; - - area->x = (column == -1) ? 0 : psppire_axis_start_pixel (sheet->haxis, column); - area->y = (row == -1) ? 0 : psppire_axis_start_pixel (sheet->vaxis, row); - - area->width= (column == -1) ? sheet->row_title_area.width - : psppire_axis_unit_size (sheet->haxis, column); - - area->height= (row == -1) ? sheet->column_title_area.height - : psppire_axis_unit_size (sheet->vaxis, row); - - return TRUE; -} - -void -psppire_sheet_set_active_cell (PsppireSheet *sheet, gint row, gint col) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (row < -1 || col < -1) - return; - - if (row >= psppire_axis_unit_count (sheet->vaxis) - || - col >= psppire_axis_unit_count (sheet->haxis)) - return; - - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - if ( row == -1 || col == -1) - { - psppire_sheet_hide_entry_widget (sheet); - return; - } - - change_active_cell (sheet, row, col); -} - -void -psppire_sheet_get_active_cell (PsppireSheet *sheet, gint *row, gint *column) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if ( row ) *row = sheet->active_cell.row; - if (column) *column = sheet->active_cell.col; -} - -static void -entry_load_text (PsppireSheet *sheet) -{ - gint row, col; - const char *text; - GtkJustification justification; - PsppireSheetCellAttr attributes; - - if (!GTK_WIDGET_VISIBLE (sheet->entry_widget)) return; - if (sheet->select_status != PSPPIRE_SHEET_NORMAL) return; - - row = sheet->active_cell.row; - col = sheet->active_cell.col; - - if (row < 0 || col < 0) return; - - text = gtk_entry_get_text (psppire_sheet_get_entry (sheet)); - - if (text && strlen (text) > 0) - { - psppire_sheet_get_attributes (sheet, row, col, &attributes); - justification = attributes.justification; - psppire_sheet_set_cell (sheet, row, col, justification, text); - } -} - - -static void -psppire_sheet_hide_entry_widget (PsppireSheet *sheet) -{ - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - if (sheet->active_cell.row < 0 || - sheet->active_cell.col < 0) return; - - gtk_widget_hide (sheet->entry_widget); - gtk_widget_unmap (sheet->entry_widget); - - GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE); -} - -static void -change_active_cell (PsppireSheet *sheet, gint row, gint col) -{ - gint old_row, old_col; - - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (row < 0 || col < 0) - return; - - if ( row > psppire_axis_unit_count (sheet->vaxis) - || col > psppire_axis_unit_count (sheet->haxis)) - return; - - old_row = sheet->active_cell.row; - old_col = sheet->active_cell.col; - - entry_load_text (sheet); - - /* Erase the old cell border */ - psppire_sheet_draw_active_cell (sheet); - - sheet->active_cell.row = row; - sheet->active_cell.col = col; - - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - - GTK_WIDGET_UNSET_FLAGS (sheet->entry_widget, GTK_HAS_FOCUS); - - psppire_sheet_draw_active_cell (sheet); - psppire_sheet_show_entry_widget (sheet); - - GTK_WIDGET_SET_FLAGS (sheet->entry_widget, GTK_HAS_FOCUS); - - g_signal_emit (sheet, sheet_signals [ACTIVATE], 0, - row, col, old_row, old_col); - -} - -static void -psppire_sheet_show_entry_widget (PsppireSheet *sheet) -{ - GtkEntry *sheet_entry; - PsppireSheetCellAttr attributes; - - gint row, col; - - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - row = sheet->active_cell.row; - col = sheet->active_cell.col; - - /* Don't show the active cell, if there is no active cell: */ - if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */ - return; - - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return; - if (sheet->select_status != PSPPIRE_SHEET_NORMAL) return; - if (PSPPIRE_SHEET_IN_SELECTION (sheet)) return; - - GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE); - - sheet_entry = psppire_sheet_get_entry (sheet); - - psppire_sheet_get_attributes (sheet, row, col, &attributes); - - if (GTK_IS_ENTRY (sheet_entry)) - { - gchar *text = psppire_sheet_cell_get_text (sheet, row, col); - const gchar *old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry)); - - if ( ! text ) - text = g_strdup (""); - - if (strcmp (old_text, text) != 0) - gtk_entry_set_text (sheet_entry, text); - - dispose_string (sheet, text); - - { - switch (attributes.justification) - { - case GTK_JUSTIFY_RIGHT: - gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 1.0); - break; - case GTK_JUSTIFY_CENTER: - gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.5); - break; - case GTK_JUSTIFY_LEFT: - default: - gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.0); - break; - } - } - } - - psppire_sheet_size_allocate_entry (sheet); - - gtk_widget_set_sensitive (GTK_WIDGET (sheet_entry), - psppire_sheet_model_is_editable (sheet->model, - row, col)); - gtk_widget_map (sheet->entry_widget); -} - -static gboolean -psppire_sheet_draw_active_cell (PsppireSheet *sheet) -{ - gint row, col; - PsppireSheetRange range; - - row = sheet->active_cell.row; - col = sheet->active_cell.col; - - if (row < 0 || col < 0) return FALSE; - - if (!psppire_sheet_cell_isvisible (sheet, row, col)) - return FALSE; - - range.col0 = range.coli = col; - range.row0 = range.rowi = row; - - psppire_sheet_draw_border (sheet, range); - - return FALSE; -} - - - -static void -psppire_sheet_draw_border (PsppireSheet *sheet, PsppireSheetRange new_range) -{ - GdkRectangle area; - - rectangle_from_range (sheet, &new_range, &area); - - area.width ++; - area.height ++; - - gdk_gc_set_clip_rectangle (sheet->xor_gc, &area); - - area.x += sheet->cell_padding->left / 2; - area.y += sheet->cell_padding->top / 2; - area.width -= (sheet->cell_padding->left + sheet->cell_padding->right ) / 2; - area.height -= (sheet->cell_padding->top + sheet->cell_padding->bottom ) / 2; - - gdk_draw_rectangle (sheet->sheet_window, sheet->xor_gc, - FALSE, - area.x, - area.y, - area.width, - area.height); - - gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL); -} - - - -/* Selection related functions */ - -void -psppire_sheet_select_row (PsppireSheet *sheet, gint row) -{ - GdkRectangle area; - sheet->select_status = PSPPIRE_SHEET_ROW_SELECTED; - - sheet->range.col0 = sheet->range.coli = -1; - sheet->range.row0 = sheet->range.rowi = row; - - rectangle_from_range (sheet, &sheet->range, &area); - area.x++; - area.y++; - - gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE); - - g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, row); -} - -void -psppire_sheet_select_column (PsppireSheet *sheet, gint column) -{ - GdkRectangle area; - sheet->select_status = PSPPIRE_SHEET_COLUMN_SELECTED; - - sheet->range.col0 = sheet->range.coli = column; - sheet->range.row0 = sheet->range.rowi = -1; - - rectangle_from_range (sheet, &sheet->range, &area); - area.x++; - area.y++; - - gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE); - - g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, column); -} - - -void -psppire_sheet_select_range (PsppireSheet *sheet, const PsppireSheetRange *range) -{ - GdkRectangle area; - sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED; - - sheet->range = *range; - - rectangle_from_range (sheet, range, &area); - area.x++; - area.y++; - gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE); -} - - -void -psppire_sheet_unselect_range (PsppireSheet *sheet) -{ - sheet->select_status = PSPPIRE_SHEET_NORMAL; - - if (sheet->sheet_window != NULL) - { - GdkRectangle area; - - rectangle_from_range (sheet, &sheet->range, &area); - area.x++; - area.y++; - gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE); - } - - g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, -1); - g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, -1); -} - -void -psppire_sheet_get_selected_range (PsppireSheet *sheet, PsppireSheetRange *range) -{ - g_return_if_fail (sheet != NULL); - *range = sheet->range; -} - - -static gint -psppire_sheet_expose (GtkWidget *widget, GdkEventExpose *event) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - g_return_val_if_fail (event != NULL, FALSE); - - if (!GTK_WIDGET_DRAWABLE (widget)) - return FALSE; - - /* exposure events on the sheet */ - if (event->window == sheet->row_title_window && - sheet->row_titles_visible) - { - draw_row_title_buttons_range (sheet, - min_visible_row (sheet), - max_visible_row (sheet)); - } - - if (event->window == sheet->column_title_window && - sheet->column_titles_visible) - { - draw_column_title_buttons_range (sheet, - min_visible_column (sheet), - max_visible_column (sheet)); - } - - if (event->window == sheet->sheet_window) - { - draw_sheet_region (sheet, event->region); - - if (sheet->select_status != PSPPIRE_SHEET_NORMAL) - { - GdkRectangle area; - - rectangle_from_range (sheet, &sheet->range, &area); - - gdk_draw_rectangle (sheet->sheet_window, - sheet->xor_gc, - TRUE, - area.x + 1, area.y + 1, - area.width, area.height); - } - - - if ((!PSPPIRE_SHEET_IN_XDRAG (sheet)) && (!PSPPIRE_SHEET_IN_YDRAG (sheet))) - { - GdkRectangle rect; - PsppireSheetRange range; - range.row0 = range.rowi = sheet->active_cell.row; - range.col0 = range.coli = sheet->active_cell.col; - - rectangle_from_range (sheet, &range, &rect); - - if (GDK_OVERLAP_RECTANGLE_OUT != - gdk_region_rect_in (event->region, &rect)) - { - psppire_sheet_draw_active_cell (sheet); - } - } - - } - - (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); - - return FALSE; -} - - -static gboolean -psppire_sheet_button_press (GtkWidget *widget, GdkEventButton *event) -{ - PsppireSheet *sheet; - GdkModifierType mods; - gint x, y; - gint row, column; - - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (PSPPIRE_IS_SHEET (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - sheet = PSPPIRE_SHEET (widget); - - /* Cancel any pending tooltips */ - if (sheet->motion_timer) - { - g_source_remove (sheet->motion_timer); - sheet->motion_timer = 0; - } - - gtk_widget_get_pointer (widget, &x, &y); - psppire_sheet_get_pixel_info (sheet, x, y, &row, &column); - - - if (event->window == sheet->column_title_window) - { - sheet->x_drag = event->x; - g_signal_emit (sheet, - sheet_signals[BUTTON_EVENT_COLUMN], 0, - column, event); - - if (psppire_sheet_model_get_column_sensitivity (sheet->model, column)) - { - if ( event->type == GDK_2BUTTON_PRESS && event->button == 1) - g_signal_emit (sheet, - sheet_signals[DOUBLE_CLICK_COLUMN], 0, column); - } - } - - if (event->window == sheet->row_title_window) - { - g_signal_emit (sheet, - sheet_signals[BUTTON_EVENT_ROW], 0, - row, event); - - if (psppire_sheet_model_get_row_sensitivity (sheet->model, row)) - { - if ( event->type == GDK_2BUTTON_PRESS && event->button == 1) - g_signal_emit (sheet, - sheet_signals[DOUBLE_CLICK_ROW], 0, row); - } - } - - gdk_window_get_pointer (widget->window, NULL, NULL, &mods); - - if (! (mods & GDK_BUTTON1_MASK)) return TRUE; - - - /* press on resize windows */ - if (event->window == sheet->column_title_window) - { - sheet->x_drag = event->x; - - if (on_column_boundary (sheet, sheet->x_drag, &sheet->drag_cell.col)) - { - PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_XDRAG); - gdk_pointer_grab (sheet->column_title_window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - - draw_xor_vline (sheet); - return TRUE; - } - } - - if (event->window == sheet->row_title_window) - { - sheet->y_drag = event->y; - - if (on_row_boundary (sheet, sheet->y_drag, &sheet->drag_cell.row)) - { - PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_YDRAG); - gdk_pointer_grab (sheet->row_title_window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - - draw_xor_hline (sheet); - return TRUE; - } - } - - /* the sheet itself does not handle other than single click events */ - if (event->type != GDK_BUTTON_PRESS) return FALSE; - - /* selections on the sheet */ - if (event->window == sheet->sheet_window) - { - gtk_widget_get_pointer (widget, &x, &y); - psppire_sheet_get_pixel_info (sheet, x, y, &row, &column); - gdk_pointer_grab (sheet->sheet_window, FALSE, - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, event->time); - gtk_grab_add (GTK_WIDGET (sheet)); - - if ( sheet->select_status == PSPPIRE_SHEET_NORMAL) - { - sheet->range.row0 = row; - sheet->range.col0 = column; - } - else - { - psppire_sheet_unselect_range (sheet); - } - psppire_sheet_click_cell (sheet, row, column); - } - - if (event->window == sheet->column_title_window) - { - gtk_widget_get_pointer (widget, &x, &y); - if ( sheet->row_titles_visible) - x -= sheet->row_title_area.width; - - x += sheet->hadjustment->value; - - column = column_from_xpixel (sheet, x); - - if (psppire_sheet_model_get_column_sensitivity (sheet->model, column)) - { - gtk_grab_add (GTK_WIDGET (sheet)); - PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - } - } - - if (event->window == sheet->row_title_window) - { - gtk_widget_get_pointer (widget, &x, &y); - if ( sheet->column_titles_visible) - y -= sheet->column_title_area.height; - - y += sheet->vadjustment->value; - - row = row_from_ypixel (sheet, y); - if (psppire_sheet_model_get_row_sensitivity (sheet->model, row)) - { - gtk_grab_add (GTK_WIDGET (sheet)); - PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - } - } - - return TRUE; -} - -static gboolean -psppire_sheet_click_cell (PsppireSheet *sheet, gint row, gint column) -{ - PsppireSheetCell cell; - gboolean forbid_move; - - cell.row = row; - cell.col = column; - - if (row >= psppire_axis_unit_count (sheet->vaxis) - || column >= psppire_axis_unit_count (sheet->haxis)) - { - return FALSE; - } - - g_signal_emit (sheet, sheet_signals[TRAVERSE], 0, - &sheet->active_cell, - &cell, - &forbid_move); - - if (forbid_move) - { - if (sheet->select_status == PSPPIRE_SHEET_NORMAL) - return FALSE; - - row = sheet->active_cell.row; - column = sheet->active_cell.col; - - change_active_cell (sheet, row, column); - return FALSE; - } - - if (row == -1 && column >= 0) - { - psppire_sheet_select_column (sheet, column); - return TRUE; - } - - if (column == -1 && row >= 0) - { - psppire_sheet_select_row (sheet, row); - return TRUE; - } - - if (row == -1 && column == -1) - { - sheet->range.row0 = 0; - sheet->range.col0 = 0; - sheet->range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1; - sheet->range.coli = psppire_axis_unit_count (sheet->haxis) - 1; - return TRUE; - } - - if (sheet->select_status == PSPPIRE_SHEET_NORMAL) - change_active_cell (sheet, row, column); - - gtk_widget_grab_focus (GTK_WIDGET (sheet->entry_widget)); - - return TRUE; -} - -static gint -psppire_sheet_button_release (GtkWidget *widget, - GdkEventButton *event) -{ - GdkDisplay *display = gtk_widget_get_display (widget); - - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - /* release on resize windows */ - if (PSPPIRE_SHEET_IN_XDRAG (sheet)) - { - gint width; - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_XDRAG); - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - - gdk_display_pointer_ungrab (display, event->time); - draw_xor_vline (sheet); - - width = event->x - - psppire_axis_start_pixel (sheet->haxis, sheet->drag_cell.col) - + sheet->hadjustment->value; - - set_column_width (sheet, sheet->drag_cell.col, width); - - return TRUE; - } - - if (PSPPIRE_SHEET_IN_YDRAG (sheet)) - { - gint height; - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_YDRAG); - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - - gdk_display_pointer_ungrab (display, event->time); - draw_xor_hline (sheet); - - height = event->y - - psppire_axis_start_pixel (sheet->vaxis, sheet->drag_cell.row) + - sheet->vadjustment->value; - - set_row_height (sheet, sheet->drag_cell.row, height); - - return TRUE; - } - - if (PSPPIRE_SHEET_IN_DRAG (sheet)) - { - PsppireSheetRange old_range; - draw_xor_rectangle (sheet, sheet->drag_range); - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_DRAG); - gdk_display_pointer_ungrab (display, event->time); - - psppire_sheet_unselect_range (sheet); - - old_range = sheet->range; - sheet->range = sheet->drag_range; - sheet->drag_range = old_range; - g_signal_emit (sheet, sheet_signals[MOVE_RANGE], 0, - &sheet->drag_range, &sheet->range); - psppire_sheet_select_range (sheet, &sheet->range); - } - - if (PSPPIRE_SHEET_IN_SELECTION (sheet)) - { - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED; - - change_active_cell (sheet, sheet->active_cell.row, - sheet->active_cell.col); - } - - gdk_display_pointer_ungrab (display, event->time); - gtk_grab_remove (GTK_WIDGET (sheet)); - - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - - return TRUE; -} - - - - - -/* Shamelessly lifted from gtktooltips */ -static gboolean -psppire_sheet_subtitle_paint_window (GtkWidget *tip_window) -{ - GtkRequisition req; - - gtk_widget_size_request (tip_window, &req); - gtk_paint_flat_box (tip_window->style, tip_window->window, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, GTK_WIDGET(tip_window), "tooltip", - 0, 0, req.width, req.height); - - return FALSE; -} - -static void -destroy_hover_window (PsppireSheetHoverTitle *h) -{ - gtk_widget_destroy (h->window); - g_free (h); -} - -static PsppireSheetHoverTitle * -create_hover_window (void) -{ - PsppireSheetHoverTitle *hw = g_malloc (sizeof (*hw)); - - hw->window = gtk_window_new (GTK_WINDOW_POPUP); - -#if GTK_CHECK_VERSION (2, 9, 0) - gtk_window_set_type_hint (GTK_WINDOW (hw->window), - GDK_WINDOW_TYPE_HINT_TOOLTIP); -#endif - - gtk_widget_set_app_paintable (hw->window, TRUE); - gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE); - gtk_widget_set_name (hw->window, "gtk-tooltips"); - gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4); - - g_signal_connect (hw->window, - "expose_event", - G_CALLBACK (psppire_sheet_subtitle_paint_window), - NULL); - - hw->label = gtk_label_new (NULL); - - - gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE); - gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5); - - gtk_container_add (GTK_CONTAINER (hw->window), hw->label); - - gtk_widget_show (hw->label); - - g_signal_connect (hw->window, - "destroy", - G_CALLBACK (gtk_widget_destroyed), - &hw->window); - - return hw; -} - -#define HOVER_WINDOW_Y_OFFSET 2 - -static void -show_subtitle (PsppireSheet *sheet, gint row, gint column, - const gchar *subtitle) -{ - gint x, y; - gint px, py; - gint width; - - if ( ! subtitle ) - return; - - gtk_label_set_text (GTK_LABEL (sheet->hover_window->label), - subtitle); - - - sheet->hover_window->row = row; - sheet->hover_window->column = column; - - gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y); - - gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py); - - gtk_widget_show (sheet->hover_window->window); - - width = GTK_WIDGET (sheet->hover_window->label)->allocation.width; - - if (row == -1 ) - { - x += px; - x -= width / 2; - y += sheet->column_title_area.y; - y += sheet->column_title_area.height; - y += HOVER_WINDOW_Y_OFFSET; - } - - if ( column == -1 ) - { - y += py; - x += sheet->row_title_area.x; - x += sheet->row_title_area.width * 2 / 3.0; - } - - gtk_window_move (GTK_WINDOW (sheet->hover_window->window), - x, y); -} - -static gboolean -motion_timeout_callback (gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - gint x, y; - gint row, column; - - gdk_threads_enter (); - gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y); - - if ( psppire_sheet_get_pixel_info (sheet, x, y, &row, &column) ) - { - if (sheet->row_title_under && row >= 0) - { - gchar *text = psppire_sheet_model_get_row_subtitle (sheet->model, row); - - show_subtitle (sheet, row, -1, text); - g_free (text); - } - - if (sheet->column_title_under && column >= 0) - { - gchar *text = psppire_sheet_model_get_column_subtitle (sheet->model, - column); - - show_subtitle (sheet, -1, column, text); - - g_free (text); - } - } - - gdk_threads_leave (); - return FALSE; -} - -static gboolean -psppire_sheet_motion (GtkWidget *widget, GdkEventMotion *event) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - GdkModifierType mods; - GdkCursorType new_cursor; - gint x, y; - gint row, column; - GdkDisplay *display; - - g_return_val_if_fail (event != NULL, FALSE); - - display = gtk_widget_get_display (widget); - - /* selections on the sheet */ - x = event->x; - y = event->y; - - if (!GTK_WIDGET_VISIBLE (sheet->hover_window->window)) - { - if ( sheet->motion_timer > 0 ) - g_source_remove (sheet->motion_timer); - sheet->motion_timer = - g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet); - } - else - { - gint row, column; - gint wx, wy; - gtk_widget_get_pointer (widget, &wx, &wy); - - if ( psppire_sheet_get_pixel_info (sheet, wx, wy, &row, &column) ) - { - if ( row != sheet->hover_window->row || - column != sheet->hover_window->column) - { - gtk_widget_hide (sheet->hover_window->window); - } - } - } - - if (event->window == sheet->column_title_window) - { - if (!PSPPIRE_SHEET_IN_SELECTION (sheet) && - on_column_boundary (sheet, x, &column)) - { - new_cursor = GDK_SB_H_DOUBLE_ARROW; - if (new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = - gdk_cursor_new_for_display (display, new_cursor); - - gdk_window_set_cursor (sheet->column_title_window, - sheet->cursor_drag); - } - } - else - { - new_cursor = GDK_TOP_LEFT_ARROW; - if (!PSPPIRE_SHEET_IN_XDRAG (sheet) && - new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = - gdk_cursor_new_for_display (display, new_cursor); - gdk_window_set_cursor (sheet->column_title_window, - sheet->cursor_drag); - } - } - } - else if (event->window == sheet->row_title_window) - { - if (!PSPPIRE_SHEET_IN_SELECTION (sheet) && - on_row_boundary (sheet, y, &row)) - { - new_cursor = GDK_SB_V_DOUBLE_ARROW; - if (new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = - gdk_cursor_new_for_display (display, new_cursor); - gdk_window_set_cursor (sheet->row_title_window, - sheet->cursor_drag); - } - } - else - { - new_cursor = GDK_TOP_LEFT_ARROW; - if (!PSPPIRE_SHEET_IN_YDRAG (sheet) && - new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = - gdk_cursor_new_for_display (display, new_cursor); - gdk_window_set_cursor (sheet->row_title_window, - sheet->cursor_drag); - } - } - } - - new_cursor = GDK_PLUS; - if ( event->window == sheet->sheet_window && - !POSSIBLE_DRAG (sheet, x, y, &row, &column) && - !PSPPIRE_SHEET_IN_DRAG (sheet) && - !POSSIBLE_RESIZE (sheet, x, y, &row, &column) && - new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS); - gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag); - } - - new_cursor = GDK_TOP_LEFT_ARROW; - if ( event->window == sheet->sheet_window && - ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ) && - (POSSIBLE_DRAG (sheet, x, y, &row, &column) || - PSPPIRE_SHEET_IN_DRAG (sheet)) && - new_cursor != sheet->cursor_drag->type) - { - gdk_cursor_unref (sheet->cursor_drag); - sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW); - gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag); - } - - gdk_window_get_pointer (widget->window, &x, &y, &mods); - if (! (mods & GDK_BUTTON1_MASK)) return FALSE; - - if (PSPPIRE_SHEET_IN_XDRAG (sheet)) - { - if (event->x != sheet->x_drag) - { - draw_xor_vline (sheet); - sheet->x_drag = event->x; - draw_xor_vline (sheet); - } - - return TRUE; - } - - if (PSPPIRE_SHEET_IN_YDRAG (sheet)) - { - if (event->y != sheet->y_drag) - { - draw_xor_hline (sheet); - sheet->y_drag = event->y; - draw_xor_hline (sheet); - } - - return TRUE; - } - - if (PSPPIRE_SHEET_IN_DRAG (sheet)) - { - PsppireSheetRange aux; - column = column_from_xpixel (sheet, x)- sheet->drag_cell.col; - row = row_from_ypixel (sheet, y) - sheet->drag_cell.row; - if (sheet->select_status == PSPPIRE_SHEET_COLUMN_SELECTED) row = 0; - if (sheet->select_status == PSPPIRE_SHEET_ROW_SELECTED) column = 0; - sheet->x_drag = x; - sheet->y_drag = y; - aux = sheet->range; - if (aux.row0 + row >= 0 && aux.rowi + row < psppire_axis_unit_count (sheet->vaxis) && - aux.col0 + column >= 0 && aux.coli + column < psppire_axis_unit_count (sheet->haxis)) - { - aux = sheet->drag_range; - sheet->drag_range.row0 = sheet->range.row0 + row; - sheet->drag_range.col0 = sheet->range.col0 + column; - sheet->drag_range.rowi = sheet->range.rowi + row; - sheet->drag_range.coli = sheet->range.coli + column; - if (aux.row0 != sheet->drag_range.row0 || - aux.col0 != sheet->drag_range.col0) - { - draw_xor_rectangle (sheet, aux); - draw_xor_rectangle (sheet, sheet->drag_range); - } - } - return TRUE; - } - - psppire_sheet_get_pixel_info (sheet, x, y, &row, &column); - - if (sheet->select_status == PSPPIRE_SHEET_NORMAL && row == sheet->active_cell.row && - column == sheet->active_cell.col) return TRUE; - - if ( mods & GDK_BUTTON1_MASK) - { - if (PSPPIRE_SHEET_IN_SELECTION (sheet) ) - { - /* Redraw the old range */ - psppire_sheet_unselect_range (sheet); - - sheet->range.rowi = row; - sheet->range.coli = column; - - /* Redraw the new range */ - psppire_sheet_select_range (sheet, &sheet->range); - } - else - { - PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - } - } - - return TRUE; -} - -static gboolean -psppire_sheet_crossing_notify (GtkWidget *widget, - GdkEventCrossing *event) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - if (event->window == sheet->column_title_window) - sheet->column_title_under = event->type == GDK_ENTER_NOTIFY; - else if (event->window == sheet->row_title_window) - sheet->row_title_under = event->type == GDK_ENTER_NOTIFY; - - if (event->type == GDK_LEAVE_NOTIFY) - gtk_widget_hide (sheet->hover_window->window); - - return TRUE; -} - - -static gboolean -psppire_sheet_focus_in (GtkWidget *w, - GdkEventFocus *event) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (w); - - gtk_widget_grab_focus (sheet->entry_widget); - - return TRUE; -} - - - -static gint -psppire_sheet_entry_key_press (GtkWidget *widget, - GdkEventKey *key) -{ - gboolean focus; - g_signal_emit_by_name (widget, "key_press_event", key, &focus); - return focus; -} - - -/* Number of rows in a step-increment */ -#define ROWS_PER_STEP 1 - - -static void -page_vertical (PsppireSheet *sheet, GtkScrollType dir) -{ - gint old_row = sheet->active_cell.row ; - glong vpixel = psppire_axis_start_pixel (sheet->vaxis, old_row); - - gint new_row; - - vpixel -= psppire_axis_start_pixel (sheet->vaxis, - min_visible_row (sheet)); - - switch ( dir) - { - case GTK_SCROLL_PAGE_DOWN: - gtk_adjustment_set_value (sheet->vadjustment, - sheet->vadjustment->value + - sheet->vadjustment->page_increment); - break; - case GTK_SCROLL_PAGE_UP: - gtk_adjustment_set_value (sheet->vadjustment, - sheet->vadjustment->value - - sheet->vadjustment->page_increment); - - break; - default: - g_assert_not_reached (); - break; - } - - - vpixel += psppire_axis_start_pixel (sheet->vaxis, - min_visible_row (sheet)); - - new_row = row_from_ypixel (sheet, vpixel); - - change_active_cell (sheet, new_row, - sheet->active_cell.col); -} - - -static void -step_sheet (PsppireSheet *sheet, GtkScrollType dir) -{ - gint current_row = sheet->active_cell.row; - gint current_col = sheet->active_cell.col; - PsppireSheetCell new_cell ; - gboolean forbidden = FALSE; - - new_cell.row = current_row; - new_cell.col = current_col; - - switch ( dir) - { - case GTK_SCROLL_STEP_DOWN: - new_cell.row++; - break; - case GTK_SCROLL_STEP_UP: - new_cell.row--; - break; - case GTK_SCROLL_STEP_RIGHT: - new_cell.col++; - break; - case GTK_SCROLL_STEP_LEFT: - new_cell.col--; - break; - case GTK_SCROLL_STEP_FORWARD: - new_cell.col++; - if (new_cell.col >= - psppire_sheet_model_get_column_count (sheet->model)) - { - new_cell.col = 0; - new_cell.row++; - } - break; - case GTK_SCROLL_STEP_BACKWARD: - new_cell.col--; - if (new_cell.col < 0) - { - new_cell.col = - psppire_sheet_model_get_column_count (sheet->model) - 1; - new_cell.row--; - } - break; - default: - g_assert_not_reached (); - break; - } - - g_signal_emit (sheet, sheet_signals[TRAVERSE], 0, - &sheet->active_cell, - &new_cell, - &forbidden); - - if (forbidden) - return; - - - maximize_int (&new_cell.row, 0); - maximize_int (&new_cell.col, 0); - - minimize_int (&new_cell.row, - psppire_axis_unit_count (sheet->vaxis) - 1); - - minimize_int (&new_cell.col, - psppire_axis_unit_count (sheet->haxis) - 1); - - change_active_cell (sheet, new_cell.row, new_cell.col); - - - if ( new_cell.col > max_fully_visible_column (sheet)) - { - glong hpos = - psppire_axis_start_pixel (sheet->haxis, - new_cell.col + 1); - hpos -= sheet->hadjustment->page_size; - - gtk_adjustment_set_value (sheet->hadjustment, - hpos); - } - else if ( new_cell.col < min_fully_visible_column (sheet)) - { - glong hpos = - psppire_axis_start_pixel (sheet->haxis, - new_cell.col); - - gtk_adjustment_set_value (sheet->hadjustment, - hpos); - } - - - if ( new_cell.row > max_fully_visible_row (sheet)) - { - glong vpos = - psppire_axis_start_pixel (sheet->vaxis, - new_cell.row + 1); - vpos -= sheet->vadjustment->page_size; - - gtk_adjustment_set_value (sheet->vadjustment, - vpos); - } - else if ( new_cell.row < min_fully_visible_row (sheet)) - { - glong vpos = - psppire_axis_start_pixel (sheet->vaxis, - new_cell.row); - - gtk_adjustment_set_value (sheet->vadjustment, - vpos); - } - - gtk_widget_grab_focus (GTK_WIDGET (sheet->entry_widget)); -} - - -static gboolean -psppire_sheet_key_press (GtkWidget *widget, - GdkEventKey *key) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (widget); - - PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION); - - switch (key->keyval) - { - case GDK_Tab: - step_sheet (sheet, GTK_SCROLL_STEP_FORWARD); - break; - case GDK_Right: - step_sheet (sheet, GTK_SCROLL_STEP_RIGHT); - break; - case GDK_ISO_Left_Tab: - step_sheet (sheet, GTK_SCROLL_STEP_BACKWARD); - break; - case GDK_Left: - step_sheet (sheet, GTK_SCROLL_STEP_LEFT); - break; - case GDK_Return: - case GDK_Down: - step_sheet (sheet, GTK_SCROLL_STEP_DOWN); - break; - case GDK_Up: - step_sheet (sheet, GTK_SCROLL_STEP_UP); - break; - - case GDK_Page_Down: - page_vertical (sheet, GTK_SCROLL_PAGE_DOWN); - break; - case GDK_Page_Up: - page_vertical (sheet, GTK_SCROLL_PAGE_UP); - break; - - case GDK_Home: - gtk_adjustment_set_value (sheet->vadjustment, - sheet->vadjustment->lower); - - change_active_cell (sheet, 0, - sheet->active_cell.col); - - break; - - case GDK_End: - gtk_adjustment_set_value (sheet->vadjustment, - sheet->vadjustment->upper - - sheet->vadjustment->page_size - - sheet->vadjustment->page_increment); - - /* - change_active_cellx (sheet, - psppire_axis_unit_count (sheet->vaxis) - 1, - sheet->active_cell.col); - */ - break; - case GDK_Delete: - psppire_sheet_real_cell_clear (sheet, sheet->active_cell.row, sheet->active_cell.col); - break; - default: - return FALSE; - break; - } - - return TRUE; -} - -static void -psppire_sheet_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - PsppireSheet *sheet; - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - g_return_if_fail (requisition != NULL); - - sheet = PSPPIRE_SHEET (widget); - - requisition->width = 3 * DEFAULT_COLUMN_WIDTH; - requisition->height = 3 * DEFAULT_ROW_HEIGHT; - - /* compute the size of the column title area */ - if (sheet->column_titles_visible) - requisition->height += sheet->column_title_area.height; - - /* compute the size of the row title area */ - if (sheet->row_titles_visible) - requisition->width += sheet->row_title_area.width; -} - - -static void -psppire_sheet_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - PsppireSheet *sheet; - GtkAllocation sheet_allocation; - gint border_width; - - g_return_if_fail (widget != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (widget)); - g_return_if_fail (allocation != NULL); - - sheet = PSPPIRE_SHEET (widget); - widget->allocation = *allocation; - border_width = GTK_CONTAINER (widget)->border_width; - - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize (widget->window, - allocation->x + border_width, - allocation->y + border_width, - allocation->width - 2 * border_width, - allocation->height - 2 * border_width); - - sheet_allocation.x = 0; - sheet_allocation.y = 0; - sheet_allocation.width = allocation->width - 2 * border_width; - sheet_allocation.height = allocation->height - 2 * border_width; - - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize (sheet->sheet_window, - sheet_allocation.x, - sheet_allocation.y, - sheet_allocation.width, - sheet_allocation.height); - - /* position the window which holds the column title buttons */ - sheet->column_title_area.x = 0; - sheet->column_title_area.y = 0; - sheet->column_title_area.width = sheet_allocation.width ; - - - /* position the window which holds the row title buttons */ - sheet->row_title_area.x = 0; - sheet->row_title_area.y = 0; - sheet->row_title_area.height = sheet_allocation.height; - - if (sheet->row_titles_visible) - sheet->column_title_area.x += sheet->row_title_area.width; - - if (sheet->column_titles_visible) - sheet->row_title_area.y += sheet->column_title_area.height; - - if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible) - gdk_window_move_resize (sheet->column_title_window, - sheet->column_title_area.x, - sheet->column_title_area.y, - sheet->column_title_area.width, - sheet->column_title_area.height); - - - if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible) - gdk_window_move_resize (sheet->row_title_window, - sheet->row_title_area.x, - sheet->row_title_area.y, - sheet->row_title_area.width, - sheet->row_title_area.height); - - size_allocate_global_button (sheet); - - if (sheet->haxis) - { - gint width = sheet->column_title_area.width; - - if ( sheet->row_titles_visible) - width -= sheet->row_title_area.width; - - g_object_set (sheet->haxis, - "minimum-extent", width, - NULL); - } - - - if (sheet->vaxis) - { - gint height = sheet->row_title_area.height; - - if ( sheet->column_titles_visible) - height -= sheet->column_title_area.height; - - g_object_set (sheet->vaxis, - "minimum-extent", height, - NULL); - } - - - /* set the scrollbars adjustments */ - adjust_scrollbars (sheet); -} - -static void -draw_column_title_buttons (PsppireSheet *sheet) -{ - gint x, width; - - if (!sheet->column_titles_visible) return; - if (!GTK_WIDGET_REALIZED (sheet)) - return; - - gdk_drawable_get_size (sheet->sheet_window, &width, NULL); - x = 0; - - if (sheet->row_titles_visible) - { - x = sheet->row_title_area.width; - } - - if (sheet->column_title_area.width != width || sheet->column_title_area.x != x) - { - sheet->column_title_area.width = width; - sheet->column_title_area.x = x; - gdk_window_move_resize (sheet->column_title_window, - sheet->column_title_area.x, - sheet->column_title_area.y, - sheet->column_title_area.width, - sheet->column_title_area.height); - } - - if (max_visible_column (sheet) == - psppire_axis_unit_count (sheet->haxis) - 1) - gdk_window_clear_area (sheet->column_title_window, - 0, 0, - sheet->column_title_area.width, - sheet->column_title_area.height); - - if (!GTK_WIDGET_DRAWABLE (sheet)) return; - - draw_column_title_buttons_range (sheet, min_visible_column (sheet), - max_visible_column (sheet)); -} - -static void -draw_row_title_buttons (PsppireSheet *sheet) -{ - gint y = 0; - gint height; - - if (!sheet->row_titles_visible) return; - if (!GTK_WIDGET_REALIZED (sheet)) - return; - - gdk_drawable_get_size (sheet->sheet_window, NULL, &height); - - if (sheet->column_titles_visible) - { - y = sheet->column_title_area.height; - } - - if (sheet->row_title_area.height != height || sheet->row_title_area.y != y) - { - sheet->row_title_area.y = y; - sheet->row_title_area.height = height; - gdk_window_move_resize (sheet->row_title_window, - sheet->row_title_area.x, - sheet->row_title_area.y, - sheet->row_title_area.width, - sheet->row_title_area.height); - } - - if (max_visible_row (sheet) == psppire_axis_unit_count (sheet->vaxis) - 1) - gdk_window_clear_area (sheet->row_title_window, - 0, 0, - sheet->row_title_area.width, - sheet->row_title_area.height); - - if (!GTK_WIDGET_DRAWABLE (sheet)) return; - - draw_row_title_buttons_range (sheet, min_visible_row (sheet), - max_visible_row (sheet)); -} - - -static void -psppire_sheet_size_allocate_entry (PsppireSheet *sheet) -{ - GtkAllocation entry_alloc; - PsppireSheetCellAttr attributes = { 0 }; - GtkEntry *sheet_entry; - - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return; - if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return; - - sheet_entry = psppire_sheet_get_entry (sheet); - - if ( ! psppire_sheet_get_attributes (sheet, sheet->active_cell.row, - sheet->active_cell.col, - &attributes) ) - return ; - - if ( GTK_WIDGET_REALIZED (sheet->entry_widget) ) - { - GtkStyle *style = GTK_WIDGET (sheet_entry)->style; - - style->bg[GTK_STATE_NORMAL] = attributes.background; - style->fg[GTK_STATE_NORMAL] = attributes.foreground; - style->text[GTK_STATE_NORMAL] = attributes.foreground; - style->bg[GTK_STATE_ACTIVE] = attributes.background; - style->fg[GTK_STATE_ACTIVE] = attributes.foreground; - style->text[GTK_STATE_ACTIVE] = attributes.foreground; - } - - rectangle_from_cell (sheet, sheet->active_cell.row, - sheet->active_cell.col, &entry_alloc); - - entry_alloc.x += sheet->cell_padding->left; - entry_alloc.y += sheet->cell_padding->right; - entry_alloc.width -= sheet->cell_padding->left + sheet->cell_padding->right; - entry_alloc.height -= sheet->cell_padding->top + sheet->cell_padding->bottom; - - - gtk_widget_set_size_request (sheet->entry_widget, entry_alloc.width, - entry_alloc.height); - gtk_widget_size_allocate (sheet->entry_widget, &entry_alloc); -} - - -/* Copy the sheet's font to the entry widget */ -static void -set_entry_widget_font (PsppireSheet *sheet) -{ - GtkRcStyle *style = gtk_widget_get_modifier_style (sheet->entry_widget); - - pango_font_description_free (style->font_desc); - style->font_desc = pango_font_description_copy (GTK_WIDGET (sheet)->style->font_desc); - - gtk_widget_modify_style (sheet->entry_widget, style); -} - -static void -create_sheet_entry (PsppireSheet *sheet) -{ - if (sheet->entry_widget) - { - gtk_widget_unparent (sheet->entry_widget); - } - - sheet->entry_widget = g_object_new (sheet->entry_type, NULL); - g_object_ref_sink (sheet->entry_widget); - - gtk_widget_size_request (sheet->entry_widget, NULL); - - if ( GTK_IS_ENTRY (sheet->entry_widget)) - { - g_object_set (sheet->entry_widget, - "has-frame", FALSE, - NULL); - } - - if (GTK_WIDGET_REALIZED (sheet)) - { - gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window); - gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet)); - gtk_widget_realize (sheet->entry_widget); - } - - g_signal_connect_swapped (sheet->entry_widget, "key_press_event", - G_CALLBACK (psppire_sheet_entry_key_press), - sheet); - - set_entry_widget_font (sheet); - - gtk_widget_show (sheet->entry_widget); -} - - -/* Finds the last child widget that happens to be of type GtkEntry */ -static void -find_entry (GtkWidget *w, gpointer user_data) -{ - GtkWidget **entry = user_data; - if ( GTK_IS_ENTRY (w)) - { - *entry = w; - } -} - - -GtkEntry * -psppire_sheet_get_entry (PsppireSheet *sheet) -{ - GtkWidget *w = sheet->entry_widget; - - g_return_val_if_fail (sheet != NULL, NULL); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL); - g_return_val_if_fail (sheet->entry_widget != NULL, NULL); - - while (! GTK_IS_ENTRY (w)) - { - GtkWidget *entry = NULL; - - if (GTK_IS_CONTAINER (w)) - { - gtk_container_forall (GTK_CONTAINER (w), find_entry, &entry); - - if (NULL == entry) - break; - - w = entry; - } - } - - return GTK_ENTRY (w); -} - - -static void -draw_button (PsppireSheet *sheet, GdkWindow *window, - PsppireSheetButton *button, gboolean is_sensitive, - GdkRectangle allocation) -{ - GtkShadowType shadow_type; - gint text_width = 0, text_height = 0; - PangoAlignment align = PANGO_ALIGN_LEFT; - - gboolean rtl ; - - gint state = 0; - - g_return_if_fail (sheet != NULL); - g_return_if_fail (button != NULL); - - - rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL; - - gdk_window_clear_area (window, - allocation.x, allocation.y, - allocation.width, allocation.height); - - gtk_widget_ensure_style (sheet->button); - - gtk_paint_box (sheet->button->style, window, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - &allocation, - GTK_WIDGET (sheet->button), - NULL, - allocation.x, allocation.y, - allocation.width, allocation.height); - - state = button->state; - if (!is_sensitive) state = GTK_STATE_INSENSITIVE; - - if (state == GTK_STATE_ACTIVE) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE) - gtk_paint_box (sheet->button->style, window, - button->state, shadow_type, - &allocation, GTK_WIDGET (sheet->button), - NULL, - allocation.x, allocation.y, - allocation.width, allocation.height); - - if ( button->overstruck) - { - GdkPoint points[2] = { - {allocation.x, allocation.y}, - {allocation.x + allocation.width, - allocation.y + allocation.height} - }; - - gtk_paint_polygon (sheet->button->style, - window, - button->state, - shadow_type, - NULL, - GTK_WIDGET (sheet), - NULL, - points, - 2, - TRUE); - } - - if (button->label_visible) - { - text_height = DEFAULT_ROW_HEIGHT - - 2 * COLUMN_TITLES_HEIGHT; - - gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state], - &allocation); - gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, - &allocation); - - allocation.y += 2 * sheet->button->style->ythickness; - - if (button->label && strlen (button->label) > 0) - { - PangoRectangle rect; - gchar *line = button->label; - - PangoLayout *layout = NULL; - gint real_x = allocation.x; - gint real_y = allocation.y; - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line); - pango_layout_get_extents (layout, NULL, &rect); - - text_width = PANGO_PIXELS (rect.width); - switch (button->justification) - { - case GTK_JUSTIFY_LEFT: - real_x = allocation.x + COLUMN_TITLES_HEIGHT; - align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; - break; - case GTK_JUSTIFY_RIGHT: - real_x = allocation.x + allocation.width - text_width - COLUMN_TITLES_HEIGHT; - align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT; - break; - case GTK_JUSTIFY_CENTER: - default: - real_x = allocation.x + (allocation.width - text_width)/2; - align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; - pango_layout_set_justify (layout, TRUE); - } - pango_layout_set_alignment (layout, align); - gtk_paint_layout (GTK_WIDGET (sheet)->style, - window, - state, - FALSE, - &allocation, - GTK_WIDGET (sheet), - "label", - real_x, real_y, - layout); - g_object_unref (layout); - } - - gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state], - NULL); - gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL); - - } - - psppire_sheet_button_free (button); -} - - -/* Draw the column title buttons FIRST through to LAST */ -static void -draw_column_title_buttons_range (PsppireSheet *sheet, gint first, gint last) -{ - GdkRectangle rect; - gint col; - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return; - - if (!sheet->column_titles_visible) return; - - g_return_if_fail (first >= min_visible_column (sheet)); - g_return_if_fail (last <= max_visible_column (sheet)); - - rect.y = 0; - rect.height = sheet->column_title_area.height; - rect.x = psppire_axis_start_pixel (sheet->haxis, first) + CELL_SPACING; - rect.width = psppire_axis_start_pixel (sheet->haxis, last) + CELL_SPACING - + psppire_axis_unit_size (sheet->haxis, last); - - rect.x -= sheet->hadjustment->value; - - minimize_int (&rect.width, sheet->column_title_area.width); - maximize_int (&rect.x, 0); - - gdk_window_begin_paint_rect (sheet->column_title_window, &rect); - - for (col = first ; col <= last ; ++col) - { - GdkRectangle allocation; - gboolean is_sensitive = FALSE; - - PsppireSheetButton * - button = psppire_sheet_model_get_column_button (sheet->model, col); - allocation.y = 0; - allocation.x = psppire_axis_start_pixel (sheet->haxis, col) - + CELL_SPACING; - allocation.x -= sheet->hadjustment->value; - - allocation.height = sheet->column_title_area.height; - allocation.width = psppire_axis_unit_size (sheet->haxis, col); - is_sensitive = psppire_sheet_model_get_column_sensitivity (sheet->model, col); - - draw_button (sheet, sheet->column_title_window, - button, is_sensitive, allocation); - } - - gdk_window_end_paint (sheet->column_title_window); -} - - -static void -draw_row_title_buttons_range (PsppireSheet *sheet, gint first, gint last) -{ - GdkRectangle rect; - gint row; - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return; - - if (!sheet->row_titles_visible) return; - - g_return_if_fail (first >= min_visible_row (sheet)); - g_return_if_fail (last <= max_visible_row (sheet)); - - rect.x = 0; - rect.width = sheet->row_title_area.width; - rect.y = psppire_axis_start_pixel (sheet->vaxis, first) + CELL_SPACING; - rect.height = psppire_axis_start_pixel (sheet->vaxis, last) + CELL_SPACING - + psppire_axis_unit_size (sheet->vaxis, last); - - rect.y -= sheet->vadjustment->value; - - minimize_int (&rect.height, sheet->row_title_area.height); - maximize_int (&rect.y, 0); - - gdk_window_begin_paint_rect (sheet->row_title_window, &rect); - for (row = first; row <= last; ++row) - { - GdkRectangle allocation; - - gboolean is_sensitive = FALSE; - - PsppireSheetButton *button = - psppire_sheet_model_get_row_button (sheet->model, row); - allocation.x = 0; - allocation.y = psppire_axis_start_pixel (sheet->vaxis, row) - + CELL_SPACING; - allocation.y -= sheet->vadjustment->value; - - allocation.width = sheet->row_title_area.width; - allocation.height = psppire_axis_unit_size (sheet->vaxis, row); - is_sensitive = psppire_sheet_model_get_row_sensitivity (sheet->model, row); - - draw_button (sheet, sheet->row_title_window, - button, is_sensitive, allocation); - } - - gdk_window_end_paint (sheet->row_title_window); -} - -/* SCROLLBARS - * - * functions: - * adjust_scrollbars - * vadjustment_value_changed - * hadjustment_value_changed */ - - -static void -update_adjustment (GtkAdjustment *adj, PsppireAxis *axis, gint page_size) -{ - double position = - (adj->value + adj->page_size) - / - (adj->upper - adj->lower); - - const glong last_item = psppire_axis_unit_count (axis) - 1; - - if (isnan (position) || position < 0) - position = 0; - - adj->upper = - psppire_axis_start_pixel (axis, last_item) - + - psppire_axis_unit_size (axis, last_item) - ; - - adj->lower = 0; - adj->page_size = page_size; - -#if 0 - adj->value = position * (adj->upper - adj->lower) - adj->page_size; - - if ( adj->value < adj->lower) - adj->value = adj->lower; -#endif - - gtk_adjustment_changed (adj); -} - - -static void -adjust_scrollbars (PsppireSheet *sheet) -{ - gint width, height; - - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - gdk_drawable_get_size (sheet->sheet_window, &width, &height); - - if ( sheet->row_titles_visible) - width -= sheet->row_title_area.width; - - if (sheet->column_titles_visible) - height -= sheet->column_title_area.height; - - if (sheet->vadjustment) - { - glong last_row = psppire_axis_unit_count (sheet->vaxis) - 1; - - sheet->vadjustment->step_increment = - ROWS_PER_STEP * - psppire_axis_unit_size (sheet->vaxis, last_row); - - sheet->vadjustment->page_increment = - height - - sheet->column_title_area.height - - psppire_axis_unit_size (sheet->vaxis, last_row); - - update_adjustment (sheet->vadjustment, sheet->vaxis, height); - } - - if (sheet->hadjustment) - { - gint last_col = psppire_axis_unit_count (sheet->haxis) - 1; - sheet->hadjustment->step_increment = 1; - - sheet->hadjustment->page_increment = width; - - sheet->hadjustment->upper = - psppire_axis_start_pixel (sheet->haxis, last_col) - + - psppire_axis_unit_size (sheet->haxis, last_col) - ; - - update_adjustment (sheet->hadjustment, sheet->haxis, width); - } -} - -/* Subtracts the region of WIDGET from REGION */ -static void -subtract_widget_region (GdkRegion *region, GtkWidget *widget) -{ - GdkRectangle rect; - GdkRectangle intersect; - GdkRegion *region2; - - gdk_region_get_clipbox (region, &rect); - gtk_widget_intersect (widget, - &rect, - &intersect); - - region2 = gdk_region_rectangle (&intersect); - gdk_region_subtract (region, region2); - gdk_region_destroy (region2); -} - -static void -vadjustment_value_changed (GtkAdjustment *adjustment, - gpointer data) -{ - GdkRegion *region; - PsppireSheet *sheet = PSPPIRE_SHEET (data); - - g_return_if_fail (adjustment != NULL); - - if ( ! GTK_WIDGET_REALIZED (sheet)) return; - - gtk_widget_hide (sheet->entry_widget); - - region = - gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->sheet_window)); - - subtract_widget_region (region, sheet->button); - gdk_window_begin_paint_region (sheet->sheet_window, region); - - draw_sheet_region (sheet, region); - - draw_row_title_buttons (sheet); - psppire_sheet_draw_active_cell (sheet); - - gdk_window_end_paint (sheet->sheet_window); - gdk_region_destroy (region); -} - - -static void -hadjustment_value_changed (GtkAdjustment *adjustment, - gpointer data) -{ - GdkRegion *region; - PsppireSheet *sheet = PSPPIRE_SHEET (data); - - g_return_if_fail (adjustment != NULL); - - if ( ! GTK_WIDGET_REALIZED (sheet)) return; - - gtk_widget_hide (sheet->entry_widget); - - - region = - gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->sheet_window)); - - subtract_widget_region (region, sheet->button); - gdk_window_begin_paint_region (sheet->sheet_window, region); - - draw_sheet_region (sheet, region); - - draw_column_title_buttons (sheet); - - psppire_sheet_draw_active_cell (sheet); - - gdk_window_end_paint (sheet->sheet_window); - - gdk_region_destroy (region); -} - - -/* COLUMN RESIZING */ -static void -draw_xor_vline (PsppireSheet *sheet) -{ - gint height; - gint xpos = sheet->x_drag; - gdk_drawable_get_size (sheet->sheet_window, - NULL, &height); - - if (sheet->row_titles_visible) - xpos += sheet->row_title_area.width; - - gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc, - xpos, - sheet->column_title_area.height, - xpos, - height + CELL_SPACING); -} - -/* ROW RESIZING */ -static void -draw_xor_hline (PsppireSheet *sheet) - -{ - gint width; - gint ypos = sheet->y_drag; - - gdk_drawable_get_size (sheet->sheet_window, - &width, NULL); - - - if (sheet->column_titles_visible) - ypos += sheet->column_title_area.height; - - gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc, - sheet->row_title_area.width, - ypos, - width + CELL_SPACING, - ypos); -} - -/* SELECTED RANGE */ -static void -draw_xor_rectangle (PsppireSheet *sheet, PsppireSheetRange range) -{ - gint i = 0; - GdkRectangle clip_area, area; - GdkGCValues values; - - area.x = psppire_axis_start_pixel (sheet->haxis, range.col0); - area.y = psppire_axis_start_pixel (sheet->vaxis, range.row0); - area.width = psppire_axis_start_pixel (sheet->haxis, range.coli)- area.x+ - psppire_axis_unit_size (sheet->haxis, range.coli); - area.height = psppire_axis_start_pixel (sheet->vaxis, range.rowi)- area.y + - psppire_axis_unit_size (sheet->vaxis, range.rowi); - - clip_area.x = sheet->row_title_area.width; - clip_area.y = sheet->column_title_area.height; - - gdk_drawable_get_size (sheet->sheet_window, - &clip_area.width, &clip_area.height); - - if (!sheet->row_titles_visible) clip_area.x = 0; - if (!sheet->column_titles_visible) clip_area.y = 0; - - if (area.x < 0) - { - area.width = area.width + area.x; - area.x = 0; - } - if (area.width > clip_area.width) area.width = clip_area.width + 10; - if (area.y < 0) - { - area.height = area.height + area.y; - area.y = 0; - } - if (area.height > clip_area.height) area.height = clip_area.height + 10; - - clip_area.x--; - clip_area.y--; - clip_area.width += 3; - clip_area.height += 3; - - gdk_gc_get_values (sheet->xor_gc, &values); - - gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area); - - gdk_draw_rectangle (sheet->sheet_window, - sheet->xor_gc, - FALSE, - area.x + i, area.y + i, - area.width - 2 * i, area.height - 2 * i); - - - gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL); - - gdk_gc_set_foreground (sheet->xor_gc, &values.foreground); -} - - -static void -set_column_width (PsppireSheet *sheet, - gint column, - gint width) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (column < 0 || column >= psppire_axis_unit_count (sheet->haxis)) - return; - - if ( width <= 0) - return; - - psppire_axis_resize (sheet->haxis, column, - width - sheet->cell_padding->left - - sheet->cell_padding->right); - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - { - draw_column_title_buttons (sheet); - adjust_scrollbars (sheet); - psppire_sheet_size_allocate_entry (sheet); - redraw_range (sheet, NULL); - } -} - -static void -set_row_height (PsppireSheet *sheet, - gint row, - gint height) -{ - g_return_if_fail (sheet != NULL); - g_return_if_fail (PSPPIRE_IS_SHEET (sheet)); - - if (row < 0 || row >= psppire_axis_unit_count (sheet->vaxis)) - return; - - if (height <= 0) - return; - - psppire_axis_resize (sheet->vaxis, row, - height - sheet->cell_padding->top - - sheet->cell_padding->bottom); - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) ) - { - draw_row_title_buttons (sheet); - adjust_scrollbars (sheet); - psppire_sheet_size_allocate_entry (sheet); - redraw_range (sheet, NULL); - } -} - -static gboolean -psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col, - PsppireSheetCellAttr *attr) -{ - GdkColor *fg, *bg; - const GtkJustification *j ; - GdkColormap *colormap; - - g_return_val_if_fail (sheet != NULL, FALSE); - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), FALSE); - - if (row < 0 || col < 0) return FALSE; - - attr->foreground = GTK_WIDGET (sheet)->style->black; - attr->background = sheet->color[BG_COLOR]; - - attr->border.width = 0; - attr->border.line_style = GDK_LINE_SOLID; - attr->border.cap_style = GDK_CAP_NOT_LAST; - attr->border.join_style = GDK_JOIN_MITER; - attr->border.mask = 0; - attr->border.color = GTK_WIDGET (sheet)->style->black; - - colormap = gtk_widget_get_colormap (GTK_WIDGET (sheet)); - fg = psppire_sheet_model_get_foreground (sheet->model, row, col); - if ( fg ) - { - gdk_colormap_alloc_color (colormap, fg, TRUE, TRUE); - attr->foreground = *fg; - } - - bg = psppire_sheet_model_get_background (sheet->model, row, col); - if ( bg ) - { - gdk_colormap_alloc_color (colormap, bg, TRUE, TRUE); - attr->background = *bg; - } - - attr->justification = - psppire_sheet_model_get_column_justification (sheet->model, col); - - j = psppire_sheet_model_get_justification (sheet->model, row, col); - if (j) - attr->justification = *j; - - return TRUE; -} - -static void -psppire_sheet_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (container); - - g_return_if_fail (callback != NULL); - - if (sheet->button && sheet->button->parent) - (* callback) (sheet->button, callback_data); - - if (sheet->entry_widget && GTK_IS_CONTAINER (sheet->entry_widget)) - (* callback) (sheet->entry_widget, callback_data); -} - - -PsppireSheetModel * -psppire_sheet_get_model (const PsppireSheet *sheet) -{ - g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), NULL); - - return sheet->model; -} - - -PsppireSheetButton * -psppire_sheet_button_new (void) -{ - PsppireSheetButton *button = g_malloc (sizeof (PsppireSheetButton)); - - button->state = GTK_STATE_NORMAL; - button->label = NULL; - button->label_visible = TRUE; - button->justification = GTK_JUSTIFY_FILL; - button->overstruck = FALSE; - - return button; -} - - -void -psppire_sheet_button_free (PsppireSheetButton *button) -{ - if (!button) return ; - - g_free (button->label); - g_free (button); -} - -static void -append_cell_text (GString *string, const PsppireSheet *sheet, gint r, gint c) -{ - gchar *celltext = psppire_sheet_cell_get_text (sheet, r, c); - - if ( NULL == celltext) - return; - - g_string_append (string, celltext); - g_free (celltext); -} - - -static GString * -range_to_text (const PsppireSheet *sheet) -{ - gint r, c; - GString *string; - - if ( !psppire_sheet_range_isvisible (sheet, &sheet->range)) - return NULL; - - string = g_string_sized_new (80); - - for (r = sheet->range.row0; r <= sheet->range.rowi; ++r) - { - for (c = sheet->range.col0; c < sheet->range.coli; ++c) - { - append_cell_text (string, sheet, r, c); - g_string_append (string, "\t"); - } - append_cell_text (string, sheet, r, c); - if ( r < sheet->range.rowi) - g_string_append (string, "\n"); - } - - return string; -} - -static GString * -range_to_html (const PsppireSheet *sheet) -{ - gint r, c; - GString *string; - - if ( !psppire_sheet_range_isvisible (sheet, &sheet->range)) - return NULL; - - string = g_string_sized_new (480); - - g_string_append (string, "\n"); - g_string_append (string, "\n"); - g_string_append (string, "\n"); - for (r = sheet->range.row0; r <= sheet->range.rowi; ++r) - { - g_string_append (string, "\n"); - for (c = sheet->range.col0; c <= sheet->range.coli; ++c) - { - g_string_append (string, "\n"); - } - g_string_append (string, "\n"); - } - g_string_append (string, "
"); - append_cell_text (string, sheet, r, c); - g_string_append (string, "
\n"); - g_string_append (string, "\n"); - g_string_append (string, "\n"); - - return string; -} - -enum { - SELECT_FMT_NULL, - SELECT_FMT_TEXT, - SELECT_FMT_HTML -}; - -static void -primary_get_cb (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - guint info, - gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - GString *string = NULL; - - switch (info) - { - case SELECT_FMT_TEXT: - string = range_to_text (sheet); - break; - case SELECT_FMT_HTML: - string = range_to_html (sheet); - break; - default: - g_assert_not_reached (); - } - - gtk_selection_data_set (selection_data, selection_data->target, - 8, - (const guchar *) string->str, string->len); - g_string_free (string, TRUE); -} - -static void -primary_clear_cb (GtkClipboard *clipboard, - gpointer data) -{ - PsppireSheet *sheet = PSPPIRE_SHEET (data); - if ( ! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) - return; - - psppire_sheet_unselect_range (sheet); -} - -static void -psppire_sheet_update_primary_selection (PsppireSheet *sheet) -{ - static const GtkTargetEntry targets[] = { - { "UTF8_STRING", 0, SELECT_FMT_TEXT }, - { "STRING", 0, SELECT_FMT_TEXT }, - { "TEXT", 0, SELECT_FMT_TEXT }, - { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT }, - { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT }, - { "text/plain", 0, SELECT_FMT_TEXT }, - { "text/html", 0, SELECT_FMT_HTML } - }; - - GtkClipboard *clipboard; - - if (!GTK_WIDGET_REALIZED (sheet)) - return; - - clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet), - GDK_SELECTION_PRIMARY); - - if (psppire_sheet_range_isvisible (sheet, &sheet->range)) - { - if (!gtk_clipboard_set_with_owner (clipboard, targets, - G_N_ELEMENTS (targets), - primary_get_cb, primary_clear_cb, - G_OBJECT (sheet))) - primary_clear_cb (clipboard, sheet); - } - else - { - if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet)) - gtk_clipboard_clear (clipboard); - } -}