1 #define GDK_MULTIHEAD_SAFE 1
3 * Copyright (C) 2006, 2008 Free Software Foundation
5 * This version of GtkSheet has been *heavily* modified, for the specific
6 * requirements of PSPPIRE. The changes are copyright by the
7 * Free Software Foundation. The copyright notice for the original work is
11 /* GtkSheet widget for Gtk+.
12 * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
14 * Based on GtkClist widget by Jay Painter, but major changes.
15 * Memory allocation routines inspired on SC (Spreadsheet Calculator)
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 * @short_description: spreadsheet widget for gtk2
36 * GtkSheet is a matrix widget for GTK+. It consists of an scrollable grid of
37 * cells where you can allocate text. Cell contents can be edited interactively
38 * through a specially designed entry, GtkItemEntry.
48 #include <gdk/gdkkeysyms.h>
49 #include <gtk/gtksignal.h>
50 #include <gtk/gtkbutton.h>
51 #include <gtk/gtkadjustment.h>
52 #include <gtk/gtktypeutils.h>
53 #include <gtk/gtkentry.h>
54 #include <gtk/gtkcontainer.h>
55 #include <gtk/gtkpixmap.h>
56 #include <pango/pango.h>
57 #include "gtkitementry.h"
59 #include "gtkextra-marshal.h"
60 #include "gsheetmodel.h"
65 GTK_SHEET_REDRAW_PENDING = 1 << 0,
66 GTK_SHEET_IN_XDRAG = 1 << 1,
67 GTK_SHEET_IN_YDRAG = 1 << 2,
68 GTK_SHEET_IN_DRAG = 1 << 3,
69 GTK_SHEET_IN_SELECTION = 1 << 4,
70 GTK_SHEET_IN_RESIZE = 1 << 5
73 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
74 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
75 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~ (flag))
77 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
78 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
79 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
80 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
81 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
82 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
84 #define CELL_SPACING 1
86 #define TIMEOUT_HOVER 300
87 #define COLUMN_MIN_WIDTH 10
88 #define COLUMN_TITLES_HEIGHT 4
89 #define DEFAULT_COLUMN_WIDTH 80
91 static void gtk_sheet_update_primary_selection (GtkSheet *sheet);
92 static void gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column);
94 static void gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row);
97 static gboolean gtk_sheet_cell_empty (const GtkSheet *, gint, gint);
99 static void destroy_hover_window (GtkSheetHoverTitle *);
100 static GtkSheetHoverTitle *create_hover_window (void);
103 dispose_string (const GtkSheet *sheet, gchar *text)
105 GSheetModel *model = gtk_sheet_get_model (sheet);
110 if (g_sheet_model_free_strings (model))
115 guint DEFAULT_ROW_HEIGHT (GtkWidget *widget)
117 if (!widget->style->font_desc) return 24;
120 PangoContext *context = gtk_widget_get_pango_context (widget);
121 PangoFontMetrics *metrics =
122 pango_context_get_metrics (context,
123 widget->style->font_desc,
124 pango_context_get_language (context));
126 guint val = pango_font_metrics_get_descent (metrics) +
127 pango_font_metrics_get_ascent (metrics);
129 pango_font_metrics_unref (metrics);
131 return PANGO_PIXELS (val) + 2 * COLUMN_TITLES_HEIGHT;
136 guint DEFAULT_FONT_ASCENT (GtkWidget *widget)
138 if (!widget->style->font_desc) return 12;
141 PangoContext *context = gtk_widget_get_pango_context (widget);
142 PangoFontMetrics *metrics =
143 pango_context_get_metrics (context,
144 widget->style->font_desc,
145 pango_context_get_language (context));
146 guint val = pango_font_metrics_get_ascent (metrics);
147 pango_font_metrics_unref (metrics);
148 return PANGO_PIXELS (val);
153 guint STRING_WIDTH (GtkWidget *widget,
154 const PangoFontDescription *font, const gchar *text)
159 layout = gtk_widget_create_pango_layout (widget, text);
160 pango_layout_set_font_description (layout, font);
162 pango_layout_get_extents (layout, NULL, &rect);
164 g_object_unref (layout);
165 return PANGO_PIXELS (rect.width);
169 guint DEFAULT_FONT_DESCENT (GtkWidget *widget)
171 if (!widget->style->font_desc) return 12;
174 PangoContext *context = gtk_widget_get_pango_context (widget);
175 PangoFontMetrics *metrics =
176 pango_context_get_metrics (context,
177 widget->style->font_desc,
178 pango_context_get_language (context));
179 guint val = pango_font_metrics_get_descent (metrics);
180 pango_font_metrics_unref (metrics);
181 return PANGO_PIXELS (val);
186 /* Return the row containing pixel Y */
188 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
190 GSheetRow *geo = sheet->row_geometry;
192 if (y < 0) return -1;
194 return g_sheet_row_pixel_to_row (geo, y);
198 #define MIN_VISIBLE_ROW(sheet) yyy_row_ypixel_to_row (sheet, sheet->vadjustment->value)
200 #define MAX_VISIBLE_ROW(sheet) \
201 yyy_row_ypixel_to_row (sheet, sheet->vadjustment->value + sheet->vadjustment->page_size)
203 #define MIN_VISIBLE_COLUMN(sheet) COLUMN_FROM_XPIXEL (sheet, sheet->hadjustment->value)
205 #define MAX_VISIBLE_COLUMN(sheet) \
206 COLUMN_FROM_XPIXEL (sheet, sheet->hadjustment->value + sheet->hadjustment->page_size)
208 /* gives the left pixel of the given column in context of
209 * the sheet's hoffset */
211 COLUMN_LEFT_XPIXEL (const GtkSheet *sheet, gint ncol)
213 return g_sheet_column_start_pixel (sheet->column_geometry, ncol);
217 /* returns the column index from a x pixel location */
219 COLUMN_FROM_XPIXEL (const GtkSheet *sheet, gint x)
224 if (x < 0) return -1;
226 i < g_sheet_column_get_column_count (sheet->column_geometry); i++)
229 x <= (cx + g_sheet_column_get_width (sheet->column_geometry, i)) &&
230 g_sheet_column_get_visibility (sheet->column_geometry, i))
232 if ( g_sheet_column_get_visibility (sheet->column_geometry, i))
233 cx += g_sheet_column_get_width (sheet->column_geometry, i);
237 return g_sheet_column_get_column_count (sheet->column_geometry) - 1;
240 /* The size of the region (in pixels) around the row/column boundaries
241 where the height/width may be grabbed to change size */
245 on_column_boundary (const GtkSheet *sheet, gint x, gint *column)
249 x += sheet->hadjustment->value;
251 col = COLUMN_FROM_XPIXEL (sheet, x);
253 if ( COLUMN_FROM_XPIXEL (sheet, x - DRAG_WIDTH / 2) < col )
259 if ( COLUMN_FROM_XPIXEL (sheet, x + DRAG_WIDTH / 2) > col )
268 static inline gboolean
269 POSSIBLE_YDRAG (const GtkSheet *sheet, gint y, gint *drag_row)
273 y += sheet->vadjustment->value;
274 row = yyy_row_ypixel_to_row (sheet, y);
277 ydrag = g_sheet_row_start_pixel (sheet->row_geometry, row) + CELL_SPACING;
278 if (y <= ydrag + DRAG_WIDTH / 2 && row != 0)
280 while (!g_sheet_row_get_visibility (sheet->row_geometry, row - 1) && row > 0) row--;
282 return g_sheet_row_get_sensitivity (sheet->row_geometry, row - 1);
285 ydrag += g_sheet_row_get_height (sheet->row_geometry, row);
287 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
288 return g_sheet_row_get_sensitivity (sheet->row_geometry, row);
293 static inline gboolean
294 POSSIBLE_DRAG (const GtkSheet *sheet, gint x, gint y,
295 gint *drag_row, gint *drag_column)
299 /* Can't drag if nothing is selected */
300 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
301 sheet->range.col0 < 0 || sheet->range.coli < 0 )
304 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
305 *drag_row = yyy_row_ypixel_to_row (sheet, y);
307 if (x >= COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0) - DRAG_WIDTH / 2 &&
308 x <= COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
309 g_sheet_column_get_width (sheet->column_geometry, sheet->range.coli) + DRAG_WIDTH / 2)
311 ydrag = g_sheet_row_start_pixel (sheet->row_geometry, sheet->range.row0);
312 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
314 *drag_row = sheet->range.row0;
317 ydrag = g_sheet_row_start_pixel (sheet->row_geometry, sheet->range.rowi) +
318 g_sheet_row_get_height (sheet->row_geometry, sheet->range.rowi);
319 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
321 *drag_row = sheet->range.rowi;
326 if (y >= g_sheet_row_start_pixel (sheet->row_geometry, sheet->range.row0) - DRAG_WIDTH / 2 &&
327 y <= g_sheet_row_start_pixel (sheet->row_geometry, sheet->range.rowi) +
328 g_sheet_row_get_height (sheet->row_geometry, sheet->range.rowi) + DRAG_WIDTH / 2)
330 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0);
331 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
333 *drag_column = sheet->range.col0;
336 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
337 g_sheet_column_get_width (sheet->column_geometry, sheet->range.coli);
338 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
340 *drag_column = sheet->range.coli;
348 static inline gboolean
349 POSSIBLE_RESIZE (const GtkSheet *sheet, gint x, gint y,
350 gint *drag_row, gint *drag_column)
354 /* Can't drag if nothing is selected */
355 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
356 sheet->range.col0 < 0 || sheet->range.coli < 0 )
359 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli)+
360 g_sheet_column_get_width (sheet->column_geometry, sheet->range.coli);
362 ydrag = g_sheet_row_start_pixel (sheet->row_geometry, sheet->range.rowi) +
363 g_sheet_row_get_height (sheet->row_geometry, sheet->range.rowi);
365 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
366 ydrag = g_sheet_row_start_pixel (sheet->row_geometry, MIN_VISIBLE_ROW (sheet));
368 if (sheet->state == GTK_SHEET_ROW_SELECTED)
369 xdrag = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
371 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
372 *drag_row = yyy_row_ypixel_to_row (sheet, y);
374 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
375 y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
380 static void gtk_sheet_class_init (GtkSheetClass * klass);
381 static void gtk_sheet_init (GtkSheet * sheet);
382 static void gtk_sheet_dispose (GObject * object);
383 static void gtk_sheet_finalize (GObject * object);
384 static void gtk_sheet_style_set (GtkWidget *widget,
385 GtkStyle *previous_style);
386 static void gtk_sheet_realize (GtkWidget * widget);
387 static void gtk_sheet_unrealize (GtkWidget * widget);
388 static void gtk_sheet_map (GtkWidget * widget);
389 static void gtk_sheet_unmap (GtkWidget * widget);
390 static gint gtk_sheet_expose (GtkWidget * widget,
391 GdkEventExpose * event);
392 static void gtk_sheet_forall (GtkContainer *container,
393 gboolean include_internals,
394 GtkCallback callback,
395 gpointer callback_data);
397 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
398 GtkAdjustment *hadjustment,
399 GtkAdjustment *vadjustment);
401 static gint gtk_sheet_button_press (GtkWidget * widget,
402 GdkEventButton * event);
403 static gint gtk_sheet_button_release (GtkWidget * widget,
404 GdkEventButton * event);
405 static gint gtk_sheet_motion (GtkWidget * widget,
406 GdkEventMotion * event);
407 static gboolean gtk_sheet_crossing_notify (GtkWidget *widget,
408 GdkEventCrossing *event);
409 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
411 static gint gtk_sheet_key_press (GtkWidget *widget,
413 static void gtk_sheet_size_request (GtkWidget * widget,
414 GtkRequisition * requisition);
415 static void gtk_sheet_size_allocate (GtkWidget * widget,
416 GtkAllocation * allocation);
420 static gboolean gtk_sheet_range_isvisible (const GtkSheet * sheet,
421 GtkSheetRange range);
422 static gboolean gtk_sheet_cell_isvisible (GtkSheet * sheet,
423 gint row, gint column);
424 /* Drawing Routines */
426 /* draw cell background and frame */
427 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
428 gint row, gint column);
430 /* draw cell contents */
431 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
432 gint row, gint column);
434 /* draw visible part of range. If range == NULL then draw the whole screen */
435 static void gtk_sheet_range_draw (GtkSheet *sheet,
436 const GtkSheetRange *range);
438 /* highlight the visible part of the selected range */
439 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
440 GtkSheetRange range);
444 static gboolean gtk_sheet_move_query (GtkSheet *sheet,
445 gint row, gint column);
446 static void gtk_sheet_real_select_range (GtkSheet * sheet,
447 const GtkSheetRange * range);
448 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
449 const GtkSheetRange * range);
450 static void gtk_sheet_extend_selection (GtkSheet *sheet,
451 gint row, gint column);
452 static void gtk_sheet_new_selection (GtkSheet *sheet,
453 GtkSheetRange *range);
454 static void gtk_sheet_draw_border (GtkSheet *sheet,
455 GtkSheetRange range);
457 /* Active Cell handling */
459 static void gtk_sheet_entry_changed (GtkWidget *widget,
461 static void gtk_sheet_deactivate_cell (GtkSheet *sheet);
462 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
463 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
465 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
466 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
467 static void gtk_sheet_click_cell (GtkSheet *sheet,
474 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet);
476 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
477 GtkSheetRange range);
480 static void adjust_scrollbars (GtkSheet * sheet);
481 static void vadjustment_value_changed (GtkAdjustment * adjustment,
483 static void hadjustment_value_changed (GtkAdjustment * adjustment,
487 static void draw_xor_vline (GtkSheet * sheet);
488 static void draw_xor_hline (GtkSheet * sheet);
489 static void draw_xor_rectangle (GtkSheet *sheet,
490 GtkSheetRange range);
492 static guint new_column_width (GtkSheet * sheet,
495 static guint new_row_height (GtkSheet * sheet,
500 static void create_global_button (GtkSheet *sheet);
501 static void global_button_clicked (GtkWidget *widget,
505 static void create_sheet_entry (GtkSheet *sheet);
506 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
507 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
509 /* Sheet button gadgets */
511 static void size_allocate_column_title_buttons (GtkSheet * sheet);
512 static void size_allocate_row_title_buttons (GtkSheet * sheet);
515 static void size_allocate_global_button (GtkSheet *sheet);
516 static void gtk_sheet_button_size_request (GtkSheet *sheet,
517 const GtkSheetButton *button,
518 GtkRequisition *requisition);
520 /* Attributes routines */
521 static void init_attributes (const GtkSheet *sheet,
523 GtkSheetCellAttr *attributes);
526 /* Memory allocation routines */
527 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
528 const GtkSheetRange *range);
530 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
535 static void gtk_sheet_column_size_request (GtkSheet *sheet,
538 static void gtk_sheet_row_size_request (GtkSheet *sheet,
546 _gtkextra_signal_emit (GtkObject *object, guint signal_id, ...);
566 static GtkContainerClass *parent_class = NULL;
567 static guint sheet_signals[LAST_SIGNAL] = { 0 };
571 gtk_sheet_get_type ()
573 static GType sheet_type = 0;
577 static const GTypeInfo sheet_info =
579 sizeof (GtkSheetClass),
582 (GClassInitFunc) gtk_sheet_class_init,
587 (GInstanceInitFunc) gtk_sheet_init,
592 g_type_register_static (GTK_TYPE_BIN, "GtkSheet",
598 static GtkSheetRange*
599 gtk_sheet_range_copy (const GtkSheetRange *range)
601 GtkSheetRange *new_range;
603 g_return_val_if_fail (range != NULL, NULL);
605 new_range = g_new (GtkSheetRange, 1);
613 gtk_sheet_range_free (GtkSheetRange *range)
615 g_return_if_fail (range != NULL);
621 gtk_sheet_range_get_type (void)
623 static GType sheet_range_type = 0;
625 if (!sheet_range_type)
628 g_boxed_type_register_static ("GtkSheetRange",
629 (GBoxedCopyFunc) gtk_sheet_range_copy,
630 (GBoxedFreeFunc) gtk_sheet_range_free);
633 return sheet_range_type;
637 static void column_titles_changed (GtkWidget *w, gint first, gint n_columns,
650 gtk_sheet_set_row_geometry (GtkSheet *sheet, GSheetRow *geo)
652 if ( sheet->row_geometry ) g_object_unref (sheet->row_geometry);
654 sheet->row_geometry = geo;
656 if ( sheet->row_geometry ) g_object_ref (sheet->row_geometry);
660 gtk_sheet_set_column_geometry (GtkSheet *sheet, GSheetColumn *geo)
662 if ( sheet->column_geometry ) g_object_unref (sheet->column_geometry);
664 sheet->column_geometry = geo;
666 if ( sheet->column_geometry ) g_object_ref (sheet->column_geometry);
671 gtk_sheet_set_property (GObject *object,
677 GtkSheet *sheet = GTK_SHEET (object);
682 gtk_sheet_set_row_geometry (sheet, g_value_get_pointer (value));
685 gtk_sheet_set_column_geometry (sheet, g_value_get_pointer (value));
686 if ( sheet->column_geometry)
687 g_signal_connect (sheet->column_geometry, "columns_changed",
688 G_CALLBACK (column_titles_changed), sheet);
691 gtk_sheet_set_model (sheet, g_value_get_pointer (value));
694 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
700 gtk_sheet_get_property (GObject *object,
705 GtkSheet *sheet = GTK_SHEET (object);
710 g_value_set_pointer (value, sheet->row_geometry);
713 g_value_set_pointer (value, sheet->column_geometry);
716 g_value_set_pointer (value, sheet->model);
719 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
726 gtk_sheet_class_init (GtkSheetClass * klass)
728 GObjectClass *object_class = G_OBJECT_CLASS (klass);
730 GParamSpec *row_geo_spec ;
731 GParamSpec *col_geo_spec ;
732 GParamSpec *model_spec ;
734 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
735 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
737 parent_class = g_type_class_peek_parent (klass);
740 * GtkSheet::select-row
741 * @sheet: the sheet widget that emitted the signal
742 * @row: the newly selected row index
744 * A row has been selected.
746 sheet_signals[SELECT_ROW] =
747 g_signal_new ("select-row",
748 G_TYPE_FROM_CLASS (object_class),
750 offsetof (GtkSheetClass, select_row),
752 g_cclosure_marshal_VOID__INT,
759 * GtkSheet::select - column
760 * @sheet: the sheet widget that emitted the signal
761 * @column: the newly selected column index
763 * A column has been selected.
765 sheet_signals[SELECT_COLUMN] =
766 g_signal_new ("select-column",
767 G_TYPE_FROM_CLASS (object_class),
769 offsetof (GtkSheetClass, select_column),
771 g_cclosure_marshal_VOID__INT,
778 * GtkSheet::double-click-row
779 * @sheet: the sheet widget that emitted the signal
780 * @row: the row that was double clicked.
782 * A row's title button has been double clicked
784 sheet_signals[DOUBLE_CLICK_ROW] =
785 g_signal_new ("double-click-row",
786 G_TYPE_FROM_CLASS (object_class),
790 g_cclosure_marshal_VOID__INT,
797 * GtkSheet::double-click-column
798 * @sheet: the sheet widget that emitted the signal
799 * @column: the column that was double clicked.
801 * A column's title button has been double clicked
803 sheet_signals[DOUBLE_CLICK_COLUMN] =
804 g_signal_new ("double-click-column",
805 G_TYPE_FROM_CLASS (object_class),
809 g_cclosure_marshal_VOID__INT,
816 * GtkSheet::button-event-column
817 * @sheet: the sheet widget that emitted the signal
818 * @column: the column on which the event occured.
820 * A button event occured on a column title button
822 sheet_signals[BUTTON_EVENT_COLUMN] =
823 g_signal_new ("button-event-column",
824 G_TYPE_FROM_CLASS (object_class),
828 gtkextra_VOID__INT_POINTER,
837 * GtkSheet::button-event-row
838 * @sheet: the sheet widget that emitted the signal
839 * @column: the column on which the event occured.
841 * A button event occured on a row title button
843 sheet_signals[BUTTON_EVENT_ROW] =
844 g_signal_new ("button-event-row",
845 G_TYPE_FROM_CLASS (object_class),
849 gtkextra_VOID__INT_POINTER,
857 sheet_signals[SELECT_RANGE] =
858 g_signal_new ("select-range",
859 G_TYPE_FROM_CLASS (object_class),
861 offsetof (GtkSheetClass, select_range),
863 g_cclosure_marshal_VOID__BOXED,
866 GTK_TYPE_SHEET_RANGE);
869 sheet_signals[RESIZE_RANGE] =
870 g_signal_new ("resize-range",
871 G_TYPE_FROM_CLASS (object_class),
873 offsetof (GtkSheetClass, resize_range),
875 gtkextra_VOID__BOXED_BOXED,
878 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
881 sheet_signals[MOVE_RANGE] =
882 g_signal_new ("move-range",
883 G_TYPE_FROM_CLASS (object_class),
885 offsetof (GtkSheetClass, move_range),
887 gtkextra_VOID__BOXED_BOXED,
890 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
893 sheet_signals[TRAVERSE] =
894 g_signal_new ("traverse",
895 G_TYPE_FROM_CLASS (object_class),
897 offsetof (GtkSheetClass, traverse),
899 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
900 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT,
901 G_TYPE_POINTER, G_TYPE_POINTER);
904 sheet_signals[DEACTIVATE] =
905 g_signal_new ("deactivate",
906 G_TYPE_FROM_CLASS (object_class),
908 offsetof (GtkSheetClass, deactivate),
910 gtkextra_VOID__INT_INT,
911 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
913 sheet_signals[ACTIVATE] =
914 g_signal_new ("activate",
915 G_TYPE_FROM_CLASS (object_class),
917 offsetof (GtkSheetClass, activate),
919 gtkextra_BOOLEAN__INT_INT,
920 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
922 sheet_signals[CHANGED] =
923 g_signal_new ("changed",
924 G_TYPE_FROM_CLASS (object_class),
926 offsetof (GtkSheetClass, changed),
928 gtkextra_VOID__INT_INT,
929 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
931 widget_class->set_scroll_adjustments_signal =
932 g_signal_new ("set-scroll-adjustments",
933 G_TYPE_FROM_CLASS (object_class),
935 offsetof (GtkSheetClass, set_scroll_adjustments),
937 gtkextra_VOID__OBJECT_OBJECT,
938 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
941 container_class->add = NULL;
942 container_class->remove = NULL;
943 container_class->forall = gtk_sheet_forall;
945 object_class->dispose = gtk_sheet_dispose;
946 object_class->finalize = gtk_sheet_finalize;
950 g_param_spec_pointer ("row-geometry",
952 "A pointer to the model of the row geometry",
953 G_PARAM_READABLE | G_PARAM_WRITABLE );
956 g_param_spec_pointer ("column-geometry",
958 "A pointer to the model of the column geometry",
959 G_PARAM_READABLE | G_PARAM_WRITABLE );
962 g_param_spec_pointer ("model",
964 "A pointer to the data model",
965 G_PARAM_READABLE | G_PARAM_WRITABLE );
968 object_class->set_property = gtk_sheet_set_property;
969 object_class->get_property = gtk_sheet_get_property;
971 g_object_class_install_property (object_class,
975 g_object_class_install_property (object_class,
979 g_object_class_install_property (object_class,
984 widget_class->realize = gtk_sheet_realize;
985 widget_class->unrealize = gtk_sheet_unrealize;
986 widget_class->map = gtk_sheet_map;
987 widget_class->unmap = gtk_sheet_unmap;
988 widget_class->style_set = gtk_sheet_style_set;
989 widget_class->button_press_event = gtk_sheet_button_press;
990 widget_class->button_release_event = gtk_sheet_button_release;
991 widget_class->motion_notify_event = gtk_sheet_motion;
992 widget_class->enter_notify_event = gtk_sheet_crossing_notify;
993 widget_class->leave_notify_event = gtk_sheet_crossing_notify;
994 widget_class->key_press_event = gtk_sheet_key_press;
995 widget_class->expose_event = gtk_sheet_expose;
996 widget_class->size_request = gtk_sheet_size_request;
997 widget_class->size_allocate = gtk_sheet_size_allocate;
998 widget_class->focus_in_event = NULL;
999 widget_class->focus_out_event = NULL;
1001 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1002 klass->select_row = NULL;
1003 klass->select_column = NULL;
1004 klass->select_range = NULL;
1005 klass->resize_range = NULL;
1006 klass->move_range = NULL;
1007 klass->traverse = NULL;
1008 klass->deactivate = NULL;
1009 klass->activate = NULL;
1010 klass->changed = NULL;
1014 gtk_sheet_init (GtkSheet *sheet)
1016 sheet->model = NULL;
1017 sheet->column_geometry = NULL;
1018 sheet->row_geometry = NULL;
1021 sheet->selection_mode = GTK_SELECTION_NONE;
1022 sheet->state = GTK_SHEET_NORMAL;
1024 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1025 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1027 sheet->column_title_window = NULL;
1028 sheet->column_title_area.x = 0;
1029 sheet->column_title_area.y = 0;
1030 sheet->column_title_area.width = 0;
1031 sheet->column_title_area.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
1033 sheet->row_title_window = NULL;
1034 sheet->row_title_area.x = 0;
1035 sheet->row_title_area.y = 0;
1036 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1037 sheet->row_title_area.height = 0;
1040 sheet->active_cell.row = 0;
1041 sheet->active_cell.col = 0;
1042 sheet->selection_cell.row = 0;
1043 sheet->selection_cell.col = 0;
1045 sheet->pixmap = NULL;
1047 sheet->range.row0 = 0;
1048 sheet->range.rowi = 0;
1049 sheet->range.col0 = 0;
1050 sheet->range.coli = 0;
1052 sheet->state = GTK_SHEET_NORMAL;
1054 sheet->sheet_window = NULL;
1055 sheet->sheet_window_width = 0;
1056 sheet->sheet_window_height = 0;
1057 sheet->entry_widget = NULL;
1058 sheet->entry_container = NULL;
1059 sheet->button = NULL;
1061 sheet->hadjustment = NULL;
1062 sheet->vadjustment = NULL;
1064 sheet->cursor_drag = NULL;
1066 sheet->xor_gc = NULL;
1067 sheet->fg_gc = NULL;
1068 sheet->bg_gc = NULL;
1071 sheet->show_grid = TRUE;
1073 sheet->motion_timer = 0;
1075 sheet->columns_resizable = TRUE;
1076 sheet->rows_resizable = TRUE;
1078 sheet->row_titles_visible = TRUE;
1079 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1081 sheet->column_titles_visible = TRUE;
1082 sheet->autoscroll = TRUE;
1083 sheet->justify_entry = TRUE;
1086 /* create sheet entry */
1087 sheet->entry_type = 0;
1088 create_sheet_entry (sheet);
1090 /* create global selection button */
1091 create_global_button (sheet);
1095 /* Callback which occurs whenever columns are inserted / deleted in the model */
1097 columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
1102 GtkSheet *sheet = GTK_SHEET (data);
1104 GtkSheetRange range;
1105 gint model_columns = g_sheet_model_get_column_count (model);
1108 /* Need to update all the columns starting from the first column and onwards.
1109 * Previous column are unchanged, so don't need to be updated.
1111 range.col0 = first_column;
1113 range.coli = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
1114 range.rowi = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
1116 adjust_scrollbars (sheet);
1118 if (sheet->active_cell.col >= model_columns)
1119 gtk_sheet_activate_cell (sheet, sheet->active_cell.row, model_columns - 1);
1121 for (i = first_column; i <= MAX_VISIBLE_COLUMN (sheet); i++)
1122 gtk_sheet_column_title_button_draw (sheet, i);
1124 gtk_sheet_range_draw (sheet, &range);
1128 /* Callback which occurs whenever rows are inserted / deleted in the model */
1130 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
1131 gint n_rows, gpointer data)
1134 GtkSheet *sheet = GTK_SHEET (data);
1136 GtkSheetRange range;
1138 gint model_rows = g_sheet_model_get_row_count (model);
1140 /* Need to update all the rows starting from the first row and onwards.
1141 * Previous rows are unchanged, so don't need to be updated.
1143 range.row0 = first_row;
1145 range.rowi = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
1146 range.coli = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
1148 adjust_scrollbars (sheet);
1150 if (sheet->active_cell.row >= model_rows)
1151 gtk_sheet_activate_cell (sheet, model_rows - 1, sheet->active_cell.col);
1153 for (i = first_row; i <= MAX_VISIBLE_ROW (sheet); i++)
1154 gtk_sheet_row_title_button_draw (sheet, i);
1156 gtk_sheet_range_draw (sheet, &range);
1160 If row0 or rowi are negative, then all rows will be updated.
1161 If col0 or coli are negative, then all columns will be updated.
1164 range_update_callback (GSheetModel *m, gint row0, gint col0,
1165 gint rowi, gint coli, gpointer data)
1167 GtkSheet *sheet = GTK_SHEET (data);
1169 GtkSheetRange range;
1176 if ( MAX_VISIBLE_ROW (sheet) >
1177 g_sheet_model_get_row_count (sheet->model)
1179 MAX_VISIBLE_COLUMN (sheet) >
1180 g_sheet_model_get_column_count (sheet->model))
1182 gtk_sheet_move_query (sheet, 0, 0);
1185 if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1188 gtk_sheet_range_draw (sheet, NULL);
1189 adjust_scrollbars (sheet);
1191 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
1192 gtk_sheet_row_title_button_draw (sheet, i);
1194 for (i = MIN_VISIBLE_COLUMN (sheet);
1195 i <= MAX_VISIBLE_COLUMN (sheet); i++)
1196 gtk_sheet_column_title_button_draw (sheet, i);
1200 else if ( row0 < 0 || rowi < 0 )
1202 range.row0 = MIN_VISIBLE_ROW (sheet);
1203 range.rowi = MAX_VISIBLE_ROW (sheet);
1205 else if ( col0 < 0 || coli < 0 )
1207 range.col0 = MIN_VISIBLE_COLUMN (sheet);
1208 range.coli = MAX_VISIBLE_COLUMN (sheet);
1211 gtk_sheet_range_draw (sheet, &range);
1217 * @rows: initial number of rows
1218 * @columns: initial number of columns
1219 * @title: sheet title
1220 * @model: the model to use for the sheet data
1222 * Creates a new sheet widget with the given number of rows and columns.
1224 * Returns: the new sheet widget
1227 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, GSheetModel *model)
1229 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET,
1230 "row-geometry", vgeo,
1231 "column-geometry", hgeo,
1239 * gtk_sheet_set_model
1240 * @sheet: the sheet to set the model for
1241 * @model: the model to use for the sheet data
1243 * Sets the model for a GtkSheet
1247 gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
1249 g_return_if_fail (GTK_IS_SHEET (sheet));
1251 if (sheet->model ) g_object_unref (sheet->model);
1253 sheet->model = model;
1257 g_object_ref (model);
1259 g_signal_connect (model, "range_changed",
1260 G_CALLBACK (range_update_callback), sheet);
1262 g_signal_connect (model, "rows_inserted",
1263 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1265 g_signal_connect (model, "rows_deleted",
1266 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1268 g_signal_connect (model, "columns_inserted",
1269 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1271 g_signal_connect (model, "columns_deleted",
1272 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1277 /* Call back for when the column titles have changed.
1278 FIRST is the first column changed.
1279 N_COLUMNS is the number of columns which have changed, or - 1, which
1280 indicates that the column has changed to its right - most extremity
1283 column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
1285 GtkSheet *sheet = GTK_SHEET (data);
1286 gboolean extremity = FALSE;
1288 if ( n_columns == -1 )
1291 n_columns = g_sheet_column_get_column_count (sheet->column_geometry) - 1 ;
1296 for ( i = first ; i <= first + n_columns ; ++i )
1298 gtk_sheet_column_title_button_draw (sheet, i);
1299 g_signal_emit (sheet, sheet_signals[CHANGED], 0, -1, i);
1304 gtk_sheet_column_title_button_draw (sheet, -1);
1309 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
1313 g_return_if_fail (sheet != NULL);
1314 g_return_if_fail (GTK_IS_SHEET (sheet));
1316 state = sheet->state;
1318 if (sheet->state == GTK_SHEET_NORMAL)
1319 gtk_sheet_hide_active_cell (sheet);
1321 sheet->entry_type = entry_type;
1323 create_sheet_entry (sheet);
1325 if (state == GTK_SHEET_NORMAL)
1327 gtk_sheet_show_active_cell (sheet);
1328 g_signal_connect (gtk_sheet_get_entry (sheet),
1330 G_CALLBACK (gtk_sheet_entry_changed),
1336 gtk_sheet_show_grid (GtkSheet *sheet, gboolean show)
1338 g_return_if_fail (sheet != NULL);
1339 g_return_if_fail (GTK_IS_SHEET (sheet));
1341 if (show == sheet->show_grid) return;
1343 sheet->show_grid = show;
1345 gtk_sheet_range_draw (sheet, NULL);
1349 gtk_sheet_grid_visible (GtkSheet *sheet)
1351 g_return_val_if_fail (sheet != NULL, 0);
1352 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1354 return sheet->show_grid;
1358 gtk_sheet_get_columns_count (GtkSheet *sheet)
1360 g_return_val_if_fail (sheet != NULL, 0);
1361 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1363 return g_sheet_column_get_column_count (sheet->column_geometry);
1367 gtk_sheet_get_rows_count (GtkSheet *sheet)
1369 g_return_val_if_fail (sheet != NULL, 0);
1370 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1372 return g_sheet_row_get_row_count (sheet->row_geometry);
1376 gtk_sheet_set_selection_mode (GtkSheet *sheet, gint mode)
1378 g_return_if_fail (sheet != NULL);
1379 g_return_if_fail (GTK_IS_SHEET (sheet));
1381 if (GTK_WIDGET_REALIZED (sheet))
1382 gtk_sheet_real_unselect_range (sheet, NULL);
1384 sheet->selection_mode = mode;
1388 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1390 g_return_if_fail (sheet != NULL);
1391 g_return_if_fail (GTK_IS_SHEET (sheet));
1393 sheet->autoresize = autoresize;
1397 gtk_sheet_autoresize (GtkSheet *sheet)
1399 g_return_val_if_fail (sheet != NULL, FALSE);
1400 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1402 return sheet->autoresize;
1406 gtk_sheet_set_column_width (GtkSheet * sheet,
1412 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1414 gint text_width = 0;
1417 g_return_if_fail (sheet != NULL);
1418 g_return_if_fail (GTK_IS_SHEET (sheet));
1419 if (column >= g_sheet_column_get_column_count (sheet->column_geometry) || column < 0) return;
1421 for (row = 0; row < g_sheet_row_get_row_count (sheet->row_geometry); row++)
1423 gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
1424 if (text && strlen (text) > 0)
1426 GtkSheetCellAttr attributes;
1428 gtk_sheet_get_attributes (sheet, row, column, &attributes);
1429 if (attributes.is_visible)
1431 gint width = STRING_WIDTH (GTK_WIDGET (sheet),
1432 attributes.font_desc,
1434 + 2 * COLUMN_TITLES_HEIGHT + attributes.border.width;
1435 text_width = MAX (text_width, width);
1438 dispose_string (sheet, text);
1441 if (text_width > g_sheet_column_get_width (sheet->column_geometry, column) )
1443 gtk_sheet_set_column_width (sheet, column, text_width);
1444 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
1450 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1452 g_return_if_fail (sheet != NULL);
1453 g_return_if_fail (GTK_IS_SHEET (sheet));
1455 sheet->autoscroll = autoscroll;
1459 gtk_sheet_autoscroll (GtkSheet *sheet)
1461 g_return_val_if_fail (sheet != NULL, FALSE);
1462 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1464 return sheet->autoscroll;
1469 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1471 g_return_if_fail (sheet != NULL);
1472 g_return_if_fail (GTK_IS_SHEET (sheet));
1474 sheet->justify_entry = justify;
1478 gtk_sheet_justify_entry (GtkSheet *sheet)
1480 g_return_val_if_fail (sheet != NULL, FALSE);
1481 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1483 return sheet->justify_entry;
1488 gtk_sheet_set_row_titles_width (GtkSheet *sheet, guint width)
1490 if (width < COLUMN_MIN_WIDTH) return;
1492 sheet->row_title_area.width = width;
1494 adjust_scrollbars (sheet);
1496 if (sheet->hadjustment)
1497 g_signal_emit_by_name (sheet->hadjustment,
1499 size_allocate_global_button (sheet);
1503 gtk_sheet_set_column_titles_height (GtkSheet *sheet, guint height)
1505 if (height < DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))) return;
1507 sheet->column_title_area.height = height;
1509 adjust_scrollbars (sheet);
1511 if (sheet->vadjustment)
1512 g_signal_emit_by_name (sheet->vadjustment,
1514 size_allocate_global_button (sheet);
1518 gtk_sheet_show_column_titles (GtkSheet *sheet)
1520 if (sheet->column_titles_visible) return;
1522 sheet->column_titles_visible = TRUE;
1524 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1527 gdk_window_show (sheet->column_title_window);
1528 gdk_window_move_resize (sheet->column_title_window,
1529 sheet->column_title_area.x,
1530 sheet->column_title_area.y,
1531 sheet->column_title_area.width,
1532 sheet->column_title_area.height);
1534 adjust_scrollbars (sheet);
1536 if (sheet->vadjustment)
1537 g_signal_emit_by_name (sheet->vadjustment,
1539 size_allocate_global_button (sheet);
1544 gtk_sheet_show_row_titles (GtkSheet *sheet)
1546 if (sheet->row_titles_visible) return;
1548 sheet->row_titles_visible = TRUE;
1551 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1553 gdk_window_show (sheet->row_title_window);
1554 gdk_window_move_resize (sheet->row_title_window,
1555 sheet->row_title_area.x,
1556 sheet->row_title_area.y,
1557 sheet->row_title_area.width,
1558 sheet->row_title_area.height);
1560 adjust_scrollbars (sheet);
1563 if (sheet->hadjustment)
1564 g_signal_emit_by_name (sheet->hadjustment,
1566 size_allocate_global_button (sheet);
1570 gtk_sheet_hide_column_titles (GtkSheet *sheet)
1572 if (!sheet->column_titles_visible) return;
1574 sheet->column_titles_visible = FALSE;
1576 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1578 if (sheet->column_title_window)
1579 gdk_window_hide (sheet->column_title_window);
1580 if (GTK_WIDGET_VISIBLE (sheet->button))
1581 gtk_widget_hide (sheet->button);
1583 adjust_scrollbars (sheet);
1586 if (sheet->vadjustment)
1587 g_signal_emit_by_name (sheet->vadjustment,
1592 gtk_sheet_hide_row_titles (GtkSheet *sheet)
1594 if (!sheet->row_titles_visible) return;
1596 sheet->row_titles_visible = FALSE;
1598 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1600 if (sheet->row_title_window)
1601 gdk_window_hide (sheet->row_title_window);
1603 if (GTK_WIDGET_VISIBLE (sheet->button))
1604 gtk_widget_hide (sheet->button);
1606 adjust_scrollbars (sheet);
1609 if (sheet->hadjustment)
1610 g_signal_emit_by_name (sheet->hadjustment,
1616 gtk_sheet_moveto (GtkSheet *sheet,
1623 guint width, height;
1625 gint min_row, min_col;
1627 g_return_if_fail (sheet != NULL);
1628 g_return_if_fail (GTK_IS_SHEET (sheet));
1629 g_return_if_fail (sheet->hadjustment != NULL);
1630 g_return_if_fail (sheet->vadjustment != NULL);
1632 if (row < 0 || row >= g_sheet_row_get_row_count (sheet->row_geometry))
1634 if (column < 0 || column >= g_sheet_column_get_column_count (sheet->column_geometry))
1637 height = sheet->sheet_window_height;
1638 width = sheet->sheet_window_width;
1640 /* adjust vertical scrollbar */
1641 if (row >= 0 && row_align >= 0.0)
1643 y = g_sheet_row_start_pixel (sheet->row_geometry, row)
1644 - (gint) ( row_align * height + (1.0 - row_align)
1645 * g_sheet_row_get_height (sheet->row_geometry, row));
1647 /* This forces the sheet to scroll when you don't see the entire cell */
1650 if (row_align >= 1.0)
1652 while (min_row >= 0 && min_row > MIN_VISIBLE_ROW (sheet))
1654 if (g_sheet_row_get_visibility (sheet->row_geometry, min_row))
1655 adjust += g_sheet_row_get_height (sheet->row_geometry, min_row);
1657 if (adjust >= height)
1663 min_row = MAX (min_row, 0);
1667 y = g_sheet_row_start_pixel (sheet->row_geometry, min_row) +
1668 g_sheet_row_get_height (sheet->row_geometry, min_row) - 1;
1672 sheet->vadjustment->value = 0.0;
1674 sheet->vadjustment->value = y;
1676 g_signal_emit_by_name (sheet->vadjustment,
1681 /* adjust horizontal scrollbar */
1682 if (column >= 0 && col_align >= 0.0)
1684 x = COLUMN_LEFT_XPIXEL (sheet, column)
1685 - (gint) ( col_align*width + (1.0 - col_align)*
1686 g_sheet_column_get_width (sheet->column_geometry, column));
1688 /* This forces the sheet to scroll when you don't see the entire cell */
1691 if (col_align == 1.0)
1693 while (min_col >= 0 && min_col > MIN_VISIBLE_COLUMN (sheet))
1695 if (g_sheet_column_get_visibility (sheet->column_geometry, min_col))
1696 adjust += g_sheet_column_get_width (sheet->column_geometry, min_col);
1698 if (adjust >= width)
1704 min_col = MAX (min_col, 0);
1705 x = COLUMN_LEFT_XPIXEL (sheet, min_col) +
1706 g_sheet_column_get_width (sheet->column_geometry, min_col) - 1;
1710 sheet->hadjustment->value = 0.0;
1712 sheet->hadjustment->value = x;
1714 g_signal_emit_by_name (sheet->hadjustment,
1721 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
1723 g_return_if_fail (sheet != NULL);
1724 g_return_if_fail (GTK_IS_SHEET (sheet));
1726 sheet->columns_resizable = resizable;
1730 gtk_sheet_columns_resizable (GtkSheet *sheet)
1732 g_return_val_if_fail (sheet != NULL, FALSE);
1733 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1735 return sheet->columns_resizable;
1740 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
1742 g_return_if_fail (sheet != NULL);
1743 g_return_if_fail (GTK_IS_SHEET (sheet));
1745 sheet->rows_resizable = resizable;
1749 gtk_sheet_rows_resizable (GtkSheet *sheet)
1751 g_return_val_if_fail (sheet != NULL, FALSE);
1752 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1754 return sheet->rows_resizable;
1759 gtk_sheet_select_row (GtkSheet *sheet, gint row)
1761 g_return_if_fail (sheet != NULL);
1762 g_return_if_fail (GTK_IS_SHEET (sheet));
1764 if (row < 0 || row >= g_sheet_row_get_row_count (sheet->row_geometry))
1767 if (sheet->state != GTK_SHEET_NORMAL)
1768 gtk_sheet_real_unselect_range (sheet, NULL);
1770 gtk_sheet_deactivate_cell (sheet);
1772 sheet->state = GTK_SHEET_ROW_SELECTED;
1773 sheet->range.row0 = row;
1774 sheet->range.col0 = 0;
1775 sheet->range.rowi = row;
1776 sheet->range.coli = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
1777 sheet->active_cell.row = row;
1778 sheet->active_cell.col = 0;
1780 g_signal_emit (sheet, sheet_signals[SELECT_ROW], 0, row);
1781 gtk_sheet_real_select_range (sheet, NULL);
1786 gtk_sheet_select_column (GtkSheet * sheet, gint column)
1788 g_return_if_fail (sheet != NULL);
1789 g_return_if_fail (GTK_IS_SHEET (sheet));
1791 if (column < 0 || column >= g_sheet_column_get_column_count (sheet->column_geometry))
1794 if (sheet->state != GTK_SHEET_NORMAL)
1795 gtk_sheet_real_unselect_range (sheet, NULL);
1797 gtk_sheet_deactivate_cell (sheet);
1800 sheet->state = GTK_SHEET_COLUMN_SELECTED;
1801 sheet->range.row0 = 0;
1802 sheet->range.col0 = column;
1803 sheet->range.rowi = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
1804 sheet->range.coli = column;
1805 sheet->active_cell.row = 0;
1806 sheet->active_cell.col = column;
1808 g_signal_emit (sheet, sheet_signals[SELECT_COLUMN], 0, column);
1809 gtk_sheet_real_select_range (sheet, NULL);
1816 gtk_sheet_range_isvisible (const GtkSheet * sheet,
1817 GtkSheetRange range)
1819 g_return_val_if_fail (sheet != NULL, FALSE);
1821 if (range.row0 < 0 || range.row0 >= g_sheet_row_get_row_count (sheet->row_geometry))
1824 if (range.rowi < 0 || range.rowi >= g_sheet_row_get_row_count (sheet->row_geometry))
1827 if (range.col0 < 0 || range.col0 >= g_sheet_column_get_column_count (sheet->column_geometry))
1830 if (range.coli < 0 || range.coli >= g_sheet_column_get_column_count (sheet->column_geometry))
1833 if (range.rowi < MIN_VISIBLE_ROW (sheet))
1836 if (range.row0 > MAX_VISIBLE_ROW (sheet))
1839 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
1842 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
1849 gtk_sheet_cell_isvisible (GtkSheet * sheet,
1850 gint row, gint column)
1852 GtkSheetRange range;
1855 range.col0 = column;
1857 range.coli = column;
1859 return gtk_sheet_range_isvisible (sheet, range);
1863 gtk_sheet_get_visible_range (GtkSheet *sheet, GtkSheetRange *range)
1865 g_return_if_fail (sheet != NULL);
1866 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
1867 g_return_if_fail (range != NULL);
1869 range->row0 = MIN_VISIBLE_ROW (sheet);
1870 range->col0 = MIN_VISIBLE_COLUMN (sheet);
1871 range->rowi = MAX_VISIBLE_ROW (sheet);
1872 range->coli = MAX_VISIBLE_COLUMN (sheet);
1877 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
1878 GtkAdjustment *hadjustment,
1879 GtkAdjustment *vadjustment)
1881 if ( sheet->vadjustment != vadjustment )
1883 if (sheet->vadjustment)
1884 g_object_unref (sheet->vadjustment);
1885 sheet->vadjustment = vadjustment;
1886 g_object_ref (vadjustment);
1888 g_signal_connect (sheet->vadjustment, "value_changed",
1889 G_CALLBACK (vadjustment_value_changed),
1893 if ( sheet->hadjustment != hadjustment )
1895 if (sheet->hadjustment)
1896 g_object_unref (sheet->hadjustment);
1897 sheet->hadjustment = hadjustment;
1898 g_object_ref (hadjustment);
1900 g_signal_connect (sheet->hadjustment, "value_changed",
1901 G_CALLBACK (hadjustment_value_changed),
1907 gtk_sheet_finalize (GObject * object)
1911 g_return_if_fail (object != NULL);
1912 g_return_if_fail (GTK_IS_SHEET (object));
1914 sheet = GTK_SHEET (object);
1916 if (G_OBJECT_CLASS (parent_class)->finalize)
1917 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
1921 gtk_sheet_dispose (GObject *object)
1923 GtkSheet *sheet = GTK_SHEET (object);
1925 g_return_if_fail (object != NULL);
1926 g_return_if_fail (GTK_IS_SHEET (object));
1928 if ( sheet->dispose_has_run )
1931 sheet->dispose_has_run = TRUE;
1933 if (sheet->model) g_object_unref (sheet->model);
1934 if (sheet->row_geometry) g_object_unref (sheet->row_geometry);
1935 if (sheet->column_geometry) g_object_unref (sheet->column_geometry);
1937 g_object_unref (sheet->entry_container);
1938 sheet->entry_container = NULL;
1940 g_object_unref (sheet->button);
1941 sheet->button = NULL;
1943 /* unref adjustments */
1944 if (sheet->hadjustment)
1946 g_signal_handlers_disconnect_matched (sheet->hadjustment,
1947 G_SIGNAL_MATCH_DATA,
1951 g_object_unref (sheet->hadjustment);
1952 sheet->hadjustment = NULL;
1955 if (sheet->vadjustment)
1957 g_signal_handlers_disconnect_matched (sheet->vadjustment,
1958 G_SIGNAL_MATCH_DATA,
1962 g_object_unref (sheet->vadjustment);
1964 sheet->vadjustment = NULL;
1967 if (G_OBJECT_CLASS (parent_class)->dispose)
1968 (*G_OBJECT_CLASS (parent_class)->dispose) (object);
1972 gtk_sheet_style_set (GtkWidget *widget,
1973 GtkStyle *previous_style)
1977 g_return_if_fail (widget != NULL);
1978 g_return_if_fail (GTK_IS_SHEET (widget));
1980 if (GTK_WIDGET_CLASS (parent_class)->style_set)
1981 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
1983 sheet = GTK_SHEET (widget);
1985 if (GTK_WIDGET_REALIZED (widget))
1987 gtk_style_set_background (widget->style, widget->window, widget->state);
1993 gtk_sheet_realize (GtkWidget *widget)
1996 GdkWindowAttr attributes;
1997 gint attributes_mask;
1998 GdkGCValues values, auxvalues;
1999 GdkColormap *colormap;
2000 GdkDisplay *display;
2002 g_return_if_fail (widget != NULL);
2003 g_return_if_fail (GTK_IS_SHEET (widget));
2005 sheet = GTK_SHEET (widget);
2007 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2009 colormap = gtk_widget_get_colormap (widget);
2010 display = gtk_widget_get_display (widget);
2012 attributes.window_type = GDK_WINDOW_CHILD;
2013 attributes.x = widget->allocation.x;
2014 attributes.y = widget->allocation.y;
2015 attributes.width = widget->allocation.width;
2016 attributes.height = widget->allocation.height;
2017 attributes.wclass = GDK_INPUT_OUTPUT;
2019 attributes.visual = gtk_widget_get_visual (widget);
2020 attributes.colormap = colormap;
2022 attributes.event_mask = gtk_widget_get_events (widget);
2023 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2024 GDK_BUTTON_PRESS_MASK |
2025 GDK_BUTTON_RELEASE_MASK |
2026 GDK_KEY_PRESS_MASK |
2027 GDK_ENTER_NOTIFY_MASK |
2028 GDK_LEAVE_NOTIFY_MASK |
2029 GDK_POINTER_MOTION_MASK |
2030 GDK_POINTER_MOTION_HINT_MASK);
2031 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2034 attributes.cursor = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
2037 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2039 gdk_window_set_user_data (widget->window, sheet);
2041 widget->style = gtk_style_attach (widget->style, widget->window);
2043 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2045 gdk_color_parse ("white", &sheet->color[BG_COLOR]);
2046 gdk_colormap_alloc_color (colormap, &sheet->color[BG_COLOR], FALSE,
2048 gdk_color_parse ("gray", &sheet->color[GRID_COLOR]);
2049 gdk_colormap_alloc_color (colormap, &sheet->color[GRID_COLOR], FALSE,
2054 attributes.width = sheet->column_title_area.width;
2055 attributes.height = sheet->column_title_area.height;
2058 /* column - title window */
2059 sheet->column_title_window =
2060 gdk_window_new (widget->window, &attributes, attributes_mask);
2061 gdk_window_set_user_data (sheet->column_title_window, sheet);
2062 gtk_style_set_background (widget->style, sheet->column_title_window,
2068 attributes.width = sheet->row_title_area.width;
2069 attributes.height = sheet->row_title_area.height;
2071 /* row - title window */
2072 sheet->row_title_window = gdk_window_new (widget->window,
2073 &attributes, attributes_mask);
2074 gdk_window_set_user_data (sheet->row_title_window, sheet);
2075 gtk_style_set_background (widget->style, sheet->row_title_window,
2078 /* sheet - window */
2079 attributes.cursor = gdk_cursor_new_for_display (display, GDK_PLUS);
2083 attributes.width = sheet->sheet_window_width;
2084 attributes.height = sheet->sheet_window_height;
2086 sheet->sheet_window = gdk_window_new (widget->window,
2087 &attributes, attributes_mask);
2088 gdk_window_set_user_data (sheet->sheet_window, sheet);
2090 gdk_cursor_unref (attributes.cursor);
2092 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2093 gdk_window_show (sheet->sheet_window);
2095 /* backing_pixmap */
2096 gtk_sheet_make_backing_pixmap (sheet);
2099 sheet->fg_gc = gdk_gc_new (widget->window);
2100 sheet->bg_gc = gdk_gc_new (widget->window);
2104 gdk_gc_get_values (sheet->fg_gc, &auxvalues);
2106 values.foreground = widget->style->white;
2107 values.function = GDK_INVERT;
2108 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2109 values.line_width = 3;
2111 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2120 gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window);
2121 gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet));
2123 gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
2124 gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
2127 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
2129 if (sheet->column_titles_visible)
2130 gdk_window_show (sheet->column_title_window);
2131 if (sheet->row_titles_visible)
2132 gdk_window_show (sheet->row_title_window);
2134 sheet->hover_window = create_hover_window ();
2136 size_allocate_row_title_buttons (sheet);
2137 size_allocate_column_title_buttons (sheet);
2139 gtk_sheet_update_primary_selection (sheet);
2143 create_global_button (GtkSheet *sheet)
2145 sheet->button = gtk_button_new_with_label (" ");
2147 g_object_ref_sink (sheet->button);
2149 g_signal_connect (sheet->button,
2151 G_CALLBACK (global_button_clicked),
2156 size_allocate_global_button (GtkSheet *sheet)
2158 GtkAllocation allocation;
2160 if (!sheet->column_titles_visible) return;
2161 if (!sheet->row_titles_visible) return;
2163 gtk_widget_size_request (sheet->button, NULL);
2167 allocation.width = sheet->row_title_area.width;
2168 allocation.height = sheet->column_title_area.height;
2170 gtk_widget_size_allocate (sheet->button, &allocation);
2171 gtk_widget_show (sheet->button);
2175 global_button_clicked (GtkWidget *widget, gpointer data)
2179 gtk_sheet_click_cell (GTK_SHEET (data), - 1, - 1, &veto);
2180 gtk_widget_grab_focus (GTK_WIDGET (data));
2185 gtk_sheet_unrealize (GtkWidget *widget)
2189 g_return_if_fail (widget != NULL);
2190 g_return_if_fail (GTK_IS_SHEET (widget));
2192 sheet = GTK_SHEET (widget);
2194 gdk_cursor_unref (sheet->cursor_drag);
2195 sheet->cursor_drag = NULL;
2197 gdk_colormap_free_colors (gtk_widget_get_colormap (widget),
2198 sheet->color, n_COLORS);
2200 g_object_unref (sheet->xor_gc);
2201 g_object_unref (sheet->fg_gc);
2202 g_object_unref (sheet->bg_gc);
2204 destroy_hover_window (sheet->hover_window);
2206 gdk_window_destroy (sheet->sheet_window);
2207 gdk_window_destroy (sheet->column_title_window);
2208 gdk_window_destroy (sheet->row_title_window);
2212 g_object_unref (sheet->pixmap);
2213 sheet->pixmap = NULL;
2216 gtk_widget_unparent (sheet->entry_widget);
2217 if (sheet->button != NULL)
2218 gtk_widget_unparent (sheet->button);
2220 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2221 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2225 gtk_sheet_map (GtkWidget * widget)
2227 GtkSheet *sheet = GTK_SHEET (widget);
2229 g_return_if_fail (widget != NULL);
2230 g_return_if_fail (GTK_IS_SHEET (widget));
2232 if (!GTK_WIDGET_MAPPED (widget))
2234 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2236 gdk_window_show (widget->window);
2237 gdk_window_show (sheet->sheet_window);
2239 if (sheet->column_titles_visible)
2241 size_allocate_column_title_buttons (sheet);
2242 gdk_window_show (sheet->column_title_window);
2244 if (sheet->row_titles_visible)
2246 size_allocate_row_title_buttons (sheet);
2247 gdk_window_show (sheet->row_title_window);
2250 if (!GTK_WIDGET_MAPPED (sheet->entry_widget)
2251 && sheet->active_cell.row >= 0
2252 && sheet->active_cell.col >= 0 )
2254 gtk_widget_show (sheet->entry_widget);
2255 gtk_widget_map (sheet->entry_widget);
2258 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2259 !GTK_WIDGET_MAPPED (sheet->button))
2261 gtk_widget_show (sheet->button);
2262 gtk_widget_map (sheet->button);
2265 if (GTK_BIN (sheet->button)->child)
2266 if (GTK_WIDGET_VISIBLE (GTK_BIN (sheet->button)->child) &&
2267 !GTK_WIDGET_MAPPED (GTK_BIN (sheet->button)->child))
2268 gtk_widget_map (GTK_BIN (sheet->button)->child);
2270 gtk_sheet_range_draw (sheet, NULL);
2271 gtk_sheet_activate_cell (sheet,
2272 sheet->active_cell.row,
2273 sheet->active_cell.col);
2278 gtk_sheet_unmap (GtkWidget * widget)
2280 GtkSheet *sheet = GTK_SHEET (widget);
2282 if (!GTK_WIDGET_MAPPED (widget))
2285 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2287 gdk_window_hide (sheet->sheet_window);
2288 if (sheet->column_titles_visible)
2289 gdk_window_hide (sheet->column_title_window);
2290 if (sheet->row_titles_visible)
2291 gdk_window_hide (sheet->row_title_window);
2292 gdk_window_hide (widget->window);
2294 if (GTK_WIDGET_MAPPED (sheet->entry_widget))
2295 gtk_widget_unmap (sheet->entry_widget);
2297 if (GTK_WIDGET_MAPPED (sheet->button))
2298 gtk_widget_unmap (sheet->button);
2303 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2305 GdkGC *fg_gc, *bg_gc;
2306 GtkSheetCellAttr attributes;
2309 g_return_if_fail (sheet != NULL);
2311 /* bail now if we arn't drawable yet */
2312 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2314 if (row < 0 || row >= g_sheet_row_get_row_count (sheet->row_geometry)) return;
2315 if (col < 0 || col >= g_sheet_column_get_column_count (sheet->column_geometry)) return;
2316 if (! g_sheet_column_get_visibility (sheet->column_geometry, col)) return;
2317 if (! g_sheet_row_get_visibility (sheet->row_geometry, row)) return;
2319 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2321 /* select GC for background rectangle */
2322 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2323 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2325 fg_gc = sheet->fg_gc;
2326 bg_gc = sheet->bg_gc;
2328 area.x = g_sheet_column_start_pixel (sheet->column_geometry, col);
2329 area.x -= sheet->hadjustment->value;
2331 area.y = g_sheet_row_start_pixel (sheet->row_geometry, row);
2332 area.y -= sheet->vadjustment->value;
2334 area.width= g_sheet_column_get_width (sheet->column_geometry, col);
2335 area.height = g_sheet_row_get_height (sheet->row_geometry, row);
2337 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
2339 if (sheet->show_grid)
2341 gdk_gc_set_foreground (sheet->bg_gc, &sheet->color[GRID_COLOR]);
2343 gdk_draw_rectangle (sheet->pixmap,
2347 area.width, area.height);
2353 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
2358 gint text_width, text_height, y;
2360 gint size, sizel, sizer;
2361 GdkGC *fg_gc, *bg_gc;
2362 GtkSheetCellAttr attributes;
2363 PangoLayout *layout;
2364 PangoRectangle rect;
2365 PangoRectangle logical_rect;
2366 PangoLayoutLine *line;
2367 PangoFontMetrics *metrics;
2368 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (sheet));
2369 gint ascent, descent, y_pos;
2373 g_return_if_fail (sheet != NULL);
2375 /* bail now if we aren't drawable yet */
2376 if (!GTK_WIDGET_DRAWABLE (sheet))
2379 label = gtk_sheet_cell_get_text (sheet, row, col);
2383 if (row < 0 || row >= g_sheet_row_get_row_count (sheet->row_geometry)) return;
2384 if (col < 0 || col >= g_sheet_column_get_column_count (sheet->column_geometry)) return;
2385 if (! g_sheet_column_get_visibility (sheet->column_geometry, col)) return;
2386 if (!g_sheet_row_get_visibility (sheet->row_geometry, row)) return;
2388 widget = GTK_WIDGET (sheet);
2390 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2392 /* select GC for background rectangle */
2393 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2394 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2396 fg_gc = sheet->fg_gc;
2397 bg_gc = sheet->bg_gc;
2399 area.x = g_sheet_column_start_pixel (sheet->column_geometry, col);
2400 area.x -= sheet->hadjustment->value;
2402 area.y = g_sheet_row_start_pixel (sheet->row_geometry, row);
2403 area.y -= sheet->vadjustment->value;
2405 area.width = g_sheet_column_get_width (sheet->column_geometry, col);
2406 area.height = g_sheet_row_get_height (sheet->row_geometry, row);
2409 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
2410 dispose_string (sheet, label);
2411 pango_layout_set_font_description (layout, attributes.font_desc);
2413 pango_layout_get_pixel_extents (layout, NULL, &rect);
2415 line = pango_layout_get_lines (layout)->data;
2416 pango_layout_line_get_extents (line, NULL, &logical_rect);
2418 metrics = pango_context_get_metrics (context,
2419 attributes.font_desc,
2420 pango_context_get_language (context));
2422 ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
2423 descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
2425 pango_font_metrics_unref (metrics);
2427 /* Align primarily for locale's ascent / descent */
2429 logical_rect.height /= PANGO_SCALE;
2430 logical_rect.y /= PANGO_SCALE;
2431 y_pos = area.height - logical_rect.height;
2433 if (logical_rect.height > area.height)
2434 y_pos = (logical_rect.height - area.height - 2 * COLUMN_TITLES_HEIGHT) / 2;
2437 else if (y_pos + logical_rect.height > area.height)
2438 y_pos = area.height - logical_rect.height;
2440 text_width = rect.width;
2441 text_height = rect.height;
2442 y = area.y + y_pos - COLUMN_TITLES_HEIGHT;
2444 switch (attributes.justification)
2446 case GTK_JUSTIFY_RIGHT:
2448 area.x +=area.width;
2450 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
2452 if ( !gtk_sheet_cell_empty (sheet, row, i)) break;
2453 if (size >= text_width + COLUMN_TITLES_HEIGHT) break;
2454 size += g_sheet_column_get_width (sheet->column_geometry, i);
2455 g_sheet_column_set_right_text_column (sheet->column_geometry, i,
2457 g_sheet_column_get_right_text_column (sheet->column_geometry, i)));
2462 xoffset += area.width - text_width - 2 * COLUMN_TITLES_HEIGHT -
2463 attributes.border.width / 2;
2465 case GTK_JUSTIFY_CENTER:
2466 sizel = area.width / 2;
2467 sizer = area.width / 2;
2468 area.x += area.width / 2;
2470 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
2472 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
2473 if (sizer >= text_width / 2) break;
2474 sizer += g_sheet_column_get_width (sheet->column_geometry, i);
2475 g_sheet_column_set_left_text_column (sheet->column_geometry, i,
2478 g_sheet_column_get_left_text_column (sheet->column_geometry, i)));
2480 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
2482 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
2483 if (sizel >= text_width / 2) break;
2484 sizel += g_sheet_column_get_width (sheet->column_geometry, i);
2485 g_sheet_column_set_right_text_column (sheet->column_geometry, i,
2487 g_sheet_column_get_right_text_column (sheet->column_geometry, i)));
2489 size = MIN (sizel, sizer);
2492 xoffset += sizel - text_width / 2 - COLUMN_TITLES_HEIGHT;
2493 area.width = sizel + sizer;
2495 case GTK_JUSTIFY_LEFT:
2499 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
2501 if (! gtk_sheet_cell_empty (sheet, row, i)) break;
2502 if (size >= text_width + COLUMN_TITLES_HEIGHT) break;
2503 size += g_sheet_column_get_width (sheet->column_geometry, i);
2504 g_sheet_column_set_left_text_column (sheet->column_geometry, i,
2507 g_sheet_column_get_left_text_column (sheet->column_geometry, i)));
2512 xoffset += attributes.border.width / 2;
2516 gdk_gc_set_clip_rectangle (fg_gc, &area);
2519 gdk_draw_layout (sheet->pixmap, fg_gc,
2520 area.x + xoffset + COLUMN_TITLES_HEIGHT,
2524 gdk_gc_set_clip_rectangle (fg_gc, NULL);
2525 g_object_unref (layout);
2530 gtk_sheet_range_draw (GtkSheet *sheet, const GtkSheetRange *range)
2533 GtkSheetRange drawing_range;
2535 g_return_if_fail (sheet != NULL);
2536 g_return_if_fail (GTK_SHEET (sheet));
2538 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
2539 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
2540 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
2542 if (sheet->sheet_window_width <= 0) return;
2543 if (sheet->sheet_window_height <=0) return;
2545 if (sheet->pixmap == NULL) return ;
2549 drawing_range.row0 = MIN_VISIBLE_ROW (sheet);
2550 drawing_range.col0 = MIN_VISIBLE_COLUMN (sheet);
2551 drawing_range.rowi = MIN (MAX_VISIBLE_ROW (sheet),
2552 g_sheet_row_get_row_count (sheet->row_geometry) - 1);
2553 drawing_range.coli = MAX_VISIBLE_COLUMN (sheet);
2555 gdk_draw_rectangle (sheet->pixmap,
2556 GTK_WIDGET (sheet)->style->white_gc,
2559 sheet->sheet_window_width,
2560 sheet->sheet_window_height);
2564 drawing_range.row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
2565 drawing_range.col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
2566 drawing_range.rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
2567 drawing_range.coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
2570 for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
2571 for (j = drawing_range.col0; j <= drawing_range.coli; j++)
2573 gtk_sheet_cell_draw_default (sheet, i, j);
2574 gtk_sheet_cell_draw_label (sheet, i, j);
2577 gtk_sheet_draw_backing_pixmap (sheet, drawing_range);
2579 if (sheet->state != GTK_SHEET_NORMAL &&
2580 gtk_sheet_range_isvisible (sheet, sheet->range))
2581 gtk_sheet_range_draw_selection (sheet, drawing_range);
2583 if (sheet->state == GTK_STATE_NORMAL &&
2584 sheet->active_cell.row >= drawing_range.row0 &&
2585 sheet->active_cell.row <= drawing_range.rowi &&
2586 sheet->active_cell.col >= drawing_range.col0 &&
2587 sheet->active_cell.col <= drawing_range.coli)
2588 gtk_sheet_show_active_cell (sheet);
2592 gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
2598 if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
2599 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
2602 if (!gtk_sheet_range_isvisible (sheet, range)) return;
2603 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
2607 range.col0 = MAX (sheet->range.col0, range.col0);
2608 range.coli = MIN (sheet->range.coli, range.coli);
2609 range.row0 = MAX (sheet->range.row0, range.row0);
2610 range.rowi = MIN (sheet->range.rowi, range.rowi);
2612 range.col0 = MAX (range.col0, MIN_VISIBLE_COLUMN (sheet));
2613 range.coli = MIN (range.coli, MAX_VISIBLE_COLUMN (sheet));
2614 range.row0 = MAX (range.row0, MIN_VISIBLE_ROW (sheet));
2615 range.rowi = MIN (range.rowi, MAX_VISIBLE_ROW (sheet));
2617 for (i = range.row0; i <= range.rowi; i++)
2619 for (j = range.col0; j <= range.coli; j++)
2622 if (gtk_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED &&
2623 g_sheet_column_get_visibility (sheet->column_geometry, j) && g_sheet_row_get_visibility (sheet->row_geometry, i))
2625 area.x = COLUMN_LEFT_XPIXEL (sheet, j);
2626 if ( sheet->row_titles_visible)
2627 area.x += sheet->row_title_area.width;
2629 area.x -= sheet->hadjustment->value;
2631 area.y = g_sheet_row_start_pixel (sheet->row_geometry, i);
2632 if ( sheet->column_titles_visible)
2633 area.y += sheet->column_title_area.height;
2635 area.y -= sheet->vadjustment->value;
2638 area.width= g_sheet_column_get_width (sheet->column_geometry, j);
2639 area.height = g_sheet_row_get_height (sheet->row_geometry, i);
2641 if (i == sheet->range.row0)
2643 area.y = area.y + 2;
2644 area.height = area.height - 2;
2646 if (i == sheet->range.rowi) area.height = area.height - 3;
2647 if (j == sheet->range.col0)
2649 area.x = area.x + 2;
2650 area.width = area.width - 2;
2652 if (j == sheet->range.coli) area.width = area.width - 3;
2654 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
2656 gdk_draw_rectangle (sheet->sheet_window,
2659 area.x + 1, area.y + 1,
2660 area.width, area.height);
2667 gtk_sheet_draw_border (sheet, sheet->range);
2671 gtk_sheet_draw_backing_pixmap (GtkSheet *sheet, GtkSheetRange range)
2675 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
2677 if ( sheet->pixmap == NULL) return;
2679 gdk_drawable_get_size (sheet->pixmap, &width, &height);
2681 gdk_draw_drawable (sheet->sheet_window,
2682 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
2685 sheet->row_titles_visible ? sheet->row_title_area.width : 0,
2686 sheet->column_titles_visible ? sheet->column_title_area.height : 0,
2690 static void gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
2691 GtkJustification justification,
2696 safe_strcmp (const gchar *s1, const gchar *s2)
2698 if ( !s1 && !s2) return 0;
2699 if ( !s1) return - 1;
2700 if ( !s2) return +1;
2701 return strcmp (s1, s2);
2705 gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
2706 GtkJustification justification,
2709 GSheetModel *model ;
2713 GtkSheetRange range;
2715 GtkSheetCellAttr attributes;
2717 g_return_if_fail (sheet != NULL);
2718 g_return_if_fail (GTK_IS_SHEET (sheet));
2719 if (col >= g_sheet_column_get_column_count (sheet->column_geometry) || row >= g_sheet_row_get_row_count (sheet->row_geometry)) return;
2720 if (col < 0 || row < 0) return;
2722 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2724 attributes.justification = justification;
2726 model = gtk_sheet_get_model (sheet);
2728 old_text = g_sheet_model_get_string (model, row, col);
2732 if (0 != safe_strcmp (old_text, text))
2733 changed = g_sheet_model_set_string (model, text, row, col);
2735 if ( g_sheet_model_free_strings (model))
2739 if (changed && attributes.is_visible)
2741 gchar *s = gtk_sheet_cell_get_text (sheet, row, col);
2743 if (s && strlen (s) > 0)
2745 text_width = STRING_WIDTH (GTK_WIDGET (sheet),
2746 attributes.font_desc, text);
2748 dispose_string (sheet, s);
2752 range.col0 = MIN_VISIBLE_COLUMN (sheet);
2753 range.coli = MAX_VISIBLE_COLUMN (sheet);
2755 if (gtk_sheet_autoresize (sheet) &&
2756 text_width > g_sheet_column_get_width (sheet->column_geometry, col) -
2757 2 * COLUMN_TITLES_HEIGHT- attributes.border.width)
2759 gtk_sheet_set_column_width (sheet, col, text_width + 2 * COLUMN_TITLES_HEIGHT
2760 + attributes.border.width);
2761 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
2764 gtk_sheet_range_draw (sheet, &range);
2768 g_signal_emit (sheet, sheet_signals[CHANGED], 0, row, col);
2774 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
2776 GtkSheetRange range;
2778 g_return_if_fail (sheet != NULL);
2779 g_return_if_fail (GTK_IS_SHEET (sheet));
2780 if (column >= g_sheet_column_get_column_count (sheet->column_geometry) ||
2781 row >= g_sheet_row_get_row_count (sheet->row_geometry)) return;
2783 if (column < 0 || row < 0) return;
2787 range.col0 = MIN_VISIBLE_COLUMN (sheet);
2788 range.coli = MAX_VISIBLE_COLUMN (sheet);
2790 gtk_sheet_real_cell_clear (sheet, row, column);
2792 gtk_sheet_range_draw (sheet, &range);
2796 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column)
2798 GSheetModel *model = gtk_sheet_get_model (sheet);
2800 gchar *old_text = gtk_sheet_cell_get_text (sheet, row, column);
2802 if (old_text && strlen (old_text) > 0 )
2804 g_sheet_model_datum_clear (model, row, column);
2807 dispose_string (sheet, old_text);
2811 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
2813 g_return_if_fail (sheet != NULL);
2814 g_return_if_fail (GTK_IS_SHEET (sheet));
2816 gtk_sheet_real_range_clear (sheet, range);
2820 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
2823 GtkSheetRange clear;
2828 clear.rowi = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
2830 clear.coli = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
2835 clear.row0 = MAX (clear.row0, 0);
2836 clear.col0 = MAX (clear.col0, 0);
2837 clear.rowi = MIN (clear.rowi, g_sheet_row_get_row_count (sheet->row_geometry) - 1 );
2838 clear.coli = MIN (clear.coli, g_sheet_column_get_column_count (sheet->column_geometry) - 1 );
2840 for (i = clear.row0; i <= clear.rowi; i++)
2841 for (j = clear.col0; j <= clear.coli; j++)
2843 gtk_sheet_real_cell_clear (sheet, i, j);
2846 gtk_sheet_range_draw (sheet, NULL);
2851 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
2854 char *text = gtk_sheet_cell_get_text (sheet, row, col);
2855 empty = (text == NULL );
2857 dispose_string (sheet, text);
2864 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
2867 g_return_val_if_fail (sheet != NULL, NULL);
2868 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2870 if (col >= g_sheet_column_get_column_count (sheet->column_geometry) || row >= g_sheet_row_get_row_count (sheet->row_geometry))
2872 if (col < 0 || row < 0) return NULL;
2874 model = gtk_sheet_get_model (sheet);
2879 return g_sheet_model_get_string (model, row, col);
2884 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
2887 GtkSheetRange *range;
2889 g_return_val_if_fail (sheet != NULL, 0);
2890 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
2891 if (col >= g_sheet_column_get_column_count (sheet->column_geometry) || row >= g_sheet_row_get_row_count (sheet->row_geometry)) return 0;
2892 if (col < 0 || row < 0) return 0;
2894 state = sheet->state;
2895 range = &sheet->range;
2899 case GTK_SHEET_NORMAL:
2900 return GTK_STATE_NORMAL;
2902 case GTK_SHEET_ROW_SELECTED:
2903 if (row >= range->row0 && row <= range->rowi)
2904 return GTK_STATE_SELECTED;
2906 case GTK_SHEET_COLUMN_SELECTED:
2907 if (col >= range->col0 && col <= range->coli)
2908 return GTK_STATE_SELECTED;
2910 case GTK_SHEET_RANGE_SELECTED:
2911 if (row >= range->row0 && row <= range->rowi && \
2912 col >= range->col0 && col <= range->coli)
2913 return GTK_STATE_SELECTED;
2916 return GTK_STATE_NORMAL;
2919 /* Convert X, Y (in pixels) to *ROW, *COLUMN
2920 If the function returns FALSE, then the results will be unreliable.
2923 gtk_sheet_get_pixel_info (GtkSheet *sheet,
2931 *column = -G_MAXINT;
2933 g_return_val_if_fail (sheet != NULL, 0);
2934 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
2936 /* bounds checking, return false if the user clicked
2944 if ( sheet->column_titles_visible)
2945 y -= sheet->column_title_area.height;
2947 y += sheet->vadjustment->value;
2949 trow = yyy_row_ypixel_to_row (sheet, y);
2950 if (trow > g_sheet_row_get_row_count (sheet->row_geometry))
2955 if ( sheet->row_titles_visible)
2956 x -= sheet->row_title_area.width;
2958 x += sheet->hadjustment->value;
2960 tcol = COLUMN_FROM_XPIXEL (sheet, x);
2961 if (tcol > g_sheet_column_get_column_count (sheet->column_geometry))
2970 gtk_sheet_get_cell_area (GtkSheet * sheet,
2975 g_return_val_if_fail (sheet != NULL, 0);
2976 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
2978 if (row >= g_sheet_row_get_row_count (sheet->row_geometry) || column >= g_sheet_column_get_column_count (sheet->column_geometry))
2981 area->x = (column == -1) ? 0 : COLUMN_LEFT_XPIXEL (sheet, column);
2982 area->y = (row == -1) ? 0 : g_sheet_row_start_pixel (sheet->row_geometry, row);
2984 area->width= (column == -1) ? sheet->row_title_area.width
2985 : g_sheet_column_get_width (sheet->column_geometry, column);
2987 area->height= (row == -1) ? sheet->column_title_area.height
2988 : g_sheet_row_get_height (sheet->row_geometry, row);
2994 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
2996 g_return_val_if_fail (sheet != NULL, 0);
2997 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
2999 if (row < - 1 || column < - 1) return FALSE;
3000 if (row >= g_sheet_row_get_row_count (sheet->row_geometry) || column >= g_sheet_column_get_column_count (sheet->column_geometry))
3003 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3004 gtk_sheet_deactivate_cell (sheet);
3006 sheet->active_cell.row = row;
3007 sheet->active_cell.col = column;
3009 if ( row == -1 || column == -1)
3011 gtk_sheet_hide_active_cell (sheet);
3015 if (!gtk_sheet_activate_cell (sheet, row, column)) return FALSE;
3017 if (gtk_sheet_autoscroll (sheet))
3018 gtk_sheet_move_query (sheet, row, column);
3024 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3026 g_return_if_fail (sheet != NULL);
3027 g_return_if_fail (GTK_IS_SHEET (sheet));
3029 if ( row ) *row = sheet->active_cell.row;
3030 if (column) *column = sheet->active_cell.col;
3034 gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
3039 GtkJustification justification;
3040 GtkSheetCellAttr attributes;
3042 g_return_if_fail (data != NULL);
3043 g_return_if_fail (GTK_IS_SHEET (data));
3045 sheet = GTK_SHEET (data);
3047 if (!GTK_WIDGET_VISIBLE (widget)) return;
3048 if (sheet->state != GTK_STATE_NORMAL) return;
3050 row = sheet->active_cell.row;
3051 col = sheet->active_cell.col;
3053 if (row < 0 || col < 0) return;
3055 sheet->active_cell.row = -1;
3056 sheet->active_cell.col = -1;
3058 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3060 if (text && strlen (text) > 0)
3062 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3063 justification = attributes.justification;
3064 gtk_sheet_set_cell (sheet, row, col, justification, text);
3067 sheet->active_cell.row = row;;
3068 sheet->active_cell.col = col;
3073 gtk_sheet_deactivate_cell (GtkSheet *sheet)
3075 g_return_if_fail (sheet != NULL);
3076 g_return_if_fail (GTK_IS_SHEET (sheet));
3078 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return ;
3079 if (sheet->state != GTK_SHEET_NORMAL) return ;
3081 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3084 g_signal_emit (sheet, sheet_signals[DEACTIVATE], 0,
3085 sheet->active_cell.row,
3086 sheet->active_cell.col);
3089 g_signal_handlers_disconnect_by_func (gtk_sheet_get_entry (sheet),
3090 G_CALLBACK (gtk_sheet_entry_changed),
3093 gtk_sheet_hide_active_cell (sheet);
3094 sheet->active_cell.row = -1;
3095 sheet->active_cell.col = -1;
3097 if (GTK_SHEET_REDRAW_PENDING (sheet))
3099 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3100 gtk_sheet_range_draw (sheet, NULL);
3105 gtk_sheet_hide_active_cell (GtkSheet *sheet)
3109 GtkJustification justification;
3110 GtkSheetCellAttr attributes;
3112 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3114 row = sheet->active_cell.row;
3115 col = sheet->active_cell.col;
3117 if (row < 0 || col < 0) return;
3119 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3121 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3122 justification = attributes.justification;
3124 row = sheet->active_cell.row;
3125 col = sheet->active_cell.col;
3127 gtk_widget_hide (sheet->entry_widget);
3128 gtk_widget_unmap (sheet->entry_widget);
3130 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3132 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE);
3136 gtk_sheet_activate_cell (GtkSheet *sheet, gint row, gint col)
3138 gboolean veto = TRUE;
3140 g_return_val_if_fail (sheet != NULL, FALSE);
3141 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3143 if (row < 0 || col < 0) return FALSE;
3145 if ( row > g_sheet_row_get_row_count (sheet->row_geometry) || col > g_sheet_column_get_column_count (sheet->column_geometry))
3148 if (!veto) return FALSE;
3149 if (sheet->state != GTK_SHEET_NORMAL)
3151 sheet->state = GTK_SHEET_NORMAL;
3152 gtk_sheet_real_unselect_range (sheet, NULL);
3155 sheet->range.row0 = row;
3156 sheet->range.col0 = col;
3157 sheet->range.rowi = row;
3158 sheet->range.coli = col;
3159 sheet->active_cell.row = row;
3160 sheet->active_cell.col = col;
3161 sheet->selection_cell.row = row;
3162 sheet->selection_cell.col = col;
3164 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
3168 gtk_sheet_show_active_cell (sheet);
3170 g_signal_connect (gtk_sheet_get_entry (sheet),
3172 G_CALLBACK (gtk_sheet_entry_changed),
3175 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals [ACTIVATE], row, col, &veto);
3181 gtk_sheet_show_active_cell (GtkSheet *sheet)
3183 GtkEntry *sheet_entry;
3184 GtkSheetCellAttr attributes;
3186 const gchar *old_text;
3187 GtkJustification justification;
3190 g_return_if_fail (sheet != NULL);
3191 g_return_if_fail (GTK_IS_SHEET (sheet));
3193 row = sheet->active_cell.row;
3194 col = sheet->active_cell.col;
3196 /* Don't show the active cell, if there is no active cell: */
3197 if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
3200 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3201 if (sheet->state != GTK_SHEET_NORMAL) return;
3202 if (GTK_SHEET_IN_SELECTION (sheet)) return;
3204 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->entry_widget), GTK_VISIBLE);
3206 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
3208 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3210 justification = GTK_JUSTIFY_LEFT;
3212 if (gtk_sheet_justify_entry (sheet))
3213 justification = attributes.justification;
3215 text = gtk_sheet_cell_get_text (sheet, row, col);
3217 text = g_strdup ("");
3219 gtk_entry_set_visibility (GTK_ENTRY (sheet_entry), attributes.is_visible);
3222 /*** Added by John Gotts. Mar 25, 2005 *********/
3223 old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
3224 if (strcmp (old_text, text) != 0)
3226 if (!GTK_IS_ITEM_ENTRY (sheet_entry))
3227 gtk_entry_set_text (GTK_ENTRY (sheet_entry), text);
3229 gtk_item_entry_set_text (GTK_ITEM_ENTRY (sheet_entry), text, justification);
3232 gtk_sheet_entry_set_max_size (sheet);
3233 gtk_sheet_size_allocate_entry (sheet);
3235 gtk_widget_map (sheet->entry_widget);
3237 gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
3239 dispose_string (sheet, text);
3243 gtk_sheet_draw_active_cell (GtkSheet *sheet)
3246 GtkSheetRange range;
3248 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3249 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3251 row = sheet->active_cell.row;
3252 col = sheet->active_cell.col;
3254 if (row < 0 || col < 0) return;
3256 if (!gtk_sheet_cell_isvisible (sheet, row, col)) return;
3258 range.col0 = range.coli = col;
3259 range.row0 = range.rowi = row;
3261 gtk_sheet_draw_border (sheet, range);
3267 gtk_sheet_make_backing_pixmap (GtkSheet *sheet)
3269 gint pixmap_width, pixmap_height;
3272 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3274 width = sheet->sheet_window_width ;
3275 height = sheet->sheet_window_height ;
3278 if ( width <= 0) return;
3279 if ( height <= 0) return;
3284 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
3288 gtk_sheet_range_draw (sheet, NULL);
3292 /* reallocate if sizes don't match */
3293 gdk_drawable_get_size (sheet->pixmap,
3294 &pixmap_width, &pixmap_height);
3295 if ( (pixmap_width != width) || (pixmap_height != height))
3297 g_object_unref (sheet->pixmap);
3298 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
3301 gtk_sheet_range_draw (sheet, NULL);
3307 gtk_sheet_new_selection (GtkSheet *sheet, GtkSheetRange *range)
3309 gint i, j, mask1, mask2;
3310 gint state, selected;
3311 gint x, y, width, height;
3312 GtkSheetRange new_range, aux_range;
3314 g_return_if_fail (sheet != NULL);
3316 if (range == NULL) range=&sheet->range;
3320 range->row0 = MIN (range->row0, sheet->range.row0);
3321 range->rowi = MAX (range->rowi, sheet->range.rowi);
3322 range->col0 = MIN (range->col0, sheet->range.col0);
3323 range->coli = MAX (range->coli, sheet->range.coli);
3325 range->row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
3326 range->rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
3327 range->col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
3328 range->coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
3330 aux_range.row0 = MAX (new_range.row0, MIN_VISIBLE_ROW (sheet));
3331 aux_range.rowi = MIN (new_range.rowi, MAX_VISIBLE_ROW (sheet));
3332 aux_range.col0 = MAX (new_range.col0, MIN_VISIBLE_COLUMN (sheet));
3333 aux_range.coli = MIN (new_range.coli, MAX_VISIBLE_COLUMN (sheet));
3335 for (i = range->row0; i <= range->rowi; i++)
3337 for (j = range->col0; j <= range->coli; j++)
3340 state = gtk_sheet_cell_get_state (sheet, i, j);
3341 selected= (i <= new_range.rowi && i >= new_range.row0 &&
3342 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
3344 if (state == GTK_STATE_SELECTED && selected &&
3345 g_sheet_column_get_visibility (sheet->column_geometry, j) && g_sheet_row_get_visibility (sheet->row_geometry, i) &&
3346 (i == sheet->range.row0 || i == sheet->range.rowi ||
3347 j == sheet->range.col0 || j == sheet->range.coli ||
3348 i == new_range.row0 || i == new_range.rowi ||
3349 j == new_range.col0 || j == new_range.coli))
3352 mask1 = i == sheet->range.row0 ? 1 : 0;
3353 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
3354 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
3355 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
3357 mask2 = i == new_range.row0 ? 1 : 0;
3358 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
3359 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
3360 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
3364 x = COLUMN_LEFT_XPIXEL (sheet, j);
3365 y = g_sheet_row_start_pixel (sheet->row_geometry, i);
3366 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
3367 g_sheet_column_get_width (sheet->column_geometry, j);
3368 height = g_sheet_row_start_pixel (sheet->row_geometry, i) - y + g_sheet_row_get_height (sheet->row_geometry, i);
3370 if (i == sheet->range.row0)
3373 height = height + 3;
3375 if (i == sheet->range.rowi) height = height + 3;
3376 if (j == sheet->range.col0)
3381 if (j == sheet->range.coli) width = width + 3;
3383 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
3385 x = COLUMN_LEFT_XPIXEL (sheet, j);
3386 y = g_sheet_row_start_pixel (sheet->row_geometry, i);
3387 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
3388 g_sheet_column_get_width (sheet->column_geometry, j);
3390 height = g_sheet_row_start_pixel (sheet->row_geometry, i) - y + g_sheet_row_get_height (sheet->row_geometry, i);
3392 if (i == new_range.row0)
3395 height = height - 2;
3397 if (i == new_range.rowi) height = height - 3;
3398 if (j == new_range.col0)
3403 if (j == new_range.coli) width = width - 3;
3405 gdk_draw_rectangle (sheet->sheet_window,
3416 for (i = range->row0; i <= range->rowi; i++)
3418 for (j = range->col0; j <= range->coli; j++)
3421 state = gtk_sheet_cell_get_state (sheet, i, j);
3422 selected= (i <= new_range.rowi && i >= new_range.row0 &&
3423 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
3425 if (state == GTK_STATE_SELECTED && !selected &&
3426 g_sheet_column_get_visibility (sheet->column_geometry, j) && g_sheet_row_get_visibility (sheet->row_geometry, i))
3429 x = COLUMN_LEFT_XPIXEL (sheet, j);
3430 y = g_sheet_row_start_pixel (sheet->row_geometry, i);
3431 width = COLUMN_LEFT_XPIXEL (sheet, j) - x + g_sheet_column_get_width (sheet->column_geometry, j);
3432 height = g_sheet_row_start_pixel (sheet->row_geometry, i) - y + g_sheet_row_get_height (sheet->row_geometry, i);
3434 if (i == sheet->range.row0)
3437 height = height + 3;
3439 if (i == sheet->range.rowi) height = height + 3;
3440 if (j == sheet->range.col0)
3445 if (j == sheet->range.coli) width = width + 3;
3451 for (i = range->row0; i <= range->rowi; i++)
3453 for (j = range->col0; j <= range->coli; j++)
3456 state = gtk_sheet_cell_get_state (sheet, i, j);
3457 selected= (i <= new_range.rowi && i >= new_range.row0 &&
3458 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
3460 if (state != GTK_STATE_SELECTED && selected &&
3461 g_sheet_column_get_visibility (sheet->column_geometry, j) && g_sheet_row_get_visibility (sheet->row_geometry, i) &&
3462 (i != sheet->active_cell.row || j != sheet->active_cell.col))
3465 x = COLUMN_LEFT_XPIXEL (sheet, j);
3466 y = g_sheet_row_start_pixel (sheet->row_geometry, i);
3467 width = COLUMN_LEFT_XPIXEL (sheet, j) - x + g_sheet_column_get_width (sheet->column_geometry, j);
3468 height = g_sheet_row_start_pixel (sheet->row_geometry, i) - y + g_sheet_row_get_height (sheet->row_geometry, i);
3470 if (i == new_range.row0)
3473 height = height - 2;
3475 if (i == new_range.rowi) height = height - 3;
3476 if (j == new_range.col0)
3481 if (j == new_range.coli) width = width - 3;
3483 gdk_draw_rectangle (sheet->sheet_window,
3494 for (i = aux_range.row0; i <= aux_range.rowi; i++)
3496 for (j = aux_range.col0; j <= aux_range.coli; j++)
3499 if (g_sheet_column_get_visibility (sheet->column_geometry, j) && g_sheet_row_get_visibility (sheet->row_geometry, i))
3502 state = gtk_sheet_cell_get_state (sheet, i, j);
3504 mask1 = i == sheet->range.row0 ? 1 : 0;
3505 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
3506 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
3507 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
3509 mask2 = i == new_range.row0 ? 1 : 0;
3510 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
3511 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
3512 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
3513 if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
3515 x = COLUMN_LEFT_XPIXEL (sheet, j);
3516 y = g_sheet_row_start_pixel (sheet->row_geometry, i);
3517 width = g_sheet_column_get_width (sheet->column_geometry, j);
3518 height = g_sheet_row_get_height (sheet->row_geometry, i);
3520 gdk_draw_rectangle (sheet->sheet_window,
3528 gdk_draw_rectangle (sheet->sheet_window,
3531 x + 1, y + height - 1,
3535 gdk_draw_rectangle (sheet->sheet_window,
3543 gdk_draw_rectangle (sheet->sheet_window,
3546 x + width - 1, y + 1,
3563 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
3568 gint x = COLUMN_LEFT_XPIXEL (sheet, new_range.col0);
3569 gint y = g_sheet_row_start_pixel (sheet->row_geometry, new_range.row0);
3571 if ( sheet->row_titles_visible)
3572 x += sheet->row_title_area.width;
3574 x -= sheet->hadjustment->value;
3576 if ( sheet->column_titles_visible)
3577 y += sheet->column_title_area.height;
3579 y -= sheet->vadjustment->value;
3581 width = COLUMN_LEFT_XPIXEL (sheet, new_range.coli) -
3582 COLUMN_LEFT_XPIXEL (sheet, new_range.col0)
3584 g_sheet_column_get_width (sheet->column_geometry, new_range.coli);
3586 height = g_sheet_row_start_pixel (sheet->row_geometry, new_range.rowi) -
3587 g_sheet_row_start_pixel (sheet->row_geometry, new_range.row0)
3589 g_sheet_row_get_height (sheet->row_geometry, new_range.rowi);
3591 area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
3592 if ( sheet->row_titles_visible)
3593 area.x += sheet->row_title_area.width;
3595 area.x -= sheet->hadjustment->value;
3597 area.y = g_sheet_row_start_pixel (sheet->row_geometry, MIN_VISIBLE_ROW (sheet));
3598 if ( sheet->column_titles_visible)
3599 area.y += sheet->column_title_area.height;
3601 area.y -= sheet->vadjustment->value;
3604 area.width = sheet->sheet_window_width;
3605 area.height = sheet->sheet_window_height;
3607 gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
3609 gdk_draw_rectangle (sheet->sheet_window,
3616 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
3621 gtk_sheet_real_select_range (GtkSheet * sheet,
3622 const GtkSheetRange * range)
3626 g_return_if_fail (sheet != NULL);
3628 if (range == NULL) range = &sheet->range;
3630 memcpy (&sheet->range, range, sizeof (*range));
3632 if (range->row0 < 0 || range->rowi < 0) return;
3633 if (range->col0 < 0 || range->coli < 0) return;
3635 state = sheet->state;
3637 if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
3638 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
3640 gtk_sheet_new_selection (sheet, &sheet->range);
3644 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
3645 gtk_sheet_range_draw_selection (sheet, sheet->range);
3648 gtk_sheet_update_primary_selection (sheet);
3650 g_signal_emit (sheet, sheet_signals[SELECT_RANGE], 0, &sheet->range);
3655 gtk_sheet_get_selected_range (GtkSheet *sheet, GtkSheetRange *range)
3657 g_return_if_fail (sheet != NULL);
3658 *range = sheet->range;
3663 gtk_sheet_select_range (GtkSheet * sheet, const GtkSheetRange *range)
3665 g_return_if_fail (sheet != NULL);
3667 if (range == NULL) range=&sheet->range;
3669 if (range->row0 < 0 || range->rowi < 0) return;
3670 if (range->col0 < 0 || range->coli < 0) return;
3673 if (sheet->state != GTK_SHEET_NORMAL)
3674 gtk_sheet_real_unselect_range (sheet, NULL);
3676 gtk_sheet_deactivate_cell (sheet);
3678 sheet->range.row0 = range->row0;
3679 sheet->range.rowi = range->rowi;
3680 sheet->range.col0 = range->col0;
3681 sheet->range.coli = range->coli;
3682 sheet->active_cell.row = range->row0;
3683 sheet->active_cell.col = range->col0;
3684 sheet->selection_cell.row = range->rowi;
3685 sheet->selection_cell.col = range->coli;
3687 sheet->state = GTK_SHEET_RANGE_SELECTED;
3688 gtk_sheet_real_select_range (sheet, NULL);
3692 gtk_sheet_unselect_range (GtkSheet * sheet)
3694 if (! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3697 gtk_sheet_real_unselect_range (sheet, NULL);
3698 sheet->state = GTK_STATE_NORMAL;
3700 gtk_sheet_activate_cell (sheet,
3701 sheet->active_cell.row, sheet->active_cell.col);
3706 gtk_sheet_real_unselect_range (GtkSheet * sheet,
3707 const GtkSheetRange *range)
3709 g_return_if_fail (sheet != NULL);
3710 g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
3713 range = &sheet->range;
3715 if (range->row0 < 0 || range->rowi < 0) return;
3716 if (range->col0 < 0 || range->coli < 0) return;
3718 g_signal_emit (sheet, sheet_signals[SELECT_COLUMN], 0, -1);
3719 g_signal_emit (sheet, sheet_signals[SELECT_ROW], 0, -1);
3721 if (gtk_sheet_range_isvisible (sheet, *range))
3722 gtk_sheet_draw_backing_pixmap (sheet, *range);
3724 sheet->range.row0 = -1;
3725 sheet->range.rowi = -1;
3726 sheet->range.col0 = -1;
3727 sheet->range.coli = -1;
3732 gtk_sheet_expose (GtkWidget * widget,
3733 GdkEventExpose * event)
3736 GtkSheetRange range;
3738 g_return_val_if_fail (widget != NULL, FALSE);
3739 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
3740 g_return_val_if_fail (event != NULL, FALSE);
3742 g_print ("%s %p\n", __FUNCTION__, widget);
3744 sheet = GTK_SHEET (widget);
3746 if (GTK_WIDGET_DRAWABLE (widget))
3748 range.row0 = yyy_row_ypixel_to_row (sheet, event->area.y);
3749 range.col0 = COLUMN_FROM_XPIXEL (sheet, event->area.x);
3750 range.rowi = yyy_row_ypixel_to_row (sheet,
3751 event->area.y + event->area.height);
3753 range.coli = COLUMN_FROM_XPIXEL (sheet,
3754 event->area.x + event->area.width);
3756 g_print ("Redrawing rows %ld--%ld, columns %ld--%ld\n",
3757 range.row0, range.rowi, range.col0, range.coli);
3760 /* exposure events on the sheet */
3761 if (event->window == sheet->row_title_window &&
3762 sheet->row_titles_visible)
3765 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
3766 gtk_sheet_row_title_button_draw (sheet, i);
3769 if (event->window == sheet->column_title_window &&
3770 sheet->column_titles_visible)
3773 for (i = MIN_VISIBLE_COLUMN (sheet);
3774 i <= MAX_VISIBLE_COLUMN (sheet);
3776 gtk_sheet_column_title_button_draw (sheet, i);
3779 if (event->window == sheet->sheet_window)
3781 gtk_sheet_draw_backing_pixmap (sheet, range);
3783 if (sheet->state != GTK_SHEET_NORMAL)
3785 if (gtk_sheet_range_isvisible (sheet, sheet->range))
3786 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
3787 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
3788 gtk_sheet_draw_backing_pixmap (sheet, sheet->drag_range);
3790 if (gtk_sheet_range_isvisible (sheet, sheet->range))
3791 gtk_sheet_range_draw_selection (sheet, sheet->range);
3792 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
3793 draw_xor_rectangle (sheet, sheet->drag_range);
3796 if ((!GTK_SHEET_IN_XDRAG (sheet)) && (!GTK_SHEET_IN_YDRAG (sheet)))
3798 if (sheet->state == GTK_SHEET_NORMAL)
3799 gtk_sheet_draw_active_cell (sheet);
3804 if (sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
3805 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3807 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
3814 gtk_sheet_button_press (GtkWidget * widget,
3815 GdkEventButton * event)
3818 GdkModifierType mods;
3819 gint x, y, row, column;
3822 g_return_val_if_fail (widget != NULL, FALSE);
3823 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
3824 g_return_val_if_fail (event != NULL, FALSE);
3826 sheet = GTK_SHEET (widget);
3828 /* Cancel any pending tooltips */
3829 if (sheet->motion_timer)
3831 g_source_remove (sheet->motion_timer);
3832 sheet->motion_timer = 0;
3835 gtk_widget_get_pointer (widget, &x, &y);
3836 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
3839 if (event->window == sheet->column_title_window)
3841 g_signal_emit (sheet,
3842 sheet_signals[BUTTON_EVENT_COLUMN], 0,
3845 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
3846 g_signal_emit (sheet,
3847 sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
3850 else if (event->window == sheet->row_title_window)
3852 g_signal_emit (sheet,
3853 sheet_signals[BUTTON_EVENT_ROW], 0,
3856 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
3857 g_signal_emit (sheet,
3858 sheet_signals[DOUBLE_CLICK_ROW], 0, row);
3862 gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
3864 if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
3867 /* press on resize windows */
3868 if (event->window == sheet->column_title_window &&
3869 gtk_sheet_columns_resizable (sheet))
3872 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
3873 if ( sheet->row_titles_visible)
3874 sheet->x_drag -= sheet->row_title_area.width;
3877 sheet->x_drag = event->x;
3879 if (on_column_boundary (sheet, sheet->x_drag, &sheet->drag_cell.col))
3882 if (event->type == GDK_2BUTTON_PRESS)
3884 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
3885 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
3888 gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
3889 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
3890 gdk_pointer_grab (sheet->column_title_window, FALSE,
3891 GDK_POINTER_MOTION_HINT_MASK |
3892 GDK_BUTTON1_MOTION_MASK |
3893 GDK_BUTTON_RELEASE_MASK,
3894 NULL, NULL, event->time);
3896 draw_xor_vline (sheet);
3901 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable (sheet))
3903 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
3905 if (POSSIBLE_YDRAG (sheet, sheet->y_drag, &sheet->drag_cell.row))
3908 gtk_sheet_row_size_request (sheet, sheet->drag_cell.row, &req);
3909 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
3910 gdk_pointer_grab (sheet->row_title_window, FALSE,
3911 GDK_POINTER_MOTION_HINT_MASK |
3912 GDK_BUTTON1_MOTION_MASK |
3913 GDK_BUTTON_RELEASE_MASK,
3914 NULL, NULL, event->time);
3916 draw_xor_hline (sheet);
3921 /* the sheet itself does not handle other than single click events */
3922 if (event->type != GDK_BUTTON_PRESS) return FALSE;
3924 /* selections on the sheet */
3925 if (event->window == sheet->sheet_window)
3927 gtk_widget_get_pointer (widget, &x, &y);
3928 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
3929 gdk_pointer_grab (sheet->sheet_window, FALSE,
3930 GDK_POINTER_MOTION_HINT_MASK |
3931 GDK_BUTTON1_MOTION_MASK |
3932 GDK_BUTTON_RELEASE_MASK,
3933 NULL, NULL, event->time);
3934 gtk_grab_add (GTK_WIDGET (sheet));
3936 /* This seems to be a kludge to work around a problem where the sheet
3937 scrolls to another position. The timeout scrolls it back to its
3938 original posn. JMD 3 July 2007
3940 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3942 if (sheet->selection_mode != GTK_SELECTION_SINGLE &&
3943 sheet->selection_mode != GTK_SELECTION_NONE &&
3944 sheet->cursor_drag->type == GDK_SIZING &&
3945 !GTK_SHEET_IN_SELECTION (sheet) && !GTK_SHEET_IN_RESIZE (sheet))
3947 if (sheet->state == GTK_STATE_NORMAL)
3949 row = sheet->active_cell.row;
3950 column = sheet->active_cell.col;
3951 gtk_sheet_deactivate_cell (sheet);
3952 sheet->active_cell.row = row;
3953 sheet->active_cell.col = column;
3954 sheet->drag_range = sheet->range;
3955 sheet->state = GTK_SHEET_RANGE_SELECTED;
3956 gtk_sheet_select_range (sheet, &sheet->drag_range);
3960 if (row > sheet->range.rowi) row--;
3961 if (column > sheet->range.coli) column--;
3962 sheet->drag_cell.row = row;
3963 sheet->drag_cell.col = column;
3964 sheet->drag_range = sheet->range;
3965 draw_xor_rectangle (sheet, sheet->drag_range);
3966 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
3968 else if (sheet->cursor_drag->type == GDK_TOP_LEFT_ARROW &&
3969 !GTK_SHEET_IN_SELECTION (sheet)
3970 && ! GTK_SHEET_IN_DRAG (sheet)
3971 && sheet->active_cell.row >= 0
3972 && sheet->active_cell.col >= 0
3975 if (sheet->state == GTK_STATE_NORMAL)
3977 row = sheet->active_cell.row;
3978 column = sheet->active_cell.col;
3979 gtk_sheet_deactivate_cell (sheet);
3980 sheet->active_cell.row = row;
3981 sheet->active_cell.col = column;
3982 sheet->drag_range = sheet->range;
3983 sheet->state = GTK_SHEET_RANGE_SELECTED;
3984 gtk_sheet_select_range (sheet, &sheet->drag_range);
3988 if (row < sheet->range.row0) row++;
3989 if (row > sheet->range.rowi) row--;
3990 if (column < sheet->range.col0) column++;
3991 if (column > sheet->range.coli) column--;
3992 sheet->drag_cell.row = row;
3993 sheet->drag_cell.col = column;
3994 sheet->drag_range = sheet->range;
3995 draw_xor_rectangle (sheet, sheet->drag_range);
3996 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
4000 gtk_sheet_click_cell (sheet, row, column, &veto);
4001 if (veto) GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4005 if (event->window == sheet->column_title_window)
4007 gtk_widget_get_pointer (widget, &x, &y);
4008 if ( sheet->row_titles_visible)
4009 x -= sheet->row_title_area.width;
4011 x += sheet->hadjustment->value;
4013 column = COLUMN_FROM_XPIXEL (sheet, x);
4015 if (g_sheet_column_get_sensitivity (sheet->column_geometry, column))
4017 gtk_sheet_click_cell (sheet, - 1, column, &veto);
4018 gtk_grab_add (GTK_WIDGET (sheet));
4019 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4020 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4024 if (event->window == sheet->row_title_window)
4026 gtk_widget_get_pointer (widget, &x, &y);
4027 if ( sheet->column_titles_visible)
4028 y -= sheet->column_title_area.height;
4030 y += sheet->vadjustment->value;
4032 row = yyy_row_ypixel_to_row (sheet, y);
4033 if (g_sheet_row_get_sensitivity (sheet->row_geometry, row))
4035 gtk_sheet_click_cell (sheet, row, - 1, &veto);
4036 gtk_grab_add (GTK_WIDGET (sheet));
4037 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4038 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4046 gtk_sheet_click_cell (GtkSheet *sheet, gint row, gint column, gboolean *veto)
4050 if (row >= g_sheet_row_get_row_count (sheet->row_geometry) || column >= g_sheet_column_get_column_count (sheet->column_geometry))
4056 if (column >= 0 && row >= 0)
4058 if (! g_sheet_column_get_visibility (sheet->column_geometry, column)
4059 || !g_sheet_row_get_visibility (sheet->row_geometry, row))
4066 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[TRAVERSE],
4067 sheet->active_cell.row, sheet->active_cell.col,
4068 &row, &column, veto);
4072 if (sheet->state == GTK_STATE_NORMAL) return;
4074 row = sheet->active_cell.row;
4075 column = sheet->active_cell.col;
4077 gtk_sheet_activate_cell (sheet, row, column);
4081 if (row == -1 && column >= 0)
4083 if (gtk_sheet_autoscroll (sheet))
4084 gtk_sheet_move_query (sheet, row, column);
4085 gtk_sheet_select_column (sheet, column);
4088 if (column == -1 && row >= 0)
4090 if (gtk_sheet_autoscroll (sheet))
4091 gtk_sheet_move_query (sheet, row, column);
4092 gtk_sheet_select_row (sheet, row);
4096 if (row == - 1 && column == - 1)
4098 sheet->range.row0 = 0;
4099 sheet->range.col0 = 0;
4100 sheet->range.rowi = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
4101 sheet->range.coli = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
4102 sheet->active_cell.row = 0;
4103 sheet->active_cell.col = 0;
4104 gtk_sheet_select_range (sheet, NULL);
4108 if (row != -1 && column != -1)
4110 if (sheet->state != GTK_SHEET_NORMAL)
4112 sheet->state = GTK_SHEET_NORMAL;
4113 gtk_sheet_real_unselect_range (sheet, NULL);
4117 gtk_sheet_deactivate_cell (sheet);
4118 gtk_sheet_activate_cell (sheet, row, column);
4121 if (gtk_sheet_autoscroll (sheet))
4122 gtk_sheet_move_query (sheet, row, column);
4123 sheet->active_cell.row = row;
4124 sheet->active_cell.col = column;
4125 sheet->selection_cell.row = row;
4126 sheet->selection_cell.col = column;
4127 sheet->range.row0 = row;
4128 sheet->range.col0 = column;
4129 sheet->range.rowi = row;
4130 sheet->range.coli = column;
4131 sheet->state = GTK_SHEET_NORMAL;
4132 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4133 gtk_sheet_draw_active_cell (sheet);
4137 g_assert_not_reached ();
4138 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
4139 sheet->active_cell.col);
4143 gtk_sheet_button_release (GtkWidget *widget,
4144 GdkEventButton *event)
4147 GdkDisplay *display = gtk_widget_get_display (widget);
4149 GtkSheet *sheet = GTK_SHEET (widget);
4151 /* release on resize windows */
4152 if (GTK_SHEET_IN_XDRAG (sheet))
4154 gint xpos = event->x;
4156 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4157 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4159 gdk_display_pointer_ungrab (display, event->time);
4160 draw_xor_vline (sheet);
4162 width = new_column_width (sheet, sheet->drag_cell.col, &xpos);
4164 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, width);
4168 if (GTK_SHEET_IN_YDRAG (sheet))
4170 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4171 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4172 gtk_widget_get_pointer (widget, NULL, &y);
4173 gdk_display_pointer_ungrab (display, event->time);
4174 draw_xor_hline (sheet);
4176 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row,
4177 new_row_height (sheet, sheet->drag_cell.row, &y));
4178 g_signal_emit_by_name (sheet->vadjustment, "value_changed");
4183 if (GTK_SHEET_IN_DRAG (sheet))
4185 GtkSheetRange old_range;
4186 draw_xor_rectangle (sheet, sheet->drag_range);
4187 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
4188 gdk_display_pointer_ungrab (display, event->time);
4190 gtk_sheet_real_unselect_range (sheet, NULL);
4192 sheet->active_cell.row = sheet->active_cell.row +
4193 (sheet->drag_range.row0 - sheet->range.row0);
4194 sheet->active_cell.col = sheet->active_cell.col +
4195 (sheet->drag_range.col0 - sheet->range.col0);
4196 sheet->selection_cell.row = sheet->selection_cell.row +
4197 (sheet->drag_range.row0 - sheet->range.row0);
4198 sheet->selection_cell.col = sheet->selection_cell.col +
4199 (sheet->drag_range.col0 - sheet->range.col0);
4200 old_range = sheet->range;
4201 sheet->range = sheet->drag_range;
4202 sheet->drag_range = old_range;
4203 g_signal_emit (sheet, sheet_signals[MOVE_RANGE], 0,
4204 &sheet->drag_range, &sheet->range);
4205 gtk_sheet_select_range (sheet, &sheet->range);
4208 if (GTK_SHEET_IN_RESIZE (sheet))
4210 GtkSheetRange old_range;
4211 draw_xor_rectangle (sheet, sheet->drag_range);
4212 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
4213 gdk_display_pointer_ungrab (display, event->time);
4215 gtk_sheet_real_unselect_range (sheet, NULL);
4217 sheet->active_cell.row = sheet->active_cell.row +
4218 (sheet->drag_range.row0 - sheet->range.row0);
4219 sheet->active_cell.col = sheet->active_cell.col +
4220 (sheet->drag_range.col0 - sheet->range.col0);
4221 if (sheet->drag_range.row0 < sheet->range.row0)
4222 sheet->selection_cell.row = sheet->drag_range.row0;
4223 if (sheet->drag_range.rowi >= sheet->range.rowi)
4224 sheet->selection_cell.row = sheet->drag_range.rowi;
4225 if (sheet->drag_range.col0 < sheet->range.col0)
4226 sheet->selection_cell.col = sheet->drag_range.col0;
4227 if (sheet->drag_range.coli >= sheet->range.coli)
4228 sheet->selection_cell.col = sheet->drag_range.coli;
4229 old_range = sheet->range;
4230 sheet->range = sheet->drag_range;
4231 sheet->drag_range = old_range;
4233 if (sheet->state == GTK_STATE_NORMAL) sheet->state = GTK_SHEET_RANGE_SELECTED;
4234 g_signal_emit (sheet, sheet_signals[RESIZE_RANGE], 0,
4235 &sheet->drag_range, &sheet->range);
4236 gtk_sheet_select_range (sheet, &sheet->range);
4239 if (sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
4241 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4242 gdk_display_pointer_ungrab (display, event->time);
4243 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
4244 sheet->active_cell.col);
4247 if (GTK_SHEET_IN_SELECTION)
4248 gdk_display_pointer_ungrab (display, event->time);
4249 gtk_grab_remove (GTK_WIDGET (sheet));
4251 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4259 /* Shamelessly lifted from gtktooltips */
4261 gtk_sheet_subtitle_paint_window (GtkWidget *tip_window)
4265 gtk_widget_size_request (tip_window, &req);
4266 gtk_paint_flat_box (tip_window->style, tip_window->window,
4267 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4268 NULL, GTK_WIDGET(tip_window), "tooltip",
4269 0, 0, req.width, req.height);
4275 destroy_hover_window (GtkSheetHoverTitle *h)
4277 gtk_widget_destroy (h->window);
4281 static GtkSheetHoverTitle *
4282 create_hover_window (void)
4284 GtkSheetHoverTitle *hw = g_malloc (sizeof (*hw));
4286 hw->window = gtk_window_new (GTK_WINDOW_POPUP);
4288 #if GTK_CHECK_VERSION (2, 9, 0)
4289 gtk_window_set_type_hint (GTK_WINDOW (hw->window),
4290 GDK_WINDOW_TYPE_HINT_TOOLTIP);
4293 gtk_widget_set_app_paintable (hw->window, TRUE);
4294 gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
4295 gtk_widget_set_name (hw->window, "gtk-tooltips");
4296 gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
4298 g_signal_connect (hw->window,
4300 G_CALLBACK (gtk_sheet_subtitle_paint_window),
4303 hw->label = gtk_label_new (NULL);
4306 gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
4307 gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
4309 gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
4311 gtk_widget_show (hw->label);
4313 g_signal_connect (hw->window,
4315 G_CALLBACK (gtk_widget_destroyed),
4321 #define HOVER_WINDOW_Y_OFFSET 2
4324 show_subtitle (GtkSheet *sheet, gint row, gint column, const gchar *subtitle)
4333 gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
4337 sheet->hover_window->row = row;
4338 sheet->hover_window->column = column;
4340 gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
4342 gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
4344 gtk_widget_show (sheet->hover_window->window);
4346 width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
4352 y += sheet->column_title_area.y;
4353 y += sheet->column_title_area.height;
4354 y += HOVER_WINDOW_Y_OFFSET;
4360 x += sheet->row_title_area.x;
4361 x += sheet->row_title_area.width * 2 / 3.0;
4364 gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
4369 motion_timeout_callback (gpointer data)
4371 GtkSheet *sheet = GTK_SHEET (data);
4374 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
4376 if ( gtk_sheet_get_pixel_info (sheet, x, y, &row, &column) )
4378 if (sheet->row_title_under)
4380 GSheetRow *row_geo = sheet->row_geometry;
4383 text = g_sheet_row_get_subtitle (row_geo, row);
4385 show_subtitle (sheet, row, -1, text);
4389 if (sheet->column_title_under)
4391 GSheetColumn *col_geo = sheet->column_geometry;
4394 text = g_sheet_column_get_subtitle (col_geo, column);
4396 show_subtitle (sheet, -1, column, text );
4406 gtk_sheet_motion (GtkWidget *widget, GdkEventMotion *event)
4409 GdkModifierType mods;
4410 GdkCursorType new_cursor;
4413 GdkDisplay *display;
4415 g_return_val_if_fail (widget != NULL, FALSE);
4416 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4417 g_return_val_if_fail (event != NULL, FALSE);
4419 sheet = GTK_SHEET (widget);
4421 display = gtk_widget_get_display (widget);
4423 /* selections on the sheet */
4427 if (!GTK_WIDGET_VISIBLE (sheet->hover_window->window))
4429 if ( sheet->motion_timer > 0 )
4430 g_source_remove (sheet->motion_timer);
4431 sheet->motion_timer =
4432 g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
4438 gtk_widget_get_pointer (widget, &wx, &wy);
4440 if ( gtk_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
4442 if ( row != sheet->hover_window->row || column != sheet->hover_window->column)
4444 gtk_widget_hide (sheet->hover_window->window);
4449 if (event->window == sheet->column_title_window &&
4450 gtk_sheet_columns_resizable (sheet))
4452 if (!GTK_SHEET_IN_SELECTION (sheet) &&
4453 on_column_boundary (sheet, x, &column))
4455 new_cursor = GDK_SB_H_DOUBLE_ARROW;
4456 if (new_cursor != sheet->cursor_drag->type)
4458 gdk_cursor_unref (sheet->cursor_drag);
4459 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_SB_H_DOUBLE_ARROW);
4460 gdk_window_set_cursor (sheet->column_title_window,
4461 sheet->cursor_drag);
4466 new_cursor = GDK_TOP_LEFT_ARROW;
4467 if (!GTK_SHEET_IN_XDRAG (sheet) &&
4468 new_cursor != sheet->cursor_drag->type)
4470 gdk_cursor_unref (sheet->cursor_drag);
4471 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
4472 gdk_window_set_cursor (sheet->column_title_window,
4473 sheet->cursor_drag);
4478 if (event->window == sheet->row_title_window &&
4479 gtk_sheet_rows_resizable (sheet))
4481 if (!GTK_SHEET_IN_SELECTION (sheet) && POSSIBLE_YDRAG (sheet, y, &column))
4483 new_cursor = GDK_SB_V_DOUBLE_ARROW;
4484 if (new_cursor != sheet->cursor_drag->type)
4486 gdk_cursor_unref (sheet->cursor_drag);
4487 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_SB_V_DOUBLE_ARROW);
4488 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
4493 new_cursor = GDK_TOP_LEFT_ARROW;
4494 if (!GTK_SHEET_IN_YDRAG (sheet) &&
4495 new_cursor != sheet->cursor_drag->type)
4497 gdk_cursor_unref (sheet->cursor_drag);
4498 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
4499 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
4504 new_cursor = GDK_PLUS;
4505 if ( event->window == sheet->sheet_window &&
4506 !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
4507 !GTK_SHEET_IN_DRAG (sheet) &&
4508 !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
4509 !GTK_SHEET_IN_RESIZE (sheet) &&
4510 new_cursor != sheet->cursor_drag->type)
4512 gdk_cursor_unref (sheet->cursor_drag);
4513 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
4514 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
4517 new_cursor = GDK_TOP_LEFT_ARROW;
4518 if ( event->window == sheet->sheet_window &&
4519 ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
4520 GTK_SHEET_IN_RESIZE (sheet)) &&
4521 (POSSIBLE_DRAG (sheet, x, y, &row, &column) ||
4522 GTK_SHEET_IN_DRAG (sheet)) &&
4523 new_cursor != sheet->cursor_drag->type)
4525 gdk_cursor_unref (sheet->cursor_drag);
4526 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_TOP_LEFT_ARROW);
4527 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
4530 new_cursor = GDK_SIZING;
4531 if ( event->window == sheet->sheet_window &&
4532 sheet->selection_mode != GTK_SELECTION_NONE &&
4533 !GTK_SHEET_IN_DRAG (sheet) &&
4534 (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
4535 GTK_SHEET_IN_RESIZE (sheet)) &&
4536 new_cursor != sheet->cursor_drag->type)
4538 gdk_cursor_unref (sheet->cursor_drag);
4539 sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_SIZING);
4540 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
4544 gdk_window_get_pointer (widget->window, &x, &y, &mods);
4545 if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
4547 if (GTK_SHEET_IN_XDRAG (sheet))
4551 new_column_width (sheet, sheet->drag_cell.col, &x);
4553 if (x != sheet->x_drag)
4555 draw_xor_vline (sheet);
4557 draw_xor_vline (sheet);
4563 if (GTK_SHEET_IN_YDRAG (sheet))
4565 if (event->is_hint || event->window != widget->window)
4566 gtk_widget_get_pointer (widget, NULL, &y);
4570 new_row_height (sheet, sheet->drag_cell.row, &y);
4571 if (y != sheet->y_drag)
4573 draw_xor_hline (sheet);
4575 draw_xor_hline (sheet);
4580 if (GTK_SHEET_IN_DRAG (sheet))
4583 column = COLUMN_FROM_XPIXEL (sheet, x)- sheet->drag_cell.col;
4584 row = yyy_row_ypixel_to_row (sheet, y) - sheet->drag_cell.row;
4585 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
4586 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
4590 if (aux.row0 + row >= 0 && aux.rowi + row < g_sheet_row_get_row_count (sheet->row_geometry) &&
4591 aux.col0 + column >= 0 && aux.coli + column < g_sheet_column_get_column_count (sheet->column_geometry))
4593 aux = sheet->drag_range;
4594 sheet->drag_range.row0 = sheet->range.row0 + row;
4595 sheet->drag_range.col0 = sheet->range.col0 + column;
4596 sheet->drag_range.rowi = sheet->range.rowi + row;
4597 sheet->drag_range.coli = sheet->range.coli + column;
4598 if (aux.row0 != sheet->drag_range.row0 ||
4599 aux.col0 != sheet->drag_range.col0)
4601 draw_xor_rectangle (sheet, aux);
4602 draw_xor_rectangle (sheet, sheet->drag_range);
4608 if (GTK_SHEET_IN_RESIZE (sheet))
4611 gint v_h, current_col, current_row, col_threshold, row_threshold;
4613 if (abs (x - COLUMN_LEFT_XPIXEL (sheet, sheet->drag_cell.col)) >
4614 abs (y - g_sheet_row_start_pixel (sheet->row_geometry, sheet->drag_cell.row))) v_h = 2;
4616 current_col = COLUMN_FROM_XPIXEL (sheet, x);
4617 current_row = yyy_row_ypixel_to_row (sheet, y);
4618 column = current_col - sheet->drag_cell.col;
4619 row = current_row - sheet->drag_cell.row;
4621 /*use half of column width resp. row height as threshold to
4623 col_threshold = COLUMN_LEFT_XPIXEL (sheet, current_col) +
4624 g_sheet_column_get_width (sheet->column_geometry, current_col) / 2;
4627 if (x < col_threshold)
4630 else if (column < 0)
4632 if (x > col_threshold)
4635 row_threshold = g_sheet_row_start_pixel (sheet->row_geometry, current_row) +
4636 g_sheet_row_get_height (sheet->row_geometry, current_row)/2;
4639 if (y < row_threshold)
4644 if (y > row_threshold)
4648 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
4649 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
4659 if (aux.row0 + row >= 0 && aux.rowi + row < g_sheet_row_get_row_count (sheet->row_geometry) &&
4660 aux.col0 + column >= 0 && aux.coli + column < g_sheet_column_get_column_count (sheet->column_geometry))
4662 aux = sheet->drag_range;
4663 sheet->drag_range = sheet->range;
4665 if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
4666 if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
4667 if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
4668 if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
4670 if (aux.row0 != sheet->drag_range.row0 ||
4671 aux.rowi != sheet->drag_range.rowi ||
4672 aux.col0 != sheet->drag_range.col0 ||
4673 aux.coli != sheet->drag_range.coli)
4675 draw_xor_rectangle (sheet, aux);
4676 draw_xor_rectangle (sheet, sheet->drag_range);
4682 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4684 if (sheet->state == GTK_SHEET_NORMAL && row == sheet->active_cell.row &&
4685 column == sheet->active_cell.col) return TRUE;
4687 if (GTK_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
4688 gtk_sheet_extend_selection (sheet, row, column);
4694 gtk_sheet_crossing_notify (GtkWidget *widget,
4695 GdkEventCrossing *event)
4697 GtkSheet *sheet = GTK_SHEET (widget);
4699 if (event->window == sheet->column_title_window)
4700 sheet->column_title_under = event->type == GDK_ENTER_NOTIFY;
4701 else if (event->window == sheet->row_title_window)
4702 sheet->row_title_under = event->type == GDK_ENTER_NOTIFY;
4709 gtk_sheet_move_query (GtkSheet *sheet, gint row, gint column)
4711 guint height, width;
4713 gint new_col = column;
4715 gint row_move = FALSE;
4716 gint column_move = FALSE;
4717 gfloat row_align = -1.0;
4718 gfloat col_align = -1.0;
4720 height = sheet->sheet_window_height;
4721 width = sheet->sheet_window_width;
4723 if (row >= MAX_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
4726 new_row = MIN (g_sheet_row_get_row_count (sheet->row_geometry) - 1, row + 1);
4728 if (MAX_VISIBLE_ROW (sheet) == g_sheet_row_get_row_count (sheet->row_geometry) - 1 &&
4729 g_sheet_row_start_pixel (sheet->row_geometry, g_sheet_row_get_row_count (sheet->row_geometry) - 1) +
4730 g_sheet_row_get_height (sheet->row_geometry, g_sheet_row_get_row_count (sheet->row_geometry) - 1) < height)
4736 if (row < MIN_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
4741 if (column >= MAX_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
4744 new_col = MIN (g_sheet_column_get_column_count (sheet->column_geometry) - 1, column + 1);
4746 if (MAX_VISIBLE_COLUMN (sheet) == (g_sheet_column_get_column_count (sheet->column_geometry) - 1) &&
4747 COLUMN_LEFT_XPIXEL (sheet, g_sheet_column_get_column_count (sheet->column_geometry) - 1) +
4748 g_sheet_column_get_width (sheet->column_geometry, g_sheet_column_get_column_count (sheet->column_geometry) - 1) < width)
4750 column_move = FALSE;
4754 if (column < MIN_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
4760 if (row_move || column_move)
4762 gtk_sheet_moveto (sheet, new_row, new_col, row_align, col_align);
4765 return (row_move || column_move);
4769 gtk_sheet_extend_selection (GtkSheet *sheet, gint row, gint column)
4771 GtkSheetRange range;
4775 if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
4778 if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
4780 gtk_sheet_move_query (sheet, row, column);
4781 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4783 if (GTK_SHEET_IN_DRAG (sheet)) return;
4785 state = sheet->state;
4787 switch (sheet->state)
4789 case GTK_SHEET_ROW_SELECTED:
4790 column = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
4792 case GTK_SHEET_COLUMN_SELECTED:
4793 row = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
4795 case GTK_SHEET_NORMAL:
4796 sheet->state = GTK_SHEET_RANGE_SELECTED;
4797 r = sheet->active_cell.row;
4798 c = sheet->active_cell.col;
4799 sheet->range.col0 = c;
4800 sheet->range.row0 = r;
4801 sheet->range.coli = c;
4802 sheet->range.rowi = r;
4803 gtk_sheet_range_draw_selection (sheet, sheet->range);
4804 case GTK_SHEET_RANGE_SELECTED:
4805 sheet->state = GTK_SHEET_RANGE_SELECTED;
4808 sheet->selection_cell.row = row;
4809 sheet->selection_cell.col = column;
4811 range.col0 = MIN (column, sheet->active_cell.col);
4812 range.coli = MAX (column, sheet->active_cell.col);
4813 range.row0 = MIN (row, sheet->active_cell.row);
4814 range.rowi = MAX (row, sheet->active_cell.row);
4816 if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
4817 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
4818 state == GTK_SHEET_NORMAL)
4819 gtk_sheet_real_select_range (sheet, &range);
4824 gtk_sheet_entry_key_press (GtkWidget *widget,
4828 g_signal_emit_by_name (widget, "key_press_event", key, &focus);
4833 gtk_sheet_key_press (GtkWidget *widget,
4839 gboolean extend_selection = FALSE;
4840 gboolean force_move = FALSE;
4841 gboolean in_selection = FALSE;
4842 gboolean veto = TRUE;
4845 sheet = GTK_SHEET (widget);
4847 if (key->state & GDK_CONTROL_MASK || key->keyval == GDK_Control_L ||
4848 key->keyval == GDK_Control_R) return FALSE;
4850 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval == GDK_Shift_L
4851 || key->keyval == GDK_Shift_R;
4853 state = sheet->state;
4854 in_selection = GTK_SHEET_IN_SELECTION (sheet);
4855 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4857 switch (key->keyval)
4859 case GDK_Return: case GDK_KP_Enter:
4860 if (sheet->state == GTK_SHEET_NORMAL &&
4861 !GTK_SHEET_IN_SELECTION (sheet))
4862 g_signal_stop_emission_by_name (gtk_sheet_get_entry (sheet),
4864 row = sheet->active_cell.row;
4865 col = sheet->active_cell.col;
4866 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4867 row = MIN_VISIBLE_ROW (sheet)- 1;
4868 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4869 col = MIN_VISIBLE_COLUMN (sheet);
4870 if (row < g_sheet_row_get_row_count (sheet->row_geometry) - 1)
4873 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row < g_sheet_row_get_row_count (sheet->row_geometry) - 1)
4876 gtk_sheet_click_cell (sheet, row, col, &veto);
4877 extend_selection = FALSE;
4879 case GDK_ISO_Left_Tab:
4880 row = sheet->active_cell.row;
4881 col = sheet->active_cell.col;
4882 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4883 col = MIN_VISIBLE_COLUMN (sheet)- 1;
4884 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4885 row = MIN_VISIBLE_ROW (sheet);
4889 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) && col > 0) col--;
4892 gtk_sheet_click_cell (sheet, row, col, &veto);
4893 extend_selection = FALSE;
4896 row = sheet->active_cell.row;
4897 col = sheet->active_cell.col;
4898 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4899 col = MIN_VISIBLE_COLUMN (sheet)- 1;
4900 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4901 row = MIN_VISIBLE_ROW (sheet);
4902 if (col < g_sheet_column_get_column_count (sheet->column_geometry) - 1)
4905 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) &&
4906 col < g_sheet_column_get_column_count (sheet->column_geometry) - 1)
4909 gtk_sheet_click_cell (sheet, row, col, &veto);
4910 extend_selection = FALSE;
4913 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
4915 if (extend_selection)
4917 if (state == GTK_STATE_NORMAL)
4919 row = sheet->active_cell.row;
4920 col = sheet->active_cell.col;
4921 gtk_sheet_click_cell (sheet, row, col, &veto);
4924 if (sheet->selection_cell.row > 0)
4926 row = sheet->selection_cell.row - scroll;
4927 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row > 0) row--;
4929 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
4933 col = sheet->active_cell.col;
4934 row = sheet->active_cell.row;
4935 if (state == GTK_SHEET_COLUMN_SELECTED)
4936 row = MIN_VISIBLE_ROW (sheet);
4937 if (state == GTK_SHEET_ROW_SELECTED)
4938 col = MIN_VISIBLE_COLUMN (sheet);
4940 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row > 0) row--;
4942 gtk_sheet_click_cell (sheet, row, col, &veto);
4943 extend_selection = FALSE;
4946 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
4948 if (extend_selection)
4950 if (state == GTK_STATE_NORMAL)
4952 row = sheet->active_cell.row;
4953 col = sheet->active_cell.col;
4954 gtk_sheet_click_cell (sheet, row, col, &veto);
4957 if (sheet->selection_cell.row < g_sheet_row_get_row_count (sheet->row_geometry) - 1)
4959 row = sheet->selection_cell.row + scroll;
4960 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row < g_sheet_row_get_row_count (sheet->row_geometry) - 1) row++;
4961 row = MIN (g_sheet_row_get_row_count (sheet->row_geometry) - 1, row);
4962 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
4966 col = sheet->active_cell.col;
4967 row = sheet->active_cell.row;
4968 if (sheet->active_cell.row < g_sheet_row_get_row_count (sheet->row_geometry) - 1)
4970 if (state == GTK_SHEET_COLUMN_SELECTED)
4971 row = MIN_VISIBLE_ROW (sheet)- 1;
4972 if (state == GTK_SHEET_ROW_SELECTED)
4973 col = MIN_VISIBLE_COLUMN (sheet);
4975 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row < g_sheet_row_get_row_count (sheet->row_geometry) - 1) row++;
4976 row = MIN (g_sheet_row_get_row_count (sheet->row_geometry) - 1, row);
4978 gtk_sheet_click_cell (sheet, row, col, &veto);
4979 extend_selection = FALSE;
4982 if (extend_selection)
4984 if (state == GTK_STATE_NORMAL)
4986 row = sheet->active_cell.row;
4987 col = sheet->active_cell.col;
4988 gtk_sheet_click_cell (sheet, row, col, &veto);
4991 if (sheet->selection_cell.col < g_sheet_column_get_column_count (sheet->column_geometry) - 1)
4993 col = sheet->selection_cell.col + 1;
4994 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) && col < g_sheet_column_get_column_count (sheet->column_geometry) - 1)
4996 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5000 col = sheet->active_cell.col;
5001 row = sheet->active_cell.row;
5002 if (sheet->active_cell.col < g_sheet_column_get_column_count (sheet->column_geometry) - 1)
5005 if (state == GTK_SHEET_ROW_SELECTED)
5006 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5007 if (state == GTK_SHEET_COLUMN_SELECTED)
5008 row = MIN_VISIBLE_ROW (sheet);
5009 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) && col < g_sheet_column_get_column_count (sheet->column_geometry) - 1) col++;
5010 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5013 gtk_sheet_click_cell (sheet, row, col, &veto);
5018 extend_selection = FALSE;
5021 if (extend_selection)
5023 if (state == GTK_STATE_NORMAL)
5025 row = sheet->active_cell.row;
5026 col = sheet->active_cell.col;
5027 gtk_sheet_click_cell (sheet, row, col, &veto);
5030 if (sheet->selection_cell.col > 0)
5032 col = sheet->selection_cell.col - 1;
5033 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) && col > 0) col--;
5034 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5038 col = sheet->active_cell.col - 1;
5039 row = sheet->active_cell.row;
5040 if (state == GTK_SHEET_ROW_SELECTED)
5041 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5042 if (state == GTK_SHEET_COLUMN_SELECTED)
5043 row = MIN_VISIBLE_ROW (sheet);
5044 while (! g_sheet_column_get_visibility (sheet->column_geometry, col) && col > 0) col--;
5047 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5050 gtk_sheet_click_cell (sheet, row, col, &veto);
5054 extend_selection = FALSE;
5058 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row < g_sheet_row_get_row_count (sheet->row_geometry) - 1) row++;
5059 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5060 extend_selection = FALSE;
5063 row = g_sheet_row_get_row_count (sheet->row_geometry) - 1;
5064 while (!g_sheet_row_get_visibility (sheet->row_geometry, row) && row > 0) row--;
5065 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5066 extend_selection = FALSE;
5071 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5072 if (extend_selection) return TRUE;
5074 if (state == GTK_SHEET_ROW_SELECTED)
5075 sheet->active_cell.col = MIN_VISIBLE_COLUMN (sheet);
5076 if (state == GTK_SHEET_COLUMN_SELECTED)
5077 sheet->active_cell.row = MIN_VISIBLE_ROW (sheet);
5081 if (extend_selection) return TRUE;
5083 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5084 sheet->active_cell.col);
5090 gtk_sheet_size_request (GtkWidget * widget,
5091 GtkRequisition * requisition)
5095 g_return_if_fail (widget != NULL);
5096 g_return_if_fail (GTK_IS_SHEET (widget));
5097 g_return_if_fail (requisition != NULL);
5099 sheet = GTK_SHEET (widget);
5101 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5102 requisition->height = 3*DEFAULT_ROW_HEIGHT (widget);
5104 /* compute the size of the column title area */
5105 if (sheet->column_titles_visible)
5106 requisition->height += sheet->column_title_area.height;
5108 /* compute the size of the row title area */
5109 if (sheet->row_titles_visible)
5110 requisition->width += sheet->row_title_area.width;
5115 gtk_sheet_size_allocate (GtkWidget * widget,
5116 GtkAllocation * allocation)
5119 GtkAllocation sheet_allocation;
5122 g_return_if_fail (widget != NULL);
5123 g_return_if_fail (GTK_IS_SHEET (widget));
5124 g_return_if_fail (allocation != NULL);
5126 sheet = GTK_SHEET (widget);
5127 widget->allocation = *allocation;
5128 border_width = GTK_CONTAINER (widget)->border_width;
5130 if (GTK_WIDGET_REALIZED (widget))
5131 gdk_window_move_resize (widget->window,
5132 allocation->x + border_width,
5133 allocation->y + border_width,
5134 allocation->width - 2 * border_width,
5135 allocation->height - 2 * border_width);
5137 /* use internal allocation structure for all the math
5138 * because it's easier than always subtracting the container
5140 sheet->internal_allocation.x = 0;
5141 sheet->internal_allocation.y = 0;
5142 sheet->internal_allocation.width = allocation->width - 2 * border_width;
5143 sheet->internal_allocation.height = allocation->height - 2 * border_width;
5145 sheet_allocation.x = 0;
5146 sheet_allocation.y = 0;
5147 sheet_allocation.width = allocation->width - 2 * border_width;
5148 sheet_allocation.height = allocation->height - 2 * border_width;
5150 sheet->sheet_window_width = sheet_allocation.width;
5151 sheet->sheet_window_height = sheet_allocation.height;
5153 if (GTK_WIDGET_REALIZED (widget))
5154 gdk_window_move_resize (sheet->sheet_window,
5157 sheet_allocation.width,
5158 sheet_allocation.height);
5160 /* position the window which holds the column title buttons */
5161 sheet->column_title_area.x = 0;
5162 sheet->column_title_area.y = 0;
5164 if (sheet->row_titles_visible)
5166 sheet->column_title_area.x = sheet->row_title_area.width;
5167 sheet->sheet_window_width -= sheet->row_title_area.width;
5170 sheet->column_title_area.width = sheet_allocation.width ;
5173 if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
5174 gdk_window_move_resize (sheet->column_title_window,
5175 sheet->column_title_area.x,
5176 sheet->column_title_area.y,
5177 sheet->column_title_area.width,
5178 sheet->column_title_area.height);
5181 /* column button allocation */
5182 size_allocate_column_title_buttons (sheet);
5184 /* position the window which holds the row title buttons */
5185 sheet->row_title_area.x = 0;
5186 sheet->row_title_area.y = 0;
5187 if (sheet->column_titles_visible)
5189 sheet->row_title_area.y = sheet->column_title_area.height;
5190 sheet->sheet_window_height -= sheet->column_title_area.height;
5193 sheet->row_title_area.height = sheet_allocation.height -
5194 sheet->row_title_area.y;
5196 if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
5197 gdk_window_move_resize (sheet->row_title_window,
5198 sheet->row_title_area.x,
5199 sheet->row_title_area.y,
5200 sheet->row_title_area.width,
5201 sheet->row_title_area.height);
5204 /* row button allocation */
5205 size_allocate_row_title_buttons (sheet);
5206 size_allocate_column_title_buttons (sheet);
5208 /* re - scale backing pixmap */
5209 gtk_sheet_make_backing_pixmap (sheet);
5211 /* set the scrollbars adjustments */
5212 adjust_scrollbars (sheet);
5216 size_allocate_column_title_buttons (GtkSheet * sheet)
5221 if (!sheet->column_titles_visible) return;
5222 if (!GTK_WIDGET_REALIZED (sheet))
5226 width = sheet->sheet_window_width;
5229 if (sheet->row_titles_visible)
5231 x = sheet->row_title_area.width;
5234 if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
5236 sheet->column_title_area.width = width;
5237 sheet->column_title_area.x = x;
5238 gdk_window_move_resize (sheet->column_title_window,
5239 sheet->column_title_area.x,
5240 sheet->column_title_area.y,
5241 sheet->column_title_area.width,
5242 sheet->column_title_area.height);
5245 if (MAX_VISIBLE_COLUMN (sheet) == g_sheet_column_get_column_count (sheet->column_geometry) - 1)
5246 gdk_window_clear_area (sheet->column_title_window,
5248 sheet->column_title_area.width,
5249 sheet->column_title_area.height);
5251 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
5253 size_allocate_global_button (sheet);
5255 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
5256 gtk_sheet_column_title_button_draw (sheet, i);
5260 size_allocate_row_title_buttons (GtkSheet * sheet)
5265 if (!sheet->row_titles_visible) return;
5266 if (!GTK_WIDGET_REALIZED (sheet))
5269 height = sheet->sheet_window_height;
5272 if (sheet->column_titles_visible)
5274 y = sheet->column_title_area.height;
5277 if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
5279 sheet->row_title_area.y = y;
5280 sheet->row_title_area.height = height;
5281 gdk_window_move_resize (sheet->row_title_window,
5282 sheet->row_title_area.x,
5283 sheet->row_title_area.y,
5284 sheet->row_title_area.width,
5285 sheet->row_title_area.height);
5287 if (MAX_VISIBLE_ROW (sheet) == g_sheet_row_get_row_count (sheet->row_geometry) - 1)
5288 gdk_window_clear_area (sheet->row_title_window,
5290 sheet->row_title_area.width,
5291 sheet->row_title_area.height);
5293 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
5295 size_allocate_global_button (sheet);
5297 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
5299 if ( i >= g_sheet_row_get_row_count (sheet->row_geometry))
5301 gtk_sheet_row_title_button_draw (sheet, i);
5307 gtk_sheet_size_allocate_entry (GtkSheet *sheet)
5309 GtkAllocation shentry_allocation;
5310 GtkSheetCellAttr attributes = { 0 };
5311 GtkEntry *sheet_entry;
5312 GtkStyle *style = NULL, *previous_style = NULL;
5314 gint size, max_size, text_size, column_width;
5317 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
5318 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
5320 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
5322 if ( ! gtk_sheet_get_attributes (sheet, sheet->active_cell.row,
5323 sheet->active_cell.col,
5327 if ( GTK_WIDGET_REALIZED (sheet->entry_widget) )
5329 if (!GTK_WIDGET (sheet_entry)->style)
5330 gtk_widget_ensure_style (GTK_WIDGET (sheet_entry));
5332 previous_style = GTK_WIDGET (sheet_entry)->style;
5334 style = gtk_style_copy (previous_style);
5335 style->bg[GTK_STATE_NORMAL] = attributes.background;
5336 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
5337 style->text[GTK_STATE_NORMAL] = attributes.foreground;
5338 style->bg[GTK_STATE_ACTIVE] = attributes.background;
5339 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
5340 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
5342 pango_font_description_free (style->font_desc);
5343 g_assert (attributes.font_desc);
5344 style->font_desc = pango_font_description_copy (attributes.font_desc);
5346 GTK_WIDGET (sheet_entry)->style = style;
5347 gtk_widget_size_request (sheet->entry_widget, NULL);
5348 GTK_WIDGET (sheet_entry)->style = previous_style;
5350 if (style != previous_style)
5352 if (!GTK_IS_ITEM_ENTRY (sheet->entry_widget))
5354 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
5355 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
5356 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
5357 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
5359 gtk_widget_set_style (GTK_WIDGET (sheet_entry), style);
5360 g_object_unref (style);
5364 if (GTK_IS_ITEM_ENTRY (sheet_entry))
5365 max_size = GTK_ITEM_ENTRY (sheet_entry)->text_max_size;
5370 text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
5371 if (text && strlen (text) > 0)
5372 text_size = STRING_WIDTH (GTK_WIDGET (sheet), attributes.font_desc, text);
5374 column_width = g_sheet_column_get_width (sheet->column_geometry, sheet->active_cell.col);
5376 size = MIN (text_size, max_size);
5377 size = MAX (size, column_width - 2 * COLUMN_TITLES_HEIGHT);
5379 row = sheet->active_cell.row;
5380 col = sheet->active_cell.col;
5382 shentry_allocation.x = COLUMN_LEFT_XPIXEL (sheet, sheet->active_cell.col);
5383 shentry_allocation.y = g_sheet_row_start_pixel (sheet->row_geometry, sheet->active_cell.row);
5384 if ( sheet->column_titles_visible)
5385 shentry_allocation.y += sheet->column_title_area.height;
5387 shentry_allocation.y -= sheet->vadjustment->value;
5389 if ( sheet->row_titles_visible)
5390 shentry_allocation.x += sheet->row_title_area.width;
5392 shentry_allocation.x -= sheet->hadjustment->value;
5394 shentry_allocation.width = column_width;
5395 shentry_allocation.height = g_sheet_row_get_height (sheet->row_geometry, sheet->active_cell.row);
5397 if (GTK_IS_ITEM_ENTRY (sheet->entry_widget))
5399 shentry_allocation.height -= 2 * COLUMN_TITLES_HEIGHT;
5400 shentry_allocation.y += COLUMN_TITLES_HEIGHT;
5401 shentry_allocation.width = size;
5403 switch (GTK_ITEM_ENTRY (sheet_entry)->justification)
5405 case GTK_JUSTIFY_CENTER:
5406 shentry_allocation.x += column_width / 2 - size / 2;
5408 case GTK_JUSTIFY_RIGHT:
5409 shentry_allocation.x += column_width - size - COLUMN_TITLES_HEIGHT;
5411 case GTK_JUSTIFY_LEFT:
5412 case GTK_JUSTIFY_FILL:
5413 shentry_allocation.x += COLUMN_TITLES_HEIGHT;
5418 if (!GTK_IS_ITEM_ENTRY (sheet->entry_widget))
5420 shentry_allocation.x += 2;
5421 shentry_allocation.y += 2;
5422 shentry_allocation.width -= MIN (shentry_allocation.width, 3);
5423 shentry_allocation.height -= MIN (shentry_allocation.height, 3);
5426 gtk_widget_size_allocate (sheet->entry_widget, &shentry_allocation);
5428 if (previous_style == style) g_object_unref (previous_style);
5432 gtk_sheet_entry_set_max_size (GtkSheet *sheet)
5436 gint sizel = 0, sizer = 0;
5438 GtkJustification justification;
5441 row = sheet->active_cell.row;
5442 col = sheet->active_cell.col;
5444 if ( ! GTK_IS_ITEM_ENTRY (sheet->entry_widget) )
5447 justification = GTK_ITEM_ENTRY (sheet->entry_widget)->justification;
5449 switch (justification)
5451 case GTK_JUSTIFY_FILL:
5452 case GTK_JUSTIFY_LEFT:
5453 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
5455 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
5460 size +=g_sheet_column_get_width (sheet->column_geometry, i);
5462 size = MIN (size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL (sheet, col));
5464 case GTK_JUSTIFY_RIGHT:
5465 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
5467 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
5472 size +=g_sheet_column_get_width (sheet->column_geometry, i);
5475 case GTK_JUSTIFY_CENTER:
5476 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
5478 sizer += g_sheet_column_get_width (sheet->column_geometry, i);
5480 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
5482 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
5487 sizel +=g_sheet_column_get_width (sheet->column_geometry, i);
5489 size = 2 * MIN (sizel, sizer);
5494 size += g_sheet_column_get_width (sheet->column_geometry, col);
5495 GTK_ITEM_ENTRY (sheet->entry_widget)->text_max_size = size;
5500 create_sheet_entry (GtkSheet *sheet)
5502 if (sheet->entry_widget)
5504 gtk_widget_unparent (sheet->entry_widget);
5507 if (sheet->entry_type)
5509 sheet->entry_container = g_object_new (sheet->entry_type, NULL);
5510 g_object_ref_sink (sheet->entry_container);
5511 sheet->entry_widget = gtk_sheet_get_entry (sheet);
5513 if ( NULL == sheet->entry_widget)
5515 g_warning ("Entry type is %s. It must be GtkEntry subclass, or a widget containing one. "
5516 "Using default", g_type_name (sheet->entry_type));
5517 g_object_unref (sheet->entry_container);
5518 sheet->entry_widget = sheet->entry_container = gtk_item_entry_new ();
5522 sheet->entry_widget = sheet->entry_container ;
5527 sheet->entry_widget = sheet->entry_container = gtk_item_entry_new ();
5528 g_object_ref_sink (sheet->entry_container);
5531 gtk_widget_size_request (sheet->entry_widget, NULL);
5533 if (GTK_WIDGET_REALIZED (sheet))
5535 gtk_widget_set_parent_window (sheet->entry_widget, sheet->sheet_window);
5536 gtk_widget_set_parent (sheet->entry_widget, GTK_WIDGET (sheet));
5537 gtk_widget_realize (sheet->entry_widget);
5540 g_signal_connect_swapped (sheet->entry_widget, "key_press_event",
5541 G_CALLBACK (gtk_sheet_entry_key_press),
5544 gtk_widget_show (sheet->entry_widget);
5548 /* Finds the last child widget that happens to be of type GtkEntry */
5550 find_entry (GtkWidget *w, gpointer user_data)
5552 GtkWidget **entry = user_data;
5553 if ( GTK_IS_ENTRY (w))
5560 gtk_sheet_get_entry (GtkSheet *sheet)
5563 GtkWidget *entry = NULL;
5565 g_return_val_if_fail (sheet != NULL, NULL);
5566 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
5567 g_return_val_if_fail (sheet->entry_widget != NULL, NULL);
5569 if (GTK_IS_ENTRY (sheet->entry_container))
5570 return (sheet->entry_container);
5572 parent = sheet->entry_container;
5574 if (GTK_IS_CONTAINER (parent))
5576 gtk_container_forall (GTK_CONTAINER (parent), find_entry, &entry);
5578 if (GTK_IS_ENTRY (entry))
5582 if (!GTK_IS_ENTRY (entry)) return NULL;
5589 gtk_sheet_get_entry_widget (GtkSheet *sheet)
5591 g_return_val_if_fail (sheet != NULL, NULL);
5592 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
5593 g_return_val_if_fail (sheet->entry_widget != NULL, NULL);
5595 return (sheet->entry_widget);
5600 gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
5601 GtkSheetButton *button, gboolean is_sensitive,
5602 GdkRectangle allocation)
5604 GtkShadowType shadow_type;
5605 gint text_width = 0, text_height = 0;
5606 PangoAlignment align = PANGO_ALIGN_LEFT;
5614 g_return_if_fail (sheet != NULL);
5615 g_return_if_fail (button != NULL);
5618 rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
5620 gdk_window_clear_area (window,
5621 allocation.x, allocation.y,
5622 allocation.width, allocation.height);
5624 gtk_paint_box (sheet->button->style, window,
5625 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
5626 &allocation, GTK_WIDGET (sheet->button),
5628 allocation.x, allocation.y,
5629 allocation.width, allocation.height);
5631 state = button->state;
5632 if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
5634 if (state == GTK_STATE_ACTIVE)
5635 shadow_type = GTK_SHADOW_IN;
5637 shadow_type = GTK_SHADOW_OUT;
5639 if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
5640 gtk_paint_box (sheet->button->style, window,
5641 button->state, shadow_type,
5642 &allocation, GTK_WIDGET (sheet->button),
5644 allocation.x, allocation.y,
5645 allocation.width, allocation.height);
5647 if (button->label_visible)
5650 text_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) -
5651 2 * COLUMN_TITLES_HEIGHT;
5653 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
5655 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc,
5658 allocation.y += 2 * sheet->button->style->ythickness;
5661 if (button->label && strlen (button->label)>0)
5664 PangoLayout *layout = NULL;
5665 gint real_x = allocation.x, real_y = allocation.y;
5667 words = button->label;
5668 line = g_new (gchar, 1);
5671 while (words && *words != '\0')
5675 len = strlen (line);
5676 line = g_realloc (line, len + 2);
5680 if (*words == '\n' || * (words + 1) == '\0')
5682 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
5684 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
5685 switch (button->justification)
5687 case GTK_JUSTIFY_LEFT:
5688 real_x = allocation.x + COLUMN_TITLES_HEIGHT;
5689 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
5691 case GTK_JUSTIFY_RIGHT:
5692 real_x = allocation.x + allocation.width - text_width - COLUMN_TITLES_HEIGHT;
5693 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
5695 case GTK_JUSTIFY_CENTER:
5697 real_x = allocation.x + (allocation.width - text_width)/2;
5698 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
5699 pango_layout_set_justify (layout, TRUE);
5701 pango_layout_set_alignment (layout, align);
5702 gtk_paint_layout (GTK_WIDGET (sheet)->style,
5711 g_object_unref (layout);
5713 real_y += text_height + 2;
5716 line = g_new (gchar, 1);
5724 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
5726 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
5730 gtk_sheet_button_free (button);
5734 gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
5736 GdkRectangle allocation;
5737 GtkSheetButton *button = NULL;
5738 gboolean is_sensitive = FALSE;
5740 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
5742 if (!sheet->column_titles_visible) return;
5743 if (!g_sheet_column_get_visibility (sheet->column_geometry, column)) return;
5745 if (column < MIN_VISIBLE_COLUMN (sheet)) return;
5746 if (column > MAX_VISIBLE_COLUMN (sheet)) return;
5748 button = g_sheet_column_get_button (sheet->column_geometry, column);
5750 allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
5751 allocation.x -= sheet->hadjustment->value;
5753 allocation.height = sheet->column_title_area.height;
5754 allocation.width = g_sheet_column_get_width (sheet->column_geometry, column);
5755 is_sensitive = g_sheet_column_get_sensitivity (sheet->column_geometry, column);
5757 gtk_sheet_button_draw (sheet, sheet->column_title_window,
5758 button, is_sensitive, allocation);
5763 gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
5765 GdkRectangle allocation;
5766 GtkSheetButton *button = NULL;
5767 gboolean is_sensitive = FALSE;
5770 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
5772 if (!sheet->row_titles_visible) return;
5773 if (!g_sheet_row_get_visibility (sheet->row_geometry, row)) return;
5775 if (row < MIN_VISIBLE_ROW (sheet)) return;
5776 if (row > MAX_VISIBLE_ROW (sheet)) return;
5778 button = g_sheet_row_get_button (sheet->row_geometry, row);
5780 allocation.y = g_sheet_row_start_pixel (sheet->row_geometry, row) + CELL_SPACING;
5781 allocation.y -= sheet->vadjustment->value;
5783 allocation.width = sheet->row_title_area.width;
5784 allocation.height = g_sheet_row_get_height (sheet->row_geometry, row);
5785 is_sensitive = g_sheet_row_get_sensitivity (sheet->row_geometry, row);
5787 gtk_sheet_button_draw (sheet, sheet->row_title_window,
5788 button, is_sensitive, allocation);
5795 * vadjustment_value_changed
5796 * hadjustment_value_changed */
5799 adjust_scrollbars (GtkSheet * sheet)
5801 if (sheet->vadjustment)
5803 sheet->vadjustment->step_increment =
5804 1 ; // DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
5806 sheet->vadjustment->page_increment =
5807 sheet->sheet_window_height - DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
5809 sheet->vadjustment->upper = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))
5810 * g_sheet_row_get_row_count (sheet->row_geometry);
5813 sheet->vadjustment->lower = 0;
5814 sheet->vadjustment->page_size = sheet->sheet_window_height;
5816 g_signal_emit_by_name (sheet->vadjustment, "changed");
5819 if (sheet->hadjustment)
5822 sheet->hadjustment->step_increment = 1 ; //DEFAULT_COLUMN_WIDTH;
5824 sheet->hadjustment->page_increment = sheet->sheet_window_width ;
5826 last_col = g_sheet_column_get_column_count (sheet->column_geometry) - 1;
5828 sheet->hadjustment->upper =
5829 g_sheet_column_start_pixel (sheet->column_geometry, last_col)
5831 g_sheet_column_get_width (sheet->column_geometry, last_col)
5834 sheet->hadjustment->lower = 0;
5835 sheet->hadjustment->page_size = sheet->sheet_window_width;
5837 g_signal_emit_by_name (sheet->hadjustment, "changed");
5842 vadjustment_value_changed (GtkAdjustment * adjustment,
5845 GtkSheet *sheet = GTK_SHEET (data);
5847 g_return_if_fail (adjustment != NULL);
5849 if ( ! GTK_WIDGET_REALIZED (sheet)) return;
5851 gtk_widget_hide (sheet->entry_widget);
5852 gtk_sheet_range_draw (sheet, NULL);
5853 size_allocate_row_title_buttons (sheet);
5854 // size_allocate_global_button (sheet);
5859 hadjustment_value_changed (GtkAdjustment * adjustment,
5862 GtkSheet *sheet = GTK_SHEET (data);
5864 g_return_if_fail (adjustment != NULL);
5866 if ( ! GTK_WIDGET_REALIZED (sheet)) return;
5868 gtk_widget_hide (sheet->entry_widget);
5869 gtk_sheet_range_draw (sheet, NULL);
5870 size_allocate_column_title_buttons (sheet);
5871 // size_allocate_global_button (sheet);
5875 /* COLUMN RESIZING */
5877 draw_xor_vline (GtkSheet * sheet)
5879 gint xpos = sheet->x_drag;
5881 if (sheet->row_titles_visible)
5882 xpos += sheet->row_title_area.width;
5884 gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc,
5886 sheet->column_title_area.height,
5888 sheet->sheet_window_height + CELL_SPACING);
5893 draw_xor_hline (GtkSheet * sheet)
5896 gint ypos = sheet->y_drag;
5898 if (sheet->column_titles_visible)
5899 ypos += sheet->column_title_area.height;
5901 gdk_draw_line (GTK_WIDGET (sheet)->window, sheet->xor_gc,
5902 sheet->row_title_area.width,
5904 sheet->sheet_window_width + CELL_SPACING,
5908 /* SELECTED RANGE */
5910 draw_xor_rectangle (GtkSheet *sheet, GtkSheetRange range)
5913 GdkRectangle clip_area, area;
5916 area.x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
5917 area.y = g_sheet_row_start_pixel (sheet->row_geometry, range.row0);
5918 area.width = COLUMN_LEFT_XPIXEL (sheet, range.coli)- area.x+
5919 g_sheet_column_get_width (sheet->column_geometry, range.coli);
5920 area.height = g_sheet_row_start_pixel (sheet->row_geometry, range.rowi)- area.y +
5921 g_sheet_row_get_height (sheet->row_geometry, range.rowi);
5923 clip_area.x = sheet->row_title_area.width;
5924 clip_area.y = sheet->column_title_area.height;
5925 clip_area.width = sheet->sheet_window_width;
5926 clip_area.height = sheet->sheet_window_height;
5928 if (!sheet->row_titles_visible) clip_area.x = 0;
5929 if (!sheet->column_titles_visible) clip_area.y = 0;
5933 area.width = area.width + area.x;
5936 if (area.width > clip_area.width) area.width = clip_area.width + 10;
5939 area.height = area.height + area.y;
5942 if (area.height > clip_area.height) area.height = clip_area.height + 10;
5946 clip_area.width += 3;
5947 clip_area.height += 3;
5949 gdk_gc_get_values (sheet->xor_gc, &values);
5951 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
5953 gdk_draw_rectangle (sheet->sheet_window,
5956 area.x + i, area.y + i,
5957 area.width - 2 * i, area.height - 2 * i);
5960 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
5962 gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
5966 /* this function returns the new width of the column being resized given
5967 * the COLUMN and X position of the cursor; the x cursor position is passed
5968 * in as a pointer and automaticaly corrected if it's outside the acceptable
5971 new_column_width (GtkSheet *sheet, gint column, gint *x)
5973 gint left_pos = COLUMN_LEFT_XPIXEL (sheet, column)
5974 - sheet->hadjustment->value;
5976 gint width = *x - left_pos;
5978 if ( width < sheet->column_requisition)
5980 width = sheet->column_requisition;
5981 *x = left_pos + width;
5984 g_sheet_column_set_width (sheet->column_geometry, column, width);
5986 size_allocate_column_title_buttons (sheet);
5991 /* this function returns the new height of the row being resized given
5992 * the row and y position of the cursor; the y cursor position is passed
5993 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
5995 new_row_height (GtkSheet *sheet, gint row, gint *y)
6001 min_height = sheet->row_requisition;
6003 /* you can't shrink a row to less than its minimum height */
6004 if (cy < g_sheet_row_start_pixel (sheet->row_geometry, row) + min_height)
6007 *y = cy = g_sheet_row_start_pixel (sheet->row_geometry, row) + min_height;
6010 /* calculate new row height making sure it doesn't end up
6011 * less than the minimum height */
6012 height = (cy - g_sheet_row_start_pixel (sheet->row_geometry, row));
6013 if (height < min_height)
6014 height = min_height;
6016 g_sheet_row_set_height (sheet->row_geometry, row, height);
6017 size_allocate_row_title_buttons (sheet);
6023 gtk_sheet_set_column_width (GtkSheet * sheet,
6029 g_return_if_fail (sheet != NULL);
6030 g_return_if_fail (GTK_IS_SHEET (sheet));
6032 if (column < 0 || column >= g_sheet_column_get_column_count (sheet->column_geometry))
6035 gtk_sheet_column_size_request (sheet, column, &min_width);
6036 if (width < min_width) return;
6038 g_sheet_column_set_width (sheet->column_geometry, column, width);
6040 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
6042 size_allocate_column_title_buttons (sheet);
6043 adjust_scrollbars (sheet);
6044 gtk_sheet_size_allocate_entry (sheet);
6045 gtk_sheet_range_draw (sheet, NULL);
6048 g_signal_emit (sheet, sheet_signals[CHANGED], 0, -1, column);
6054 gtk_sheet_set_row_height (GtkSheet * sheet,
6060 g_return_if_fail (sheet != NULL);
6061 g_return_if_fail (GTK_IS_SHEET (sheet));
6063 if (row < 0 || row >= g_sheet_row_get_row_count (sheet->row_geometry))
6066 gtk_sheet_row_size_request (sheet, row, &min_height);
6067 if (height < min_height) return;
6069 g_sheet_row_set_height (sheet->row_geometry, row, height);
6071 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) )
6073 size_allocate_row_title_buttons (sheet);
6074 adjust_scrollbars (sheet);
6075 gtk_sheet_size_allocate_entry (sheet);
6076 gtk_sheet_range_draw (sheet, NULL);
6079 g_signal_emit (sheet, sheet_signals[CHANGED], 0, row, - 1);
6082 gtk_sheet_get_attributes (const GtkSheet *sheet, gint row, gint col,
6083 GtkSheetCellAttr *attributes)
6085 const GdkColor *fg, *bg;
6086 const GtkJustification *j ;
6087 const PangoFontDescription *font_desc ;
6088 const GtkSheetCellBorder *border ;
6090 g_return_val_if_fail (sheet != NULL, FALSE);
6091 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
6093 if (row < 0 || col < 0) return FALSE;
6095 init_attributes (sheet, col, attributes);
6100 attributes->is_editable = g_sheet_model_is_editable (sheet->model, row, col);
6101 attributes->is_visible = g_sheet_model_is_visible (sheet->model, row, col);
6103 fg = g_sheet_model_get_foreground (sheet->model, row, col);
6105 attributes->foreground = *fg;
6107 bg = g_sheet_model_get_background (sheet->model, row, col);
6109 attributes->background = *bg;
6111 j = g_sheet_model_get_justification (sheet->model, row, col);
6112 if (j) attributes->justification = *j;
6114 font_desc = g_sheet_model_get_font_desc (sheet->model, row, col);
6115 if ( font_desc ) attributes->font_desc = font_desc;
6117 border = g_sheet_model_get_cell_border (sheet->model, row, col);
6119 if ( border ) attributes->border = *border;
6125 init_attributes (const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
6127 /* DEFAULT VALUES */
6128 attributes->foreground = GTK_WIDGET (sheet)->style->black;
6129 attributes->background = sheet->color[BG_COLOR];
6130 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
6132 attributes->background = sheet->color[BG_COLOR];
6134 attributes->justification = g_sheet_column_get_justification (sheet->column_geometry, col);
6135 attributes->border.width = 0;
6136 attributes->border.line_style = GDK_LINE_SOLID;
6137 attributes->border.cap_style = GDK_CAP_NOT_LAST;
6138 attributes->border.join_style = GDK_JOIN_MITER;
6139 attributes->border.mask = 0;
6140 attributes->border.color = GTK_WIDGET (sheet)->style->black;
6141 attributes->is_editable = TRUE;
6142 attributes->is_visible = TRUE;
6143 attributes->font_desc = GTK_WIDGET (sheet)->style->font_desc;
6147 label_size_request (GtkSheet *sheet, gchar *label, GtkRequisition *req)
6152 gint row_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) - 2 * COLUMN_TITLES_HEIGHT + 2;
6158 while (words && *words != '\0')
6160 if (*words == '\n' || * (words + 1) == '\0')
6162 req->height += row_height;
6165 req->width = MAX (req->width, STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, word));
6175 if (n > 0) req->height -= 2;
6179 gtk_sheet_button_size_request (GtkSheet *sheet,
6180 const GtkSheetButton *button,
6181 GtkRequisition *button_requisition)
6183 GtkRequisition requisition;
6184 GtkRequisition label_requisition;
6186 if (gtk_sheet_autoresize (sheet) && button->label && strlen (button->label) > 0)
6188 label_size_request (sheet, button->label, &label_requisition);
6189 label_requisition.width += 2 * COLUMN_TITLES_HEIGHT;
6190 label_requisition.height += 2 * COLUMN_TITLES_HEIGHT;
6194 label_requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
6195 label_requisition.width = COLUMN_MIN_WIDTH;
6198 requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
6199 requisition.width = COLUMN_MIN_WIDTH;
6202 *button_requisition = requisition;
6203 button_requisition->width = MAX (requisition.width, label_requisition.width);
6204 button_requisition->height = MAX (requisition.height, label_requisition.height);
6209 gtk_sheet_row_size_request (GtkSheet *sheet,
6213 GtkRequisition button_requisition;
6215 gtk_sheet_button_size_request (sheet,
6216 g_sheet_row_get_button (sheet->row_geometry, row),
6217 &button_requisition);
6219 *requisition = button_requisition.height;
6221 sheet->row_requisition = * requisition;
6225 gtk_sheet_column_size_request (GtkSheet *sheet,
6229 GtkRequisition button_requisition;
6231 GtkSheetButton *button = g_sheet_column_get_button (sheet->column_geometry, col);
6233 gtk_sheet_button_size_request (sheet,
6235 &button_requisition);
6237 gtk_sheet_button_free (button);
6239 *requisition = button_requisition.width;
6241 sheet->column_requisition = *requisition;
6246 gtk_sheet_forall (GtkContainer *container,
6247 gboolean include_internals,
6248 GtkCallback callback,
6249 gpointer callback_data)
6251 GtkSheet *sheet = GTK_SHEET (container);
6253 g_return_if_fail (callback != NULL);
6255 if (sheet->button && sheet->button->parent)
6256 (* callback) (sheet->button, callback_data);
6258 if (sheet->entry_container && GTK_IS_CONTAINER (sheet->entry_container))
6259 (* callback) (sheet->entry_container, callback_data);
6264 gtk_sheet_get_model (const GtkSheet *sheet)
6266 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6268 return sheet->model;
6273 gtk_sheet_button_new (void)
6275 GtkSheetButton *button = g_malloc (sizeof (GtkSheetButton));
6277 button->state = GTK_STATE_NORMAL;
6278 button->label = NULL;
6279 button->label_visible = TRUE;
6280 button->justification = GTK_JUSTIFY_FILL;
6287 gtk_sheet_button_free (GtkSheetButton *button)
6289 if (!button) return ;
6291 g_free (button->label);
6297 append_cell_text (GString *string, const GtkSheet *sheet, gint r, gint c)
6299 gchar *celltext = gtk_sheet_cell_get_text (sheet, r, c);
6301 if ( NULL == celltext)
6304 g_string_append (string, celltext);
6310 range_to_text (const GtkSheet *sheet)
6315 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
6318 string = g_string_sized_new (80);
6320 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
6322 for (c = sheet->range.col0; c < sheet->range.coli; ++c)
6324 append_cell_text (string, sheet, r, c);
6325 g_string_append (string, "\t");
6327 append_cell_text (string, sheet, r, c);
6328 if ( r < sheet->range.rowi)
6329 g_string_append (string, "\n");
6336 range_to_html (const GtkSheet *sheet)
6341 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
6344 string = g_string_sized_new (480);
6346 g_string_append (string, "<html>\n");
6347 g_string_append (string, "<body>\n");
6348 g_string_append (string, "<table>\n");
6349 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
6351 g_string_append (string, "<tr>\n");
6352 for (c = sheet->range.col0; c <= sheet->range.coli; ++c)
6354 g_string_append (string, "<td>");
6355 append_cell_text (string, sheet, r, c);
6356 g_string_append (string, "</td>\n");
6358 g_string_append (string, "</tr>\n");
6360 g_string_append (string, "</table>\n");
6361 g_string_append (string, "</body>\n");
6362 g_string_append (string, "</html>\n");
6374 primary_get_cb (GtkClipboard *clipboard,
6375 GtkSelectionData *selection_data,
6379 GtkSheet *sheet = GTK_SHEET (data);
6380 GString *string = NULL;
6384 case SELECT_FMT_TEXT:
6385 string = range_to_text (sheet);
6387 case SELECT_FMT_HTML:
6388 string = range_to_html (sheet);
6391 g_assert_not_reached ();
6394 gtk_selection_data_set (selection_data, selection_data->target,
6396 (const guchar *) string->str, string->len);
6397 g_string_free (string, TRUE);
6401 primary_clear_cb (GtkClipboard *clipboard,
6404 GtkSheet *sheet = GTK_SHEET (data);
6405 if ( ! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
6408 gtk_sheet_real_unselect_range (sheet, NULL);
6412 gtk_sheet_update_primary_selection (GtkSheet *sheet)
6414 static const GtkTargetEntry targets[] = {
6415 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
6416 { "STRING", 0, SELECT_FMT_TEXT },
6417 { "TEXT", 0, SELECT_FMT_TEXT },
6418 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
6419 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
6420 { "text/plain", 0, SELECT_FMT_TEXT },
6421 { "text/html", 0, SELECT_FMT_HTML }
6424 GtkClipboard *clipboard;
6426 if (!GTK_WIDGET_REALIZED (sheet))
6429 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet),
6430 GDK_SELECTION_PRIMARY);
6432 if (gtk_sheet_range_isvisible (sheet, sheet->range))
6434 if (!gtk_clipboard_set_with_owner (clipboard, targets,
6435 G_N_ELEMENTS (targets),
6436 primary_get_cb, primary_clear_cb,
6438 primary_clear_cb (clipboard, sheet);
6442 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet))
6443 gtk_clipboard_clear (clipboard);