2 * Copyright (C) 2006, 2008 Free Software Foundation
4 * This version of GtkSheet has been *heavily* modified, for the specific
5 * requirements of PSPPIRE. The changes are copyright by the
6 * Free Software Foundation. The copyright notice for the original work is
10 /* GtkSheet widget for Gtk+.
11 * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
13 * Based on GtkClist widget by Jay Painter, but major changes.
14 * Memory allocation routines inspired on SC (Spreadsheet Calculator)
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 * @short_description: spreadsheet widget for gtk2
35 * GtkSheet is a matrix widget for GTK+. It consists of an scrollable grid of
36 * cells where you can allocate text. Cell contents can be edited interactively
37 * through a specially designed entry, GtkItemEntry. It is also a container
38 * subclass, allowing you to display buttons, curves, pixmaps and any other
41 * You can also set many attributes as: border, foreground and background color,
42 * text justification, and more.
44 * The testgtksheet program shows how easy is to create a spreadsheet-like GUI
54 #include <gdk/gdkkeysyms.h>
55 #include <gtk/gtksignal.h>
56 #include <gtk/gtklabel.h>
57 #include <gtk/gtkbutton.h>
58 #include <gtk/gtkadjustment.h>
59 #include <gtk/gtktable.h>
60 #include <gtk/gtkbox.h>
61 #include <gtk/gtkmain.h>
62 #include <gtk/gtktypeutils.h>
63 #include <gtk/gtkentry.h>
64 #include <gtk/gtkcontainer.h>
65 #include <gtk/gtkpixmap.h>
66 #include <pango/pango.h>
67 #include "gtkitementry.h"
69 #include "gtkextra-marshal.h"
70 #include "gsheetmodel.h"
75 GTK_SHEET_IS_FROZEN = 1 << 1,
76 GTK_SHEET_IN_XDRAG = 1 << 2,
77 GTK_SHEET_IN_YDRAG = 1 << 3,
78 GTK_SHEET_IN_DRAG = 1 << 4,
79 GTK_SHEET_IN_SELECTION = 1 << 5,
80 GTK_SHEET_IN_RESIZE = 1 << 6,
81 GTK_SHEET_REDRAW_PENDING = 1 << 7,
84 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
85 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
86 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~ (flag))
88 #define GTK_SHEET_IS_FROZEN(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
89 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
90 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
91 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
92 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
93 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
94 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
96 #define CELL_SPACING 1
98 #define TIMEOUT_HOVER 300
99 #define TIME_INTERVAL 8
100 #define COLUMN_MIN_WIDTH 10
105 #define DEFAULT_COLUMN_WIDTH 80
108 static void gtk_sheet_update_primary_selection (GtkSheet *sheet);
111 static void gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column);
113 static void gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row);
116 static gboolean gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col);
119 void dispose_string (const GtkSheet *sheet, gchar *text)
121 GSheetModel *model = gtk_sheet_get_model (sheet);
126 if (g_sheet_model_free_strings (model))
131 guint DEFAULT_ROW_HEIGHT (GtkWidget *widget)
133 if (!widget->style->font_desc) return 24;
136 PangoContext *context = gtk_widget_get_pango_context (widget);
137 PangoFontMetrics *metrics =
138 pango_context_get_metrics (context,
139 widget->style->font_desc,
140 pango_context_get_language (context));
142 guint val = pango_font_metrics_get_descent (metrics) +
143 pango_font_metrics_get_ascent (metrics);
145 pango_font_metrics_unref (metrics);
147 return PANGO_PIXELS (val) + 2 * CELLOFFSET;
152 guint DEFAULT_FONT_ASCENT (GtkWidget *widget)
154 if (!widget->style->font_desc) return 12;
157 PangoContext *context = gtk_widget_get_pango_context (widget);
158 PangoFontMetrics *metrics =
159 pango_context_get_metrics (context,
160 widget->style->font_desc,
161 pango_context_get_language (context));
162 guint val = pango_font_metrics_get_ascent (metrics);
163 pango_font_metrics_unref (metrics);
164 return PANGO_PIXELS (val);
169 guint STRING_WIDTH (GtkWidget *widget,
170 const PangoFontDescription *font, const gchar *text)
175 layout = gtk_widget_create_pango_layout (widget, text);
176 pango_layout_set_font_description (layout, font);
178 pango_layout_get_extents (layout, NULL, &rect);
180 g_object_unref (G_OBJECT (layout));
181 return PANGO_PIXELS (rect.width);
185 guint DEFAULT_FONT_DESCENT (GtkWidget *widget)
187 if (!widget->style->font_desc) return 12;
190 PangoContext *context = gtk_widget_get_pango_context (widget);
191 PangoFontMetrics *metrics =
192 pango_context_get_metrics (context,
193 widget->style->font_desc,
194 pango_context_get_language (context));
195 guint val = pango_font_metrics_get_descent (metrics);
196 pango_font_metrics_unref (metrics);
197 return PANGO_PIXELS (val);
203 yyy_row_is_visible (const GtkSheet *sheet, gint row)
205 GSheetRow *row_geo = sheet->row_geometry;
207 return g_sheet_row_get_visibility (row_geo, row, 0);
212 yyy_row_is_sensitive (const GtkSheet *sheet, gint row)
214 GSheetRow *row_geo = sheet->row_geometry;
216 return g_sheet_row_get_sensitivity (row_geo, row, 0);
222 yyy_row_count (const GtkSheet *sheet)
224 GSheetRow *row_geo = sheet->row_geometry;
226 return g_sheet_row_get_row_count (row_geo, 0);
230 yyy_row_height (const GtkSheet *sheet, gint row)
232 GSheetRow *row_geo = sheet->row_geometry;
234 return g_sheet_row_get_height (row_geo, row, 0);
238 yyy_row_top_ypixel (const GtkSheet *sheet, gint row)
240 GSheetRow *geo = sheet->row_geometry;
242 gint y = g_sheet_row_start_pixel (geo, row, 0);
244 if ( sheet->column_titles_visible )
245 y += sheet->column_title_area.height;
251 /* Return the row containing pixel Y */
253 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
255 GSheetRow *geo = sheet->row_geometry;
257 gint cy = sheet->voffset;
259 if (sheet->column_titles_visible)
260 cy += sheet->column_title_area.height;
262 if (y < cy) return 0;
264 return g_sheet_row_pixel_to_row (geo, y - cy, 0);
268 /* gives the top pixel of the given row in context of
269 * the sheet's voffset */
271 ROW_TOP_YPIXEL (const GtkSheet *sheet, gint row)
273 return (sheet->voffset + yyy_row_top_ypixel (sheet, row));
277 /* returns the row index from a y pixel location in the
278 * context of the sheet's voffset */
280 ROW_FROM_YPIXEL (const GtkSheet *sheet, gint y)
282 return (yyy_row_ypixel_to_row (sheet, y));
285 static inline GtkSheetButton *
286 xxx_column_button (const GtkSheet *sheet, gint col)
288 GSheetColumn *col_geo = sheet->column_geometry;
289 if ( col < 0 ) return NULL ;
291 return g_sheet_column_get_button (col_geo, col);
296 xxx_column_left_xpixel (const GtkSheet *sheet, gint col)
298 GSheetColumn *geo = sheet->column_geometry;
300 gint x = g_sheet_column_start_pixel (geo, col);
302 if ( sheet->row_titles_visible )
303 x += sheet->row_title_area.width;
309 xxx_column_width (const GtkSheet *sheet, gint col)
311 GSheetColumn *col_geo = sheet->column_geometry;
313 return g_sheet_column_get_width (col_geo, col);
318 xxx_set_column_width (GtkSheet *sheet, gint col, gint width)
320 if ( sheet->column_geometry )
321 g_sheet_column_set_width (sheet->column_geometry, col, width);
325 xxx_column_set_left_column (GtkSheet *sheet, gint col, gint i)
327 GSheetColumn *col_geo = sheet->column_geometry;
329 g_sheet_column_set_left_text_column (col_geo, col, i);
333 xxx_column_left_column (const GtkSheet *sheet, gint col)
335 GSheetColumn *col_geo = sheet->column_geometry;
337 return g_sheet_column_get_left_text_column (col_geo, col);
341 xxx_column_set_right_column (GtkSheet *sheet, gint col, gint i)
343 GSheetColumn *col_geo = sheet->column_geometry;
345 g_sheet_column_set_right_text_column (col_geo, col, i);
349 xxx_column_right_column (const GtkSheet *sheet, gint col)
351 GSheetColumn *col_geo = sheet->column_geometry;
353 return g_sheet_column_get_right_text_column (col_geo, col);
356 static inline GtkJustification
357 xxx_column_justification (const GtkSheet *sheet, gint col)
359 GSheetColumn *col_geo = sheet->column_geometry;
361 return g_sheet_column_get_justification (col_geo, col);
365 xxx_column_is_visible (const GtkSheet *sheet, gint col)
367 GSheetColumn *col_geo = sheet->column_geometry;
369 return g_sheet_column_get_visibility (col_geo, col);
374 xxx_column_is_sensitive (const GtkSheet *sheet, gint col)
376 GSheetColumn *col_geo = sheet->column_geometry;
378 return g_sheet_column_get_sensitivity (col_geo, col);
382 /* gives the left pixel of the given column in context of
383 * the sheet's hoffset */
385 COLUMN_LEFT_XPIXEL (const GtkSheet *sheet, gint ncol)
387 return (sheet->hoffset + xxx_column_left_xpixel (sheet, ncol));
391 xxx_column_count (const GtkSheet *sheet)
393 GSheetColumn *col_geo = sheet->column_geometry;
395 return g_sheet_column_get_column_count (col_geo);
398 /* returns the column index from a x pixel location in the
399 * context of the sheet's hoffset */
401 COLUMN_FROM_XPIXEL (const GtkSheet * sheet,
407 if ( sheet->row_titles_visible )
408 cx += sheet->row_title_area.width;
410 if (x < cx) return 0;
411 for (i = 0; i < xxx_column_count (sheet); i++)
413 if (x >= cx && x <= (cx + xxx_column_width (sheet, i)) &&
414 xxx_column_is_visible (sheet, i))
416 if ( xxx_column_is_visible (sheet, i))
417 cx += xxx_column_width (sheet, i);
421 return xxx_column_count (sheet) - 1;
424 /* returns the total height of the sheet */
425 static inline gint SHEET_HEIGHT (GtkSheet *sheet)
427 const gint n_rows = yyy_row_count (sheet);
429 return yyy_row_top_ypixel (sheet, n_rows - 1) +
430 yyy_row_height (sheet, n_rows - 1);
434 static inline GtkSheetButton *
435 yyy_row_button (GtkSheet *sheet, gint row)
437 GSheetRow *row_geo = sheet->row_geometry;
439 return g_sheet_row_get_button (row_geo, row, sheet);
446 yyy_set_row_height (GtkSheet *sheet, gint row, gint height)
448 if ( sheet->row_geometry )
449 g_sheet_row_set_height (sheet->row_geometry, row, height, sheet);
454 /* returns the total width of the sheet */
455 static inline gint SHEET_WIDTH (GtkSheet *sheet)
459 cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
461 for (i = 0; i < xxx_column_count (sheet); i++)
462 if (xxx_column_is_visible (sheet, i))
463 cx += xxx_column_width (sheet, i);
468 #define MIN_VISIBLE_ROW(sheet) \
469 ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + 1)
471 #define MAX_VISIBLE_ROW(sheet) \
472 ROW_FROM_YPIXEL (sheet, sheet->sheet_window_height - 1)
474 #define MIN_VISIBLE_COLUMN(sheet) \
475 COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + 1)
477 #define MAX_VISIBLE_COLUMN(sheet) \
478 COLUMN_FROM_XPIXEL (sheet, sheet->sheet_window_width)
482 static inline gboolean
483 POSSIBLE_XDRAG (const GtkSheet *sheet, gint x, gint *drag_column)
487 column = COLUMN_FROM_XPIXEL (sheet, x);
488 *drag_column = column;
490 xdrag = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
491 if (x <= xdrag + DRAG_WIDTH / 2 && column != 0)
493 while (! xxx_column_is_visible (sheet, column - 1) && column > 0) column--;
494 *drag_column = column - 1;
495 return xxx_column_is_sensitive (sheet, column - 1);
498 xdrag += xxx_column_width (sheet, column);
499 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
500 return xxx_column_is_sensitive (sheet, column);
505 static inline gboolean
506 POSSIBLE_YDRAG (const GtkSheet *sheet, gint y, gint *drag_row)
509 row = ROW_FROM_YPIXEL (sheet, y);
512 ydrag = ROW_TOP_YPIXEL (sheet, row)+CELL_SPACING;
513 if (y <= ydrag + DRAG_WIDTH / 2 && row != 0)
515 while (!yyy_row_is_visible (sheet, row - 1) && row > 0) row--;
517 return yyy_row_is_sensitive (sheet, row - 1);
520 ydrag +=yyy_row_height (sheet, row);
522 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
523 return yyy_row_is_sensitive (sheet, row);
529 static inline gboolean
530 POSSIBLE_DRAG (const GtkSheet *sheet, gint x, gint y,
531 gint *drag_row, gint *drag_column)
535 /* Can't drag if nothing is selected */
536 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
537 sheet->range.col0 < 0 || sheet->range.coli < 0 )
540 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
541 *drag_row = ROW_FROM_YPIXEL (sheet, y);
543 if (x >= COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0) - DRAG_WIDTH / 2 &&
544 x <= COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
545 xxx_column_width (sheet, sheet->range.coli) + DRAG_WIDTH / 2)
547 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.row0);
548 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
550 *drag_row = sheet->range.row0;
553 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
554 yyy_row_height (sheet, sheet->range.rowi);
555 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
557 *drag_row = sheet->range.rowi;
562 if (y >= ROW_TOP_YPIXEL (sheet, sheet->range.row0) - DRAG_WIDTH / 2 &&
563 y <= ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
564 yyy_row_height (sheet, sheet->range.rowi) + DRAG_WIDTH / 2)
566 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0);
567 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
569 *drag_column = sheet->range.col0;
572 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
573 xxx_column_width (sheet, sheet->range.coli);
574 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
576 *drag_column = sheet->range.coli;
584 static inline gboolean
585 POSSIBLE_RESIZE (const GtkSheet *sheet, gint x, gint y,
586 gint *drag_row, gint *drag_column)
590 /* Can't drag if nothing is selected */
591 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
592 sheet->range.col0 < 0 || sheet->range.coli < 0 )
595 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli)+
596 xxx_column_width (sheet, sheet->range.coli);
598 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi)+
599 yyy_row_height (sheet, sheet->range.rowi);
601 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
602 ydrag = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
604 if (sheet->state == GTK_SHEET_ROW_SELECTED)
605 xdrag = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
607 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
608 *drag_row = ROW_FROM_YPIXEL (sheet, y);
610 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
611 y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
616 static void gtk_sheet_class_init (GtkSheetClass * klass);
617 static void gtk_sheet_init (GtkSheet * sheet);
618 static void gtk_sheet_destroy (GtkObject * object);
619 static void gtk_sheet_finalize (GObject * object);
620 static void gtk_sheet_style_set (GtkWidget *widget,
621 GtkStyle *previous_style);
622 static void gtk_sheet_realize (GtkWidget * widget);
623 static void gtk_sheet_unrealize (GtkWidget * widget);
624 static void gtk_sheet_map (GtkWidget * widget);
625 static void gtk_sheet_unmap (GtkWidget * widget);
626 static gint gtk_sheet_expose (GtkWidget * widget,
627 GdkEventExpose * event);
628 static void gtk_sheet_forall (GtkContainer *container,
629 gboolean include_internals,
630 GtkCallback callback,
631 gpointer callback_data);
633 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
634 GtkAdjustment *hadjustment,
635 GtkAdjustment *vadjustment);
637 static gint gtk_sheet_button_press (GtkWidget * widget,
638 GdkEventButton * event);
639 static gint gtk_sheet_button_release (GtkWidget * widget,
640 GdkEventButton * event);
641 static gint gtk_sheet_motion (GtkWidget * widget,
642 GdkEventMotion * event);
643 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
645 static gint gtk_sheet_key_press (GtkWidget *widget,
647 static void gtk_sheet_size_request (GtkWidget * widget,
648 GtkRequisition * requisition);
649 static void gtk_sheet_size_allocate (GtkWidget * widget,
650 GtkAllocation * allocation);
654 static gboolean gtk_sheet_range_isvisible (const GtkSheet * sheet,
655 GtkSheetRange range);
656 static gboolean gtk_sheet_cell_isvisible (GtkSheet * sheet,
657 gint row, gint column);
658 /* Drawing Routines */
660 /* draw cell background and frame */
661 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
662 gint row, gint column);
664 /* draw cell contents */
665 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
666 gint row, gint column);
668 /* draw visible part of range. If range == NULL then draw the whole screen */
669 static void gtk_sheet_range_draw (GtkSheet *sheet,
670 const GtkSheetRange *range);
672 /* highlight the visible part of the selected range */
673 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
674 GtkSheetRange range);
678 static gboolean gtk_sheet_move_query (GtkSheet *sheet,
679 gint row, gint column);
680 static void gtk_sheet_real_select_range (GtkSheet * sheet,
681 const GtkSheetRange * range);
682 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
683 const GtkSheetRange * range);
684 static void gtk_sheet_extend_selection (GtkSheet *sheet,
685 gint row, gint column);
686 static void gtk_sheet_new_selection (GtkSheet *sheet,
687 GtkSheetRange *range);
688 static void gtk_sheet_draw_border (GtkSheet *sheet,
689 GtkSheetRange range);
690 static void gtk_sheet_draw_corners (GtkSheet *sheet,
691 GtkSheetRange range);
694 /* Active Cell handling */
696 static void gtk_sheet_entry_changed (GtkWidget *widget,
698 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
699 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
700 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
702 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
703 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
704 static void gtk_sheet_click_cell (GtkSheet *sheet,
711 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
712 guint width, guint height);
713 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
714 GtkSheetRange range);
717 static void adjust_scrollbars (GtkSheet * sheet);
718 static void vadjustment_value_changed (GtkAdjustment * adjustment,
720 static void hadjustment_value_changed (GtkAdjustment * adjustment,
724 static void draw_xor_vline (GtkSheet * sheet);
725 static void draw_xor_hline (GtkSheet * sheet);
726 static void draw_xor_rectangle (GtkSheet *sheet,
727 GtkSheetRange range);
729 static guint new_column_width (GtkSheet * sheet,
732 static guint new_row_height (GtkSheet * sheet,
737 static void create_global_button (GtkSheet *sheet);
738 static void global_button_clicked (GtkWidget *widget,
742 static void create_sheet_entry (GtkSheet *sheet);
743 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
744 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
746 /* Sheet button gadgets */
748 static void size_allocate_column_title_buttons (GtkSheet * sheet);
749 static void size_allocate_row_title_buttons (GtkSheet * sheet);
752 static void size_allocate_global_button (GtkSheet *sheet);
753 static void gtk_sheet_button_size_request (GtkSheet *sheet,
754 const GtkSheetButton *button,
755 GtkRequisition *requisition);
757 /* Attributes routines */
758 static void init_attributes (const GtkSheet *sheet, gint col,
759 GtkSheetCellAttr *attributes);
762 /* Memory allocation routines */
763 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
764 const GtkSheetRange *range);
766 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
771 /* Container Functions */
772 static void gtk_sheet_remove (GtkContainer *container,
774 static void gtk_sheet_realize_child (GtkSheet *sheet,
775 GtkSheetChild *child);
776 static void gtk_sheet_position_child (GtkSheet *sheet,
777 GtkSheetChild *child);
778 static void gtk_sheet_position_children (GtkSheet *sheet);
779 static void gtk_sheet_child_show (GtkSheetChild *child);
780 static void gtk_sheet_child_hide (GtkSheetChild *child);
781 static void gtk_sheet_column_size_request (GtkSheet *sheet,
784 static void gtk_sheet_row_size_request (GtkSheet *sheet,
792 _gtkextra_signal_emit (GtkObject *object, guint signal_id, ...);
816 static GtkContainerClass *parent_class = NULL;
817 static guint sheet_signals[LAST_SIGNAL] = { 0 };
821 gtk_sheet_get_type ()
823 static GType sheet_type = 0;
827 static const GTypeInfo sheet_info =
829 sizeof (GtkSheetClass),
832 (GClassInitFunc) gtk_sheet_class_init,
837 (GInstanceInitFunc) gtk_sheet_init,
841 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
847 static GtkSheetRange*
848 gtk_sheet_range_copy (const GtkSheetRange *range)
850 GtkSheetRange *new_range;
852 g_return_val_if_fail (range != NULL, NULL);
854 new_range = g_new (GtkSheetRange, 1);
862 gtk_sheet_range_free (GtkSheetRange *range)
864 g_return_if_fail (range != NULL);
870 gtk_sheet_range_get_type (void)
872 static GType sheet_range_type = 0;
874 if (!sheet_range_type)
877 g_boxed_type_register_static ("GtkSheetRange",
878 (GBoxedCopyFunc) gtk_sheet_range_copy,
879 (GBoxedFreeFunc) gtk_sheet_range_free);
882 return sheet_range_type;
886 gtk_sheet_class_init (GtkSheetClass * klass)
888 GtkObjectClass *object_class;
889 GtkWidgetClass *widget_class;
890 GtkContainerClass *container_class;
891 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
893 object_class = (GtkObjectClass *) klass;
894 widget_class = (GtkWidgetClass *) klass;
895 container_class = (GtkContainerClass *) klass;
897 parent_class = g_type_class_peek_parent (klass);
900 * GtkSheet::select-row
901 * @sheet: the sheet widget that emitted the signal
902 * @row: the newly selected row index
904 * A row has been selected.
906 sheet_signals[SELECT_ROW] =
907 g_signal_new ("select-row",
908 G_TYPE_FROM_CLASS (object_class),
910 offsetof (GtkSheetClass, select_row),
919 * GtkSheet::select - column
920 * @sheet: the sheet widget that emitted the signal
921 * @column: the newly selected column index
923 * A column has been selected.
925 sheet_signals[SELECT_COLUMN] =
926 g_signal_new ("select-column",
927 G_TYPE_FROM_CLASS (object_class),
929 offsetof (GtkSheetClass, select_column),
938 * GtkSheet::double-click-row
939 * @sheet: the sheet widget that emitted the signal
940 * @row: the row that was double clicked.
942 * A row's title button has been double clicked
944 sheet_signals[DOUBLE_CLICK_ROW] =
945 g_signal_new ("double-click-row",
946 G_TYPE_FROM_CLASS (object_class),
957 * GtkSheet::double-click-column
958 * @sheet: the sheet widget that emitted the signal
959 * @column: the column that was double clicked.
961 * A column's title button has been double clicked
963 sheet_signals[DOUBLE_CLICK_COLUMN] =
964 g_signal_new ("double-click-column",
965 G_TYPE_FROM_CLASS (object_class),
976 * GtkSheet::button-event-column
977 * @sheet: the sheet widget that emitted the signal
978 * @column: the column on which the event occured.
980 * A button event occured on a column title button
982 sheet_signals[BUTTON_EVENT_COLUMN] =
983 g_signal_new ("button-event-column",
984 G_TYPE_FROM_CLASS (object_class),
988 gtkextra_VOID__INT_POINTER,
997 * GtkSheet::button-event-row
998 * @sheet: the sheet widget that emitted the signal
999 * @column: the column on which the event occured.
1001 * A button event occured on a row title button
1003 sheet_signals[BUTTON_EVENT_ROW] =
1004 g_signal_new ("button-event-row",
1005 G_TYPE_FROM_CLASS (object_class),
1009 gtkextra_VOID__INT_POINTER,
1017 sheet_signals[SELECT_RANGE] =
1018 g_signal_new ("select-range",
1019 G_TYPE_FROM_CLASS (object_class),
1021 offsetof (GtkSheetClass, select_range),
1023 gtkextra_VOID__BOXED,
1026 GTK_TYPE_SHEET_RANGE);
1029 sheet_signals[RESIZE_RANGE] =
1030 g_signal_new ("resize-range",
1031 G_TYPE_FROM_CLASS (object_class),
1033 offsetof (GtkSheetClass, resize_range),
1035 gtkextra_VOID__BOXED_BOXED,
1038 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1041 sheet_signals[MOVE_RANGE] =
1042 g_signal_new ("move-range",
1043 G_TYPE_FROM_CLASS (object_class),
1045 offsetof (GtkSheetClass, move_range),
1047 gtkextra_VOID__BOXED_BOXED,
1050 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1053 sheet_signals[TRAVERSE] =
1054 g_signal_new ("traverse",
1055 G_TYPE_FROM_CLASS (object_class),
1057 offsetof (GtkSheetClass, traverse),
1059 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
1060 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT,
1061 G_TYPE_POINTER, G_TYPE_POINTER);
1064 sheet_signals[DEACTIVATE] =
1065 g_signal_new ("deactivate",
1066 G_TYPE_FROM_CLASS (object_class),
1068 offsetof (GtkSheetClass, deactivate),
1070 gtkextra_BOOLEAN__INT_INT,
1071 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1073 sheet_signals[ACTIVATE] =
1074 g_signal_new ("activate",
1075 G_TYPE_FROM_CLASS (object_class),
1077 offsetof (GtkSheetClass, activate),
1079 gtkextra_BOOLEAN__INT_INT,
1080 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1082 sheet_signals[SET_CELL] =
1083 g_signal_new ("set-cell",
1084 G_TYPE_FROM_CLASS (object_class),
1086 offsetof (GtkSheetClass, set_cell),
1088 gtkextra_VOID__INT_INT,
1089 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1092 sheet_signals[CLEAR_CELL] =
1093 g_signal_new ("clear-cell",
1094 G_TYPE_FROM_CLASS (object_class),
1096 offsetof (GtkSheetClass, clear_cell),
1098 gtkextra_VOID__INT_INT,
1099 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1101 sheet_signals[CHANGED] =
1102 g_signal_new ("changed",
1103 G_TYPE_FROM_CLASS (object_class),
1105 offsetof (GtkSheetClass, changed),
1107 gtkextra_VOID__INT_INT,
1108 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1110 sheet_signals[NEW_COL_WIDTH] =
1111 g_signal_new ("new-column-width",
1112 G_TYPE_FROM_CLASS (object_class),
1114 offsetof (GtkSheetClass, new_column_width), /*!!!! */
1116 gtkextra_VOID__INT_INT,
1117 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1119 sheet_signals[NEW_ROW_HEIGHT] =
1120 g_signal_new ("new-row-height",
1121 G_TYPE_FROM_CLASS (object_class),
1123 offsetof (GtkSheetClass, new_row_height), /*!!!! */
1125 gtkextra_VOID__INT_INT,
1126 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1128 widget_class->set_scroll_adjustments_signal =
1129 g_signal_new ("set-scroll-adjustments",
1130 G_TYPE_FROM_CLASS (object_class),
1132 offsetof (GtkSheetClass, set_scroll_adjustments),
1134 gtkextra_VOID__OBJECT_OBJECT,
1135 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1138 container_class->add = NULL;
1139 container_class->remove = gtk_sheet_remove;
1140 container_class->forall = gtk_sheet_forall;
1142 object_class->destroy = gtk_sheet_destroy;
1143 gobject_class->finalize = gtk_sheet_finalize;
1145 widget_class->realize = gtk_sheet_realize;
1146 widget_class->unrealize = gtk_sheet_unrealize;
1147 widget_class->map = gtk_sheet_map;
1148 widget_class->unmap = gtk_sheet_unmap;
1149 widget_class->style_set = gtk_sheet_style_set;
1150 widget_class->button_press_event = gtk_sheet_button_press;
1151 widget_class->button_release_event = gtk_sheet_button_release;
1152 widget_class->motion_notify_event = gtk_sheet_motion;
1153 widget_class->key_press_event = gtk_sheet_key_press;
1154 widget_class->expose_event = gtk_sheet_expose;
1155 widget_class->size_request = gtk_sheet_size_request;
1156 widget_class->size_allocate = gtk_sheet_size_allocate;
1157 widget_class->focus_in_event = NULL;
1158 widget_class->focus_out_event = NULL;
1160 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1161 klass->select_row = NULL;
1162 klass->select_column = NULL;
1163 klass->select_range = NULL;
1164 klass->resize_range = NULL;
1165 klass->move_range = NULL;
1166 klass->traverse = NULL;
1167 klass->deactivate = NULL;
1168 klass->activate = NULL;
1169 klass->set_cell = NULL;
1170 klass->clear_cell = NULL;
1171 klass->changed = NULL;
1175 gtk_sheet_init (GtkSheet *sheet)
1177 sheet->column_geometry = NULL;
1178 sheet->row_geometry = NULL;
1180 sheet->children = NULL;
1183 sheet->selection_mode = GTK_SELECTION_NONE;
1184 sheet->freeze_count = 0;
1185 sheet->state = GTK_SHEET_NORMAL;
1187 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1188 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1190 sheet->column_title_window = NULL;
1191 sheet->column_title_area.x = 0;
1192 sheet->column_title_area.y = 0;
1193 sheet->column_title_area.width = 0;
1194 sheet->column_title_area.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
1196 sheet->row_title_window = NULL;
1197 sheet->row_title_area.x = 0;
1198 sheet->row_title_area.y = 0;
1199 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1200 sheet->row_title_area.height = 0;
1203 sheet->active_cell.row = 0;
1204 sheet->active_cell.col = 0;
1205 sheet->selection_cell.row = 0;
1206 sheet->selection_cell.col = 0;
1208 sheet->sheet_entry = NULL;
1209 sheet->pixmap = NULL;
1211 sheet->range.row0 = 0;
1212 sheet->range.rowi = 0;
1213 sheet->range.col0 = 0;
1214 sheet->range.coli = 0;
1216 sheet->state = GTK_SHEET_NORMAL;
1218 sheet->sheet_window = NULL;
1219 sheet->sheet_window_width = 0;
1220 sheet->sheet_window_height = 0;
1221 sheet->sheet_entry = NULL;
1222 sheet->button = NULL;
1227 sheet->hadjustment = NULL;
1228 sheet->vadjustment = NULL;
1230 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
1231 sheet->xor_gc = NULL;
1232 sheet->fg_gc = NULL;
1233 sheet->bg_gc = NULL;
1237 gdk_color_parse ("white", &sheet->bg_color);
1238 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1239 gdk_color_parse ("gray", &sheet->grid_color);
1240 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1241 sheet->show_grid = TRUE;
1243 sheet->motion_timer = 0;
1247 /* Callback which occurs whenever columns are inserted / deleted in the model */
1249 columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
1254 GtkSheet *sheet = GTK_SHEET (data);
1256 GtkSheetRange range;
1257 gint model_columns = g_sheet_model_get_column_count (model);
1260 /* Need to update all the columns starting from the first column and onwards.
1261 * Previous column are unchanged, so don't need to be updated.
1263 range.col0 = first_column;
1265 range.coli = xxx_column_count (sheet) - 1;
1266 range.rowi = yyy_row_count (sheet) - 1;
1268 adjust_scrollbars (sheet);
1270 if (sheet->active_cell.col >= model_columns)
1271 gtk_sheet_activate_cell (sheet, sheet->active_cell.row, model_columns - 1);
1273 for (i = first_column; i <= MAX_VISIBLE_COLUMN (sheet); i++)
1274 gtk_sheet_column_title_button_draw (sheet, i);
1276 gtk_sheet_range_draw (sheet, &range);
1280 /* Callback which occurs whenever rows are inserted / deleted in the model */
1282 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
1283 gint n_rows, gpointer data)
1286 GtkSheet *sheet = GTK_SHEET (data);
1288 GtkSheetRange range;
1290 gint model_rows = g_sheet_model_get_row_count (model);
1292 /* Need to update all the rows starting from the first row and onwards.
1293 * Previous rows are unchanged, so don't need to be updated.
1295 range.row0 = first_row;
1297 range.rowi = yyy_row_count (sheet) - 1;
1298 range.coli = xxx_column_count (sheet) - 1;
1300 adjust_scrollbars (sheet);
1302 if (sheet->active_cell.row >= model_rows)
1303 gtk_sheet_activate_cell (sheet, model_rows - 1, sheet->active_cell.col);
1305 for (i = first_row; i <= MAX_VISIBLE_ROW (sheet); i++)
1306 gtk_sheet_row_title_button_draw (sheet, i);
1308 gtk_sheet_range_draw (sheet, &range);
1312 If row0 or rowi are negative, then all rows will be updated.
1313 If col0 or coli are negative, then all columns will be updated.
1316 range_update_callback (GSheetModel *m, gint row0, gint col0,
1317 gint rowi, gint coli, gpointer data)
1319 GtkSheet *sheet = GTK_SHEET (data);
1321 GtkSheetRange range;
1328 if ( MAX_VISIBLE_ROW (sheet) >
1329 g_sheet_model_get_row_count (sheet->model)
1331 MAX_VISIBLE_COLUMN (sheet) >
1332 g_sheet_model_get_column_count (sheet->model))
1334 gtk_sheet_move_query (sheet, 0, 0);
1337 if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1340 gtk_sheet_range_draw (sheet, NULL);
1341 adjust_scrollbars (sheet);
1343 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
1344 gtk_sheet_row_title_button_draw (sheet, i);
1346 for (i = MIN_VISIBLE_COLUMN (sheet);
1347 i <= MAX_VISIBLE_COLUMN (sheet); i++)
1348 gtk_sheet_column_title_button_draw (sheet, i);
1352 else if ( row0 < 0 || rowi < 0 )
1354 range.row0 = MIN_VISIBLE_ROW (sheet);
1355 range.rowi = MAX_VISIBLE_ROW (sheet);
1357 else if ( col0 < 0 || coli < 0 )
1359 range.col0 = MIN_VISIBLE_COLUMN (sheet);
1360 range.coli = MAX_VISIBLE_COLUMN (sheet);
1363 gtk_sheet_range_draw (sheet, &range);
1367 static void gtk_sheet_construct (GtkSheet *sheet,
1370 const gchar *title);
1375 * @rows: initial number of rows
1376 * @columns: initial number of columns
1377 * @title: sheet title
1378 * @model: the model to use for the sheet data
1380 * Creates a new sheet widget with the given number of rows and columns.
1382 * Returns: the new sheet widget
1385 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1388 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1390 gtk_sheet_construct (GTK_SHEET (widget), vgeo, hgeo, title);
1393 gtk_sheet_set_model (GTK_SHEET (widget), model);
1401 * gtk_sheet_set_model
1402 * @sheet: the sheet to set the model for
1403 * @model: the model to use for the sheet data
1405 * Sets the model for a GtkSheet
1409 gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
1411 g_return_if_fail (GTK_IS_SHEET (sheet));
1412 g_return_if_fail (G_IS_SHEET_MODEL (model));
1414 sheet->model = model;
1416 g_signal_connect (model, "range_changed",
1417 G_CALLBACK (range_update_callback), sheet);
1419 g_signal_connect (model, "rows_inserted",
1420 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1422 g_signal_connect (model, "rows_deleted",
1423 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1425 g_signal_connect (model, "columns_inserted",
1426 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1428 g_signal_connect (model, "columns_deleted",
1429 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1434 /* Call back for when the column titles have changed.
1435 FIRST is the first column changed.
1436 N_COLUMNS is the number of columns which have changed, or - 1, which
1437 indicates that the column has changed to its right - most extremity
1440 column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
1442 GtkSheet *sheet = GTK_SHEET (data);
1443 gboolean extremity = FALSE;
1445 if ( n_columns == -1 )
1448 n_columns = xxx_column_count (sheet) - 1 ;
1451 if (!GTK_SHEET_IS_FROZEN (sheet))
1454 for ( i = first ; i <= first + n_columns ; ++i )
1456 gtk_sheet_column_title_button_draw (sheet, i);
1457 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, i);
1462 gtk_sheet_column_title_button_draw (sheet, -1);
1467 gtk_sheet_construct (GtkSheet *sheet,
1472 g_return_if_fail (G_IS_SHEET_COLUMN (hgeo));
1473 g_return_if_fail (G_IS_SHEET_ROW (vgeo));
1475 sheet->column_geometry = hgeo;
1476 sheet->row_geometry = vgeo;
1479 sheet->columns_resizable = TRUE;
1480 sheet->rows_resizable = TRUE;
1482 sheet->row_titles_visible = TRUE;
1483 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1485 sheet->column_titles_visible = TRUE;
1486 sheet->autoscroll = TRUE;
1487 sheet->justify_entry = TRUE;
1490 /* create sheet entry */
1491 sheet->entry_type = 0;
1492 create_sheet_entry (sheet);
1494 /* create global selection button */
1495 create_global_button (sheet);
1498 sheet->name = g_strdup (title);
1500 g_signal_connect (sheet->column_geometry, "columns_changed",
1501 G_CALLBACK (column_titles_changed), sheet);
1507 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns,
1508 const gchar *title, GtkType entry_type)
1510 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1512 gtk_sheet_construct_with_custom_entry (GTK_SHEET (widget),
1513 rows, columns, title, entry_type);
1519 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1525 gtk_sheet_construct (sheet, vgeo, hgeo, title);
1527 sheet->entry_type = entry_type;
1528 create_sheet_entry (sheet);
1534 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
1538 g_return_if_fail (sheet != NULL);
1539 g_return_if_fail (GTK_IS_SHEET (sheet));
1541 state = sheet->state;
1543 if (sheet->state == GTK_SHEET_NORMAL)
1544 gtk_sheet_hide_active_cell (sheet);
1546 sheet->entry_type = entry_type;
1548 create_sheet_entry (sheet);
1550 if (state == GTK_SHEET_NORMAL)
1552 gtk_sheet_show_active_cell (sheet);
1553 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
1555 G_CALLBACK (gtk_sheet_entry_changed),
1561 gtk_sheet_show_grid (GtkSheet *sheet, gboolean show)
1563 g_return_if_fail (sheet != NULL);
1564 g_return_if_fail (GTK_IS_SHEET (sheet));
1566 if (show == sheet->show_grid) return;
1568 sheet->show_grid = show;
1570 if (!GTK_SHEET_IS_FROZEN (sheet))
1571 gtk_sheet_range_draw (sheet, NULL);
1575 gtk_sheet_grid_visible (GtkSheet *sheet)
1577 g_return_val_if_fail (sheet != NULL, 0);
1578 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1580 return sheet->show_grid;
1584 gtk_sheet_set_background (GtkSheet *sheet, GdkColor *color)
1586 g_return_if_fail (sheet != NULL);
1587 g_return_if_fail (GTK_IS_SHEET (sheet));
1591 gdk_color_parse ("white", &sheet->bg_color);
1592 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1595 sheet->bg_color = *color;
1597 if (!GTK_SHEET_IS_FROZEN (sheet))
1598 gtk_sheet_range_draw (sheet, NULL);
1602 gtk_sheet_set_grid (GtkSheet *sheet, GdkColor *color)
1604 g_return_if_fail (sheet != NULL);
1605 g_return_if_fail (GTK_IS_SHEET (sheet));
1609 gdk_color_parse ("black", &sheet->grid_color);
1610 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1613 sheet->grid_color = *color;
1615 if (!GTK_SHEET_IS_FROZEN (sheet))
1616 gtk_sheet_range_draw (sheet, NULL);
1620 gtk_sheet_get_columns_count (GtkSheet *sheet)
1622 g_return_val_if_fail (sheet != NULL, 0);
1623 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1625 return xxx_column_count (sheet);
1629 gtk_sheet_get_rows_count (GtkSheet *sheet)
1631 g_return_val_if_fail (sheet != NULL, 0);
1632 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1634 return yyy_row_count (sheet);
1638 gtk_sheet_get_state (GtkSheet *sheet)
1640 g_return_val_if_fail (sheet != NULL, 0);
1641 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1643 return (sheet->state);
1647 gtk_sheet_set_selection_mode (GtkSheet *sheet, gint mode)
1649 g_return_if_fail (sheet != NULL);
1650 g_return_if_fail (GTK_IS_SHEET (sheet));
1652 if (GTK_WIDGET_REALIZED (sheet))
1653 gtk_sheet_real_unselect_range (sheet, NULL);
1655 sheet->selection_mode = mode;
1659 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1661 g_return_if_fail (sheet != NULL);
1662 g_return_if_fail (GTK_IS_SHEET (sheet));
1664 sheet->autoresize = autoresize;
1668 gtk_sheet_autoresize (GtkSheet *sheet)
1670 g_return_val_if_fail (sheet != NULL, FALSE);
1671 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1673 return sheet->autoresize;
1677 gtk_sheet_set_column_width (GtkSheet * sheet,
1683 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1685 gint text_width = 0;
1688 g_return_if_fail (sheet != NULL);
1689 g_return_if_fail (GTK_IS_SHEET (sheet));
1690 if (column >= xxx_column_count (sheet) || column < 0) return;
1692 for (row = 0; row < yyy_row_count (sheet); row++)
1694 gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
1695 if (text && strlen (text) > 0)
1697 GtkSheetCellAttr attributes;
1699 gtk_sheet_get_attributes (sheet, row, column, &attributes);
1700 if (attributes.is_visible)
1702 gint width = STRING_WIDTH (GTK_WIDGET (sheet),
1703 attributes.font_desc,
1705 + 2 * CELLOFFSET + attributes.border.width;
1706 text_width = MAX (text_width, width);
1709 dispose_string (sheet, text);
1712 if (text_width > xxx_column_width (sheet, column) )
1714 gtk_sheet_set_column_width (sheet, column, text_width);
1715 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
1721 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1723 g_return_if_fail (sheet != NULL);
1724 g_return_if_fail (GTK_IS_SHEET (sheet));
1726 sheet->autoscroll = autoscroll;
1730 gtk_sheet_autoscroll (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->autoscroll;
1740 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1742 g_return_if_fail (sheet != NULL);
1743 g_return_if_fail (GTK_IS_SHEET (sheet));
1745 sheet->justify_entry = justify;
1749 gtk_sheet_justify_entry (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->justify_entry;
1758 /* This routine has problems with gtk+- 1.2 related with the
1759 label / button drawing - I think it's a bug in gtk+- 1.2 */
1761 gtk_sheet_set_title (GtkSheet *sheet, const gchar *title)
1765 g_return_if_fail (sheet != NULL);
1766 g_return_if_fail (title != NULL);
1767 g_return_if_fail (GTK_IS_SHEET (sheet));
1770 g_free (sheet->name);
1772 sheet->name = g_strdup (title);
1774 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) || !title) return;
1776 if (GTK_BIN (sheet->button)->child)
1777 label = GTK_BIN (sheet->button)->child;
1779 size_allocate_global_button (sheet);
1783 gtk_sheet_freeze (GtkSheet *sheet)
1785 g_return_if_fail (sheet != NULL);
1786 g_return_if_fail (GTK_IS_SHEET (sheet));
1788 sheet->freeze_count++;
1789 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1793 gtk_sheet_thaw (GtkSheet *sheet)
1795 g_return_if_fail (sheet != NULL);
1796 g_return_if_fail (GTK_IS_SHEET (sheet));
1798 if (sheet->freeze_count == 0) return;
1800 sheet->freeze_count--;
1801 if (sheet->freeze_count > 0) return;
1803 adjust_scrollbars (sheet);
1805 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1807 sheet->old_vadjustment = -1.;
1808 sheet->old_hadjustment = -1.;
1810 if (sheet->hadjustment)
1811 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1813 if (sheet->vadjustment)
1814 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1817 if (sheet->state == GTK_STATE_NORMAL)
1818 if (sheet->sheet_entry && GTK_WIDGET_MAPPED (sheet->sheet_entry))
1820 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
1821 sheet->active_cell.col);
1827 gtk_sheet_set_row_titles_width (GtkSheet *sheet, guint width)
1829 if (width < COLUMN_MIN_WIDTH) return;
1831 sheet->row_title_area.width = width;
1833 adjust_scrollbars (sheet);
1835 sheet->old_hadjustment = -1.;
1836 if (sheet->hadjustment)
1837 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1839 size_allocate_global_button (sheet);
1843 gtk_sheet_set_column_titles_height (GtkSheet *sheet, guint height)
1845 if (height < DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))) return;
1847 sheet->column_title_area.height = height;
1849 adjust_scrollbars (sheet);
1851 sheet->old_vadjustment = -1.;
1852 if (sheet->vadjustment)
1853 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1855 size_allocate_global_button (sheet);
1859 gtk_sheet_show_column_titles (GtkSheet *sheet)
1863 if (sheet->column_titles_visible) return;
1865 sheet->column_titles_visible = TRUE;
1868 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1870 gdk_window_show (sheet->column_title_window);
1871 gdk_window_move_resize (sheet->column_title_window,
1872 sheet->column_title_area.x,
1873 sheet->column_title_area.y,
1874 sheet->column_title_area.width,
1875 sheet->column_title_area.height);
1877 for (col = MIN_VISIBLE_COLUMN (sheet);
1878 col <= MAX_VISIBLE_COLUMN (sheet);
1881 GtkSheetButton *button = xxx_column_button (sheet, col);
1882 GtkSheetChild *child = button->child;
1884 gtk_sheet_child_show (child);
1885 gtk_sheet_button_free (button);
1887 adjust_scrollbars (sheet);
1890 sheet->old_vadjustment = -1.;
1891 if (sheet->vadjustment)
1892 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1894 size_allocate_global_button (sheet);
1899 gtk_sheet_show_row_titles (GtkSheet *sheet)
1903 if (sheet->row_titles_visible) return;
1905 sheet->row_titles_visible = TRUE;
1908 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1910 gdk_window_show (sheet->row_title_window);
1911 gdk_window_move_resize (sheet->row_title_window,
1912 sheet->row_title_area.x,
1913 sheet->row_title_area.y,
1914 sheet->row_title_area.width,
1915 sheet->row_title_area.height);
1917 for (row = MIN_VISIBLE_ROW (sheet);
1918 row <= MAX_VISIBLE_ROW (sheet);
1921 const GtkSheetButton *button = yyy_row_button (sheet, row);
1922 GtkSheetChild *child = button->child;
1926 gtk_sheet_child_show (child);
1929 adjust_scrollbars (sheet);
1932 sheet->old_hadjustment = -1.;
1933 if (sheet->hadjustment)
1934 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1936 size_allocate_global_button (sheet);
1940 gtk_sheet_hide_column_titles (GtkSheet *sheet)
1944 if (!sheet->column_titles_visible) return;
1946 sheet->column_titles_visible = FALSE;
1948 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1950 if (sheet->column_title_window)
1951 gdk_window_hide (sheet->column_title_window);
1952 if (GTK_WIDGET_VISIBLE (sheet->button))
1953 gtk_widget_hide (sheet->button);
1955 for (col = MIN_VISIBLE_COLUMN (sheet);
1956 col <= MAX_VISIBLE_COLUMN (sheet);
1959 GtkSheetButton *button = xxx_column_button (sheet, col);
1960 GtkSheetChild *child = button->child;
1962 gtk_sheet_child_hide (child);
1963 gtk_sheet_button_free (button);
1965 adjust_scrollbars (sheet);
1968 sheet->old_vadjustment = -1.;
1969 if (sheet->vadjustment)
1970 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1975 gtk_sheet_hide_row_titles (GtkSheet *sheet)
1979 if (!sheet->row_titles_visible) return;
1981 sheet->row_titles_visible = FALSE;
1984 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1986 if (sheet->row_title_window)
1987 gdk_window_hide (sheet->row_title_window);
1988 if (GTK_WIDGET_VISIBLE (sheet->button))
1989 gtk_widget_hide (sheet->button);
1990 for (row = MIN_VISIBLE_ROW (sheet);
1991 row <= MAX_VISIBLE_ROW (sheet);
1994 const GtkSheetButton *button = yyy_row_button (sheet, row);
1995 GtkSheetChild *child = button->child;
1998 gtk_sheet_child_hide (child);
2000 adjust_scrollbars (sheet);
2003 sheet->old_hadjustment = -1.;
2004 if (sheet->hadjustment)
2005 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2010 gtk_sheet_column_titles_visible (GtkSheet *sheet)
2012 g_return_val_if_fail (sheet != NULL, FALSE);
2013 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2014 return sheet->column_titles_visible;
2018 gtk_sheet_row_titles_visible (GtkSheet *sheet)
2020 g_return_val_if_fail (sheet != NULL, FALSE);
2021 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2022 return sheet->row_titles_visible;
2026 gtk_sheet_moveto (GtkSheet *sheet,
2033 guint width, height;
2035 gint min_row, min_col;
2037 g_return_if_fail (sheet != NULL);
2038 g_return_if_fail (GTK_IS_SHEET (sheet));
2039 g_return_if_fail (sheet->hadjustment != NULL);
2040 g_return_if_fail (sheet->vadjustment != NULL);
2042 if (row < 0 || row >= yyy_row_count (sheet))
2044 if (column < 0 || column >= xxx_column_count (sheet))
2047 height = sheet->sheet_window_height;
2048 width = sheet->sheet_window_width;
2050 /* adjust vertical scrollbar */
2051 if (row >= 0 && row_align >= 0.0)
2053 y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
2054 - (gint) ( row_align * height + (1.0 - row_align)
2055 * yyy_row_height (sheet, row));
2057 /* This forces the sheet to scroll when you don't see the entire cell */
2060 if (row_align >= 1.0)
2062 while (min_row >= 0 && min_row > MIN_VISIBLE_ROW (sheet))
2064 if (yyy_row_is_visible (sheet, min_row))
2065 adjust += yyy_row_height (sheet, min_row);
2067 if (adjust >= height)
2073 min_row = MAX (min_row, 0);
2077 y = ROW_TOP_YPIXEL (sheet, min_row) - sheet->voffset +
2078 yyy_row_height (sheet, min_row) - 1;
2082 sheet->vadjustment->value = 0.0;
2084 sheet->vadjustment->value = y;
2086 sheet->old_vadjustment = -1.;
2087 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2092 /* adjust horizontal scrollbar */
2093 if (column >= 0 && col_align >= 0.0)
2095 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2096 - (gint) ( col_align*width + (1.0 - col_align)*
2097 xxx_column_width (sheet, column));
2099 /* This forces the sheet to scroll when you don't see the entire cell */
2102 if (col_align == 1.0)
2104 while (min_col >= 0 && min_col > MIN_VISIBLE_COLUMN (sheet))
2106 if (xxx_column_is_visible (sheet, min_col))
2107 adjust += xxx_column_width (sheet, min_col);
2109 if (adjust >= width)
2115 min_col = MAX (min_col, 0);
2116 x = COLUMN_LEFT_XPIXEL (sheet, min_col) - sheet->hoffset +
2117 xxx_column_width (sheet, min_col) - 1;
2121 sheet->hadjustment->value = 0.0;
2123 sheet->hadjustment->value = x;
2125 sheet->old_vadjustment = -1.;
2126 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2133 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2135 g_return_if_fail (sheet != NULL);
2136 g_return_if_fail (GTK_IS_SHEET (sheet));
2138 sheet->columns_resizable = resizable;
2142 gtk_sheet_columns_resizable (GtkSheet *sheet)
2144 g_return_val_if_fail (sheet != NULL, FALSE);
2145 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2147 return sheet->columns_resizable;
2152 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2154 g_return_if_fail (sheet != NULL);
2155 g_return_if_fail (GTK_IS_SHEET (sheet));
2157 sheet->rows_resizable = resizable;
2161 gtk_sheet_rows_resizable (GtkSheet *sheet)
2163 g_return_val_if_fail (sheet != NULL, FALSE);
2164 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2166 return sheet->rows_resizable;
2171 gtk_sheet_select_row (GtkSheet * sheet,
2174 g_return_if_fail (sheet != NULL);
2175 g_return_if_fail (GTK_IS_SHEET (sheet));
2177 if (row < 0 || row >= yyy_row_count (sheet))
2180 if (sheet->state != GTK_SHEET_NORMAL)
2181 gtk_sheet_real_unselect_range (sheet, NULL);
2184 gboolean veto = TRUE;
2185 veto = gtk_sheet_deactivate_cell (sheet);
2189 sheet->state = GTK_SHEET_ROW_SELECTED;
2190 sheet->range.row0 = row;
2191 sheet->range.col0 = 0;
2192 sheet->range.rowi = row;
2193 sheet->range.coli = xxx_column_count (sheet) - 1;
2194 sheet->active_cell.row = row;
2195 sheet->active_cell.col = 0;
2197 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, row);
2198 gtk_sheet_real_select_range (sheet, NULL);
2203 gtk_sheet_select_column (GtkSheet * sheet, gint column)
2205 g_return_if_fail (sheet != NULL);
2206 g_return_if_fail (GTK_IS_SHEET (sheet));
2208 if (column < 0 || column >= xxx_column_count (sheet))
2211 if (sheet->state != GTK_SHEET_NORMAL)
2212 gtk_sheet_real_unselect_range (sheet, NULL);
2215 gboolean veto = TRUE;
2216 veto = gtk_sheet_deactivate_cell (sheet);
2220 sheet->state = GTK_SHEET_COLUMN_SELECTED;
2221 sheet->range.row0 = 0;
2222 sheet->range.col0 = column;
2223 sheet->range.rowi = yyy_row_count (sheet) - 1;
2224 sheet->range.coli = column;
2225 sheet->active_cell.row = 0;
2226 sheet->active_cell.col = column;
2228 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, column);
2229 gtk_sheet_real_select_range (sheet, NULL);
2236 gtk_sheet_range_isvisible (const GtkSheet * sheet,
2237 GtkSheetRange range)
2239 g_return_val_if_fail (sheet != NULL, FALSE);
2241 if (range.row0 < 0 || range.row0 >= yyy_row_count (sheet))
2244 if (range.rowi < 0 || range.rowi >= yyy_row_count (sheet))
2247 if (range.col0 < 0 || range.col0 >= xxx_column_count (sheet))
2250 if (range.coli < 0 || range.coli >= xxx_column_count (sheet))
2253 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2256 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2259 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2262 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2269 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2270 gint row, gint column)
2272 GtkSheetRange range;
2275 range.col0 = column;
2277 range.coli = column;
2279 return gtk_sheet_range_isvisible (sheet, range);
2283 gtk_sheet_get_visible_range (GtkSheet *sheet, GtkSheetRange *range)
2285 g_return_if_fail (sheet != NULL);
2286 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2287 g_return_if_fail (range != NULL);
2289 range->row0 = MIN_VISIBLE_ROW (sheet);
2290 range->col0 = MIN_VISIBLE_COLUMN (sheet);
2291 range->rowi = MAX_VISIBLE_ROW (sheet);
2292 range->coli = MAX_VISIBLE_COLUMN (sheet);
2296 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2298 g_return_val_if_fail (sheet != NULL, NULL);
2299 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2301 return sheet->vadjustment;
2305 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2307 g_return_val_if_fail (sheet != NULL, NULL);
2308 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2310 return sheet->hadjustment;
2314 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2315 GtkAdjustment *adjustment)
2317 GtkAdjustment *old_adjustment;
2319 g_return_if_fail (sheet != NULL);
2320 g_return_if_fail (GTK_IS_SHEET (sheet));
2322 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2324 if (sheet->vadjustment == adjustment)
2327 old_adjustment = sheet->vadjustment;
2329 if (sheet->vadjustment)
2331 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2332 G_SIGNAL_MATCH_DATA,
2335 g_object_unref (G_OBJECT (sheet->vadjustment));
2338 sheet->vadjustment = adjustment;
2340 if (sheet->vadjustment)
2342 g_object_ref (G_OBJECT (sheet->vadjustment));
2343 g_object_ref_sink (G_OBJECT (sheet->vadjustment));
2345 g_signal_connect (G_OBJECT (sheet->vadjustment), "value_changed",
2346 G_CALLBACK (vadjustment_value_changed),
2350 if (!sheet->vadjustment || !old_adjustment)
2352 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2356 sheet->old_vadjustment = sheet->vadjustment->value;
2360 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2361 GtkAdjustment *adjustment)
2363 GtkAdjustment *old_adjustment;
2365 g_return_if_fail (sheet != NULL);
2366 g_return_if_fail (GTK_IS_SHEET (sheet));
2368 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2370 if (sheet->hadjustment == adjustment)
2373 old_adjustment = sheet->hadjustment;
2375 if (sheet->hadjustment)
2377 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2378 G_SIGNAL_MATCH_DATA,
2381 g_object_unref (G_OBJECT (sheet->hadjustment));
2384 sheet->hadjustment = adjustment;
2386 if (sheet->hadjustment)
2388 g_object_ref (G_OBJECT (sheet->hadjustment));
2389 g_object_ref_sink (G_OBJECT (sheet->hadjustment));
2391 g_signal_connect (G_OBJECT (sheet->hadjustment), "value_changed",
2392 G_CALLBACK (hadjustment_value_changed),
2396 if (!sheet->hadjustment || !old_adjustment)
2398 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2402 sheet->old_hadjustment = sheet->hadjustment->value;
2406 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2407 GtkAdjustment *hadjustment,
2408 GtkAdjustment *vadjustment)
2410 if (sheet->hadjustment != hadjustment)
2411 gtk_sheet_set_hadjustment (sheet, hadjustment);
2413 if (sheet->vadjustment != vadjustment)
2414 gtk_sheet_set_vadjustment (sheet, vadjustment);
2418 gtk_sheet_finalize (GObject * object)
2422 g_return_if_fail (object != NULL);
2423 g_return_if_fail (GTK_IS_SHEET (object));
2425 sheet = GTK_SHEET (object);
2429 g_free (sheet->name);
2433 if (G_OBJECT_CLASS (parent_class)->finalize)
2434 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2438 gtk_sheet_destroy (GtkObject * object)
2443 g_return_if_fail (object != NULL);
2444 g_return_if_fail (GTK_IS_SHEET (object));
2446 sheet = GTK_SHEET (object);
2448 /* destroy the entry */
2449 if (sheet->sheet_entry && GTK_IS_WIDGET (sheet->sheet_entry))
2451 gtk_widget_destroy (sheet->sheet_entry);
2452 sheet->sheet_entry = NULL;
2455 /* destroy the global selection button */
2456 if (sheet->button && GTK_IS_WIDGET (sheet->button))
2458 gtk_widget_destroy (sheet->button);
2459 sheet->button = NULL;
2462 /* unref adjustments */
2463 if (sheet->hadjustment)
2465 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2466 G_SIGNAL_MATCH_DATA,
2470 g_object_unref (G_OBJECT (sheet->hadjustment));
2471 sheet->hadjustment = NULL;
2474 if (sheet->vadjustment)
2476 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2477 G_SIGNAL_MATCH_DATA,
2481 g_object_unref (G_OBJECT (sheet->vadjustment));
2483 sheet->vadjustment = NULL;
2486 children = sheet->children;
2489 GtkSheetChild *child = (GtkSheetChild *)children->data;
2490 if (child && child->widget)
2491 gtk_sheet_remove (GTK_CONTAINER (sheet), child->widget);
2492 children = sheet->children;
2494 sheet->children = NULL;
2496 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2497 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2501 gtk_sheet_style_set (GtkWidget *widget,
2502 GtkStyle *previous_style)
2506 g_return_if_fail (widget != NULL);
2507 g_return_if_fail (GTK_IS_SHEET (widget));
2509 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2510 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2512 sheet = GTK_SHEET (widget);
2514 if (GTK_WIDGET_REALIZED (widget))
2516 gtk_style_set_background (widget->style, widget->window, widget->state);
2522 gtk_sheet_realize (GtkWidget * widget)
2525 GdkWindowAttr attributes;
2526 gint attributes_mask;
2527 GdkGCValues values, auxvalues;
2528 GdkColormap *colormap;
2530 GtkSheetChild *child;
2533 g_return_if_fail (widget != NULL);
2534 g_return_if_fail (GTK_IS_SHEET (widget));
2536 sheet = GTK_SHEET (widget);
2538 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2540 attributes.window_type = GDK_WINDOW_CHILD;
2541 attributes.x = widget->allocation.x;
2542 attributes.y = widget->allocation.y;
2543 attributes.width = widget->allocation.width;
2544 attributes.height = widget->allocation.height;
2545 attributes.wclass = GDK_INPUT_OUTPUT;
2547 attributes.visual = gtk_widget_get_visual (widget);
2548 attributes.colormap = gtk_widget_get_colormap (widget);
2550 attributes.event_mask = gtk_widget_get_events (widget);
2551 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2552 GDK_BUTTON_PRESS_MASK |
2553 GDK_BUTTON_RELEASE_MASK |
2554 GDK_KEY_PRESS_MASK |
2555 GDK_POINTER_MOTION_MASK |
2556 GDK_POINTER_MOTION_HINT_MASK);
2557 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2560 attributes.cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2563 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2565 gdk_window_set_user_data (widget->window, sheet);
2567 widget->style = gtk_style_attach (widget->style, widget->window);
2569 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2572 if (sheet->row_titles_visible)
2573 attributes.x = sheet->row_title_area.width;
2575 attributes.width = sheet->column_title_area.width;
2576 attributes.height = sheet->column_title_area.height;
2578 /* column - title window */
2579 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2580 gdk_window_set_user_data (sheet->column_title_window, sheet);
2581 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2585 if (sheet->column_titles_visible)
2586 attributes.y = sheet->column_title_area.height;
2587 attributes.width = sheet->row_title_area.width;
2588 attributes.height = sheet->row_title_area.height;
2590 /* row - title window */
2591 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2592 gdk_window_set_user_data (sheet->row_title_window, sheet);
2593 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2595 /* sheet - window */
2596 attributes.cursor = gdk_cursor_new (GDK_PLUS);
2600 attributes.width = sheet->sheet_window_width,
2601 attributes.height = sheet->sheet_window_height;
2603 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2604 gdk_window_set_user_data (sheet->sheet_window, sheet);
2606 gdk_cursor_unref (attributes.cursor);
2608 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2609 gdk_window_show (sheet->sheet_window);
2611 /* backing_pixmap */
2612 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
2616 gdk_gc_unref (sheet->fg_gc);
2618 gdk_gc_unref (sheet->bg_gc);
2619 sheet->fg_gc = gdk_gc_new (widget->window);
2620 sheet->bg_gc = gdk_gc_new (widget->window);
2622 colormap = gtk_widget_get_colormap (widget);
2624 gdk_color_white (colormap, &widget->style->white);
2625 gdk_color_black (colormap, &widget->style->black);
2627 gdk_gc_get_values (sheet->fg_gc, &auxvalues);
2629 values.foreground = widget->style->white;
2630 values.function = GDK_INVERT;
2631 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2633 gdk_gc_unref (sheet->xor_gc);
2634 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2640 if (sheet->sheet_entry->parent)
2642 gtk_widget_ref (sheet->sheet_entry);
2643 gtk_widget_unparent (sheet->sheet_entry);
2645 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2646 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
2648 if (sheet->button && sheet->button->parent)
2650 gtk_widget_ref (sheet->button);
2651 gtk_widget_unparent (sheet->button);
2653 gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
2654 gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
2656 if (!sheet->cursor_drag)
2657 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2659 if (sheet->column_titles_visible)
2660 gdk_window_show (sheet->column_title_window);
2661 if (sheet->row_titles_visible)
2662 gdk_window_show (sheet->row_title_window);
2664 size_allocate_row_title_buttons (sheet);
2665 size_allocate_column_title_buttons (sheet);
2667 name = g_strdup (sheet->name);
2668 gtk_sheet_set_title (sheet, name);
2672 children = sheet->children;
2675 child = children->data;
2676 children = children->next;
2678 gtk_sheet_realize_child (sheet, child);
2681 gtk_sheet_update_primary_selection (sheet);
2685 create_global_button (GtkSheet *sheet)
2687 sheet->button = gtk_button_new_with_label (" ");
2689 g_signal_connect (G_OBJECT (sheet->button),
2691 G_CALLBACK (global_button_clicked),
2696 size_allocate_global_button (GtkSheet *sheet)
2698 GtkAllocation allocation;
2700 if (!sheet->column_titles_visible) return;
2701 if (!sheet->row_titles_visible) return;
2703 gtk_widget_size_request (sheet->button, NULL);
2707 allocation.width = sheet->row_title_area.width;
2708 allocation.height = sheet->column_title_area.height;
2710 gtk_widget_size_allocate (sheet->button, &allocation);
2711 gtk_widget_show (sheet->button);
2715 global_button_clicked (GtkWidget *widget, gpointer data)
2719 gtk_sheet_click_cell (GTK_SHEET (data), - 1, - 1, &veto);
2720 gtk_widget_grab_focus (GTK_WIDGET (data));
2725 gtk_sheet_unrealize (GtkWidget * widget)
2729 g_return_if_fail (widget != NULL);
2730 g_return_if_fail (GTK_IS_SHEET (widget));
2732 sheet = GTK_SHEET (widget);
2734 gdk_cursor_destroy (sheet->cursor_drag);
2736 gdk_gc_destroy (sheet->xor_gc);
2737 gdk_gc_destroy (sheet->fg_gc);
2738 gdk_gc_destroy (sheet->bg_gc);
2740 gdk_window_destroy (sheet->sheet_window);
2741 gdk_window_destroy (sheet->column_title_window);
2742 gdk_window_destroy (sheet->row_title_window);
2746 g_object_unref (sheet->pixmap);
2747 sheet->pixmap = NULL;
2750 sheet->column_title_window = NULL;
2751 sheet->sheet_window = NULL;
2752 sheet->cursor_drag = NULL;
2753 sheet->xor_gc = NULL;
2754 sheet->fg_gc = NULL;
2755 sheet->bg_gc = NULL;
2757 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2758 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2762 gtk_sheet_map (GtkWidget * widget)
2765 GtkSheetChild *child;
2768 g_return_if_fail (widget != NULL);
2769 g_return_if_fail (GTK_IS_SHEET (widget));
2771 sheet = GTK_SHEET (widget);
2773 if (!GTK_WIDGET_MAPPED (widget))
2775 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2777 if (!sheet->cursor_drag) sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2779 gdk_window_show (widget->window);
2781 gdk_window_show (sheet->sheet_window);
2783 if (sheet->column_titles_visible)
2785 size_allocate_column_title_buttons (sheet);
2786 gdk_window_show (sheet->column_title_window);
2788 if (sheet->row_titles_visible)
2790 size_allocate_row_title_buttons (sheet);
2791 gdk_window_show (sheet->row_title_window);
2794 if (!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2795 && sheet->active_cell.row >= 0
2796 && sheet->active_cell.col >= 0 )
2798 gtk_widget_show (sheet->sheet_entry);
2799 gtk_widget_map (sheet->sheet_entry);
2802 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2803 !GTK_WIDGET_MAPPED (sheet->button))
2805 gtk_widget_show (sheet->button);
2806 gtk_widget_map (sheet->button);
2809 if (GTK_BIN (sheet->button)->child)
2810 if (GTK_WIDGET_VISIBLE (GTK_BIN (sheet->button)->child) &&
2811 !GTK_WIDGET_MAPPED (GTK_BIN (sheet->button)->child))
2812 gtk_widget_map (GTK_BIN (sheet->button)->child);
2814 gtk_sheet_range_draw (sheet, NULL);
2815 gtk_sheet_activate_cell (sheet,
2816 sheet->active_cell.row,
2817 sheet->active_cell.col);
2819 children = sheet->children;
2822 child = children->data;
2823 children = children->next;
2825 if (GTK_WIDGET_VISIBLE (child->widget) &&
2826 !GTK_WIDGET_MAPPED (child->widget))
2828 gtk_widget_map (child->widget);
2829 gtk_sheet_position_child (sheet, child);
2837 gtk_sheet_unmap (GtkWidget * widget)
2840 GtkSheetChild *child;
2843 g_return_if_fail (widget != NULL);
2844 g_return_if_fail (GTK_IS_SHEET (widget));
2846 sheet = GTK_SHEET (widget);
2848 if (GTK_WIDGET_MAPPED (widget))
2850 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2852 gdk_window_hide (sheet->sheet_window);
2853 if (sheet->column_titles_visible)
2854 gdk_window_hide (sheet->column_title_window);
2855 if (sheet->row_titles_visible)
2856 gdk_window_hide (sheet->row_title_window);
2857 gdk_window_hide (widget->window);
2859 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2860 gtk_widget_unmap (sheet->sheet_entry);
2862 if (GTK_WIDGET_MAPPED (sheet->button))
2863 gtk_widget_unmap (sheet->button);
2865 children = sheet->children;
2868 child = children->data;
2869 children = children->next;
2871 if (GTK_WIDGET_VISIBLE (child->widget) &&
2872 GTK_WIDGET_MAPPED (child->widget))
2874 gtk_widget_unmap (child->widget);
2883 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2886 GdkGC *fg_gc, *bg_gc;
2887 GtkSheetCellAttr attributes;
2890 g_return_if_fail (sheet != NULL);
2892 /* bail now if we arn't drawable yet */
2893 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2895 if (row < 0 || row >= yyy_row_count (sheet)) return;
2896 if (col < 0 || col >= xxx_column_count (sheet)) return;
2897 if (! xxx_column_is_visible (sheet, col)) return;
2898 if (! yyy_row_is_visible (sheet, row)) return;
2900 widget = GTK_WIDGET (sheet);
2902 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2904 /* select GC for background rectangle */
2905 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2906 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2908 fg_gc = sheet->fg_gc;
2909 bg_gc = sheet->bg_gc;
2911 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
2912 area.y = ROW_TOP_YPIXEL (sheet, row);
2913 area.width= xxx_column_width (sheet, col);
2914 area.height = yyy_row_height (sheet, row);
2916 gdk_draw_rectangle (sheet->pixmap,
2924 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
2926 if (sheet->show_grid)
2928 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
2930 gdk_draw_rectangle (sheet->pixmap,
2934 area.width, area.height);
2939 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
2944 gint text_width, text_height, y;
2946 gint size, sizel, sizer;
2947 GdkGC *fg_gc, *bg_gc;
2948 GtkSheetCellAttr attributes;
2949 PangoLayout *layout;
2950 PangoRectangle rect;
2951 PangoRectangle logical_rect;
2952 PangoLayoutLine *line;
2953 PangoFontMetrics *metrics;
2954 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (sheet));
2955 gint ascent, descent, y_pos;
2959 g_return_if_fail (sheet != NULL);
2961 /* bail now if we aren't drawable yet */
2962 if (!GTK_WIDGET_DRAWABLE (sheet))
2965 label = gtk_sheet_cell_get_text (sheet, row, col);
2969 if (row < 0 || row >= yyy_row_count (sheet)) return;
2970 if (col < 0 || col >= xxx_column_count (sheet)) return;
2971 if (! xxx_column_is_visible (sheet, col)) return;
2972 if (!yyy_row_is_visible (sheet, row)) return;
2975 widget = GTK_WIDGET (sheet);
2977 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2979 /* select GC for background rectangle */
2980 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2981 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2983 fg_gc = sheet->fg_gc;
2984 bg_gc = sheet->bg_gc;
2986 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
2987 area.y = ROW_TOP_YPIXEL (sheet, row);
2988 area.width = xxx_column_width (sheet, col);
2989 area.height = yyy_row_height (sheet, row);
2992 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
2993 dispose_string (sheet, label);
2994 pango_layout_set_font_description (layout, attributes.font_desc);
2996 pango_layout_get_pixel_extents (layout, NULL, &rect);
2998 line = pango_layout_get_lines (layout)->data;
2999 pango_layout_line_get_extents (line, NULL, &logical_rect);
3001 metrics = pango_context_get_metrics (context,
3002 attributes.font_desc,
3003 pango_context_get_language (context));
3005 ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
3006 descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
3008 pango_font_metrics_unref (metrics);
3010 /* Align primarily for locale's ascent / descent */
3012 logical_rect.height /= PANGO_SCALE;
3013 logical_rect.y /= PANGO_SCALE;
3014 y_pos = area.height - logical_rect.height;
3016 if (logical_rect.height > area.height)
3017 y_pos = (logical_rect.height - area.height - 2 * CELLOFFSET) / 2;
3020 else if (y_pos + logical_rect.height > area.height)
3021 y_pos = area.height - logical_rect.height;
3023 text_width = rect.width;
3024 text_height = rect.height;
3025 y = area.y + y_pos - CELLOFFSET;
3027 switch (attributes.justification)
3029 case GTK_JUSTIFY_RIGHT:
3031 area.x +=area.width;
3033 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3035 if ( !gtk_sheet_cell_empty (sheet, row, i)) break;
3036 if (size >= text_width + CELLOFFSET) break;
3037 size +=xxx_column_width (sheet, i);
3038 xxx_column_set_right_column (sheet, i,
3040 xxx_column_right_column (sheet, i)));
3045 xoffset += area.width - text_width - 2 * CELLOFFSET -
3046 attributes.border.width / 2;
3048 case GTK_JUSTIFY_CENTER:
3049 sizel = area.width / 2;
3050 sizer = area.width / 2;
3051 area.x += area.width / 2;
3053 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3055 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3056 if (sizer >= text_width / 2) break;
3057 sizer += xxx_column_width (sheet, i);
3058 xxx_column_set_left_column (sheet, i,
3061 xxx_column_left_column (sheet, i)));
3063 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3065 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3066 if (sizel >= text_width / 2) break;
3067 sizel +=xxx_column_width (sheet, i);
3068 xxx_column_set_right_column (sheet, i,
3070 xxx_column_right_column (sheet, i)));
3072 size = MIN (sizel, sizer);
3075 xoffset += sizel - text_width / 2 - CELLOFFSET;
3076 area.width = sizel + sizer;
3078 case GTK_JUSTIFY_LEFT:
3082 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3084 if (! gtk_sheet_cell_empty (sheet, row, i)) break;
3085 if (size >= text_width + CELLOFFSET) break;
3086 size +=xxx_column_width (sheet, i);
3087 xxx_column_set_left_column (sheet, i,
3090 xxx_column_left_column (sheet, i)));
3095 xoffset += attributes.border.width / 2;
3099 gdk_gc_set_clip_rectangle (fg_gc, &area);
3102 gdk_draw_layout (sheet->pixmap, fg_gc,
3103 area.x + xoffset + CELLOFFSET,
3107 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3108 g_object_unref (G_OBJECT (layout));
3110 gdk_draw_pixmap (sheet->sheet_window,
3111 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3123 gtk_sheet_range_draw (GtkSheet *sheet, const GtkSheetRange *range)
3126 GtkSheetRange drawing_range;
3129 g_return_if_fail (sheet != NULL);
3130 g_return_if_fail (GTK_SHEET (sheet));
3132 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3133 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3134 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
3138 drawing_range.row0 = MIN_VISIBLE_ROW (sheet);
3139 drawing_range.col0 = MIN_VISIBLE_COLUMN (sheet);
3140 drawing_range.rowi = MIN (MAX_VISIBLE_ROW (sheet),
3141 yyy_row_count (sheet) - 1);
3142 drawing_range.coli = MAX_VISIBLE_COLUMN (sheet);
3145 gdk_draw_rectangle (sheet->pixmap,
3146 GTK_WIDGET (sheet)->style->white_gc,
3149 sheet->sheet_window_width,
3150 sheet->sheet_window_height);
3154 drawing_range.row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
3155 drawing_range.col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
3156 drawing_range.rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
3157 drawing_range.coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
3160 if (drawing_range.coli == xxx_column_count (sheet) - 1)
3162 area.x = COLUMN_LEFT_XPIXEL (sheet,
3163 xxx_column_count (sheet) - 1) +
3164 xxx_column_width (sheet, xxx_column_count (sheet) - 1) + 1;
3168 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3170 gdk_draw_rectangle (sheet->pixmap,
3174 sheet->sheet_window_width - area.x,
3175 sheet->sheet_window_height);
3177 gdk_draw_pixmap (sheet->sheet_window,
3178 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3184 sheet->sheet_window_width - area.x,
3185 sheet->sheet_window_height);
3188 if (drawing_range.rowi == yyy_row_count (sheet) - 1)
3191 area.y = ROW_TOP_YPIXEL (sheet,
3192 yyy_row_count (sheet) - 1) +
3193 yyy_row_height (sheet, yyy_row_count (sheet) - 1) + 1;
3195 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3197 gdk_draw_rectangle (sheet->pixmap,
3201 sheet->sheet_window_width,
3202 sheet->sheet_window_height - area.y);
3204 gdk_draw_pixmap (sheet->sheet_window,
3205 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3211 sheet->sheet_window_width,
3212 sheet->sheet_window_height - area.y);
3215 for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
3216 for (j = drawing_range.col0; j <= drawing_range.coli; j++)
3218 gtk_sheet_cell_draw_default (sheet, i, j);
3219 gtk_sheet_cell_draw_label (sheet, i, j);
3222 gtk_sheet_draw_backing_pixmap (sheet, drawing_range);
3224 if (sheet->state != GTK_SHEET_NORMAL &&
3225 gtk_sheet_range_isvisible (sheet, sheet->range))
3226 gtk_sheet_range_draw_selection (sheet, drawing_range);
3228 if (sheet->state == GTK_STATE_NORMAL &&
3229 sheet->active_cell.row >= drawing_range.row0 &&
3230 sheet->active_cell.row <= drawing_range.rowi &&
3231 sheet->active_cell.col >= drawing_range.col0 &&
3232 sheet->active_cell.col <= drawing_range.coli)
3233 gtk_sheet_show_active_cell (sheet);
3237 gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
3243 if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3244 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3247 if (!gtk_sheet_range_isvisible (sheet, range)) return;
3248 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3252 range.col0 = MAX (sheet->range.col0, range.col0);
3253 range.coli = MIN (sheet->range.coli, range.coli);
3254 range.row0 = MAX (sheet->range.row0, range.row0);
3255 range.rowi = MIN (sheet->range.rowi, range.rowi);
3257 range.col0 = MAX (range.col0, MIN_VISIBLE_COLUMN (sheet));
3258 range.coli = MIN (range.coli, MAX_VISIBLE_COLUMN (sheet));
3259 range.row0 = MAX (range.row0, MIN_VISIBLE_ROW (sheet));
3260 range.rowi = MIN (range.rowi, MAX_VISIBLE_ROW (sheet));
3262 for (i = range.row0; i <= range.rowi; i++)
3264 for (j = range.col0; j <= range.coli; j++)
3267 if (gtk_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED &&
3268 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
3271 area.x = COLUMN_LEFT_XPIXEL (sheet, j);
3272 area.y = ROW_TOP_YPIXEL (sheet, i);
3273 area.width= xxx_column_width (sheet, j);
3274 area.height = yyy_row_height (sheet, i);
3276 if (i == sheet->range.row0)
3278 area.y = area.y + 2;
3279 area.height = area.height - 2;
3281 if (i == sheet->range.rowi) area.height = area.height - 3;
3282 if (j == sheet->range.col0)
3284 area.x = area.x + 2;
3285 area.width = area.width - 2;
3287 if (j == sheet->range.coli) area.width = area.width - 3;
3289 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
3291 gdk_draw_rectangle (sheet->sheet_window,
3294 area.x + 1, area.y + 1,
3295 area.width, area.height);
3302 gtk_sheet_draw_border (sheet, sheet->range);
3306 gtk_sheet_draw_backing_pixmap (GtkSheet *sheet, GtkSheetRange range)
3308 gint x, y, width, height;
3310 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3312 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
3313 y = ROW_TOP_YPIXEL (sheet, range.row0);
3314 width = COLUMN_LEFT_XPIXEL (sheet, range.coli) - x +
3315 xxx_column_width (sheet, range.coli);
3317 height = ROW_TOP_YPIXEL (sheet, range.rowi)- y + yyy_row_height (sheet, range.rowi);
3319 if (range.row0 == sheet->range.row0)
3322 height = height + 5;
3324 if (range.rowi == sheet->range.rowi) height = height + 5;
3325 if (range.col0 == sheet->range.col0)
3330 if (range.coli == sheet->range.coli) width = width + 5;
3332 width = MIN (width, sheet->sheet_window_width - x);
3333 height = MIN (height, sheet->sheet_window_height - y);
3340 x = (sheet->row_titles_visible)
3341 ? MAX (x, sheet->row_title_area.width) : MAX (x, 0);
3342 y = (sheet->column_titles_visible)
3343 ? MAX (y, sheet->column_title_area.height) : MAX (y, 0);
3345 if (range.coli == xxx_column_count (sheet) - 1)
3346 width = sheet->sheet_window_width - x;
3347 if (range.rowi == yyy_row_count (sheet) - 1)
3348 height = sheet->sheet_window_height - y;
3350 gdk_draw_pixmap (sheet->sheet_window,
3351 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3363 gtk_sheet_set_cell_text (GtkSheet *sheet, gint row, gint col, const gchar *text)
3365 GtkSheetCellAttr attributes;
3367 g_return_if_fail (sheet != NULL);
3368 g_return_if_fail (GTK_IS_SHEET (sheet));
3369 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3370 if (col < 0 || row < 0) return;
3372 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3373 gtk_sheet_set_cell (sheet, row, col, attributes.justification, text);
3377 safe_strcmp (const gchar *s1, const gchar *s2)
3379 if ( !s1 && !s2) return 0;
3380 if ( !s1) return - 1;
3381 if ( !s2) return +1;
3382 return strcmp (s1, s2);
3386 gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
3387 GtkJustification justification,
3390 GSheetModel *model ;
3394 GtkSheetRange range;
3396 GtkSheetCellAttr attributes;
3398 g_return_if_fail (sheet != NULL);
3399 g_return_if_fail (GTK_IS_SHEET (sheet));
3400 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3401 if (col < 0 || row < 0) return;
3403 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3405 attributes.justification = justification;
3407 model = gtk_sheet_get_model (sheet);
3409 old_text = g_sheet_model_get_string (model, row, col);
3413 if (0 != safe_strcmp (old_text, text))
3414 changed = g_sheet_model_set_string (model, text, row, col);
3416 if ( g_sheet_model_free_strings (model))
3420 if (changed && attributes.is_visible)
3422 gchar *s = gtk_sheet_cell_get_text (sheet, row, col);
3424 if (s && strlen (s) > 0)
3426 text_width = STRING_WIDTH (GTK_WIDGET (sheet),
3427 attributes.font_desc, text);
3429 dispose_string (sheet, s);
3433 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3434 range.coli = MAX_VISIBLE_COLUMN (sheet);
3436 if (gtk_sheet_autoresize (sheet) &&
3437 text_width > xxx_column_width (sheet, col) -
3438 2 * CELLOFFSET- attributes.border.width)
3440 gtk_sheet_set_column_width (sheet, col, text_width + 2 * CELLOFFSET
3441 + attributes.border.width);
3442 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3445 if (!GTK_SHEET_IS_FROZEN (sheet))
3446 gtk_sheet_range_draw (sheet, &range);
3450 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, col);
3456 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3458 GtkSheetRange range;
3460 g_return_if_fail (sheet != NULL);
3461 g_return_if_fail (GTK_IS_SHEET (sheet));
3462 if (column >= xxx_column_count (sheet) ||
3463 row >= yyy_row_count (sheet)) return;
3465 if (column < 0 || row < 0) return;
3469 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3470 range.coli = MAX_VISIBLE_COLUMN (sheet);
3472 gtk_sheet_real_cell_clear (sheet, row, column);
3474 if (!GTK_SHEET_IS_FROZEN (sheet))
3476 gtk_sheet_range_draw (sheet, &range);
3481 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column)
3483 GSheetModel *model = gtk_sheet_get_model (sheet);
3485 gchar *old_text = gtk_sheet_cell_get_text (sheet, row, column);
3487 if (old_text && strlen (old_text) > 0 )
3489 g_sheet_model_datum_clear (model, row, column);
3491 if (GTK_IS_OBJECT (sheet) && G_OBJECT (sheet)->ref_count > 0)
3492 g_signal_emit (G_OBJECT (sheet), sheet_signals[CLEAR_CELL], 0,
3496 dispose_string (sheet, old_text);
3500 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3502 g_return_if_fail (sheet != NULL);
3503 g_return_if_fail (GTK_IS_SHEET (sheet));
3505 gtk_sheet_real_range_clear (sheet, range);
3509 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3512 GtkSheetRange clear;
3517 clear.rowi = yyy_row_count (sheet) - 1;
3519 clear.coli = xxx_column_count (sheet) - 1;
3524 clear.row0 = MAX (clear.row0, 0);
3525 clear.col0 = MAX (clear.col0, 0);
3526 clear.rowi = MIN (clear.rowi, yyy_row_count (sheet) - 1 );
3527 clear.coli = MIN (clear.coli, xxx_column_count (sheet) - 1 );
3529 for (i = clear.row0; i <= clear.rowi; i++)
3530 for (j = clear.col0; j <= clear.coli; j++)
3532 gtk_sheet_real_cell_clear (sheet, i, j);
3535 gtk_sheet_range_draw (sheet, NULL);
3540 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3543 char *text = gtk_sheet_cell_get_text (sheet, row, col);
3544 empty = (text == NULL );
3546 dispose_string (sheet, text);
3553 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3556 g_return_val_if_fail (sheet != NULL, NULL);
3557 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3559 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet))
3561 if (col < 0 || row < 0) return NULL;
3563 model = gtk_sheet_get_model (sheet);
3568 return g_sheet_model_get_string (model, row, col);
3573 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3576 GtkSheetRange *range;
3578 g_return_val_if_fail (sheet != NULL, 0);
3579 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3580 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return 0;
3581 if (col < 0 || row < 0) return 0;
3583 state = sheet->state;
3584 range = &sheet->range;
3588 case GTK_SHEET_NORMAL:
3589 return GTK_STATE_NORMAL;
3591 case GTK_SHEET_ROW_SELECTED:
3592 if (row >= range->row0 && row <= range->rowi)
3593 return GTK_STATE_SELECTED;
3595 case GTK_SHEET_COLUMN_SELECTED:
3596 if (col >= range->col0 && col <= range->coli)
3597 return GTK_STATE_SELECTED;
3599 case GTK_SHEET_RANGE_SELECTED:
3600 if (row >= range->row0 && row <= range->rowi && \
3601 col >= range->col0 && col <= range->coli)
3602 return GTK_STATE_SELECTED;
3605 return GTK_STATE_NORMAL;
3608 /* Convert X, Y (in pixels) to *ROW, *COLUMN (in cell coords)
3609 -1 indicates the title buttons.
3610 If the function returns FALSE, then the results will be unreliable.
3613 gtk_sheet_get_pixel_info (GtkSheet *sheet,
3621 *column = -G_MAXINT;
3623 g_return_val_if_fail (sheet != NULL, 0);
3624 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3626 /* bounds checking, return false if the user clicked
3634 if ( y < sheet->column_title_area.height + sheet->column_title_area.y)
3639 trow = ROW_FROM_YPIXEL (sheet, y);
3640 if (trow > yyy_row_count (sheet))
3646 if ( x < sheet->row_title_area.width + sheet->row_title_area.x)
3650 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3651 if (tcol > xxx_column_count (sheet))
3661 gtk_sheet_get_cell_area (GtkSheet * sheet,
3666 g_return_val_if_fail (sheet != NULL, 0);
3667 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3669 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3672 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL (sheet, column) -
3673 (sheet->row_titles_visible
3674 ? sheet->row_title_area.width
3676 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL (sheet, row) -
3677 (sheet->column_titles_visible
3678 ? sheet->column_title_area.height
3680 area->width= (column == -1) ? sheet->row_title_area.width
3681 : xxx_column_width (sheet, column);
3683 area->height= (row == -1) ? sheet->column_title_area.height
3684 : yyy_row_height (sheet, row);
3690 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3692 g_return_val_if_fail (sheet != NULL, 0);
3693 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3695 if (row < - 1 || column < - 1) return FALSE;
3696 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3699 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3701 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
3704 sheet->active_cell.row = row;
3705 sheet->active_cell.col = column;
3707 if ( row == -1 || column == -1)
3709 gtk_sheet_hide_active_cell (sheet);
3713 if (!gtk_sheet_activate_cell (sheet, row, column)) return FALSE;
3715 if (gtk_sheet_autoscroll (sheet))
3716 gtk_sheet_move_query (sheet, row, column);
3722 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3724 g_return_if_fail (sheet != NULL);
3725 g_return_if_fail (GTK_IS_SHEET (sheet));
3727 if ( row ) *row = sheet->active_cell.row;
3728 if (column) *column = sheet->active_cell.col;
3732 gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
3737 GtkJustification justification;
3738 GtkSheetCellAttr attributes;
3740 g_return_if_fail (data != NULL);
3741 g_return_if_fail (GTK_IS_SHEET (data));
3743 sheet = GTK_SHEET (data);
3745 if (!GTK_WIDGET_VISIBLE (widget)) return;
3746 if (sheet->state != GTK_STATE_NORMAL) return;
3748 row = sheet->active_cell.row;
3749 col = sheet->active_cell.col;
3751 if (row < 0 || col < 0) return;
3753 sheet->active_cell.row =- 1;
3754 sheet->active_cell.col =- 1;
3756 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3758 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3760 if (text && strlen (text) > 0)
3762 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3763 justification = attributes.justification;
3764 gtk_sheet_set_cell (sheet, row, col, justification, text);
3767 if (sheet->freeze_count == 0)
3768 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3770 sheet->active_cell.row = row;;
3771 sheet->active_cell.col = col;
3776 gtk_sheet_deactivate_cell (GtkSheet *sheet)
3778 gboolean veto = TRUE;
3780 g_return_val_if_fail (sheet != NULL, FALSE);
3781 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3783 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return FALSE;
3784 if (sheet->state != GTK_SHEET_NORMAL) return FALSE;
3786 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[DEACTIVATE],
3787 sheet->active_cell.row,
3788 sheet->active_cell.col, &veto);
3790 if (!veto) return FALSE;
3792 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3795 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_sheet_get_entry (sheet)),
3796 G_CALLBACK (gtk_sheet_entry_changed),
3799 gtk_sheet_hide_active_cell (sheet);
3800 sheet->active_cell.row = -1;
3801 sheet->active_cell.col = -1;
3803 if (GTK_SHEET_REDRAW_PENDING (sheet))
3805 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3806 gtk_sheet_range_draw (sheet, NULL);
3813 gtk_sheet_hide_active_cell (GtkSheet *sheet)
3817 GtkJustification justification;
3818 GtkSheetCellAttr attributes;
3820 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3822 row = sheet->active_cell.row;
3823 col = sheet->active_cell.col;
3825 if (row < 0 || col < 0) return;
3827 if (sheet->freeze_count == 0)
3828 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3830 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3832 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3833 justification = attributes.justification;
3835 row = sheet->active_cell.row;
3836 col = sheet->active_cell.col;
3838 gtk_widget_hide (sheet->sheet_entry);
3839 gtk_widget_unmap (sheet->sheet_entry);
3841 if (row != -1 && col != -1)
3842 gdk_draw_pixmap (sheet->sheet_window,
3843 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3845 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3846 ROW_TOP_YPIXEL (sheet, row)- 1,
3847 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3848 ROW_TOP_YPIXEL (sheet, row)- 1,
3849 xxx_column_width (sheet, col) + 4,
3850 yyy_row_height (sheet, row)+4);
3852 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3854 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3859 gtk_sheet_activate_cell (GtkSheet *sheet, gint row, gint col)
3861 gboolean veto = TRUE;
3863 g_return_val_if_fail (sheet != NULL, FALSE);
3864 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3866 if (row < 0 || col < 0) return FALSE;
3868 if ( row > yyy_row_count (sheet) || col > xxx_column_count (sheet))
3871 if (!veto) return FALSE;
3872 if (sheet->state != GTK_SHEET_NORMAL)
3874 sheet->state = GTK_SHEET_NORMAL;
3875 gtk_sheet_real_unselect_range (sheet, NULL);
3878 sheet->range.row0 = row;
3879 sheet->range.col0 = col;
3880 sheet->range.rowi = row;
3881 sheet->range.coli = col;
3882 sheet->active_cell.row = row;
3883 sheet->active_cell.col = col;
3884 sheet->selection_cell.row = row;
3885 sheet->selection_cell.col = col;
3887 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
3889 gtk_sheet_show_active_cell (sheet);
3891 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
3893 G_CALLBACK (gtk_sheet_entry_changed),
3896 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals [ACTIVATE], row, col, &veto);
3902 gtk_sheet_show_active_cell (GtkSheet *sheet)
3904 GtkEntry *sheet_entry;
3905 GtkSheetCellAttr attributes;
3907 const gchar *old_text;
3908 GtkJustification justification;
3911 g_return_if_fail (sheet != NULL);
3912 g_return_if_fail (GTK_IS_SHEET (sheet));
3914 row = sheet->active_cell.row;
3915 col = sheet->active_cell.col;
3917 /* Don't show the active cell, if there is no active cell: */
3918 if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
3921 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3922 if (sheet->state != GTK_SHEET_NORMAL) return;
3923 if (GTK_SHEET_IN_SELECTION (sheet)) return;
3925 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3927 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
3929 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3931 justification = GTK_JUSTIFY_LEFT;
3933 if (gtk_sheet_justify_entry (sheet))
3934 justification = attributes.justification;
3936 text = gtk_sheet_cell_get_text (sheet, row, col);
3938 text = g_strdup ("");
3940 gtk_entry_set_visibility (GTK_ENTRY (sheet_entry), attributes.is_visible);
3943 /*** Added by John Gotts. Mar 25, 2005 *********/
3944 old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
3945 if (strcmp (old_text, text) != 0)
3947 if (!GTK_IS_ITEM_ENTRY (sheet_entry))
3948 gtk_entry_set_text (GTK_ENTRY (sheet_entry), text);
3950 gtk_item_entry_set_text (GTK_ITEM_ENTRY (sheet_entry), text, justification);
3953 gtk_sheet_entry_set_max_size (sheet);
3954 gtk_sheet_size_allocate_entry (sheet);
3956 gtk_widget_map (sheet->sheet_entry);
3958 gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
3960 dispose_string (sheet, text);
3964 gtk_sheet_draw_active_cell (GtkSheet *sheet)
3967 GtkSheetRange range;
3969 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3970 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3972 row = sheet->active_cell.row;
3973 col = sheet->active_cell.col;
3975 if (row < 0 || col < 0) return;
3977 if (!gtk_sheet_cell_isvisible (sheet, row, col)) return;
3979 range.col0 = range.coli = col;
3980 range.row0 = range.rowi = row;
3982 gtk_sheet_draw_border (sheet, range);
3987 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
3989 gint pixmap_width, pixmap_height;
3991 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3993 if (width == 0 && height == 0)
3995 width = sheet->sheet_window_width + 80;
3996 height = sheet->sheet_window_height + 80;
4002 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4005 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4009 /* reallocate if sizes don't match */
4010 gdk_window_get_size (sheet->pixmap,
4011 &pixmap_width, &pixmap_height);
4012 if ( (pixmap_width != width) || (pixmap_height != height))
4014 g_object_unref (sheet->pixmap);
4015 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4018 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4024 gtk_sheet_new_selection (GtkSheet *sheet, GtkSheetRange *range)
4026 gint i, j, mask1, mask2;
4027 gint state, selected;
4028 gint x, y, width, height;
4029 GtkSheetRange new_range, aux_range;
4031 g_return_if_fail (sheet != NULL);
4033 if (range == NULL) range=&sheet->range;
4037 range->row0 = MIN (range->row0, sheet->range.row0);
4038 range->rowi = MAX (range->rowi, sheet->range.rowi);
4039 range->col0 = MIN (range->col0, sheet->range.col0);
4040 range->coli = MAX (range->coli, sheet->range.coli);
4042 range->row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
4043 range->rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
4044 range->col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
4045 range->coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
4047 aux_range.row0 = MAX (new_range.row0, MIN_VISIBLE_ROW (sheet));
4048 aux_range.rowi = MIN (new_range.rowi, MAX_VISIBLE_ROW (sheet));
4049 aux_range.col0 = MAX (new_range.col0, MIN_VISIBLE_COLUMN (sheet));
4050 aux_range.coli = MIN (new_range.coli, MAX_VISIBLE_COLUMN (sheet));
4052 for (i = range->row0; i <= range->rowi; i++)
4054 for (j = range->col0; j <= range->coli; j++)
4057 state = gtk_sheet_cell_get_state (sheet, i, j);
4058 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4059 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4061 if (state == GTK_STATE_SELECTED && selected &&
4062 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4063 (i == sheet->range.row0 || i == sheet->range.rowi ||
4064 j == sheet->range.col0 || j == sheet->range.coli ||
4065 i == new_range.row0 || i == new_range.rowi ||
4066 j == new_range.col0 || j == new_range.coli))
4069 mask1 = i == sheet->range.row0 ? 1 : 0;
4070 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4071 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4072 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4074 mask2 = i == new_range.row0 ? 1 : 0;
4075 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4076 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4077 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4081 x = COLUMN_LEFT_XPIXEL (sheet, j);
4082 y = ROW_TOP_YPIXEL (sheet, i);
4083 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4084 xxx_column_width (sheet, j);
4085 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4087 if (i == sheet->range.row0)
4090 height = height + 3;
4092 if (i == sheet->range.rowi) height = height + 3;
4093 if (j == sheet->range.col0)
4098 if (j == sheet->range.coli) width = width + 3;
4100 gdk_draw_pixmap (sheet->sheet_window,
4101 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4110 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
4112 x = COLUMN_LEFT_XPIXEL (sheet, j);
4113 y = ROW_TOP_YPIXEL (sheet, i);
4114 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4115 xxx_column_width (sheet, j);
4117 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4119 if (i == new_range.row0)
4122 height = height - 2;
4124 if (i == new_range.rowi) height = height - 3;
4125 if (j == new_range.col0)
4130 if (j == new_range.coli) width = width - 3;
4132 gdk_draw_rectangle (sheet->sheet_window,
4143 for (i = range->row0; i <= range->rowi; i++)
4145 for (j = range->col0; j <= range->coli; j++)
4148 state = gtk_sheet_cell_get_state (sheet, i, j);
4149 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4150 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4152 if (state == GTK_STATE_SELECTED && !selected &&
4153 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4156 x = COLUMN_LEFT_XPIXEL (sheet, j);
4157 y = ROW_TOP_YPIXEL (sheet, i);
4158 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4159 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4161 if (i == sheet->range.row0)
4164 height = height + 3;
4166 if (i == sheet->range.rowi) height = height + 3;
4167 if (j == sheet->range.col0)
4172 if (j == sheet->range.coli) width = width + 3;
4174 gdk_draw_pixmap (sheet->sheet_window,
4175 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4187 for (i = range->row0; i <= range->rowi; i++)
4189 for (j = range->col0; j <= range->coli; j++)
4192 state = gtk_sheet_cell_get_state (sheet, i, j);
4193 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4194 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4196 if (state != GTK_STATE_SELECTED && selected &&
4197 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4198 (i != sheet->active_cell.row || j != sheet->active_cell.col))
4201 x = COLUMN_LEFT_XPIXEL (sheet, j);
4202 y = ROW_TOP_YPIXEL (sheet, i);
4203 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4204 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4206 if (i == new_range.row0)
4209 height = height - 2;
4211 if (i == new_range.rowi) height = height - 3;
4212 if (j == new_range.col0)
4217 if (j == new_range.coli) width = width - 3;
4219 gdk_draw_rectangle (sheet->sheet_window,
4230 for (i = aux_range.row0; i <= aux_range.rowi; i++)
4232 for (j = aux_range.col0; j <= aux_range.coli; j++)
4235 if (xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4238 state = gtk_sheet_cell_get_state (sheet, i, j);
4240 mask1 = i == sheet->range.row0 ? 1 : 0;
4241 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4242 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4243 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4245 mask2 = i == new_range.row0 ? 1 : 0;
4246 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4247 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4248 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4249 if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
4251 x = COLUMN_LEFT_XPIXEL (sheet, j);
4252 y = ROW_TOP_YPIXEL (sheet, i);
4253 width = xxx_column_width (sheet, j);
4254 height = yyy_row_height (sheet, i);
4256 gdk_draw_rectangle (sheet->sheet_window,
4264 gdk_draw_rectangle (sheet->sheet_window,
4267 x + 1, y + height - 1,
4271 gdk_draw_rectangle (sheet->sheet_window,
4279 gdk_draw_rectangle (sheet->sheet_window,
4282 x + width - 1, y + 1,
4296 gtk_sheet_draw_corners (sheet, new_range);
4301 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4306 gint x, y, width, height;
4308 widget = GTK_WIDGET (sheet);
4310 x = COLUMN_LEFT_XPIXEL (sheet, new_range.col0);
4311 y = ROW_TOP_YPIXEL (sheet, new_range.row0);
4312 width = COLUMN_LEFT_XPIXEL (sheet, new_range.coli) - x +
4313 xxx_column_width (sheet, new_range.coli);
4315 height = ROW_TOP_YPIXEL (sheet, new_range.rowi) - y +
4316 yyy_row_height (sheet, new_range.rowi);
4318 area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
4319 area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
4320 area.width = sheet->sheet_window_width;
4321 area.height = sheet->sheet_window_height;
4328 if (width > area.width) width = area.width + 10;
4331 height = height + y;
4334 if (height > area.height) height = area.height + 10;
4336 gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
4338 for (i =- 1; i <= 1; ++i)
4339 gdk_draw_rectangle (sheet->sheet_window,
4347 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
4350 gtk_sheet_draw_corners (sheet, new_range);
4354 gtk_sheet_draw_corners (GtkSheet *sheet, GtkSheetRange range)
4359 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.col0))
4361 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4362 y = ROW_TOP_YPIXEL (sheet, range.row0);
4363 gdk_draw_pixmap (sheet->sheet_window,
4364 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4372 gdk_draw_rectangle (sheet->sheet_window,
4379 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.coli) ||
4380 sheet->state == GTK_SHEET_COLUMN_SELECTED)
4382 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4383 xxx_column_width (sheet, range.coli);
4384 y = ROW_TOP_YPIXEL (sheet, range.row0);
4386 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4388 y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet))+3;
4391 gdk_draw_pixmap (sheet->sheet_window,
4392 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4400 gdk_draw_rectangle (sheet->sheet_window,
4403 x - width + width / 2, y - width + width / 2,
4404 2 + width, 2 + width);
4407 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.col0) ||
4408 sheet->state == GTK_SHEET_ROW_SELECTED)
4410 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4411 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4412 yyy_row_height (sheet, range.rowi);
4414 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4416 x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet))+3;
4419 gdk_draw_pixmap (sheet->sheet_window,
4420 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4428 gdk_draw_rectangle (sheet->sheet_window,
4431 x - width + width / 2, y - width + width / 2,
4432 2 + width, 2 + width);
4435 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.coli))
4437 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4438 xxx_column_width (sheet, range.coli);
4439 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4440 yyy_row_height (sheet, range.rowi);
4442 if (sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4443 if (sheet->state == GTK_SHEET_NORMAL) width = 3;
4444 gdk_draw_pixmap (sheet->sheet_window,
4445 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4453 gdk_draw_rectangle (sheet->sheet_window,
4456 x - width + width / 2, y - width + width / 2,
4457 2 + width, 2 + width);
4465 gtk_sheet_real_select_range (GtkSheet * sheet,
4466 const GtkSheetRange * range)
4470 g_return_if_fail (sheet != NULL);
4472 if (range == NULL) range = &sheet->range;
4474 memcpy (&sheet->range, range, sizeof (*range));
4476 if (range->row0 < 0 || range->rowi < 0) return;
4477 if (range->col0 < 0 || range->coli < 0) return;
4479 state = sheet->state;
4481 if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4482 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4484 gtk_sheet_new_selection (sheet, &sheet->range);
4488 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4489 gtk_sheet_range_draw_selection (sheet, sheet->range);
4492 gtk_sheet_update_primary_selection (sheet);
4494 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_RANGE], 0, &sheet->range);
4499 gtk_sheet_get_selected_range (GtkSheet *sheet,
4500 GtkSheetRange *range)
4502 g_return_if_fail (sheet != NULL);
4503 *range = sheet->range;
4508 gtk_sheet_select_range (GtkSheet * sheet, const GtkSheetRange *range)
4510 g_return_if_fail (sheet != NULL);
4512 if (range == NULL) range=&sheet->range;
4514 if (range->row0 < 0 || range->rowi < 0) return;
4515 if (range->col0 < 0 || range->coli < 0) return;
4518 if (sheet->state != GTK_SHEET_NORMAL)
4519 gtk_sheet_real_unselect_range (sheet, NULL);
4522 gboolean veto = TRUE;
4523 veto = gtk_sheet_deactivate_cell (sheet);
4527 sheet->range.row0 = range->row0;
4528 sheet->range.rowi = range->rowi;
4529 sheet->range.col0 = range->col0;
4530 sheet->range.coli = range->coli;
4531 sheet->active_cell.row = range->row0;
4532 sheet->active_cell.col = range->col0;
4533 sheet->selection_cell.row = range->rowi;
4534 sheet->selection_cell.col = range->coli;
4536 sheet->state = GTK_SHEET_RANGE_SELECTED;
4537 gtk_sheet_real_select_range (sheet, NULL);
4542 gtk_sheet_unselect_range (GtkSheet * sheet)
4544 gtk_sheet_real_unselect_range (sheet, NULL);
4545 sheet->state = GTK_STATE_NORMAL;
4547 gtk_sheet_activate_cell (sheet,
4548 sheet->active_cell.row, sheet->active_cell.col);
4553 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4554 const GtkSheetRange *range)
4556 g_return_if_fail (sheet != NULL);
4557 g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
4560 range = &sheet->range;
4562 if (range->row0 < 0 || range->rowi < 0) return;
4563 if (range->col0 < 0 || range->coli < 0) return;
4565 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, -1);
4566 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, -1);
4568 if (gtk_sheet_range_isvisible (sheet, *range))
4569 gtk_sheet_draw_backing_pixmap (sheet, *range);
4571 sheet->range.row0 = -1;
4572 sheet->range.rowi = -1;
4573 sheet->range.col0 = -1;
4574 sheet->range.coli = -1;
4576 gtk_sheet_position_children (sheet);
4581 gtk_sheet_expose (GtkWidget * widget,
4582 GdkEventExpose * event)
4585 GtkSheetRange range;
4587 g_return_val_if_fail (widget != NULL, FALSE);
4588 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4589 g_return_val_if_fail (event != NULL, FALSE);
4592 sheet = GTK_SHEET (widget);
4594 if (GTK_WIDGET_DRAWABLE (widget))
4596 range.row0 = ROW_FROM_YPIXEL (sheet, event->area.y);
4597 range.col0 = COLUMN_FROM_XPIXEL (sheet, event->area.x);
4598 range.rowi = ROW_FROM_YPIXEL (sheet, event->area.y + event->area.height);
4599 range.coli = COLUMN_FROM_XPIXEL (sheet, event->area.x + event->area.width);
4601 /* exposure events on the sheet */
4602 if (event->window == sheet->row_title_window &&
4603 sheet->row_titles_visible)
4606 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
4607 gtk_sheet_row_title_button_draw (sheet, i);
4610 if (event->window == sheet->column_title_window &&
4611 sheet->column_titles_visible)
4614 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
4615 gtk_sheet_column_title_button_draw (sheet, i);
4618 if (event->window == sheet->sheet_window)
4620 gtk_sheet_draw_backing_pixmap (sheet, range);
4622 if (sheet->state != GTK_SHEET_NORMAL)
4624 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4625 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4626 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4627 gtk_sheet_draw_backing_pixmap (sheet, sheet->drag_range);
4629 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4630 gtk_sheet_range_draw_selection (sheet, sheet->range);
4631 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4632 draw_xor_rectangle (sheet, sheet->drag_range);
4635 if ((!GTK_SHEET_IN_XDRAG (sheet)) && (!GTK_SHEET_IN_YDRAG (sheet)))
4637 if (sheet->state == GTK_SHEET_NORMAL)
4639 gtk_sheet_draw_active_cell (sheet);
4640 if (!GTK_SHEET_IN_SELECTION (sheet))
4641 gtk_widget_queue_draw (sheet->sheet_entry);
4647 if (sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
4648 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4650 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4657 gtk_sheet_button_press (GtkWidget * widget,
4658 GdkEventButton * event)
4661 GdkModifierType mods;
4662 gint x, y, row, column;
4665 g_return_val_if_fail (widget != NULL, FALSE);
4666 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4667 g_return_val_if_fail (event != NULL, FALSE);
4669 sheet = GTK_SHEET (widget);
4671 /* Cancel any pending tooltips */
4672 if (sheet->motion_timer)
4674 g_source_remove (sheet->motion_timer);
4675 sheet->motion_timer = 0;
4678 gtk_widget_get_pointer (widget, &x, &y);
4679 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4682 if (event->window == sheet->column_title_window)
4684 g_signal_emit (G_OBJECT (sheet),
4685 sheet_signals[BUTTON_EVENT_COLUMN], 0,
4688 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4689 g_signal_emit (G_OBJECT (sheet),
4690 sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
4693 else if (event->window == sheet->row_title_window)
4695 g_signal_emit (G_OBJECT (sheet),
4696 sheet_signals[BUTTON_EVENT_ROW], 0,
4699 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4700 g_signal_emit (G_OBJECT (sheet),
4701 sheet_signals[DOUBLE_CLICK_ROW], 0, row);
4705 gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
4707 if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
4710 /* press on resize windows */
4711 if (event->window == sheet->column_title_window &&
4712 gtk_sheet_columns_resizable (sheet))
4714 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4715 if (POSSIBLE_XDRAG (sheet, sheet->x_drag, &sheet->drag_cell.col))
4718 if (event->type == GDK_2BUTTON_PRESS)
4720 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4721 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4724 gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
4725 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4726 gdk_pointer_grab (sheet->column_title_window, FALSE,
4727 GDK_POINTER_MOTION_HINT_MASK |
4728 GDK_BUTTON1_MOTION_MASK |
4729 GDK_BUTTON_RELEASE_MASK,
4730 NULL, NULL, event->time);
4732 draw_xor_vline (sheet);
4737 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable (sheet))
4739 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4741 if (POSSIBLE_YDRAG (sheet, sheet->y_drag, &sheet->drag_cell.row))
4744 gtk_sheet_row_size_request (sheet, sheet->drag_cell.row, &req);
4745 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4746 gdk_pointer_grab (sheet->row_title_window, FALSE,
4747 GDK_POINTER_MOTION_HINT_MASK |
4748 GDK_BUTTON1_MOTION_MASK |
4749 GDK_BUTTON_RELEASE_MASK,
4750 NULL, NULL, event->time);
4752 draw_xor_hline (sheet);
4757 /* the sheet itself does not handle other than single click events */
4758 if (event->type != GDK_BUTTON_PRESS) return FALSE;
4760 /* selections on the sheet */
4761 if (event->window == sheet->sheet_window)
4763 gtk_widget_get_pointer (widget, &x, &y);
4764 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4765 gdk_pointer_grab (sheet->sheet_window, FALSE,
4766 GDK_POINTER_MOTION_HINT_MASK |
4767 GDK_BUTTON1_MOTION_MASK |
4768 GDK_BUTTON_RELEASE_MASK,
4769 NULL, NULL, event->time);
4770 gtk_grab_add (GTK_WIDGET (sheet));
4772 /* This seems to be a kludge to work around a problem where the sheet
4773 scrolls to another position. The timeout scrolls it back to its
4774 original posn. JMD 3 July 2007
4776 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4778 if (sheet->selection_mode != GTK_SELECTION_SINGLE &&
4779 sheet->selection_mode != GTK_SELECTION_NONE &&
4780 sheet->cursor_drag->type == GDK_SIZING &&
4781 !GTK_SHEET_IN_SELECTION (sheet) && !GTK_SHEET_IN_RESIZE (sheet))
4783 if (sheet->state == GTK_STATE_NORMAL)
4785 row = sheet->active_cell.row;
4786 column = sheet->active_cell.col;
4787 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4788 sheet->active_cell.row = row;
4789 sheet->active_cell.col = column;
4790 sheet->drag_range = sheet->range;
4791 sheet->state = GTK_SHEET_RANGE_SELECTED;
4792 gtk_sheet_select_range (sheet, &sheet->drag_range);
4796 if (row > sheet->range.rowi) row--;
4797 if (column > sheet->range.coli) column--;
4798 sheet->drag_cell.row = row;
4799 sheet->drag_cell.col = column;
4800 sheet->drag_range = sheet->range;
4801 draw_xor_rectangle (sheet, sheet->drag_range);
4802 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
4804 else if (sheet->cursor_drag->type == GDK_TOP_LEFT_ARROW &&
4805 !GTK_SHEET_IN_SELECTION (sheet)
4806 && ! GTK_SHEET_IN_DRAG (sheet)
4807 && sheet->active_cell.row >= 0
4808 && sheet->active_cell.col >= 0
4811 if (sheet->state == GTK_STATE_NORMAL)
4813 row = sheet->active_cell.row;
4814 column = sheet->active_cell.col;
4815 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4816 sheet->active_cell.row = row;
4817 sheet->active_cell.col = column;
4818 sheet->drag_range = sheet->range;
4819 sheet->state = GTK_SHEET_RANGE_SELECTED;
4820 gtk_sheet_select_range (sheet, &sheet->drag_range);
4824 if (row < sheet->range.row0) row++;
4825 if (row > sheet->range.rowi) row--;
4826 if (column < sheet->range.col0) column++;
4827 if (column > sheet->range.coli) column--;
4828 sheet->drag_cell.row = row;
4829 sheet->drag_cell.col = column;
4830 sheet->drag_range = sheet->range;
4831 draw_xor_rectangle (sheet, sheet->drag_range);
4832 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
4836 gtk_sheet_click_cell (sheet, row, column, &veto);
4837 if (veto) GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4841 if (event->window == sheet->column_title_window)
4843 gtk_widget_get_pointer (widget, &x, &y);
4844 column = COLUMN_FROM_XPIXEL (sheet, x);
4846 if (xxx_column_is_sensitive (sheet, column))
4848 gtk_sheet_click_cell (sheet, - 1, column, &veto);
4849 gtk_grab_add (GTK_WIDGET (sheet));
4850 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4851 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4855 if (event->window == sheet->row_title_window)
4857 gtk_widget_get_pointer (widget, &x, &y);
4858 row = ROW_FROM_YPIXEL (sheet, y);
4859 if (yyy_row_is_sensitive (sheet, row))
4861 gtk_sheet_click_cell (sheet, row, - 1, &veto);
4862 gtk_grab_add (GTK_WIDGET (sheet));
4863 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4864 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4872 gtk_sheet_click_cell (GtkSheet *sheet, gint row, gint column, gboolean *veto)
4876 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
4882 if (column >= 0 && row >= 0)
4883 if (! xxx_column_is_visible (sheet, column) || !yyy_row_is_visible (sheet, row))
4889 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[TRAVERSE],
4890 sheet->active_cell.row, sheet->active_cell.col,
4891 &row, &column, veto);
4895 if (sheet->state == GTK_STATE_NORMAL) return;
4897 row = sheet->active_cell.row;
4898 column = sheet->active_cell.col;
4900 gtk_sheet_activate_cell (sheet, row, column);
4904 if (row == -1 && column >= 0)
4906 if (gtk_sheet_autoscroll (sheet))
4907 gtk_sheet_move_query (sheet, row, column);
4908 gtk_sheet_select_column (sheet, column);
4911 if (column == -1 && row >= 0)
4913 if (gtk_sheet_autoscroll (sheet))
4914 gtk_sheet_move_query (sheet, row, column);
4915 gtk_sheet_select_row (sheet, row);
4919 if (row == - 1 && column == - 1)
4921 sheet->range.row0 = 0;
4922 sheet->range.col0 = 0;
4923 sheet->range.rowi = yyy_row_count (sheet) - 1;
4924 sheet->range.coli = xxx_column_count (sheet) - 1;
4925 sheet->active_cell.row = 0;
4926 sheet->active_cell.col = 0;
4927 gtk_sheet_select_range (sheet, NULL);
4931 if (row != -1 && column != -1)
4933 if (sheet->state != GTK_SHEET_NORMAL)
4935 sheet->state = GTK_SHEET_NORMAL;
4936 gtk_sheet_real_unselect_range (sheet, NULL);
4940 if (!gtk_sheet_deactivate_cell (sheet))
4945 gtk_sheet_activate_cell (sheet, row, column);
4948 if (gtk_sheet_autoscroll (sheet))
4949 gtk_sheet_move_query (sheet, row, column);
4950 sheet->active_cell.row = row;
4951 sheet->active_cell.col = column;
4952 sheet->selection_cell.row = row;
4953 sheet->selection_cell.col = column;
4954 sheet->range.row0 = row;
4955 sheet->range.col0 = column;
4956 sheet->range.rowi = row;
4957 sheet->range.coli = column;
4958 sheet->state = GTK_SHEET_NORMAL;
4959 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4960 gtk_sheet_draw_active_cell (sheet);
4964 g_assert_not_reached ();
4965 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
4966 sheet->active_cell.col);
4970 gtk_sheet_button_release (GtkWidget * widget,
4971 GdkEventButton * event)
4976 sheet = GTK_SHEET (widget);
4978 /* release on resize windows */
4979 if (GTK_SHEET_IN_XDRAG (sheet))
4981 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4982 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4983 gtk_widget_get_pointer (widget, &x, NULL);
4984 gdk_pointer_ungrab (event->time);
4985 draw_xor_vline (sheet);
4987 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col,
4988 new_column_width (sheet, sheet->drag_cell.col, &x));
4989 sheet->old_hadjustment = -1.;
4990 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "value_changed");
4994 if (GTK_SHEET_IN_YDRAG (sheet))
4996 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4997 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4998 gtk_widget_get_pointer (widget, NULL, &y);
4999 gdk_pointer_ungrab (event->time);
5000 draw_xor_hline (sheet);
5002 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5003 sheet->old_vadjustment = -1.;
5004 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "value_changed");
5009 if (GTK_SHEET_IN_DRAG (sheet))
5011 GtkSheetRange old_range;
5012 draw_xor_rectangle (sheet, sheet->drag_range);
5013 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
5014 gdk_pointer_ungrab (event->time);
5016 gtk_sheet_real_unselect_range (sheet, NULL);
5018 sheet->active_cell.row = sheet->active_cell.row +
5019 (sheet->drag_range.row0 - sheet->range.row0);
5020 sheet->active_cell.col = sheet->active_cell.col +
5021 (sheet->drag_range.col0 - sheet->range.col0);
5022 sheet->selection_cell.row = sheet->selection_cell.row +
5023 (sheet->drag_range.row0 - sheet->range.row0);
5024 sheet->selection_cell.col = sheet->selection_cell.col +
5025 (sheet->drag_range.col0 - sheet->range.col0);
5026 old_range = sheet->range;
5027 sheet->range = sheet->drag_range;
5028 sheet->drag_range = old_range;
5029 g_signal_emit (G_OBJECT (sheet), sheet_signals[MOVE_RANGE], 0,
5030 &sheet->drag_range, &sheet->range);
5031 gtk_sheet_select_range (sheet, &sheet->range);
5034 if (GTK_SHEET_IN_RESIZE (sheet))
5036 GtkSheetRange old_range;
5037 draw_xor_rectangle (sheet, sheet->drag_range);
5038 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
5039 gdk_pointer_ungrab (event->time);
5041 gtk_sheet_real_unselect_range (sheet, NULL);
5043 sheet->active_cell.row = sheet->active_cell.row +
5044 (sheet->drag_range.row0 - sheet->range.row0);
5045 sheet->active_cell.col = sheet->active_cell.col +
5046 (sheet->drag_range.col0 - sheet->range.col0);
5047 if (sheet->drag_range.row0 < sheet->range.row0)
5048 sheet->selection_cell.row = sheet->drag_range.row0;
5049 if (sheet->drag_range.rowi >= sheet->range.rowi)
5050 sheet->selection_cell.row = sheet->drag_range.rowi;
5051 if (sheet->drag_range.col0 < sheet->range.col0)
5052 sheet->selection_cell.col = sheet->drag_range.col0;
5053 if (sheet->drag_range.coli >= sheet->range.coli)
5054 sheet->selection_cell.col = sheet->drag_range.coli;
5055 old_range = sheet->range;
5056 sheet->range = sheet->drag_range;
5057 sheet->drag_range = old_range;
5059 if (sheet->state == GTK_STATE_NORMAL) sheet->state = GTK_SHEET_RANGE_SELECTED;
5060 g_signal_emit (G_OBJECT (sheet), sheet_signals[RESIZE_RANGE], 0,
5061 &sheet->drag_range, &sheet->range);
5062 gtk_sheet_select_range (sheet, &sheet->range);
5065 if (sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
5067 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5068 gdk_pointer_ungrab (event->time);
5069 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5070 sheet->active_cell.col);
5073 if (GTK_SHEET_IN_SELECTION)
5074 gdk_pointer_ungrab (event->time);
5075 gtk_grab_remove (GTK_WIDGET (sheet));
5077 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5082 /* Shamelessly lifted from gtktooltips */
5084 gtk_sheet_subtitle_paint_window (GtkWidget *tip_window)
5088 gtk_widget_size_request (tip_window, &req);
5089 gtk_paint_flat_box (tip_window->style, tip_window->window,
5090 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
5091 NULL, GTK_WIDGET(tip_window), "tooltip",
5092 0, 0, req.width, req.height);
5097 static GtkSheetHoverTitle *
5098 create_hover_window (void)
5100 GtkSheetHoverTitle *hw = malloc (sizeof (*hw));
5102 hw->window = gtk_window_new (GTK_WINDOW_POPUP);
5104 #if GTK_CHECK_VERSION (2, 9, 0)
5105 gtk_window_set_type_hint (GTK_WINDOW (hw->window),
5106 GDK_WINDOW_TYPE_HINT_TOOLTIP);
5109 gtk_widget_set_app_paintable (hw->window, TRUE);
5110 gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
5111 gtk_widget_set_name (hw->window, "gtk-tooltips");
5112 gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
5114 g_signal_connect (hw->window,
5116 G_CALLBACK (gtk_sheet_subtitle_paint_window),
5119 hw->label = gtk_label_new (NULL);
5122 gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
5123 gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
5125 gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
5127 gtk_widget_show (hw->label);
5129 g_signal_connect (hw->window,
5131 G_CALLBACK (gtk_widget_destroyed),
5137 #define HOVER_WINDOW_Y_OFFSET 2
5140 show_subtitle (GtkSheet *sheet, gint row, gint column, const gchar *subtitle)
5149 if ( ! sheet->hover_window)
5151 sheet->hover_window = create_hover_window ();
5152 gtk_widget_add_events (GTK_WIDGET (sheet), GDK_LEAVE_NOTIFY_MASK);
5154 g_signal_connect_swapped (sheet, "leave-notify-event",
5155 G_CALLBACK (gtk_widget_hide),
5156 sheet->hover_window->window);
5159 gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
5163 sheet->hover_window->row = row;
5164 sheet->hover_window->column = column;
5166 gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
5168 gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
5170 gtk_widget_show (sheet->hover_window->window);
5172 width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
5178 y += sheet->column_title_area.y;
5179 y += sheet->column_title_area.height;
5180 y += HOVER_WINDOW_Y_OFFSET;
5186 x += sheet->row_title_area.x;
5187 x += sheet->row_title_area.width * 2 / 3.0;
5190 gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
5195 motion_timeout_callback (gpointer data)
5197 GtkSheet *sheet = GTK_SHEET (data);
5200 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
5202 if ( gtk_sheet_get_pixel_info (sheet, x, y, &row, &column) )
5204 if ( column == -1 && row == -1 )
5209 GSheetRow *row_geo = sheet->row_geometry;
5212 text = g_sheet_row_get_subtitle (row_geo, row);
5214 show_subtitle (sheet, row, column, text);
5220 GSheetColumn *col_geo = sheet->column_geometry;
5223 text = g_sheet_column_get_subtitle (col_geo, column);
5225 show_subtitle (sheet, row, column, text );
5235 gtk_sheet_motion (GtkWidget * widget,
5236 GdkEventMotion * event)
5239 GdkModifierType mods;
5240 GdkCursorType new_cursor;
5244 g_return_val_if_fail (widget != NULL, FALSE);
5245 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5246 g_return_val_if_fail (event != NULL, FALSE);
5248 sheet = GTK_SHEET (widget);
5250 /* selections on the sheet */
5254 if (!sheet->hover_window || ! GTK_WIDGET_VISIBLE (sheet->hover_window->window))
5256 if ( sheet->motion_timer > 0 )
5257 g_source_remove (sheet->motion_timer);
5258 sheet->motion_timer = g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
5264 gtk_widget_get_pointer (widget, &wx, &wy);
5266 if ( gtk_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
5268 if ( row != sheet->hover_window->row || column != sheet->hover_window->column)
5270 gtk_widget_hide (sheet->hover_window->window);
5275 if (event->window == sheet->column_title_window &&
5276 gtk_sheet_columns_resizable (sheet))
5278 gtk_widget_get_pointer (widget, &x, &y);
5279 if (!GTK_SHEET_IN_SELECTION (sheet) &&
5280 POSSIBLE_XDRAG (sheet, x, &column))
5282 new_cursor = GDK_SB_H_DOUBLE_ARROW;
5283 if (new_cursor != sheet->cursor_drag->type)
5285 gdk_cursor_destroy (sheet->cursor_drag);
5286 sheet->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
5287 gdk_window_set_cursor (sheet->column_title_window,
5288 sheet->cursor_drag);
5293 new_cursor = GDK_TOP_LEFT_ARROW;
5294 if (!GTK_SHEET_IN_XDRAG (sheet) &&
5295 new_cursor != sheet->cursor_drag->type)
5297 gdk_cursor_destroy (sheet->cursor_drag);
5298 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5299 gdk_window_set_cursor (sheet->column_title_window,
5300 sheet->cursor_drag);
5305 if (event->window == sheet->row_title_window &&
5306 gtk_sheet_rows_resizable (sheet))
5308 gtk_widget_get_pointer (widget, &x, &y);
5309 if (!GTK_SHEET_IN_SELECTION (sheet) && POSSIBLE_YDRAG (sheet, y, &column))
5311 new_cursor = GDK_SB_V_DOUBLE_ARROW;
5312 if (new_cursor != sheet->cursor_drag->type)
5314 gdk_cursor_destroy (sheet->cursor_drag);
5315 sheet->cursor_drag = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
5316 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5321 new_cursor = GDK_TOP_LEFT_ARROW;
5322 if (!GTK_SHEET_IN_YDRAG (sheet) &&
5323 new_cursor != sheet->cursor_drag->type)
5325 gdk_cursor_destroy (sheet->cursor_drag);
5326 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5327 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5332 new_cursor = GDK_PLUS;
5333 if ( event->window == sheet->sheet_window &&
5334 !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
5335 !GTK_SHEET_IN_DRAG (sheet) &&
5336 !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
5337 !GTK_SHEET_IN_RESIZE (sheet) &&
5338 new_cursor != sheet->cursor_drag->type)
5340 gdk_cursor_destroy (sheet->cursor_drag);
5341 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
5342 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5345 new_cursor = GDK_TOP_LEFT_ARROW;
5346 if ( event->window == sheet->sheet_window &&
5347 ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) || GTK_SHEET_IN_RESIZE (sheet)) && (POSSIBLE_DRAG (sheet, x, y, &row, &column) || GTK_SHEET_IN_DRAG (sheet)) &&
5349 new_cursor != sheet->cursor_drag->type)
5351 gdk_cursor_destroy (sheet->cursor_drag);
5352 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5353 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5356 new_cursor = GDK_SIZING;
5357 if ( event->window == sheet->sheet_window &&
5358 sheet->selection_mode != GTK_SELECTION_NONE &&
5359 !GTK_SHEET_IN_DRAG (sheet) &&
5360 (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
5361 GTK_SHEET_IN_RESIZE (sheet)) &&
5362 new_cursor != sheet->cursor_drag->type)
5364 gdk_cursor_destroy (sheet->cursor_drag);
5365 sheet->cursor_drag = gdk_cursor_new (GDK_SIZING);
5366 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5370 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5371 if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
5373 if (GTK_SHEET_IN_XDRAG (sheet))
5375 if (event->is_hint || event->window != widget->window)
5376 gtk_widget_get_pointer (widget, &x, NULL);
5380 new_column_width (sheet, sheet->drag_cell.col, &x);
5381 if (x != sheet->x_drag)
5383 draw_xor_vline (sheet);
5385 draw_xor_vline (sheet);
5390 if (GTK_SHEET_IN_YDRAG (sheet))
5392 if (event->is_hint || event->window != widget->window)
5393 gtk_widget_get_pointer (widget, NULL, &y);
5397 new_row_height (sheet, sheet->drag_cell.row, &y);
5398 if (y != sheet->y_drag)
5400 draw_xor_hline (sheet);
5402 draw_xor_hline (sheet);
5407 if (GTK_SHEET_IN_DRAG (sheet))
5410 column = COLUMN_FROM_XPIXEL (sheet, x)- sheet->drag_cell.col;
5411 row = ROW_FROM_YPIXEL (sheet, y)- sheet->drag_cell.row;
5412 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5413 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5417 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5418 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5420 aux = sheet->drag_range;
5421 sheet->drag_range.row0 = sheet->range.row0 + row;
5422 sheet->drag_range.col0 = sheet->range.col0 + column;
5423 sheet->drag_range.rowi = sheet->range.rowi + row;
5424 sheet->drag_range.coli = sheet->range.coli + column;
5425 if (aux.row0 != sheet->drag_range.row0 ||
5426 aux.col0 != sheet->drag_range.col0)
5428 draw_xor_rectangle (sheet, aux);
5429 draw_xor_rectangle (sheet, sheet->drag_range);
5435 if (GTK_SHEET_IN_RESIZE (sheet))
5438 gint v_h, current_col, current_row, col_threshold, row_threshold;
5441 if (abs (x - COLUMN_LEFT_XPIXEL (sheet, sheet->drag_cell.col)) >
5442 abs (y - ROW_TOP_YPIXEL (sheet, sheet->drag_cell.row))) v_h = 2;
5444 current_col = COLUMN_FROM_XPIXEL (sheet, x);
5445 current_row = ROW_FROM_YPIXEL (sheet, y);
5446 column = current_col - sheet->drag_cell.col;
5447 row = current_row - sheet->drag_cell.row;
5449 /*use half of column width resp. row height as threshold to
5451 col_threshold = COLUMN_LEFT_XPIXEL (sheet, current_col) +
5452 xxx_column_width (sheet, current_col) / 2;
5455 if (x < col_threshold)
5458 else if (column < 0)
5460 if (x > col_threshold)
5463 row_threshold = ROW_TOP_YPIXEL (sheet, current_row) +
5464 yyy_row_height (sheet, current_row)/2;
5467 if (y < row_threshold)
5472 if (y > row_threshold)
5476 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5477 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5487 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5488 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5490 aux = sheet->drag_range;
5491 sheet->drag_range = sheet->range;
5493 if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
5494 if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
5495 if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
5496 if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
5498 if (aux.row0 != sheet->drag_range.row0 ||
5499 aux.rowi != sheet->drag_range.rowi ||
5500 aux.col0 != sheet->drag_range.col0 ||
5501 aux.coli != sheet->drag_range.coli)
5503 draw_xor_rectangle (sheet, aux);
5504 draw_xor_rectangle (sheet, sheet->drag_range);
5510 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5512 if (sheet->state == GTK_SHEET_NORMAL && row == sheet->active_cell.row &&
5513 column == sheet->active_cell.col) return TRUE;
5515 if (GTK_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
5516 gtk_sheet_extend_selection (sheet, row, column);
5522 gtk_sheet_move_query (GtkSheet *sheet, gint row, gint column)
5524 gint row_move, column_move;
5525 gfloat row_align, col_align;
5526 guint height, width;
5528 gint new_col = column;
5531 column_move = FALSE;
5535 height = sheet->sheet_window_height;
5536 width = sheet->sheet_window_width;
5538 if (row >= MAX_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5541 new_row = MIN (yyy_row_count (sheet) - 1, row + 1);
5543 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet) - 1 &&
5544 ROW_TOP_YPIXEL (sheet, yyy_row_count (sheet)- 1) +
5545 yyy_row_height (sheet, yyy_row_count (sheet)- 1) < height)
5551 if (row < MIN_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5556 if (column >= MAX_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5559 new_col = MIN (xxx_column_count (sheet) - 1, column + 1);
5561 if (MAX_VISIBLE_COLUMN (sheet) == (xxx_column_count (sheet) - 1) &&
5562 COLUMN_LEFT_XPIXEL (sheet, xxx_column_count (sheet) - 1) +
5563 xxx_column_width (sheet, xxx_column_count (sheet) - 1) < width)
5565 column_move = FALSE;
5569 if (column < MIN_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5575 if (row_move || column_move)
5577 gtk_sheet_moveto (sheet, new_row, new_col, row_align, col_align);
5580 return (row_move || column_move);
5584 gtk_sheet_extend_selection (GtkSheet *sheet, gint row, gint column)
5586 GtkSheetRange range;
5590 if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5593 if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5595 gtk_sheet_move_query (sheet, row, column);
5596 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5598 if (GTK_SHEET_IN_DRAG (sheet)) return;
5600 state = sheet->state;
5602 switch (sheet->state)
5604 case GTK_SHEET_ROW_SELECTED:
5605 column = xxx_column_count (sheet) - 1;
5607 case GTK_SHEET_COLUMN_SELECTED:
5608 row = yyy_row_count (sheet) - 1;
5610 case GTK_SHEET_NORMAL:
5611 sheet->state = GTK_SHEET_RANGE_SELECTED;
5612 r = sheet->active_cell.row;
5613 c = sheet->active_cell.col;
5614 sheet->range.col0 = c;
5615 sheet->range.row0 = r;
5616 sheet->range.coli = c;
5617 sheet->range.rowi = r;
5618 gdk_draw_pixmap (sheet->sheet_window,
5619 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
5621 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5622 ROW_TOP_YPIXEL (sheet, r)- 1,
5623 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5624 ROW_TOP_YPIXEL (sheet, r)- 1,
5625 xxx_column_width (sheet, c)+4,
5626 yyy_row_height (sheet, r)+4);
5627 gtk_sheet_range_draw_selection (sheet, sheet->range);
5628 case GTK_SHEET_RANGE_SELECTED:
5629 sheet->state = GTK_SHEET_RANGE_SELECTED;
5632 sheet->selection_cell.row = row;
5633 sheet->selection_cell.col = column;
5635 range.col0 = MIN (column, sheet->active_cell.col);
5636 range.coli = MAX (column, sheet->active_cell.col);
5637 range.row0 = MIN (row, sheet->active_cell.row);
5638 range.rowi = MAX (row, sheet->active_cell.row);
5640 if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5641 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5642 state == GTK_SHEET_NORMAL)
5643 gtk_sheet_real_select_range (sheet, &range);
5648 gtk_sheet_entry_key_press (GtkWidget *widget,
5652 g_signal_emit_by_name (G_OBJECT (widget), "key_press_event", key, &focus);
5657 gtk_sheet_key_press (GtkWidget *widget,
5663 gboolean extend_selection = FALSE;
5664 gboolean force_move = FALSE;
5665 gboolean in_selection = FALSE;
5666 gboolean veto = TRUE;
5669 sheet = GTK_SHEET (widget);
5671 if (key->state & GDK_CONTROL_MASK || key->keyval == GDK_Control_L ||
5672 key->keyval == GDK_Control_R) return FALSE;
5674 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval == GDK_Shift_L
5675 || key->keyval == GDK_Shift_R;
5677 state = sheet->state;
5678 in_selection = GTK_SHEET_IN_SELECTION (sheet);
5679 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5681 switch (key->keyval)
5683 case GDK_Return: case GDK_KP_Enter:
5684 if (sheet->state == GTK_SHEET_NORMAL &&
5685 !GTK_SHEET_IN_SELECTION (sheet))
5686 g_signal_stop_emission_by_name (gtk_sheet_get_entry (sheet),
5688 row = sheet->active_cell.row;
5689 col = sheet->active_cell.col;
5690 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5691 row = MIN_VISIBLE_ROW (sheet)- 1;
5692 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5693 col = MIN_VISIBLE_COLUMN (sheet);
5694 if (row < yyy_row_count (sheet) - 1)
5697 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1)
5700 gtk_sheet_click_cell (sheet, row, col, &veto);
5701 extend_selection = FALSE;
5703 case GDK_ISO_Left_Tab:
5704 row = sheet->active_cell.row;
5705 col = sheet->active_cell.col;
5706 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5707 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5708 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5709 row = MIN_VISIBLE_ROW (sheet);
5713 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5716 gtk_sheet_click_cell (sheet, row, col, &veto);
5717 extend_selection = FALSE;
5720 row = sheet->active_cell.row;
5721 col = sheet->active_cell.col;
5722 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5723 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5724 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5725 row = MIN_VISIBLE_ROW (sheet);
5726 if (col < xxx_column_count (sheet) - 1)
5729 while (! xxx_column_is_visible (sheet, col) &&
5730 col < xxx_column_count (sheet) - 1)
5733 gtk_sheet_click_cell (sheet, row, col, &veto);
5734 extend_selection = FALSE;
5737 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5739 if (extend_selection)
5741 if (state == GTK_STATE_NORMAL)
5743 row = sheet->active_cell.row;
5744 col = sheet->active_cell.col;
5745 gtk_sheet_click_cell (sheet, row, col, &veto);
5748 if (sheet->selection_cell.row > 0)
5750 row = sheet->selection_cell.row - scroll;
5751 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5753 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5757 col = sheet->active_cell.col;
5758 row = sheet->active_cell.row;
5759 if (state == GTK_SHEET_COLUMN_SELECTED)
5760 row = MIN_VISIBLE_ROW (sheet);
5761 if (state == GTK_SHEET_ROW_SELECTED)
5762 col = MIN_VISIBLE_COLUMN (sheet);
5764 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5766 gtk_sheet_click_cell (sheet, row, col, &veto);
5767 extend_selection = FALSE;
5770 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5772 if (extend_selection)
5774 if (state == GTK_STATE_NORMAL)
5776 row = sheet->active_cell.row;
5777 col = sheet->active_cell.col;
5778 gtk_sheet_click_cell (sheet, row, col, &veto);
5781 if (sheet->selection_cell.row < yyy_row_count (sheet)- 1)
5783 row = sheet->selection_cell.row + scroll;
5784 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5785 row = MIN (yyy_row_count (sheet)- 1, row);
5786 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5790 col = sheet->active_cell.col;
5791 row = sheet->active_cell.row;
5792 if (sheet->active_cell.row < yyy_row_count (sheet)- 1)
5794 if (state == GTK_SHEET_COLUMN_SELECTED)
5795 row = MIN_VISIBLE_ROW (sheet)- 1;
5796 if (state == GTK_SHEET_ROW_SELECTED)
5797 col = MIN_VISIBLE_COLUMN (sheet);
5799 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5800 row = MIN (yyy_row_count (sheet)- 1, row);
5802 gtk_sheet_click_cell (sheet, row, col, &veto);
5803 extend_selection = FALSE;
5806 if (extend_selection)
5808 if (state == GTK_STATE_NORMAL)
5810 row = sheet->active_cell.row;
5811 col = sheet->active_cell.col;
5812 gtk_sheet_click_cell (sheet, row, col, &veto);
5815 if (sheet->selection_cell.col < xxx_column_count (sheet) - 1)
5817 col = sheet->selection_cell.col + 1;
5818 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1)
5820 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5824 col = sheet->active_cell.col;
5825 row = sheet->active_cell.row;
5826 if (sheet->active_cell.col < xxx_column_count (sheet) - 1)
5829 if (state == GTK_SHEET_ROW_SELECTED)
5830 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5831 if (state == GTK_SHEET_COLUMN_SELECTED)
5832 row = MIN_VISIBLE_ROW (sheet);
5833 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1) col++;
5834 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5837 gtk_sheet_click_cell (sheet, row, col, &veto);
5842 extend_selection = FALSE;
5845 if (extend_selection)
5847 if (state == GTK_STATE_NORMAL)
5849 row = sheet->active_cell.row;
5850 col = sheet->active_cell.col;
5851 gtk_sheet_click_cell (sheet, row, col, &veto);
5854 if (sheet->selection_cell.col > 0)
5856 col = sheet->selection_cell.col - 1;
5857 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5858 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5862 col = sheet->active_cell.col - 1;
5863 row = sheet->active_cell.row;
5864 if (state == GTK_SHEET_ROW_SELECTED)
5865 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5866 if (state == GTK_SHEET_COLUMN_SELECTED)
5867 row = MIN_VISIBLE_ROW (sheet);
5868 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5871 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5874 gtk_sheet_click_cell (sheet, row, col, &veto);
5878 extend_selection = FALSE;
5882 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet) - 1) row++;
5883 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5884 extend_selection = FALSE;
5887 row = yyy_row_count (sheet) - 1;
5888 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5889 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5890 extend_selection = FALSE;
5895 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5896 if (extend_selection) return TRUE;
5898 if (state == GTK_SHEET_ROW_SELECTED)
5899 sheet->active_cell.col = MIN_VISIBLE_COLUMN (sheet);
5900 if (state == GTK_SHEET_COLUMN_SELECTED)
5901 sheet->active_cell.row = MIN_VISIBLE_ROW (sheet);
5905 if (extend_selection) return TRUE;
5907 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5908 sheet->active_cell.col);
5914 gtk_sheet_size_request (GtkWidget * widget,
5915 GtkRequisition * requisition)
5919 GtkSheetChild *child;
5920 GtkRequisition child_requisition;
5922 g_return_if_fail (widget != NULL);
5923 g_return_if_fail (GTK_IS_SHEET (widget));
5924 g_return_if_fail (requisition != NULL);
5926 sheet = GTK_SHEET (widget);
5928 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5929 requisition->height = 3*DEFAULT_ROW_HEIGHT (widget);
5931 /* compute the size of the column title area */
5932 if (sheet->column_titles_visible)
5933 requisition->height += sheet->column_title_area.height;
5935 /* compute the size of the row title area */
5936 if (sheet->row_titles_visible)
5937 requisition->width += sheet->row_title_area.width;
5939 children = sheet->children;
5942 child = children->data;
5943 children = children->next;
5945 gtk_widget_size_request (child->widget, &child_requisition);
5951 gtk_sheet_size_allocate (GtkWidget * widget,
5952 GtkAllocation * allocation)
5955 GtkAllocation sheet_allocation;
5958 g_return_if_fail (widget != NULL);
5959 g_return_if_fail (GTK_IS_SHEET (widget));
5960 g_return_if_fail (allocation != NULL);
5962 sheet = GTK_SHEET (widget);
5963 widget->allocation = *allocation;
5964 border_width = GTK_CONTAINER (widget)->border_width;
5966 if (GTK_WIDGET_REALIZED (widget))
5967 gdk_window_move_resize (widget->window,
5968 allocation->x + border_width,
5969 allocation->y + border_width,
5970 allocation->width - 2 * border_width,
5971 allocation->height - 2 * border_width);
5973 /* use internal allocation structure for all the math
5974 * because it's easier than always subtracting the container
5976 sheet->internal_allocation.x = 0;
5977 sheet->internal_allocation.y = 0;
5978 sheet->internal_allocation.width = allocation->width - 2 * border_width;
5979 sheet->internal_allocation.height = allocation->height - 2 * border_width;
5981 sheet_allocation.x = 0;
5982 sheet_allocation.y = 0;
5983 sheet_allocation.width = allocation->width - 2 * border_width;
5984 sheet_allocation.height = allocation->height - 2 * border_width;
5986 sheet->sheet_window_width = sheet_allocation.width;
5987 sheet->sheet_window_height = sheet_allocation.height;
5989 if (GTK_WIDGET_REALIZED (widget))
5990 gdk_window_move_resize (sheet->sheet_window,
5993 sheet_allocation.width,
5994 sheet_allocation.height);
5996 /* position the window which holds the column title buttons */
5997 sheet->column_title_area.x = 0;
5998 sheet->column_title_area.y = 0;
5999 if (sheet->row_titles_visible)
6000 sheet->column_title_area.x = sheet->row_title_area.width;
6001 sheet->column_title_area.width = sheet_allocation.width -
6002 sheet->column_title_area.x;
6003 if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
6004 gdk_window_move_resize (sheet->column_title_window,
6005 sheet->column_title_area.x,
6006 sheet->column_title_area.y,
6007 sheet->column_title_area.width,
6008 sheet->column_title_area.height);
6010 sheet->sheet_window_width = sheet_allocation.width;
6011 sheet->sheet_window_height = sheet_allocation.height;
6013 /* column button allocation */
6014 size_allocate_column_title_buttons (sheet);
6016 /* position the window which holds the row title buttons */
6017 sheet->row_title_area.x = 0;
6018 sheet->row_title_area.y = 0;
6019 if (sheet->column_titles_visible)
6020 sheet->row_title_area.y = sheet->column_title_area.height;
6021 sheet->row_title_area.height = sheet_allocation.height -
6022 sheet->row_title_area.y;
6024 if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
6025 gdk_window_move_resize (sheet->row_title_window,
6026 sheet->row_title_area.x,
6027 sheet->row_title_area.y,
6028 sheet->row_title_area.width,
6029 sheet->row_title_area.height);
6032 /* row button allocation */
6033 size_allocate_row_title_buttons (sheet);
6034 size_allocate_column_title_buttons (sheet);
6036 /* re - scale backing pixmap */
6037 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
6038 gtk_sheet_position_children (sheet);
6040 /* set the scrollbars adjustments */
6041 adjust_scrollbars (sheet);
6045 size_allocate_column_title_buttons (GtkSheet * sheet)
6050 if (!sheet->column_titles_visible) return;
6051 if (!GTK_WIDGET_REALIZED (sheet))
6054 width = sheet->sheet_window_width;
6057 if (sheet->row_titles_visible)
6059 width -= sheet->row_title_area.width;
6060 x = sheet->row_title_area.width;
6063 if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6065 sheet->column_title_area.width = width;
6066 sheet->column_title_area.x = x;
6067 gdk_window_move_resize (sheet->column_title_window,
6068 sheet->column_title_area.x,
6069 sheet->column_title_area.y,
6070 sheet->column_title_area.width,
6071 sheet->column_title_area.height);
6075 if (MAX_VISIBLE_COLUMN (sheet) == xxx_column_count (sheet) - 1)
6076 gdk_window_clear_area (sheet->column_title_window,
6078 sheet->column_title_area.width,
6079 sheet->column_title_area.height);
6081 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6083 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
6084 gtk_sheet_column_title_button_draw (sheet, i);
6088 size_allocate_row_title_buttons (GtkSheet * sheet)
6093 if (!sheet->row_titles_visible) return;
6094 if (!GTK_WIDGET_REALIZED (sheet))
6097 height = sheet->sheet_window_height;
6100 if (sheet->column_titles_visible)
6102 height -= sheet->column_title_area.height;
6103 y = sheet->column_title_area.height;
6106 if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6108 sheet->row_title_area.y = y;
6109 sheet->row_title_area.height = height;
6110 gdk_window_move_resize (sheet->row_title_window,
6111 sheet->row_title_area.x,
6112 sheet->row_title_area.y,
6113 sheet->row_title_area.width,
6114 sheet->row_title_area.height);
6116 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet)- 1)
6117 gdk_window_clear_area (sheet->row_title_window,
6119 sheet->row_title_area.width,
6120 sheet->row_title_area.height);
6122 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6124 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
6126 if ( i >= yyy_row_count (sheet))
6128 gtk_sheet_row_title_button_draw (sheet, i);
6134 gtk_sheet_size_allocate_entry (GtkSheet *sheet)
6136 GtkAllocation shentry_allocation;
6137 GtkSheetCellAttr attributes = { 0 };
6138 GtkEntry *sheet_entry;
6139 GtkStyle *style = NULL, *previous_style = NULL;
6141 gint size, max_size, text_size, column_width;
6144 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6145 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
6147 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
6149 if ( ! gtk_sheet_get_attributes (sheet, sheet->active_cell.row,
6150 sheet->active_cell.col,
6154 if ( GTK_WIDGET_REALIZED (sheet->sheet_entry) )
6156 if (!GTK_WIDGET (sheet_entry)->style)
6157 gtk_widget_ensure_style (GTK_WIDGET (sheet_entry));
6159 previous_style = GTK_WIDGET (sheet_entry)->style;
6161 style = gtk_style_copy (previous_style);
6162 style->bg[GTK_STATE_NORMAL] = attributes.background;
6163 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6164 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6165 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6166 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6167 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6169 pango_font_description_free (style->font_desc);
6170 g_assert (attributes.font_desc);
6171 style->font_desc = pango_font_description_copy (attributes.font_desc);
6173 GTK_WIDGET (sheet_entry)->style = style;
6174 gtk_widget_size_request (sheet->sheet_entry, NULL);
6175 GTK_WIDGET (sheet_entry)->style = previous_style;
6177 if (style != previous_style)
6179 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6181 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6182 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6183 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6184 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6186 gtk_widget_set_style (GTK_WIDGET (sheet_entry), style);
6187 g_object_unref (style);
6191 if (GTK_IS_ITEM_ENTRY (sheet_entry))
6192 max_size = GTK_ITEM_ENTRY (sheet_entry)->text_max_size;
6197 text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
6198 if (text && strlen (text) > 0)
6199 text_size = STRING_WIDTH (GTK_WIDGET (sheet), attributes.font_desc, text);
6201 column_width = xxx_column_width (sheet, sheet->active_cell.col);
6203 size = MIN (text_size, max_size);
6204 size = MAX (size, column_width - 2 * CELLOFFSET);
6206 row = sheet->active_cell.row;
6207 col = sheet->active_cell.col;
6209 shentry_allocation.x = COLUMN_LEFT_XPIXEL (sheet, sheet->active_cell.col);
6210 shentry_allocation.y = ROW_TOP_YPIXEL (sheet, sheet->active_cell.row);
6211 shentry_allocation.width = column_width;
6212 shentry_allocation.height = yyy_row_height (sheet, sheet->active_cell.row);
6214 if (GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6216 shentry_allocation.height -= 2 * CELLOFFSET;
6217 shentry_allocation.y += CELLOFFSET;
6218 shentry_allocation.width = size;
6220 switch (GTK_ITEM_ENTRY (sheet_entry)->justification)
6222 case GTK_JUSTIFY_CENTER:
6223 shentry_allocation.x += column_width / 2 - size / 2;
6225 case GTK_JUSTIFY_RIGHT:
6226 shentry_allocation.x += column_width - size - CELLOFFSET;
6228 case GTK_JUSTIFY_LEFT:
6229 case GTK_JUSTIFY_FILL:
6230 shentry_allocation.x += CELLOFFSET;
6235 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6237 shentry_allocation.x += 2;
6238 shentry_allocation.y += 2;
6239 shentry_allocation.width -= MIN (shentry_allocation.width, 3);
6240 shentry_allocation.height -= MIN (shentry_allocation.height, 3);
6243 gtk_widget_size_allocate (sheet->sheet_entry, &shentry_allocation);
6245 if (previous_style == style) g_object_unref (previous_style);
6249 gtk_sheet_entry_set_max_size (GtkSheet *sheet)
6253 gint sizel = 0, sizer = 0;
6255 GtkJustification justification;
6258 row = sheet->active_cell.row;
6259 col = sheet->active_cell.col;
6261 if ( ! GTK_IS_ITEM_ENTRY (sheet->sheet_entry) )
6264 justification = GTK_ITEM_ENTRY (sheet->sheet_entry)->justification;
6266 switch (justification)
6268 case GTK_JUSTIFY_FILL:
6269 case GTK_JUSTIFY_LEFT:
6270 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6272 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6277 size +=xxx_column_width (sheet, i);
6279 size = MIN (size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL (sheet, col));
6281 case GTK_JUSTIFY_RIGHT:
6282 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6284 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6289 size +=xxx_column_width (sheet, i);
6292 case GTK_JUSTIFY_CENTER:
6293 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6295 sizer += xxx_column_width (sheet, i);
6297 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6299 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6304 sizel +=xxx_column_width (sheet, i);
6306 size = 2 * MIN (sizel, sizer);
6311 size += xxx_column_width (sheet, col);
6312 GTK_ITEM_ENTRY (sheet->sheet_entry)->text_max_size = size;
6317 create_sheet_entry (GtkSheet *sheet)
6322 gint found_entry = FALSE;
6324 widget = GTK_WIDGET (sheet);
6326 if (sheet->sheet_entry)
6328 /* avoids warnings */
6329 gtk_widget_ref (sheet->sheet_entry);
6330 gtk_widget_unparent (sheet->sheet_entry);
6331 gtk_widget_destroy (sheet->sheet_entry);
6334 if (sheet->entry_type)
6336 if (!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY))
6338 parent = g_object_new (sheet->entry_type, NULL);
6340 sheet->sheet_entry = parent;
6342 entry = gtk_sheet_get_entry (sheet);
6343 if (GTK_IS_ENTRY (entry))
6348 parent = g_object_new (sheet->entry_type, NULL);
6355 g_warning ("Entry type must be GtkEntry subclass, using default");
6356 entry = gtk_item_entry_new ();
6357 sheet->sheet_entry = entry;
6360 sheet->sheet_entry = parent;
6364 entry = gtk_item_entry_new ();
6365 sheet->sheet_entry = entry;
6368 gtk_widget_size_request (sheet->sheet_entry, NULL);
6370 if (GTK_WIDGET_REALIZED (sheet))
6372 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6373 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
6374 gtk_widget_realize (sheet->sheet_entry);
6377 g_signal_connect_swapped (G_OBJECT (entry), "key_press_event",
6378 G_CALLBACK (gtk_sheet_entry_key_press),
6381 gtk_widget_show (sheet->sheet_entry);
6385 /* Finds the last child widget that happens to be of type GtkEntry */
6387 find_entry (GtkWidget *w, gpointer user_data)
6389 GtkWidget **entry = user_data;
6390 if ( GTK_IS_ENTRY (w))
6397 gtk_sheet_get_entry (GtkSheet *sheet)
6400 GtkWidget *entry = NULL;
6401 GtkTableChild *table_child;
6402 GtkBoxChild *box_child;
6403 GList *children = NULL;
6405 g_return_val_if_fail (sheet != NULL, NULL);
6406 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6407 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6409 if (GTK_IS_ENTRY (sheet->sheet_entry)) return (sheet->sheet_entry);
6411 parent = GTK_WIDGET (sheet->sheet_entry);
6413 if (GTK_IS_TABLE (parent)) children = GTK_TABLE (parent)->children;
6414 if (GTK_IS_BOX (parent)) children = GTK_BOX (parent)->children;
6416 if (GTK_IS_CONTAINER (parent))
6418 gtk_container_forall (GTK_CONTAINER (parent), find_entry, &entry);
6420 if (GTK_IS_ENTRY (entry))
6424 if (!children) return NULL;
6428 if (GTK_IS_TABLE (parent))
6430 table_child = children->data;
6431 entry = table_child->widget;
6433 if (GTK_IS_BOX (parent))
6435 box_child = children->data;
6436 entry = box_child->widget;
6439 if (GTK_IS_ENTRY (entry))
6441 children = children->next;
6445 if (!GTK_IS_ENTRY (entry)) return NULL;
6452 gtk_sheet_get_entry_widget (GtkSheet *sheet)
6454 g_return_val_if_fail (sheet != NULL, NULL);
6455 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6456 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6458 return (sheet->sheet_entry);
6463 gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
6464 GtkSheetButton *button, gboolean is_sensitive,
6465 GdkRectangle allocation)
6467 GtkShadowType shadow_type;
6468 gint text_width = 0, text_height = 0;
6469 GtkSheetChild *child = NULL;
6470 PangoAlignment align = PANGO_ALIGN_LEFT;
6478 g_return_if_fail (sheet != NULL);
6479 g_return_if_fail (button != NULL);
6481 rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
6483 gdk_window_clear_area (window,
6484 allocation.x, allocation.y,
6485 allocation.width, allocation.height);
6487 gtk_paint_box (sheet->button->style, window,
6488 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6489 &allocation, GTK_WIDGET (sheet->button),
6491 allocation.x, allocation.y,
6492 allocation.width, allocation.height);
6494 state = button->state;
6495 if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
6497 if (state == GTK_STATE_ACTIVE)
6498 shadow_type = GTK_SHADOW_IN;
6500 shadow_type = GTK_SHADOW_OUT;
6502 if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6503 gtk_paint_box (sheet->button->style, window,
6504 button->state, shadow_type,
6505 &allocation, GTK_WIDGET (sheet->button),
6507 allocation.x, allocation.y,
6508 allocation.width, allocation.height);
6510 if (button->label_visible)
6513 text_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))- 2 * CELLOFFSET;
6515 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6517 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, &allocation);
6519 allocation.y += 2 * sheet->button->style->ythickness;
6522 if (button->label && strlen (button->label)>0)
6525 PangoLayout *layout = NULL;
6526 gint real_x = allocation.x, real_y = allocation.y;
6528 words = button->label;
6529 line = g_new (gchar, 1);
6532 while (words && *words != '\0')
6536 len = strlen (line);
6537 line = g_realloc (line, len + 2);
6541 if (*words == '\n' || * (words + 1) == '\0')
6543 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
6545 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
6546 switch (button->justification)
6548 case GTK_JUSTIFY_LEFT:
6549 real_x = allocation.x + CELLOFFSET;
6550 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6552 case GTK_JUSTIFY_RIGHT:
6553 real_x = allocation.x + allocation.width - text_width - CELLOFFSET;
6554 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6556 case GTK_JUSTIFY_CENTER:
6558 real_x = allocation.x + (allocation.width - text_width)/2;
6559 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6560 pango_layout_set_justify (layout, TRUE);
6562 pango_layout_set_alignment (layout, align);
6563 gtk_paint_layout (GTK_WIDGET (sheet)->style,
6572 g_object_unref (G_OBJECT (layout));
6574 real_y += text_height + 2;
6577 line = g_new (gchar, 1);
6585 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6587 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
6591 if ((child = button->child) && (child->widget))
6593 child->x = allocation.x;
6594 child->y = allocation.y;
6596 child->x += (allocation.width - child->widget->requisition.width) / 2;
6597 child->y += (allocation.height - child->widget->requisition.height) / 2;
6598 allocation.x = child->x;
6599 allocation.y = child->y;
6600 allocation.width = child->widget->requisition.width;
6601 allocation.height = child->widget->requisition.height;
6603 allocation.x = child->x;
6604 allocation.y = child->y;
6606 gtk_widget_set_state (child->widget, button->state);
6608 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
6609 GTK_WIDGET_MAPPED (child->widget))
6611 gtk_widget_size_allocate (child->widget,
6613 gtk_widget_queue_draw (child->widget);
6617 gtk_sheet_button_free (button);
6621 /* COLUMN value of - 1 indicates that the area to the right of the rightmost
6622 button should be redrawn */
6624 gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
6626 GdkWindow *window = NULL;
6627 GdkRectangle allocation;
6629 gboolean is_sensitive = FALSE;
6631 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6633 if (column >= 0 && ! xxx_column_is_visible (sheet, column)) return;
6634 if (column >= 0 && !sheet->column_titles_visible) return;
6635 if (column >= 0 && column < MIN_VISIBLE_COLUMN (sheet)) return;
6636 if (column >= 0 && column > MAX_VISIBLE_COLUMN (sheet)) return;
6638 window = sheet->column_title_window;
6640 allocation.height = sheet->column_title_area.height;
6644 const gint cols = xxx_column_count (sheet) ;
6645 allocation.x = COLUMN_LEFT_XPIXEL (sheet, cols - 1)
6647 allocation.width = sheet->column_title_area.width
6648 + sheet->column_title_area.x
6651 gdk_window_clear_area (window,
6652 allocation.x, allocation.y,
6653 allocation.width, allocation.height);
6657 GtkSheetButton *button = xxx_column_button (sheet, column);
6658 allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
6659 if (sheet->row_titles_visible)
6660 allocation.x -= sheet->row_title_area.width;
6662 allocation.width = xxx_column_width (sheet, column);
6664 is_sensitive = xxx_column_is_sensitive (sheet, column);
6665 gtk_sheet_button_draw (sheet, window, button,
6666 is_sensitive, allocation);
6668 /* FIXME: Not freeing this button is correct (sort of),
6669 because in PSPP the model always returns a static copy */
6671 /* gtk_sheet_button_free (button); */
6677 gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
6679 GdkWindow *window = NULL;
6680 GdkRectangle allocation;
6681 GtkSheetButton *button = NULL;
6682 gboolean is_sensitive = FALSE;
6685 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6687 if (row >= 0 && !yyy_row_is_visible (sheet, row)) return;
6688 if (row >= 0 && !sheet->row_titles_visible) return;
6689 if (row >= 0 && row < MIN_VISIBLE_ROW (sheet)) return;
6690 if (row >= 0 && row > MAX_VISIBLE_ROW (sheet)) return;
6693 window = sheet->row_title_window;
6694 button = yyy_row_button (sheet, row);
6696 allocation.y = ROW_TOP_YPIXEL (sheet, row) + CELL_SPACING;
6697 if (sheet->column_titles_visible)
6698 allocation.y -= sheet->column_title_area.height;
6699 allocation.width = sheet->row_title_area.width;
6700 allocation.height = yyy_row_height (sheet, row);
6701 is_sensitive = yyy_row_is_sensitive (sheet, row);
6703 gtk_sheet_button_draw (sheet, window, button, is_sensitive, allocation);
6710 * vadjustment_value_changed
6711 * hadjustment_value_changed */
6714 adjust_scrollbars (GtkSheet * sheet)
6716 if (sheet->vadjustment)
6718 sheet->vadjustment->page_size = sheet->sheet_window_height;
6719 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6720 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
6721 sheet->vadjustment->lower = 0;
6722 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6723 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "changed");
6727 if (sheet->hadjustment)
6729 sheet->hadjustment->page_size = sheet->sheet_window_width;
6730 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6731 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6732 sheet->hadjustment->lower = 0;
6733 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6734 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "changed");
6740 vadjustment_value_changed (GtkAdjustment * adjustment,
6744 gint diff, value, old_value;
6748 g_return_if_fail (adjustment != NULL);
6749 g_return_if_fail (data != NULL);
6750 g_return_if_fail (GTK_IS_SHEET (data));
6752 sheet = GTK_SHEET (data);
6754 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6756 row = ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + CELL_SPACING);
6757 if (!sheet->column_titles_visible)
6758 row = ROW_FROM_YPIXEL (sheet, CELL_SPACING);
6760 old_value = - sheet->voffset;
6762 new_row = g_sheet_row_pixel_to_row (sheet->row_geometry,
6763 adjustment->value, sheet);
6765 y = g_sheet_row_start_pixel (sheet->row_geometry, new_row, sheet);
6767 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6768 yyy_row_height (sheet, row) > sheet->vadjustment->step_increment)
6770 /* This avoids embarrassing twitching */
6771 if (row == new_row && row != yyy_row_count (sheet) - 1 &&
6772 adjustment->value - sheet->old_vadjustment >=
6773 sheet->vadjustment->step_increment &&
6774 new_row + 1 != MIN_VISIBLE_ROW (sheet))
6777 y = y+yyy_row_height (sheet, row);
6781 /* Negative old_adjustment enforces the redraw, otherwise avoid
6783 if (sheet->old_vadjustment >= 0. && row == new_row)
6785 sheet->old_vadjustment = sheet->vadjustment->value;
6789 sheet->old_vadjustment = sheet->vadjustment->value;
6790 adjustment->value = y;
6795 sheet->vadjustment->step_increment = yyy_row_height (sheet, 0);
6799 sheet->vadjustment->step_increment =
6800 MIN (yyy_row_height (sheet, new_row), yyy_row_height (sheet, new_row - 1));
6803 sheet->vadjustment->value = adjustment->value;
6805 value = adjustment->value;
6807 if (value >= - sheet->voffset)
6810 diff = value + sheet->voffset;
6815 diff = - sheet->voffset - value;
6818 sheet->voffset = - value;
6820 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
6821 sheet->state == GTK_SHEET_NORMAL &&
6822 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6823 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
6824 sheet->active_cell.col))
6828 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
6830 if (!text || strlen (text) == 0)
6831 gtk_sheet_cell_clear (sheet,
6832 sheet->active_cell.row,
6833 sheet->active_cell.col);
6834 gtk_widget_unmap (sheet->sheet_entry);
6837 gtk_sheet_position_children (sheet);
6839 gtk_sheet_range_draw (sheet, NULL);
6840 size_allocate_row_title_buttons (sheet);
6841 size_allocate_global_button (sheet);
6845 hadjustment_value_changed (GtkAdjustment * adjustment,
6849 gint i, diff, value, old_value;
6850 gint column, new_column;
6853 g_return_if_fail (adjustment != NULL);
6854 g_return_if_fail (data != NULL);
6855 g_return_if_fail (GTK_IS_SHEET (data));
6857 sheet = GTK_SHEET (data);
6859 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6861 column = COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + CELL_SPACING);
6862 if (!sheet->row_titles_visible)
6863 column = COLUMN_FROM_XPIXEL (sheet, CELL_SPACING);
6865 old_value = - sheet->hoffset;
6867 for (i = 0; i < xxx_column_count (sheet); i++)
6869 if (xxx_column_is_visible (sheet, i)) x += xxx_column_width (sheet, i);
6870 if (x > adjustment->value) break;
6872 x -= xxx_column_width (sheet, i);
6875 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6876 xxx_column_width (sheet, i) > sheet->hadjustment->step_increment)
6878 /* This avoids embarrassing twitching */
6879 if (column == new_column && column != xxx_column_count (sheet) - 1 &&
6880 adjustment->value - sheet->old_hadjustment >=
6881 sheet->hadjustment->step_increment &&
6882 new_column + 1 != MIN_VISIBLE_COLUMN (sheet))
6885 x += xxx_column_width (sheet, column);
6889 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6890 if (sheet->old_hadjustment >= 0. && new_column == column)
6892 sheet->old_hadjustment = sheet->hadjustment->value;
6896 sheet->old_hadjustment = sheet->hadjustment->value;
6897 adjustment->value = x;
6899 if (new_column == 0)
6901 sheet->hadjustment->step_increment = xxx_column_width (sheet, 0);
6905 sheet->hadjustment->step_increment =
6906 MIN (xxx_column_width (sheet, new_column), xxx_column_width (sheet, new_column - 1));
6910 sheet->hadjustment->value = adjustment->value;
6912 value = adjustment->value;
6914 if (value >= - sheet->hoffset)
6917 diff = value + sheet->hoffset;
6922 diff = - sheet->hoffset - value;
6925 sheet->hoffset = - value;
6926 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
6927 sheet->state == GTK_SHEET_NORMAL &&
6928 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6929 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
6930 sheet->active_cell.col))
6934 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
6935 if (!text || strlen (text) == 0)
6936 gtk_sheet_cell_clear (sheet,
6937 sheet->active_cell.row,
6938 sheet->active_cell.col);
6940 gtk_widget_unmap (sheet->sheet_entry);
6943 gtk_sheet_position_children (sheet);
6945 gtk_sheet_range_draw (sheet, NULL);
6946 size_allocate_column_title_buttons (sheet);
6950 /* COLUMN RESIZING */
6952 draw_xor_vline (GtkSheet * sheet)
6956 g_return_if_fail (sheet != NULL);
6958 widget = GTK_WIDGET (sheet);
6960 gdk_draw_line (widget->window, sheet->xor_gc,
6962 sheet->column_title_area.height,
6964 sheet->sheet_window_height + 1);
6969 draw_xor_hline (GtkSheet * sheet)
6973 g_return_if_fail (sheet != NULL);
6975 widget = GTK_WIDGET (sheet);
6977 gdk_draw_line (widget->window, sheet->xor_gc,
6978 sheet->row_title_area.width,
6981 sheet->sheet_window_width + 1,
6985 /* SELECTED RANGE */
6987 draw_xor_rectangle (GtkSheet *sheet, GtkSheetRange range)
6990 GdkRectangle clip_area, area;
6993 area.x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
6994 area.y = ROW_TOP_YPIXEL (sheet, range.row0);
6995 area.width = COLUMN_LEFT_XPIXEL (sheet, range.coli)- area.x+
6996 xxx_column_width (sheet, range.coli);
6997 area.height = ROW_TOP_YPIXEL (sheet, range.rowi)- area.y+
6998 yyy_row_height (sheet, range.rowi);
7000 clip_area.x = sheet->row_title_area.width;
7001 clip_area.y = sheet->column_title_area.height;
7002 clip_area.width = sheet->sheet_window_width;
7003 clip_area.height = sheet->sheet_window_height;
7005 if (!sheet->row_titles_visible) clip_area.x = 0;
7006 if (!sheet->column_titles_visible) clip_area.y = 0;
7010 area.width = area.width + area.x;
7013 if (area.width > clip_area.width) area.width = clip_area.width + 10;
7016 area.height = area.height + area.y;
7019 if (area.height > clip_area.height) area.height = clip_area.height + 10;
7023 clip_area.width += 3;
7024 clip_area.height += 3;
7026 gdk_gc_get_values (sheet->xor_gc, &values);
7028 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
7030 for (i =- 1; i <= 1; ++i)
7031 gdk_draw_rectangle (sheet->sheet_window,
7034 area.x + i, area.y + i,
7035 area.width - 2 * i, area.height - 2 * i);
7038 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
7040 gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
7045 /* this function returns the new width of the column being resized given
7046 * the column and x position of the cursor; the x cursor position is passed
7047 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7049 new_column_width (GtkSheet * sheet,
7058 min_width = sheet->column_requisition;
7060 /* you can't shrink a column to less than its minimum width */
7061 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7063 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7066 /* calculate new column width making sure it doesn't end up
7067 * less than the minimum width */
7068 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7069 if (width < min_width)
7072 xxx_set_column_width (sheet, column, width);
7073 size_allocate_column_title_buttons (sheet);
7078 /* this function returns the new height of the row being resized given
7079 * the row and y position of the cursor; the y cursor position is passed
7080 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7082 new_row_height (GtkSheet * sheet,
7090 min_height = sheet->row_requisition;
7092 /* you can't shrink a row to less than its minimum height */
7093 if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7096 *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7099 /* calculate new row height making sure it doesn't end up
7100 * less than the minimum height */
7101 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7102 if (height < min_height)
7103 height = min_height;
7105 yyy_set_row_height (sheet, row, height);
7106 size_allocate_row_title_buttons (sheet);
7112 gtk_sheet_set_column_width (GtkSheet * sheet,
7118 g_return_if_fail (sheet != NULL);
7119 g_return_if_fail (GTK_IS_SHEET (sheet));
7121 if (column < 0 || column >= xxx_column_count (sheet))
7124 gtk_sheet_column_size_request (sheet, column, &min_width);
7125 if (width < min_width) return;
7127 xxx_set_column_width (sheet, column, width);
7129 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7131 size_allocate_column_title_buttons (sheet);
7132 adjust_scrollbars (sheet);
7133 gtk_sheet_size_allocate_entry (sheet);
7134 gtk_sheet_range_draw (sheet, NULL);
7137 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, column);
7138 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_COL_WIDTH], 0,
7145 gtk_sheet_set_row_height (GtkSheet * sheet,
7151 g_return_if_fail (sheet != NULL);
7152 g_return_if_fail (GTK_IS_SHEET (sheet));
7154 if (row < 0 || row >= yyy_row_count (sheet))
7157 gtk_sheet_row_size_request (sheet, row, &min_height);
7158 if (height < min_height) return;
7160 yyy_set_row_height (sheet, row, height);
7162 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7164 size_allocate_row_title_buttons (sheet);
7165 adjust_scrollbars (sheet);
7166 gtk_sheet_size_allocate_entry (sheet);
7167 gtk_sheet_range_draw (sheet, NULL);
7170 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, - 1);
7171 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_ROW_HEIGHT], 0,
7178 gtk_sheet_get_attributes (const GtkSheet *sheet, gint row, gint col,
7179 GtkSheetCellAttr *attributes)
7181 const GdkColor *fg, *bg;
7182 const GtkJustification *j ;
7183 const PangoFontDescription *font_desc ;
7184 const GtkSheetCellBorder *border ;
7186 g_return_val_if_fail (sheet != NULL, FALSE);
7187 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7189 if (row < 0 || col < 0) return FALSE;
7191 init_attributes (sheet, col, attributes);
7196 attributes->is_editable = g_sheet_model_is_editable (sheet->model, row, col);
7197 attributes->is_visible = g_sheet_model_is_visible (sheet->model, row, col);
7199 fg = g_sheet_model_get_foreground (sheet->model, row, col);
7201 attributes->foreground = *fg;
7203 bg = g_sheet_model_get_background (sheet->model, row, col);
7205 attributes->background = *bg;
7207 j = g_sheet_model_get_justification (sheet->model, row, col);
7208 if (j) attributes->justification = *j;
7210 font_desc = g_sheet_model_get_font_desc (sheet->model, row, col);
7211 if ( font_desc ) attributes->font_desc = font_desc;
7213 border = g_sheet_model_get_cell_border (sheet->model, row, col);
7215 if ( border ) attributes->border = *border;
7221 init_attributes (const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7223 /* DEFAULT VALUES */
7224 attributes->foreground = GTK_WIDGET (sheet)->style->black;
7225 attributes->background = sheet->bg_color;
7226 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7228 GdkColormap *colormap;
7229 colormap = gdk_colormap_get_system ();
7230 gdk_color_black (colormap, &attributes->foreground);
7231 attributes->background = sheet->bg_color;
7233 attributes->justification = xxx_column_justification (sheet, col);
7234 attributes->border.width = 0;
7235 attributes->border.line_style = GDK_LINE_SOLID;
7236 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7237 attributes->border.join_style = GDK_JOIN_MITER;
7238 attributes->border.mask = 0;
7239 attributes->border.color = GTK_WIDGET (sheet)->style->black;
7240 attributes->is_editable = TRUE;
7241 attributes->is_visible = TRUE;
7242 attributes->font_desc = GTK_WIDGET (sheet)->style->font_desc;
7246 /********************************************************************
7247 * Container Functions:
7252 * gtk_sheet_move_child
7253 * gtk_sheet_position_child
7254 * gtk_sheet_position_children
7255 * gtk_sheet_realize_child
7256 * gtk_sheet_get_child_at
7257 ********************************************************************/
7260 gtk_sheet_put (GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7262 GtkRequisition child_requisition;
7263 GtkSheetChild *child_info;
7265 g_return_val_if_fail (sheet != NULL, NULL);
7266 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7267 g_return_val_if_fail (child != NULL, NULL);
7268 g_return_val_if_fail (child->parent == NULL, NULL);
7270 child_info = g_new (GtkSheetChild, 1);
7271 child_info->widget = child;
7274 child_info->attached_to_cell = FALSE;
7275 child_info->floating = TRUE;
7276 child_info->xpadding = child_info->ypadding = 0;
7277 child_info->xexpand = child_info->yexpand = FALSE;
7278 child_info->xshrink = child_info->yshrink = FALSE;
7279 child_info->xfill = child_info->yfill = FALSE;
7281 sheet->children = g_list_append (sheet->children, child_info);
7283 gtk_widget_set_parent (child, GTK_WIDGET (sheet));
7285 gtk_widget_size_request (child, &child_requisition);
7287 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7289 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7290 (!GTK_WIDGET_REALIZED (child) || GTK_WIDGET_NO_WINDOW (child)))
7291 gtk_sheet_realize_child (sheet, child_info);
7293 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7294 !GTK_WIDGET_MAPPED (child))
7295 gtk_widget_map (child);
7298 gtk_sheet_position_child (sheet, child_info);
7300 /* This will avoid drawing on the titles */
7302 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7304 if (sheet->row_titles_visible)
7305 gdk_window_show (sheet->row_title_window);
7306 if (sheet->column_titles_visible)
7307 gdk_window_show (sheet->column_title_window);
7310 return (child_info);
7314 gtk_sheet_attach_floating (GtkSheet *sheet,
7319 GtkSheetChild *child;
7321 if (row < 0 || col < 0)
7323 gtk_sheet_button_attach (sheet, widget, row, col);
7327 gtk_sheet_get_cell_area (sheet, row, col, &area);
7328 child = gtk_sheet_put (sheet, widget, area.x, area.y);
7329 child->attached_to_cell = TRUE;
7335 gtk_sheet_attach_default (GtkSheet *sheet,
7339 if (row < 0 || col < 0)
7341 gtk_sheet_button_attach (sheet, widget, row, col);
7345 gtk_sheet_attach (sheet, widget, row, col,
7346 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
7350 gtk_sheet_attach (GtkSheet *sheet,
7359 GtkSheetChild *child = NULL;
7361 if (row < 0 || col < 0)
7363 gtk_sheet_button_attach (sheet, widget, row, col);
7367 child = g_new0 (GtkSheetChild, 1);
7368 child->attached_to_cell = TRUE;
7369 child->floating = FALSE;
7370 child->widget = widget;
7373 child->xpadding = xpadding;
7374 child->ypadding = ypadding;
7375 child->xexpand = (xoptions & GTK_EXPAND) != 0;
7376 child->yexpand = (yoptions & GTK_EXPAND) != 0;
7377 child->xshrink = (xoptions & GTK_SHRINK) != 0;
7378 child->yshrink = (yoptions & GTK_SHRINK) != 0;
7379 child->xfill = (xoptions & GTK_FILL) != 0;
7380 child->yfill = (yoptions & GTK_FILL) != 0;
7382 sheet->children = g_list_append (sheet->children, child);
7384 gtk_sheet_get_cell_area (sheet, row, col, &area);
7386 child->x = area.x + child->xpadding;
7387 child->y = area.y + child->ypadding;
7389 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7391 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7392 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7393 gtk_sheet_realize_child (sheet, child);
7395 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7396 !GTK_WIDGET_MAPPED (widget))
7397 gtk_widget_map (widget);
7400 gtk_sheet_position_child (sheet, child);
7402 /* This will avoid drawing on the titles */
7404 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7406 if (GTK_SHEET_ROW_TITLES_VISIBLE (sheet))
7407 gdk_window_show (sheet->row_title_window);
7408 if (GTK_SHEET_COL_TITLES_VISIBLE (sheet))
7409 gdk_window_show (sheet->column_title_window);
7415 gtk_sheet_button_attach (GtkSheet *sheet,
7419 GtkSheetButton *button = 0;
7420 GtkSheetChild *child;
7421 GtkRequisition button_requisition;
7423 if (row >= 0 && col >= 0) return;
7424 if (row < 0 && col < 0) return;
7426 child = g_new (GtkSheetChild, 1);
7427 child->widget = widget;
7430 child->attached_to_cell = TRUE;
7431 child->floating = FALSE;
7434 child->xpadding = child->ypadding = 0;
7435 child->xshrink = child->yshrink = FALSE;
7436 child->xfill = child->yfill = FALSE;
7439 sheet->children = g_list_append (sheet->children, child);
7441 gtk_sheet_button_size_request (sheet, button, &button_requisition);
7444 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7446 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7447 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7448 gtk_sheet_realize_child (sheet, child);
7450 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7451 !GTK_WIDGET_MAPPED (widget))
7452 gtk_widget_map (widget);
7455 if (row == -1) size_allocate_column_title_buttons (sheet);
7456 if (col == -1) size_allocate_row_title_buttons (sheet);
7461 label_size_request (GtkSheet *sheet, gchar *label, GtkRequisition *req)
7466 gint row_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) - 2 * CELLOFFSET + 2;
7472 while (words && *words != '\0')
7474 if (*words == '\n' || * (words + 1) == '\0')
7476 req->height += row_height;
7479 req->width = MAX (req->width, STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, word));
7489 if (n > 0) req->height -= 2;
7493 gtk_sheet_button_size_request (GtkSheet *sheet,
7494 const GtkSheetButton *button,
7495 GtkRequisition *button_requisition)
7497 GtkRequisition requisition;
7498 GtkRequisition label_requisition;
7500 if (gtk_sheet_autoresize (sheet) && button->label && strlen (button->label) > 0)
7502 label_size_request (sheet, button->label, &label_requisition);
7503 label_requisition.width += 2 * CELLOFFSET;
7504 label_requisition.height += 2 * CELLOFFSET;
7508 label_requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7509 label_requisition.width = COLUMN_MIN_WIDTH;
7514 gtk_widget_size_request (button->child->widget, &requisition);
7515 requisition.width += 2 * button->child->xpadding;
7516 requisition.height += 2 * button->child->ypadding;
7517 requisition.width += 2 * sheet->button->style->xthickness;
7518 requisition.height += 2 * sheet->button->style->ythickness;
7522 requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7523 requisition.width = COLUMN_MIN_WIDTH;
7526 *button_requisition = requisition;
7527 button_requisition->width = MAX (requisition.width, label_requisition.width);
7528 button_requisition->height = MAX (requisition.height, label_requisition.height);
7533 gtk_sheet_row_size_request (GtkSheet *sheet,
7537 GtkRequisition button_requisition;
7540 gtk_sheet_button_size_request (sheet,
7541 yyy_row_button (sheet, row),
7542 &button_requisition);
7544 *requisition = button_requisition.height;
7546 children = sheet->children;
7549 GtkSheetChild *child = (GtkSheetChild *)children->data;
7550 GtkRequisition child_requisition;
7552 if (child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink)
7554 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7556 if (child_requisition.height + 2 * child->ypadding > *requisition)
7557 *requisition = child_requisition.height + 2 * child->ypadding;
7559 children = children->next;
7562 sheet->row_requisition = * requisition;
7566 gtk_sheet_column_size_request (GtkSheet *sheet,
7570 GtkRequisition button_requisition;
7572 GtkSheetButton *button = xxx_column_button (sheet, col);
7574 gtk_sheet_button_size_request (sheet,
7576 &button_requisition);
7578 gtk_sheet_button_free (button);
7580 *requisition = button_requisition.width;
7582 children = sheet->children;
7585 GtkSheetChild *child = (GtkSheetChild *)children->data;
7586 GtkRequisition child_requisition;
7588 if (child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink)
7590 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7592 if (child_requisition.width + 2 * child->xpadding > *requisition)
7593 *requisition = child_requisition.width + 2 * child->xpadding;
7595 children = children->next;
7598 sheet->column_requisition = *requisition;
7602 gtk_sheet_move_child (GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7604 GtkSheetChild *child;
7607 g_return_if_fail (sheet != NULL);
7608 g_return_if_fail (GTK_IS_SHEET (sheet));
7610 children = sheet->children;
7613 child = children->data;
7615 if (child->widget == widget)
7619 child->row = ROW_FROM_YPIXEL (sheet, y);
7620 child->col = COLUMN_FROM_XPIXEL (sheet, x);
7621 gtk_sheet_position_child (sheet, child);
7625 children = children->next;
7628 g_warning ("Widget must be a GtkSheet child");
7633 gtk_sheet_position_child (GtkSheet *sheet, GtkSheetChild *child)
7635 GtkRequisition child_requisition;
7636 GtkAllocation child_allocation;
7642 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7644 if (sheet->column_titles_visible)
7645 yoffset = sheet->column_title_area.height;
7647 if (sheet->row_titles_visible)
7648 xoffset = sheet->row_title_area.width;
7650 if (child->attached_to_cell)
7652 gtk_sheet_get_cell_area (sheet, child->row, child->col, &area);
7653 child->x = area.x + child->xpadding;
7654 child->y = area.y + child->ypadding;
7656 if (!child->floating)
7658 if (child_requisition.width + 2 * child->xpadding <= xxx_column_width (sheet, child->col))
7662 child_requisition.width = child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7668 child->x = area.x + xxx_column_width (sheet, child->col) / 2 -
7669 child_requisition.width / 2;
7671 child_allocation.width = child_requisition.width;
7676 if (!child->xshrink)
7678 gtk_sheet_set_column_width (sheet, child->col, child_requisition.width + 2 * child->xpadding);
7680 child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7683 if (child_requisition.height +
7684 2 * child->ypadding <= yyy_row_height (sheet, child->row))
7688 child_requisition.height = child_allocation.height =
7689 yyy_row_height (sheet, child->row) - 2 * child->ypadding;
7695 child->y = area.y + yyy_row_height (sheet, child->row) / 2
7696 - child_requisition.height / 2;
7698 child_allocation.height = child_requisition.height;
7703 if (!child->yshrink)
7705 gtk_sheet_set_row_height (sheet, child->row, child_requisition.height + 2 * child->ypadding);
7707 child_allocation.height = yyy_row_height (sheet, child->row) -
7708 2 * child->ypadding;
7713 child_allocation.width = child_requisition.width;
7714 child_allocation.height = child_requisition.height;
7717 x = child_allocation.x = child->x + xoffset;
7718 y = child_allocation.y = child->y + yoffset;
7722 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
7723 x = child_allocation.x = child->x + xoffset;
7724 y = child_allocation.y = child->y + sheet->voffset + yoffset;
7725 y = child_allocation.y = child->y + yoffset;
7726 child_allocation.width = child_requisition.width;
7727 child_allocation.height = child_requisition.height;
7730 gtk_widget_size_allocate (child->widget, &child_allocation);
7731 gtk_widget_queue_draw (child->widget);
7735 gtk_sheet_forall (GtkContainer *container,
7736 gboolean include_internals,
7737 GtkCallback callback,
7738 gpointer callback_data)
7741 GtkSheetChild *child;
7744 g_return_if_fail (GTK_IS_SHEET (container));
7745 g_return_if_fail (callback != NULL);
7747 sheet = GTK_SHEET (container);
7748 children = sheet->children;
7751 child = children->data;
7752 children = children->next;
7754 (* callback) (child->widget, callback_data);
7757 (* callback) (sheet->button, callback_data);
7758 if (sheet->sheet_entry)
7759 (* callback) (sheet->sheet_entry, callback_data);
7764 gtk_sheet_position_children (GtkSheet *sheet)
7767 GtkSheetChild *child;
7769 children = sheet->children;
7773 child = (GtkSheetChild *)children->data;
7775 if (child->col != -1 && child->row != -1)
7776 gtk_sheet_position_child (sheet, child);
7778 if (child->row == -1)
7780 if (child->col < MIN_VISIBLE_COLUMN (sheet) ||
7781 child->col > MAX_VISIBLE_COLUMN (sheet))
7782 gtk_sheet_child_hide (child);
7784 gtk_sheet_child_show (child);
7786 if (child->col == -1)
7788 if (child->row < MIN_VISIBLE_ROW (sheet) ||
7789 child->row > MAX_VISIBLE_ROW (sheet))
7790 gtk_sheet_child_hide (child);
7792 gtk_sheet_child_show (child);
7795 children = children->next;
7800 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7804 GtkSheetChild *child = 0;
7806 g_return_if_fail (container != NULL);
7807 g_return_if_fail (GTK_IS_SHEET (container));
7809 sheet = GTK_SHEET (container);
7811 children = sheet->children;
7815 child = (GtkSheetChild *)children->data;
7817 if (child->widget == widget) break;
7819 children = children->next;
7824 gtk_widget_unparent (widget);
7825 child->widget = NULL;
7827 sheet->children = g_list_remove_link (sheet->children, children);
7828 g_list_free_1 (children);
7835 gtk_sheet_realize_child (GtkSheet *sheet, GtkSheetChild *child)
7839 widget = GTK_WIDGET (sheet);
7841 if (GTK_WIDGET_REALIZED (widget))
7843 if (child->row == -1)
7844 gtk_widget_set_parent_window (child->widget, sheet->column_title_window);
7845 else if (child->col == -1)
7846 gtk_widget_set_parent_window (child->widget, sheet->row_title_window);
7848 gtk_widget_set_parent_window (child->widget, sheet->sheet_window);
7851 gtk_widget_set_parent (child->widget, widget);
7857 gtk_sheet_get_child_at (GtkSheet *sheet, gint row, gint col)
7860 GtkSheetChild *child = 0;
7862 g_return_val_if_fail (sheet != NULL, NULL);
7863 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7865 children = sheet->children;
7869 child = (GtkSheetChild *)children->data;
7871 if (child->attached_to_cell)
7872 if (child->row == row && child->col == col) break;
7874 children = children->next;
7877 if (children) return child;
7883 gtk_sheet_child_hide (GtkSheetChild *child)
7885 g_return_if_fail (child != NULL);
7886 gtk_widget_hide (child->widget);
7890 gtk_sheet_child_show (GtkSheetChild *child)
7892 g_return_if_fail (child != NULL);
7894 gtk_widget_show (child->widget);
7898 gtk_sheet_get_model (const GtkSheet *sheet)
7900 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7902 return sheet->model;
7907 gtk_sheet_button_new (void)
7909 GtkSheetButton *button = g_malloc (sizeof (GtkSheetButton));
7911 button->state = GTK_STATE_NORMAL;
7912 button->label = NULL;
7913 button->label_visible = TRUE;
7914 button->child = NULL;
7915 button->justification = GTK_JUSTIFY_FILL;
7922 gtk_sheet_button_free (GtkSheetButton *button)
7924 if (!button) return ;
7926 g_free (button->label);
7932 range_to_text (const GtkSheet *sheet)
7934 gchar *celltext = NULL;
7938 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
7941 string = g_string_sized_new (80);
7943 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
7945 for (c = sheet->range.col0; c < sheet->range.coli; ++c)
7947 celltext = gtk_sheet_cell_get_text (sheet, r, c);
7948 g_string_append (string, celltext);
7949 g_string_append (string, "\t");
7952 celltext = gtk_sheet_cell_get_text (sheet, r, c);
7953 g_string_append (string, celltext);
7954 if ( r < sheet->range.rowi)
7955 g_string_append (string, "\n");
7963 range_to_html (const GtkSheet *sheet)
7965 gchar *celltext = NULL;
7969 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
7972 string = g_string_sized_new (480);
7974 g_string_append (string, "<html>\n");
7975 g_string_append (string, "<body>\n");
7976 g_string_append (string, "<table>\n");
7977 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
7979 g_string_append (string, "<tr>\n");
7980 for (c = sheet->range.col0; c <= sheet->range.coli; ++c)
7982 g_string_append (string, "<td>");
7983 celltext = gtk_sheet_cell_get_text (sheet, r, c);
7984 g_string_append (string, celltext);
7985 g_string_append (string, "</td>\n");
7988 g_string_append (string, "</tr>\n");
7990 g_string_append (string, "</table>\n");
7991 g_string_append (string, "</body>\n");
7992 g_string_append (string, "</html>\n");
8004 primary_get_cb (GtkClipboard *clipboard,
8005 GtkSelectionData *selection_data,
8009 GtkSheet *sheet = GTK_SHEET (data);
8010 GString *string = NULL;
8014 case SELECT_FMT_TEXT:
8015 string = range_to_text (sheet);
8017 case SELECT_FMT_HTML:
8018 string = range_to_html (sheet);
8021 g_assert_not_reached ();
8024 gtk_selection_data_set (selection_data, selection_data->target,
8026 (const guchar *) string->str, string->len);
8027 g_string_free (string, TRUE);
8031 primary_clear_cb (GtkClipboard *clipboard,
8034 GtkSheet *sheet = GTK_SHEET (data);
8035 gtk_sheet_real_unselect_range (sheet, NULL);
8039 gtk_sheet_update_primary_selection (GtkSheet *sheet)
8041 static const GtkTargetEntry targets[] = {
8042 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
8043 { "STRING", 0, SELECT_FMT_TEXT },
8044 { "TEXT", 0, SELECT_FMT_TEXT },
8045 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
8046 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
8047 { "text/plain", 0, SELECT_FMT_TEXT },
8048 { "text/html", 0, SELECT_FMT_HTML }
8051 GtkClipboard *clipboard;
8053 if (!GTK_WIDGET_REALIZED (sheet))
8056 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet),
8057 GDK_SELECTION_PRIMARY);
8059 if (gtk_sheet_range_isvisible (sheet, sheet->range))
8061 if (!gtk_clipboard_set_with_owner (clipboard, targets,
8062 G_N_ELEMENTS (targets),
8063 primary_get_cb, primary_clear_cb,
8065 primary_clear_cb (clipboard, sheet);
8069 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet))
8070 gtk_clipboard_clear (clipboard);