1 /* This version of GtkSheet has been *heavily* modified, for the specific
2 requirements of PSPPIRE. */
4 /* GtkSheet widget for Gtk+.
5 * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
7 * Based on GtkClist widget by Jay Painter, but major changes.
8 * Memory allocation routines inspired on SC (Spreadsheet Calculator)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 * @short_description: spreadsheet widget for gtk2
29 * GtkSheet is a matrix widget for GTK+. It consists of an scrollable grid of
30 * cells where you can allocate text. Cell contents can be edited interactively
31 * through a specially designed entry, GtkItemEntry. It is also a container
32 * subclass, allowing you to display buttons, curves, pixmaps and any other
35 * You can also set many attributes as: border, foreground and background color,
36 * text justification, and more.
38 * The testgtksheet program shows how easy is to create a spreadsheet-like GUI
48 #include <gdk/gdkkeysyms.h>
49 #include <gtk/gtksignal.h>
50 #include <gtk/gtklabel.h>
51 #include <gtk/gtkbutton.h>
52 #include <gtk/gtkadjustment.h>
53 #include <gtk/gtktable.h>
54 #include <gtk/gtkbox.h>
55 #include <gtk/gtkmain.h>
56 #include <gtk/gtktypeutils.h>
57 #include <gtk/gtkentry.h>
58 #include <gtk/gtkcontainer.h>
59 #include <gtk/gtkpixmap.h>
60 #include <pango/pango.h>
61 #include "gtkitementry.h"
63 #include "gtkextra-marshal.h"
64 #include "gsheetmodel.h"
69 GTK_SHEET_IS_LOCKED = 1 << 0,
70 GTK_SHEET_IS_FROZEN = 1 << 1,
71 GTK_SHEET_IN_XDRAG = 1 << 2,
72 GTK_SHEET_IN_YDRAG = 1 << 3,
73 GTK_SHEET_IN_DRAG = 1 << 4,
74 GTK_SHEET_IN_SELECTION = 1 << 5,
75 GTK_SHEET_IN_RESIZE = 1 << 6,
76 GTK_SHEET_REDRAW_PENDING = 1 << 7,
79 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
80 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
81 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~ (flag))
83 #define GTK_SHEET_IS_LOCKED(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_LOCKED)
86 #define GTK_SHEET_IS_FROZEN(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
87 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
88 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
89 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
90 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
91 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
92 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
94 #define CELL_SPACING 1
96 #define TIMEOUT_HOVER 300
97 #define TIME_INTERVAL 8
98 #define COLUMN_MIN_WIDTH 10
103 #define DEFAULT_COLUMN_WIDTH 80
106 static void gtk_sheet_update_primary_selection (GtkSheet *sheet);
109 static void gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column);
111 static void gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row);
114 static gboolean gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col);
117 void dispose_string (const GtkSheet *sheet, gchar *text)
119 GSheetModel *model = gtk_sheet_get_model (sheet);
124 if (g_sheet_model_free_strings (model))
129 guint DEFAULT_ROW_HEIGHT (GtkWidget *widget)
131 if (!widget->style->font_desc) return 24;
134 PangoContext *context = gtk_widget_get_pango_context (widget);
135 PangoFontMetrics *metrics =
136 pango_context_get_metrics (context,
137 widget->style->font_desc,
138 pango_context_get_language (context));
139 guint val = pango_font_metrics_get_descent (metrics) +
140 pango_font_metrics_get_ascent (metrics);
141 pango_font_metrics_unref (metrics);
142 return PANGO_PIXELS (val)+2 * CELLOFFSET;
147 guint DEFAULT_FONT_ASCENT (GtkWidget *widget)
149 if (!widget->style->font_desc) return 12;
152 PangoContext *context = gtk_widget_get_pango_context (widget);
153 PangoFontMetrics *metrics =
154 pango_context_get_metrics (context,
155 widget->style->font_desc,
156 pango_context_get_language (context));
157 guint val = pango_font_metrics_get_ascent (metrics);
158 pango_font_metrics_unref (metrics);
159 return PANGO_PIXELS (val);
164 guint STRING_WIDTH (GtkWidget *widget,
165 const PangoFontDescription *font, const gchar *text)
170 layout = gtk_widget_create_pango_layout (widget, text);
171 pango_layout_set_font_description (layout, font);
173 pango_layout_get_extents (layout, NULL, &rect);
175 g_object_unref (G_OBJECT (layout));
176 return PANGO_PIXELS (rect.width);
180 guint DEFAULT_FONT_DESCENT (GtkWidget *widget)
182 if (!widget->style->font_desc) return 12;
185 PangoContext *context = gtk_widget_get_pango_context (widget);
186 PangoFontMetrics *metrics =
187 pango_context_get_metrics (context,
188 widget->style->font_desc,
189 pango_context_get_language (context));
190 guint val = pango_font_metrics_get_descent (metrics);
191 pango_font_metrics_unref (metrics);
192 return PANGO_PIXELS (val);
198 yyy_row_is_visible (const GtkSheet *sheet, gint row)
200 GSheetRow *row_geo = sheet->row_geometry;
202 return g_sheet_row_get_visibility (row_geo, row, 0);
207 yyy_row_is_sensitive (const GtkSheet *sheet, gint row)
209 GSheetRow *row_geo = sheet->row_geometry;
211 return g_sheet_row_get_sensitivity (row_geo, row, 0);
217 yyy_row_count (const GtkSheet *sheet)
219 GSheetRow *row_geo = sheet->row_geometry;
221 return g_sheet_row_get_row_count (row_geo, 0);
225 yyy_row_height (const GtkSheet *sheet, gint row)
227 GSheetRow *row_geo = sheet->row_geometry;
229 return g_sheet_row_get_height (row_geo, row, 0);
233 yyy_row_top_ypixel (const GtkSheet *sheet, gint row)
235 GSheetRow *geo = sheet->row_geometry;
237 gint y = g_sheet_row_start_pixel (geo, row, 0);
239 if ( sheet->column_titles_visible )
240 y += sheet->column_title_area.height;
246 /* Return the row containing pixel Y */
248 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
250 GSheetRow *geo = sheet->row_geometry;
252 gint cy = sheet->voffset;
254 if (sheet->column_titles_visible)
255 cy += sheet->column_title_area.height;
257 if (y < cy) return 0;
259 return g_sheet_row_pixel_to_row (geo, y - cy, 0);
263 /* gives the top pixel of the given row in context of
264 * the sheet's voffset */
266 ROW_TOP_YPIXEL (const GtkSheet *sheet, gint row)
268 return (sheet->voffset + yyy_row_top_ypixel (sheet, row));
272 /* returns the row index from a y pixel location in the
273 * context of the sheet's voffset */
275 ROW_FROM_YPIXEL (const GtkSheet *sheet, gint y)
277 return (yyy_row_ypixel_to_row (sheet, y));
280 static inline GtkSheetButton *
281 xxx_column_button (const GtkSheet *sheet, gint col)
283 GSheetColumn *col_geo = sheet->column_geometry;
284 if ( col < 0 ) return NULL ;
286 return g_sheet_column_get_button (col_geo, col);
291 xxx_column_left_xpixel (const GtkSheet *sheet, gint col)
293 GSheetColumn *geo = sheet->column_geometry;
295 gint x = g_sheet_column_start_pixel (geo, col);
297 if ( sheet->row_titles_visible )
298 x += sheet->row_title_area.width;
304 xxx_column_width (const GtkSheet *sheet, gint col)
306 GSheetColumn *col_geo = sheet->column_geometry;
308 return g_sheet_column_get_width (col_geo, col);
313 xxx_set_column_width (GtkSheet *sheet, gint col, gint width)
315 if ( sheet->column_geometry )
316 g_sheet_column_set_width (sheet->column_geometry, col, width);
320 xxx_column_set_left_column (GtkSheet *sheet, gint col, gint i)
322 GSheetColumn *col_geo = sheet->column_geometry;
324 g_sheet_column_set_left_text_column (col_geo, col, i);
328 xxx_column_left_column (const GtkSheet *sheet, gint col)
330 GSheetColumn *col_geo = sheet->column_geometry;
332 return g_sheet_column_get_left_text_column (col_geo, col);
336 xxx_column_set_right_column (GtkSheet *sheet, gint col, gint i)
338 GSheetColumn *col_geo = sheet->column_geometry;
340 g_sheet_column_set_right_text_column (col_geo, col, i);
344 xxx_column_right_column (const GtkSheet *sheet, gint col)
346 GSheetColumn *col_geo = sheet->column_geometry;
348 return g_sheet_column_get_right_text_column (col_geo, col);
351 static inline GtkJustification
352 xxx_column_justification (const GtkSheet *sheet, gint col)
354 GSheetColumn *col_geo = sheet->column_geometry;
356 return g_sheet_column_get_justification (col_geo, col);
360 xxx_column_is_visible (const GtkSheet *sheet, gint col)
362 GSheetColumn *col_geo = sheet->column_geometry;
364 return g_sheet_column_get_visibility (col_geo, col);
369 xxx_column_is_sensitive (const GtkSheet *sheet, gint col)
371 GSheetColumn *col_geo = sheet->column_geometry;
373 return g_sheet_column_get_sensitivity (col_geo, col);
377 /* gives the left pixel of the given column in context of
378 * the sheet's hoffset */
380 COLUMN_LEFT_XPIXEL (const GtkSheet *sheet, gint ncol)
382 return (sheet->hoffset + xxx_column_left_xpixel (sheet, ncol));
386 xxx_column_count (const GtkSheet *sheet)
388 GSheetColumn *col_geo = sheet->column_geometry;
390 return g_sheet_column_get_column_count (col_geo);
393 /* returns the column index from a x pixel location in the
394 * context of the sheet's hoffset */
396 COLUMN_FROM_XPIXEL (const GtkSheet * sheet,
402 if ( sheet->row_titles_visible )
403 cx += sheet->row_title_area.width;
405 if (x < cx) return 0;
406 for (i = 0; i < xxx_column_count (sheet); i++)
408 if (x >= cx && x <= (cx + xxx_column_width (sheet, i)) &&
409 xxx_column_is_visible (sheet, i))
411 if ( xxx_column_is_visible (sheet, i))
412 cx += xxx_column_width (sheet, i);
416 return xxx_column_count (sheet) - 1;
419 /* returns the total height of the sheet */
420 static inline gint SHEET_HEIGHT (GtkSheet *sheet)
422 const gint n_rows = yyy_row_count (sheet);
424 return yyy_row_top_ypixel (sheet, n_rows - 1) +
425 yyy_row_height (sheet, n_rows - 1);
429 static inline GtkSheetButton *
430 yyy_row_button (GtkSheet *sheet, gint row)
432 GSheetRow *row_geo = sheet->row_geometry;
434 return g_sheet_row_get_button (row_geo, row, sheet);
441 yyy_set_row_height (GtkSheet *sheet, gint row, gint height)
443 if ( sheet->row_geometry )
444 g_sheet_row_set_height (sheet->row_geometry, row, height, sheet);
449 /* returns the total width of the sheet */
450 static inline gint SHEET_WIDTH (GtkSheet *sheet)
454 cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
456 for (i = 0; i < xxx_column_count (sheet); i++)
457 if (xxx_column_is_visible (sheet, i))
458 cx += xxx_column_width (sheet, i);
463 #define MIN_VISIBLE_ROW(sheet) \
464 ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + 1)
466 #define MAX_VISIBLE_ROW(sheet) \
467 ROW_FROM_YPIXEL (sheet, sheet->sheet_window_height - 1)
469 #define MIN_VISIBLE_COLUMN(sheet) \
470 COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + 1)
472 #define MAX_VISIBLE_COLUMN(sheet) \
473 COLUMN_FROM_XPIXEL (sheet, sheet->sheet_window_width)
477 static inline gboolean
478 POSSIBLE_XDRAG (const GtkSheet *sheet, gint x, gint *drag_column)
482 column = COLUMN_FROM_XPIXEL (sheet, x);
483 *drag_column = column;
485 xdrag = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
486 if (x <= xdrag + DRAG_WIDTH / 2 && column != 0)
488 while (! xxx_column_is_visible (sheet, column - 1) && column > 0) column--;
489 *drag_column = column - 1;
490 return xxx_column_is_sensitive (sheet, column - 1);
493 xdrag += xxx_column_width (sheet, column);
494 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
495 return xxx_column_is_sensitive (sheet, column);
500 static inline gboolean
501 POSSIBLE_YDRAG (const GtkSheet *sheet, gint y, gint *drag_row)
504 row = ROW_FROM_YPIXEL (sheet, y);
507 ydrag = ROW_TOP_YPIXEL (sheet, row)+CELL_SPACING;
508 if (y <= ydrag + DRAG_WIDTH / 2 && row != 0)
510 while (!yyy_row_is_visible (sheet, row - 1) && row > 0) row--;
512 return yyy_row_is_sensitive (sheet, row - 1);
515 ydrag +=yyy_row_height (sheet, row);
517 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
518 return yyy_row_is_sensitive (sheet, row);
524 static inline gboolean
525 POSSIBLE_DRAG (const GtkSheet *sheet, gint x, gint y,
526 gint *drag_row, gint *drag_column)
530 /* Can't drag if nothing is selected */
531 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
532 sheet->range.col0 < 0 || sheet->range.coli < 0 )
535 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
536 *drag_row = ROW_FROM_YPIXEL (sheet, y);
538 if (x >= COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0) - DRAG_WIDTH / 2 &&
539 x <= COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
540 xxx_column_width (sheet, sheet->range.coli) + DRAG_WIDTH / 2)
542 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.row0);
543 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
545 *drag_row = sheet->range.row0;
548 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
549 yyy_row_height (sheet, sheet->range.rowi);
550 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
552 *drag_row = sheet->range.rowi;
557 if (y >= ROW_TOP_YPIXEL (sheet, sheet->range.row0) - DRAG_WIDTH / 2 &&
558 y <= ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
559 yyy_row_height (sheet, sheet->range.rowi) + DRAG_WIDTH / 2)
561 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0);
562 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
564 *drag_column = sheet->range.col0;
567 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
568 xxx_column_width (sheet, sheet->range.coli);
569 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
571 *drag_column = sheet->range.coli;
579 static inline gboolean
580 POSSIBLE_RESIZE (const GtkSheet *sheet, gint x, gint y,
581 gint *drag_row, gint *drag_column)
585 /* Can't drag if nothing is selected */
586 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
587 sheet->range.col0 < 0 || sheet->range.coli < 0 )
590 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli)+
591 xxx_column_width (sheet, sheet->range.coli);
593 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi)+
594 yyy_row_height (sheet, sheet->range.rowi);
596 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
597 ydrag = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
599 if (sheet->state == GTK_SHEET_ROW_SELECTED)
600 xdrag = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
602 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
603 *drag_row = ROW_FROM_YPIXEL (sheet, y);
605 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
606 y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
611 static void gtk_sheet_class_init (GtkSheetClass * klass);
612 static void gtk_sheet_init (GtkSheet * sheet);
613 static void gtk_sheet_destroy (GtkObject * object);
614 static void gtk_sheet_finalize (GObject * object);
615 static void gtk_sheet_style_set (GtkWidget *widget,
616 GtkStyle *previous_style);
617 static void gtk_sheet_realize (GtkWidget * widget);
618 static void gtk_sheet_unrealize (GtkWidget * widget);
619 static void gtk_sheet_map (GtkWidget * widget);
620 static void gtk_sheet_unmap (GtkWidget * widget);
621 static gint gtk_sheet_expose (GtkWidget * widget,
622 GdkEventExpose * event);
623 static void gtk_sheet_forall (GtkContainer *container,
624 gboolean include_internals,
625 GtkCallback callback,
626 gpointer callback_data);
628 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
629 GtkAdjustment *hadjustment,
630 GtkAdjustment *vadjustment);
632 static gint gtk_sheet_button_press (GtkWidget * widget,
633 GdkEventButton * event);
634 static gint gtk_sheet_button_release (GtkWidget * widget,
635 GdkEventButton * event);
636 static gint gtk_sheet_motion (GtkWidget * widget,
637 GdkEventMotion * event);
638 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
640 static gint gtk_sheet_key_press (GtkWidget *widget,
642 static void gtk_sheet_size_request (GtkWidget * widget,
643 GtkRequisition * requisition);
644 static void gtk_sheet_size_allocate (GtkWidget * widget,
645 GtkAllocation * allocation);
649 static gboolean gtk_sheet_range_isvisible (const GtkSheet * sheet,
650 GtkSheetRange range);
651 static gboolean gtk_sheet_cell_isvisible (GtkSheet * sheet,
652 gint row, gint column);
653 /* Drawing Routines */
655 /* draw cell background and frame */
656 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
657 gint row, gint column);
659 /* draw cell contents */
660 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
661 gint row, gint column);
663 /* draw visible part of range. If range == NULL then draw the whole screen */
664 static void gtk_sheet_range_draw (GtkSheet *sheet,
665 const GtkSheetRange *range);
667 /* highlight the visible part of the selected range */
668 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
669 GtkSheetRange range);
673 static gboolean gtk_sheet_move_query (GtkSheet *sheet,
674 gint row, gint column);
675 static void gtk_sheet_real_select_range (GtkSheet * sheet,
676 const GtkSheetRange * range);
677 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
678 const GtkSheetRange * range);
679 static void gtk_sheet_extend_selection (GtkSheet *sheet,
680 gint row, gint column);
681 static void gtk_sheet_new_selection (GtkSheet *sheet,
682 GtkSheetRange *range);
683 static void gtk_sheet_draw_border (GtkSheet *sheet,
684 GtkSheetRange range);
685 static void gtk_sheet_draw_corners (GtkSheet *sheet,
686 GtkSheetRange range);
689 /* Active Cell handling */
691 static void gtk_sheet_entry_changed (GtkWidget *widget,
693 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
694 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
695 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
697 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
698 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
699 static void gtk_sheet_click_cell (GtkSheet *sheet,
706 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
707 guint width, guint height);
708 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
709 GtkSheetRange range);
712 static void adjust_scrollbars (GtkSheet * sheet);
713 static void vadjustment_value_changed (GtkAdjustment * adjustment,
715 static void hadjustment_value_changed (GtkAdjustment * adjustment,
719 static void draw_xor_vline (GtkSheet * sheet);
720 static void draw_xor_hline (GtkSheet * sheet);
721 static void draw_xor_rectangle (GtkSheet *sheet,
722 GtkSheetRange range);
724 static guint new_column_width (GtkSheet * sheet,
727 static guint new_row_height (GtkSheet * sheet,
732 static void create_global_button (GtkSheet *sheet);
733 static void global_button_clicked (GtkWidget *widget,
737 static void create_sheet_entry (GtkSheet *sheet);
738 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
739 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
741 /* Sheet button gadgets */
743 static void size_allocate_column_title_buttons (GtkSheet * sheet);
744 static void size_allocate_row_title_buttons (GtkSheet * sheet);
747 static void size_allocate_global_button (GtkSheet *sheet);
748 static void gtk_sheet_button_size_request (GtkSheet *sheet,
749 const GtkSheetButton *button,
750 GtkRequisition *requisition);
752 /* Attributes routines */
753 static void init_attributes (const GtkSheet *sheet, gint col,
754 GtkSheetCellAttr *attributes);
757 /* Memory allocation routines */
758 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
759 const GtkSheetRange *range);
761 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
766 /* Container Functions */
767 static void gtk_sheet_remove (GtkContainer *container,
769 static void gtk_sheet_realize_child (GtkSheet *sheet,
770 GtkSheetChild *child);
771 static void gtk_sheet_position_child (GtkSheet *sheet,
772 GtkSheetChild *child);
773 static void gtk_sheet_position_children (GtkSheet *sheet);
774 static void gtk_sheet_child_show (GtkSheetChild *child);
775 static void gtk_sheet_child_hide (GtkSheetChild *child);
776 static void gtk_sheet_column_size_request (GtkSheet *sheet,
779 static void gtk_sheet_row_size_request (GtkSheet *sheet,
787 _gtkextra_signal_emit (GtkObject *object, guint signal_id, ...);
811 static GtkContainerClass *parent_class = NULL;
812 static guint sheet_signals[LAST_SIGNAL] = { 0 };
816 gtk_sheet_get_type ()
818 static GType sheet_type = 0;
822 static const GTypeInfo sheet_info =
824 sizeof (GtkSheetClass),
827 (GClassInitFunc) gtk_sheet_class_init,
832 (GInstanceInitFunc) gtk_sheet_init,
836 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
842 static GtkSheetRange*
843 gtk_sheet_range_copy (const GtkSheetRange *range)
845 GtkSheetRange *new_range;
847 g_return_val_if_fail (range != NULL, NULL);
849 new_range = g_new (GtkSheetRange, 1);
857 gtk_sheet_range_free (GtkSheetRange *range)
859 g_return_if_fail (range != NULL);
865 gtk_sheet_range_get_type (void)
867 static GType sheet_range_type = 0;
869 if (!sheet_range_type)
872 g_boxed_type_register_static ("GtkSheetRange",
873 (GBoxedCopyFunc) gtk_sheet_range_copy,
874 (GBoxedFreeFunc) gtk_sheet_range_free);
877 return sheet_range_type;
881 gtk_sheet_class_init (GtkSheetClass * klass)
883 GtkObjectClass *object_class;
884 GtkWidgetClass *widget_class;
885 GtkContainerClass *container_class;
886 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
888 object_class = (GtkObjectClass *) klass;
889 widget_class = (GtkWidgetClass *) klass;
890 container_class = (GtkContainerClass *) klass;
892 parent_class = g_type_class_peek_parent (klass);
895 * GtkSheet::select-row
896 * @sheet: the sheet widget that emitted the signal
897 * @row: the newly selected row index
899 * A row has been selected.
901 sheet_signals[SELECT_ROW] =
902 g_signal_new ("select-row",
903 G_TYPE_FROM_CLASS (object_class),
905 offsetof (GtkSheetClass, select_row),
914 * GtkSheet::select - column
915 * @sheet: the sheet widget that emitted the signal
916 * @column: the newly selected column index
918 * A column has been selected.
920 sheet_signals[SELECT_COLUMN] =
921 g_signal_new ("select-column",
922 G_TYPE_FROM_CLASS (object_class),
924 offsetof (GtkSheetClass, select_column),
933 * GtkSheet::double-click-row
934 * @sheet: the sheet widget that emitted the signal
935 * @row: the row that was double clicked.
937 * A row's title button has been double clicked
939 sheet_signals[DOUBLE_CLICK_ROW] =
940 g_signal_new ("double-click-row",
941 G_TYPE_FROM_CLASS (object_class),
952 * GtkSheet::double-click-column
953 * @sheet: the sheet widget that emitted the signal
954 * @column: the column that was double clicked.
956 * A column's title button has been double clicked
958 sheet_signals[DOUBLE_CLICK_COLUMN] =
959 g_signal_new ("double-click-column",
960 G_TYPE_FROM_CLASS (object_class),
971 * GtkSheet::button-event-column
972 * @sheet: the sheet widget that emitted the signal
973 * @column: the column on which the event occured.
975 * A button event occured on a column title button
977 sheet_signals[BUTTON_EVENT_COLUMN] =
978 g_signal_new ("button-event-column",
979 G_TYPE_FROM_CLASS (object_class),
983 gtkextra_VOID__INT_POINTER,
992 * GtkSheet::button-event-row
993 * @sheet: the sheet widget that emitted the signal
994 * @column: the column on which the event occured.
996 * A button event occured on a row title button
998 sheet_signals[BUTTON_EVENT_ROW] =
999 g_signal_new ("button-event-row",
1000 G_TYPE_FROM_CLASS (object_class),
1004 gtkextra_VOID__INT_POINTER,
1012 sheet_signals[SELECT_RANGE] =
1013 g_signal_new ("select-range",
1014 G_TYPE_FROM_CLASS (object_class),
1016 offsetof (GtkSheetClass, select_range),
1018 gtkextra_VOID__BOXED,
1021 GTK_TYPE_SHEET_RANGE);
1024 sheet_signals[RESIZE_RANGE] =
1025 g_signal_new ("resize-range",
1026 G_TYPE_FROM_CLASS (object_class),
1028 offsetof (GtkSheetClass, resize_range),
1030 gtkextra_VOID__BOXED_BOXED,
1033 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1036 sheet_signals[MOVE_RANGE] =
1037 g_signal_new ("move-range",
1038 G_TYPE_FROM_CLASS (object_class),
1040 offsetof (GtkSheetClass, move_range),
1042 gtkextra_VOID__BOXED_BOXED,
1045 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1048 sheet_signals[TRAVERSE] =
1049 g_signal_new ("traverse",
1050 G_TYPE_FROM_CLASS (object_class),
1052 offsetof (GtkSheetClass, traverse),
1054 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
1055 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT,
1056 G_TYPE_POINTER, G_TYPE_POINTER);
1059 sheet_signals[DEACTIVATE] =
1060 g_signal_new ("deactivate",
1061 G_TYPE_FROM_CLASS (object_class),
1063 offsetof (GtkSheetClass, deactivate),
1065 gtkextra_BOOLEAN__INT_INT,
1066 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1068 sheet_signals[ACTIVATE] =
1069 g_signal_new ("activate",
1070 G_TYPE_FROM_CLASS (object_class),
1072 offsetof (GtkSheetClass, activate),
1074 gtkextra_BOOLEAN__INT_INT,
1075 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1077 sheet_signals[SET_CELL] =
1078 g_signal_new ("set-cell",
1079 G_TYPE_FROM_CLASS (object_class),
1081 offsetof (GtkSheetClass, set_cell),
1083 gtkextra_VOID__INT_INT,
1084 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1087 sheet_signals[CLEAR_CELL] =
1088 g_signal_new ("clear-cell",
1089 G_TYPE_FROM_CLASS (object_class),
1091 offsetof (GtkSheetClass, clear_cell),
1093 gtkextra_VOID__INT_INT,
1094 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1096 sheet_signals[CHANGED] =
1097 g_signal_new ("changed",
1098 G_TYPE_FROM_CLASS (object_class),
1100 offsetof (GtkSheetClass, changed),
1102 gtkextra_VOID__INT_INT,
1103 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1105 sheet_signals[NEW_COL_WIDTH] =
1106 g_signal_new ("new-column-width",
1107 G_TYPE_FROM_CLASS (object_class),
1109 offsetof (GtkSheetClass, new_column_width), /*!!!! */
1111 gtkextra_VOID__INT_INT,
1112 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1114 sheet_signals[NEW_ROW_HEIGHT] =
1115 g_signal_new ("new-row-height",
1116 G_TYPE_FROM_CLASS (object_class),
1118 offsetof (GtkSheetClass, new_row_height), /*!!!! */
1120 gtkextra_VOID__INT_INT,
1121 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1123 widget_class->set_scroll_adjustments_signal =
1124 g_signal_new ("set-scroll-adjustments",
1125 G_TYPE_FROM_CLASS (object_class),
1127 offsetof (GtkSheetClass, set_scroll_adjustments),
1129 gtkextra_VOID__OBJECT_OBJECT,
1130 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1133 container_class->add = NULL;
1134 container_class->remove = gtk_sheet_remove;
1135 container_class->forall = gtk_sheet_forall;
1137 object_class->destroy = gtk_sheet_destroy;
1138 gobject_class->finalize = gtk_sheet_finalize;
1140 widget_class->realize = gtk_sheet_realize;
1141 widget_class->unrealize = gtk_sheet_unrealize;
1142 widget_class->map = gtk_sheet_map;
1143 widget_class->unmap = gtk_sheet_unmap;
1144 widget_class->style_set = gtk_sheet_style_set;
1145 widget_class->button_press_event = gtk_sheet_button_press;
1146 widget_class->button_release_event = gtk_sheet_button_release;
1147 widget_class->motion_notify_event = gtk_sheet_motion;
1148 widget_class->key_press_event = gtk_sheet_key_press;
1149 widget_class->expose_event = gtk_sheet_expose;
1150 widget_class->size_request = gtk_sheet_size_request;
1151 widget_class->size_allocate = gtk_sheet_size_allocate;
1152 widget_class->focus_in_event = NULL;
1153 widget_class->focus_out_event = NULL;
1155 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1156 klass->select_row = NULL;
1157 klass->select_column = NULL;
1158 klass->select_range = NULL;
1159 klass->resize_range = NULL;
1160 klass->move_range = NULL;
1161 klass->traverse = NULL;
1162 klass->deactivate = NULL;
1163 klass->activate = NULL;
1164 klass->set_cell = NULL;
1165 klass->clear_cell = NULL;
1166 klass->changed = NULL;
1170 gtk_sheet_init (GtkSheet *sheet)
1172 sheet->column_geometry = NULL;
1173 sheet->row_geometry = NULL;
1175 sheet->children = NULL;
1178 sheet->selection_mode = GTK_SELECTION_NONE;
1179 sheet->freeze_count = 0;
1180 sheet->state = GTK_SHEET_NORMAL;
1182 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1183 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1185 sheet->column_title_window = NULL;
1186 sheet->column_title_area.x = 0;
1187 sheet->column_title_area.y = 0;
1188 sheet->column_title_area.width = 0;
1189 sheet->column_title_area.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
1191 sheet->row_title_window = NULL;
1192 sheet->row_title_area.x = 0;
1193 sheet->row_title_area.y = 0;
1194 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1195 sheet->row_title_area.height = 0;
1198 sheet->active_cell.row = 0;
1199 sheet->active_cell.col = 0;
1200 sheet->selection_cell.row = 0;
1201 sheet->selection_cell.col = 0;
1203 sheet->sheet_entry = NULL;
1204 sheet->pixmap = NULL;
1206 sheet->range.row0 = 0;
1207 sheet->range.rowi = 0;
1208 sheet->range.col0 = 0;
1209 sheet->range.coli = 0;
1211 sheet->state = GTK_SHEET_NORMAL;
1213 sheet->sheet_window = NULL;
1214 sheet->sheet_window_width = 0;
1215 sheet->sheet_window_height = 0;
1216 sheet->sheet_entry = NULL;
1217 sheet->button = NULL;
1222 sheet->hadjustment = NULL;
1223 sheet->vadjustment = NULL;
1225 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
1226 sheet->xor_gc = NULL;
1227 sheet->fg_gc = NULL;
1228 sheet->bg_gc = NULL;
1232 gdk_color_parse ("white", &sheet->bg_color);
1233 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1234 gdk_color_parse ("gray", &sheet->grid_color);
1235 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1236 sheet->show_grid = TRUE;
1238 sheet->motion_timer = 0;
1242 /* Callback which occurs whenever columns are inserted / deleted in the model */
1244 columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
1249 GtkSheet *sheet = GTK_SHEET (data);
1251 GtkSheetRange range;
1252 gint model_columns = g_sheet_model_get_column_count (model);
1255 /* Need to update all the columns starting from the first column and onwards.
1256 * Previous column are unchanged, so don't need to be updated.
1258 range.col0 = first_column;
1260 range.coli = xxx_column_count (sheet) - 1;
1261 range.rowi = yyy_row_count (sheet) - 1;
1263 adjust_scrollbars (sheet);
1265 if (sheet->active_cell.col >= model_columns)
1266 gtk_sheet_activate_cell (sheet, sheet->active_cell.row, model_columns - 1);
1268 for (i = first_column; i <= MAX_VISIBLE_COLUMN (sheet); i++)
1269 gtk_sheet_column_title_button_draw (sheet, i);
1271 gtk_sheet_range_draw (sheet, &range);
1275 /* Callback which occurs whenever rows are inserted / deleted in the model */
1277 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
1278 gint n_rows, gpointer data)
1281 GtkSheet *sheet = GTK_SHEET (data);
1283 GtkSheetRange range;
1285 gint model_rows = g_sheet_model_get_row_count (model);
1287 /* Need to update all the rows starting from the first row and onwards.
1288 * Previous rows are unchanged, so don't need to be updated.
1290 range.row0 = first_row;
1292 range.rowi = yyy_row_count (sheet) - 1;
1293 range.coli = xxx_column_count (sheet) - 1;
1295 adjust_scrollbars (sheet);
1297 if (sheet->active_cell.row >= model_rows)
1298 gtk_sheet_activate_cell (sheet, model_rows - 1, sheet->active_cell.col);
1300 for (i = first_row; i <= MAX_VISIBLE_ROW (sheet); i++)
1301 gtk_sheet_row_title_button_draw (sheet, i);
1303 gtk_sheet_range_draw (sheet, &range);
1307 If row0 or rowi are negative, then all rows will be updated.
1308 If col0 or coli are negative, then all columns will be updated.
1311 range_update_callback (GSheetModel *m, gint row0, gint col0,
1312 gint rowi, gint coli, gpointer data)
1314 GtkSheet *sheet = GTK_SHEET (data);
1316 GtkSheetRange range;
1323 if ( MAX_VISIBLE_ROW (sheet) >
1324 g_sheet_model_get_row_count (sheet->model)
1326 MAX_VISIBLE_COLUMN (sheet) >
1327 g_sheet_model_get_column_count (sheet->model))
1329 gtk_sheet_move_query (sheet, 0, 0);
1332 if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1335 gtk_sheet_range_draw (sheet, NULL);
1336 adjust_scrollbars (sheet);
1338 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
1339 gtk_sheet_row_title_button_draw (sheet, i);
1341 for (i = MIN_VISIBLE_COLUMN (sheet);
1342 i <= MAX_VISIBLE_COLUMN (sheet); i++)
1343 gtk_sheet_column_title_button_draw (sheet, i);
1347 else if ( row0 < 0 || rowi < 0 )
1349 range.row0 = MIN_VISIBLE_ROW (sheet);
1350 range.rowi = MAX_VISIBLE_ROW (sheet);
1352 else if ( col0 < 0 || coli < 0 )
1354 range.col0 = MIN_VISIBLE_COLUMN (sheet);
1355 range.coli = MAX_VISIBLE_COLUMN (sheet);
1358 gtk_sheet_range_draw (sheet, &range);
1362 static void gtk_sheet_construct (GtkSheet *sheet,
1365 const gchar *title);
1370 * @rows: initial number of rows
1371 * @columns: initial number of columns
1372 * @title: sheet title
1373 * @model: the model to use for the sheet data
1375 * Creates a new sheet widget with the given number of rows and columns.
1377 * Returns: the new sheet widget
1380 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1383 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1385 gtk_sheet_construct (GTK_SHEET (widget), vgeo, hgeo, title);
1388 gtk_sheet_set_model (GTK_SHEET (widget), model);
1396 * gtk_sheet_set_model
1397 * @sheet: the sheet to set the model for
1398 * @model: the model to use for the sheet data
1400 * Sets the model for a GtkSheet
1404 gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
1406 g_return_if_fail (GTK_IS_SHEET (sheet));
1407 g_return_if_fail (G_IS_SHEET_MODEL (model));
1409 sheet->model = model;
1411 g_signal_connect (model, "range_changed",
1412 G_CALLBACK (range_update_callback), sheet);
1414 g_signal_connect (model, "rows_inserted",
1415 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1417 g_signal_connect (model, "rows_deleted",
1418 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1420 g_signal_connect (model, "columns_inserted",
1421 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1423 g_signal_connect (model, "columns_deleted",
1424 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1429 /* Call back for when the column titles have changed.
1430 FIRST is the first column changed.
1431 N_COLUMNS is the number of columns which have changed, or - 1, which
1432 indicates that the column has changed to its right - most extremity
1435 column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
1437 GtkSheet *sheet = GTK_SHEET (data);
1438 gboolean extremity = FALSE;
1440 if ( n_columns == -1 )
1443 n_columns = xxx_column_count (sheet) - 1 ;
1446 if (!GTK_SHEET_IS_FROZEN (sheet))
1449 for ( i = first ; i <= first + n_columns ; ++i )
1451 gtk_sheet_column_title_button_draw (sheet, i);
1452 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, i);
1457 gtk_sheet_column_title_button_draw (sheet, -1);
1462 gtk_sheet_construct (GtkSheet *sheet,
1467 g_return_if_fail (G_IS_SHEET_COLUMN (hgeo));
1468 g_return_if_fail (G_IS_SHEET_ROW (vgeo));
1470 sheet->column_geometry = hgeo;
1471 sheet->row_geometry = vgeo;
1474 sheet->columns_resizable = TRUE;
1475 sheet->rows_resizable = TRUE;
1477 sheet->row_titles_visible = TRUE;
1478 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1480 sheet->column_titles_visible = TRUE;
1481 sheet->autoscroll = TRUE;
1482 sheet->justify_entry = TRUE;
1485 /* create sheet entry */
1486 sheet->entry_type = 0;
1487 create_sheet_entry (sheet);
1489 /* create global selection button */
1490 create_global_button (sheet);
1493 sheet->name = g_strdup (title);
1495 g_signal_connect (sheet->column_geometry, "columns_changed",
1496 G_CALLBACK (column_titles_changed), sheet);
1502 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns,
1503 const gchar *title, GtkType entry_type)
1505 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1507 gtk_sheet_construct_with_custom_entry (GTK_SHEET (widget),
1508 rows, columns, title, entry_type);
1514 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1520 gtk_sheet_construct (sheet, vgeo, hgeo, title);
1522 sheet->entry_type = entry_type;
1523 create_sheet_entry (sheet);
1529 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
1533 g_return_if_fail (sheet != NULL);
1534 g_return_if_fail (GTK_IS_SHEET (sheet));
1536 state = sheet->state;
1538 if (sheet->state == GTK_SHEET_NORMAL)
1539 gtk_sheet_hide_active_cell (sheet);
1541 sheet->entry_type = entry_type;
1543 create_sheet_entry (sheet);
1545 if (state == GTK_SHEET_NORMAL)
1547 gtk_sheet_show_active_cell (sheet);
1548 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
1550 G_CALLBACK (gtk_sheet_entry_changed),
1556 gtk_sheet_show_grid (GtkSheet *sheet, gboolean show)
1558 g_return_if_fail (sheet != NULL);
1559 g_return_if_fail (GTK_IS_SHEET (sheet));
1561 if (show == sheet->show_grid) return;
1563 sheet->show_grid = show;
1565 if (!GTK_SHEET_IS_FROZEN (sheet))
1566 gtk_sheet_range_draw (sheet, NULL);
1570 gtk_sheet_grid_visible (GtkSheet *sheet)
1572 g_return_val_if_fail (sheet != NULL, 0);
1573 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1575 return sheet->show_grid;
1579 gtk_sheet_set_background (GtkSheet *sheet, GdkColor *color)
1581 g_return_if_fail (sheet != NULL);
1582 g_return_if_fail (GTK_IS_SHEET (sheet));
1586 gdk_color_parse ("white", &sheet->bg_color);
1587 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1590 sheet->bg_color = *color;
1592 if (!GTK_SHEET_IS_FROZEN (sheet))
1593 gtk_sheet_range_draw (sheet, NULL);
1597 gtk_sheet_set_grid (GtkSheet *sheet, GdkColor *color)
1599 g_return_if_fail (sheet != NULL);
1600 g_return_if_fail (GTK_IS_SHEET (sheet));
1604 gdk_color_parse ("black", &sheet->grid_color);
1605 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1608 sheet->grid_color = *color;
1610 if (!GTK_SHEET_IS_FROZEN (sheet))
1611 gtk_sheet_range_draw (sheet, NULL);
1615 gtk_sheet_get_columns_count (GtkSheet *sheet)
1617 g_return_val_if_fail (sheet != NULL, 0);
1618 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1620 return xxx_column_count (sheet);
1624 gtk_sheet_get_rows_count (GtkSheet *sheet)
1626 g_return_val_if_fail (sheet != NULL, 0);
1627 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1629 return yyy_row_count (sheet);
1633 gtk_sheet_get_state (GtkSheet *sheet)
1635 g_return_val_if_fail (sheet != NULL, 0);
1636 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1638 return (sheet->state);
1642 gtk_sheet_set_selection_mode (GtkSheet *sheet, gint mode)
1644 g_return_if_fail (sheet != NULL);
1645 g_return_if_fail (GTK_IS_SHEET (sheet));
1647 if (GTK_WIDGET_REALIZED (sheet))
1648 gtk_sheet_real_unselect_range (sheet, NULL);
1650 sheet->selection_mode = mode;
1654 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1656 g_return_if_fail (sheet != NULL);
1657 g_return_if_fail (GTK_IS_SHEET (sheet));
1659 sheet->autoresize = autoresize;
1663 gtk_sheet_autoresize (GtkSheet *sheet)
1665 g_return_val_if_fail (sheet != NULL, FALSE);
1666 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1668 return sheet->autoresize;
1672 gtk_sheet_set_column_width (GtkSheet * sheet,
1678 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1680 gint text_width = 0;
1683 g_return_if_fail (sheet != NULL);
1684 g_return_if_fail (GTK_IS_SHEET (sheet));
1685 if (column >= xxx_column_count (sheet) || column < 0) return;
1687 for (row = 0; row < yyy_row_count (sheet); row++)
1689 gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
1690 if (text && strlen (text) > 0)
1692 GtkSheetCellAttr attributes;
1694 gtk_sheet_get_attributes (sheet, row, column, &attributes);
1695 if (attributes.is_visible)
1697 gint width = STRING_WIDTH (GTK_WIDGET (sheet),
1698 attributes.font_desc,
1700 + 2 * CELLOFFSET + attributes.border.width;
1701 text_width = MAX (text_width, width);
1704 dispose_string (sheet, text);
1707 if (text_width > xxx_column_width (sheet, column) )
1709 gtk_sheet_set_column_width (sheet, column, text_width);
1710 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
1716 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1718 g_return_if_fail (sheet != NULL);
1719 g_return_if_fail (GTK_IS_SHEET (sheet));
1721 sheet->autoscroll = autoscroll;
1725 gtk_sheet_autoscroll (GtkSheet *sheet)
1727 g_return_val_if_fail (sheet != NULL, FALSE);
1728 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1730 return sheet->autoscroll;
1735 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1737 g_return_if_fail (sheet != NULL);
1738 g_return_if_fail (GTK_IS_SHEET (sheet));
1740 sheet->justify_entry = justify;
1744 gtk_sheet_justify_entry (GtkSheet *sheet)
1746 g_return_val_if_fail (sheet != NULL, FALSE);
1747 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1749 return sheet->justify_entry;
1753 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1755 g_return_if_fail (sheet != NULL);
1756 g_return_if_fail (GTK_IS_SHEET (sheet));
1760 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_LOCKED);
1761 gtk_widget_hide (sheet->sheet_entry);
1762 gtk_widget_unmap (sheet->sheet_entry);
1766 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_LOCKED);
1767 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)))
1769 gtk_widget_show (sheet->sheet_entry);
1770 gtk_widget_map (sheet->sheet_entry);
1774 gtk_editable_set_editable (GTK_EDITABLE (sheet->sheet_entry), locked);
1779 gtk_sheet_locked (const GtkSheet *sheet)
1781 g_return_val_if_fail (sheet != NULL, FALSE);
1782 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1784 return GTK_SHEET_IS_LOCKED (sheet);
1787 /* This routine has problems with gtk+- 1.2 related with the
1788 label / button drawing - I think it's a bug in gtk+- 1.2 */
1790 gtk_sheet_set_title (GtkSheet *sheet, const gchar *title)
1794 g_return_if_fail (sheet != NULL);
1795 g_return_if_fail (title != NULL);
1796 g_return_if_fail (GTK_IS_SHEET (sheet));
1799 g_free (sheet->name);
1801 sheet->name = g_strdup (title);
1803 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) || !title) return;
1805 if (GTK_BIN (sheet->button)->child)
1806 label = GTK_BIN (sheet->button)->child;
1808 size_allocate_global_button (sheet);
1812 gtk_sheet_freeze (GtkSheet *sheet)
1814 g_return_if_fail (sheet != NULL);
1815 g_return_if_fail (GTK_IS_SHEET (sheet));
1817 sheet->freeze_count++;
1818 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1822 gtk_sheet_thaw (GtkSheet *sheet)
1824 g_return_if_fail (sheet != NULL);
1825 g_return_if_fail (GTK_IS_SHEET (sheet));
1827 if (sheet->freeze_count == 0) return;
1829 sheet->freeze_count--;
1830 if (sheet->freeze_count > 0) return;
1832 adjust_scrollbars (sheet);
1834 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1836 sheet->old_vadjustment = -1.;
1837 sheet->old_hadjustment = -1.;
1839 if (sheet->hadjustment)
1840 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1842 if (sheet->vadjustment)
1843 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1846 if (sheet->state == GTK_STATE_NORMAL)
1847 if (sheet->sheet_entry && GTK_WIDGET_MAPPED (sheet->sheet_entry))
1849 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
1850 sheet->active_cell.col);
1856 gtk_sheet_set_row_titles_width (GtkSheet *sheet, guint width)
1858 if (width < COLUMN_MIN_WIDTH) return;
1860 sheet->row_title_area.width = width;
1862 adjust_scrollbars (sheet);
1864 sheet->old_hadjustment = -1.;
1865 if (sheet->hadjustment)
1866 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1868 size_allocate_global_button (sheet);
1872 gtk_sheet_set_column_titles_height (GtkSheet *sheet, guint height)
1874 if (height < DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))) return;
1876 sheet->column_title_area.height = height;
1878 adjust_scrollbars (sheet);
1880 sheet->old_vadjustment = -1.;
1881 if (sheet->vadjustment)
1882 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1884 size_allocate_global_button (sheet);
1888 gtk_sheet_show_column_titles (GtkSheet *sheet)
1892 if (sheet->column_titles_visible) return;
1894 sheet->column_titles_visible = TRUE;
1897 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1899 gdk_window_show (sheet->column_title_window);
1900 gdk_window_move_resize (sheet->column_title_window,
1901 sheet->column_title_area.x,
1902 sheet->column_title_area.y,
1903 sheet->column_title_area.width,
1904 sheet->column_title_area.height);
1906 for (col = MIN_VISIBLE_COLUMN (sheet);
1907 col <= MAX_VISIBLE_COLUMN (sheet);
1910 GtkSheetButton *button = xxx_column_button (sheet, col);
1911 GtkSheetChild *child = button->child;
1913 gtk_sheet_child_show (child);
1914 gtk_sheet_button_free (button);
1916 adjust_scrollbars (sheet);
1919 sheet->old_vadjustment = -1.;
1920 if (sheet->vadjustment)
1921 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1923 size_allocate_global_button (sheet);
1928 gtk_sheet_show_row_titles (GtkSheet *sheet)
1932 if (sheet->row_titles_visible) return;
1934 sheet->row_titles_visible = TRUE;
1937 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1939 gdk_window_show (sheet->row_title_window);
1940 gdk_window_move_resize (sheet->row_title_window,
1941 sheet->row_title_area.x,
1942 sheet->row_title_area.y,
1943 sheet->row_title_area.width,
1944 sheet->row_title_area.height);
1946 for (row = MIN_VISIBLE_ROW (sheet);
1947 row <= MAX_VISIBLE_ROW (sheet);
1950 const GtkSheetButton *button = yyy_row_button (sheet, row);
1951 GtkSheetChild *child = button->child;
1955 gtk_sheet_child_show (child);
1958 adjust_scrollbars (sheet);
1961 sheet->old_hadjustment = -1.;
1962 if (sheet->hadjustment)
1963 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1965 size_allocate_global_button (sheet);
1969 gtk_sheet_hide_column_titles (GtkSheet *sheet)
1973 if (!sheet->column_titles_visible) return;
1975 sheet->column_titles_visible = FALSE;
1977 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1979 if (sheet->column_title_window)
1980 gdk_window_hide (sheet->column_title_window);
1981 if (GTK_WIDGET_VISIBLE (sheet->button))
1982 gtk_widget_hide (sheet->button);
1984 for (col = MIN_VISIBLE_COLUMN (sheet);
1985 col <= MAX_VISIBLE_COLUMN (sheet);
1988 GtkSheetButton *button = xxx_column_button (sheet, col);
1989 GtkSheetChild *child = button->child;
1991 gtk_sheet_child_hide (child);
1992 gtk_sheet_button_free (button);
1994 adjust_scrollbars (sheet);
1997 sheet->old_vadjustment = -1.;
1998 if (sheet->vadjustment)
1999 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2004 gtk_sheet_hide_row_titles (GtkSheet *sheet)
2008 if (!sheet->row_titles_visible) return;
2010 sheet->row_titles_visible = FALSE;
2013 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
2015 if (sheet->row_title_window)
2016 gdk_window_hide (sheet->row_title_window);
2017 if (GTK_WIDGET_VISIBLE (sheet->button))
2018 gtk_widget_hide (sheet->button);
2019 for (row = MIN_VISIBLE_ROW (sheet);
2020 row <= MAX_VISIBLE_ROW (sheet);
2023 const GtkSheetButton *button = yyy_row_button (sheet, row);
2024 GtkSheetChild *child = button->child;
2027 gtk_sheet_child_hide (child);
2029 adjust_scrollbars (sheet);
2032 sheet->old_hadjustment = -1.;
2033 if (sheet->hadjustment)
2034 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2039 gtk_sheet_column_titles_visible (GtkSheet *sheet)
2041 g_return_val_if_fail (sheet != NULL, FALSE);
2042 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2043 return sheet->column_titles_visible;
2047 gtk_sheet_row_titles_visible (GtkSheet *sheet)
2049 g_return_val_if_fail (sheet != NULL, FALSE);
2050 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2051 return sheet->row_titles_visible;
2055 gtk_sheet_moveto (GtkSheet *sheet,
2062 guint width, height;
2064 gint min_row, min_col;
2066 g_return_if_fail (sheet != NULL);
2067 g_return_if_fail (GTK_IS_SHEET (sheet));
2068 g_return_if_fail (sheet->hadjustment != NULL);
2069 g_return_if_fail (sheet->vadjustment != NULL);
2071 if (row < 0 || row >= yyy_row_count (sheet))
2073 if (column < 0 || column >= xxx_column_count (sheet))
2076 height = sheet->sheet_window_height;
2077 width = sheet->sheet_window_width;
2079 /* adjust vertical scrollbar */
2080 if (row >= 0 && row_align >= 0.)
2082 y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
2083 - (gint) ( row_align*height + (1. - row_align)
2084 * yyy_row_height (sheet, row));
2086 /* This forces the sheet to scroll when you don't see the entire cell */
2089 if (row_align == 1.)
2091 while (min_row >= 0 && min_row > MIN_VISIBLE_ROW (sheet))
2093 if (yyy_row_is_visible (sheet, min_row))
2094 adjust += yyy_row_height (sheet, min_row);
2095 if (adjust >= height)
2101 min_row = MAX (min_row, 0);
2102 y = ROW_TOP_YPIXEL (sheet, min_row) - sheet->voffset +
2103 yyy_row_height (sheet, min_row) - 1;
2107 sheet->vadjustment->value = 0.0;
2109 sheet->vadjustment->value = y;
2111 sheet->old_vadjustment = -1.;
2112 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2117 /* adjust horizontal scrollbar */
2118 if (column >= 0 && col_align >= 0.)
2120 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2121 - (gint) ( col_align*width + (1.- col_align)*
2122 xxx_column_width (sheet, column));
2125 /* This forces the sheet to scroll when you don't see the entire cell */
2128 if (col_align == 1.)
2130 while (min_col >= 0 && min_col > MIN_VISIBLE_COLUMN (sheet))
2132 if (xxx_column_is_visible (sheet, min_col))
2133 adjust += xxx_column_width (sheet, min_col);
2135 if (adjust >= width)
2141 min_col = MAX (min_col, 0);
2142 x = COLUMN_LEFT_XPIXEL (sheet, min_col) - sheet->hoffset +
2143 xxx_column_width (sheet, min_col) - 1;
2147 sheet->hadjustment->value = 0.0;
2149 sheet->hadjustment->value = x;
2151 sheet->old_vadjustment = -1.;
2152 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2160 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2162 g_return_if_fail (sheet != NULL);
2163 g_return_if_fail (GTK_IS_SHEET (sheet));
2165 sheet->columns_resizable = resizable;
2169 gtk_sheet_columns_resizable (GtkSheet *sheet)
2171 g_return_val_if_fail (sheet != NULL, FALSE);
2172 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2174 return sheet->columns_resizable;
2179 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2181 g_return_if_fail (sheet != NULL);
2182 g_return_if_fail (GTK_IS_SHEET (sheet));
2184 sheet->rows_resizable = resizable;
2188 gtk_sheet_rows_resizable (GtkSheet *sheet)
2190 g_return_val_if_fail (sheet != NULL, FALSE);
2191 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2193 return sheet->rows_resizable;
2198 gtk_sheet_select_row (GtkSheet * sheet,
2201 g_return_if_fail (sheet != NULL);
2202 g_return_if_fail (GTK_IS_SHEET (sheet));
2204 if (row < 0 || row >= yyy_row_count (sheet))
2207 if (sheet->state != GTK_SHEET_NORMAL)
2208 gtk_sheet_real_unselect_range (sheet, NULL);
2211 gboolean veto = TRUE;
2212 veto = gtk_sheet_deactivate_cell (sheet);
2216 sheet->state = GTK_SHEET_ROW_SELECTED;
2217 sheet->range.row0 = row;
2218 sheet->range.col0 = 0;
2219 sheet->range.rowi = row;
2220 sheet->range.coli = xxx_column_count (sheet) - 1;
2221 sheet->active_cell.row = row;
2222 sheet->active_cell.col = 0;
2224 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, row);
2225 gtk_sheet_real_select_range (sheet, NULL);
2230 gtk_sheet_select_column (GtkSheet * sheet, gint column)
2232 g_return_if_fail (sheet != NULL);
2233 g_return_if_fail (GTK_IS_SHEET (sheet));
2235 if (column < 0 || column >= xxx_column_count (sheet))
2238 if (sheet->state != GTK_SHEET_NORMAL)
2239 gtk_sheet_real_unselect_range (sheet, NULL);
2242 gboolean veto = TRUE;
2243 veto = gtk_sheet_deactivate_cell (sheet);
2247 sheet->state = GTK_SHEET_COLUMN_SELECTED;
2248 sheet->range.row0 = 0;
2249 sheet->range.col0 = column;
2250 sheet->range.rowi = yyy_row_count (sheet) - 1;
2251 sheet->range.coli = column;
2252 sheet->active_cell.row = 0;
2253 sheet->active_cell.col = column;
2255 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, column);
2256 gtk_sheet_real_select_range (sheet, NULL);
2263 gtk_sheet_range_isvisible (const GtkSheet * sheet,
2264 GtkSheetRange range)
2266 g_return_val_if_fail (sheet != NULL, FALSE);
2268 if (range.row0 < 0 || range.row0 >= yyy_row_count (sheet))
2271 if (range.rowi < 0 || range.rowi >= yyy_row_count (sheet))
2274 if (range.col0 < 0 || range.col0 >= xxx_column_count (sheet))
2277 if (range.coli < 0 || range.coli >= xxx_column_count (sheet))
2280 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2283 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2286 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2289 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2296 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2297 gint row, gint column)
2299 GtkSheetRange range;
2302 range.col0 = column;
2304 range.coli = column;
2306 return gtk_sheet_range_isvisible (sheet, range);
2310 gtk_sheet_get_visible_range (GtkSheet *sheet, GtkSheetRange *range)
2312 g_return_if_fail (sheet != NULL);
2313 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2314 g_return_if_fail (range != NULL);
2316 range->row0 = MIN_VISIBLE_ROW (sheet);
2317 range->col0 = MIN_VISIBLE_COLUMN (sheet);
2318 range->rowi = MAX_VISIBLE_ROW (sheet);
2319 range->coli = MAX_VISIBLE_COLUMN (sheet);
2323 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2325 g_return_val_if_fail (sheet != NULL, NULL);
2326 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2328 return sheet->vadjustment;
2332 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2334 g_return_val_if_fail (sheet != NULL, NULL);
2335 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2337 return sheet->hadjustment;
2341 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2342 GtkAdjustment *adjustment)
2344 GtkAdjustment *old_adjustment;
2346 g_return_if_fail (sheet != NULL);
2347 g_return_if_fail (GTK_IS_SHEET (sheet));
2349 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2351 if (sheet->vadjustment == adjustment)
2354 old_adjustment = sheet->vadjustment;
2356 if (sheet->vadjustment)
2358 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2359 G_SIGNAL_MATCH_DATA,
2362 g_object_unref (G_OBJECT (sheet->vadjustment));
2365 sheet->vadjustment = adjustment;
2367 if (sheet->vadjustment)
2369 g_object_ref (G_OBJECT (sheet->vadjustment));
2370 g_object_ref_sink (G_OBJECT (sheet->vadjustment));
2372 g_signal_connect (G_OBJECT (sheet->vadjustment), "value_changed",
2373 G_CALLBACK (vadjustment_value_changed),
2377 if (!sheet->vadjustment || !old_adjustment)
2379 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2383 sheet->old_vadjustment = sheet->vadjustment->value;
2387 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2388 GtkAdjustment *adjustment)
2390 GtkAdjustment *old_adjustment;
2392 g_return_if_fail (sheet != NULL);
2393 g_return_if_fail (GTK_IS_SHEET (sheet));
2395 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2397 if (sheet->hadjustment == adjustment)
2400 old_adjustment = sheet->hadjustment;
2402 if (sheet->hadjustment)
2404 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2405 G_SIGNAL_MATCH_DATA,
2408 g_object_unref (G_OBJECT (sheet->hadjustment));
2411 sheet->hadjustment = adjustment;
2413 if (sheet->hadjustment)
2415 g_object_ref (G_OBJECT (sheet->hadjustment));
2416 g_object_ref_sink (G_OBJECT (sheet->hadjustment));
2418 g_signal_connect (G_OBJECT (sheet->hadjustment), "value_changed",
2419 G_CALLBACK (hadjustment_value_changed),
2423 if (!sheet->hadjustment || !old_adjustment)
2425 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2429 sheet->old_hadjustment = sheet->hadjustment->value;
2433 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2434 GtkAdjustment *hadjustment,
2435 GtkAdjustment *vadjustment)
2437 if (sheet->hadjustment != hadjustment)
2438 gtk_sheet_set_hadjustment (sheet, hadjustment);
2440 if (sheet->vadjustment != vadjustment)
2441 gtk_sheet_set_vadjustment (sheet, vadjustment);
2445 gtk_sheet_finalize (GObject * object)
2449 g_return_if_fail (object != NULL);
2450 g_return_if_fail (GTK_IS_SHEET (object));
2452 sheet = GTK_SHEET (object);
2456 g_free (sheet->name);
2460 if (G_OBJECT_CLASS (parent_class)->finalize)
2461 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2465 gtk_sheet_destroy (GtkObject * object)
2470 g_return_if_fail (object != NULL);
2471 g_return_if_fail (GTK_IS_SHEET (object));
2473 sheet = GTK_SHEET (object);
2475 /* destroy the entry */
2476 if (sheet->sheet_entry && GTK_IS_WIDGET (sheet->sheet_entry))
2478 gtk_widget_destroy (sheet->sheet_entry);
2479 sheet->sheet_entry = NULL;
2482 /* destroy the global selection button */
2483 if (sheet->button && GTK_IS_WIDGET (sheet->button))
2485 gtk_widget_destroy (sheet->button);
2486 sheet->button = NULL;
2489 /* unref adjustments */
2490 if (sheet->hadjustment)
2492 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2493 G_SIGNAL_MATCH_DATA,
2497 g_object_unref (G_OBJECT (sheet->hadjustment));
2498 sheet->hadjustment = NULL;
2501 if (sheet->vadjustment)
2503 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2504 G_SIGNAL_MATCH_DATA,
2508 g_object_unref (G_OBJECT (sheet->vadjustment));
2510 sheet->vadjustment = NULL;
2513 children = sheet->children;
2516 GtkSheetChild *child = (GtkSheetChild *)children->data;
2517 if (child && child->widget)
2518 gtk_sheet_remove (GTK_CONTAINER (sheet), child->widget);
2519 children = sheet->children;
2521 sheet->children = NULL;
2523 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2524 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2528 gtk_sheet_style_set (GtkWidget *widget,
2529 GtkStyle *previous_style)
2533 g_return_if_fail (widget != NULL);
2534 g_return_if_fail (GTK_IS_SHEET (widget));
2536 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2537 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2539 sheet = GTK_SHEET (widget);
2541 if (GTK_WIDGET_REALIZED (widget))
2543 gtk_style_set_background (widget->style, widget->window, widget->state);
2549 gtk_sheet_realize (GtkWidget * widget)
2552 GdkWindowAttr attributes;
2553 gint attributes_mask;
2554 GdkGCValues values, auxvalues;
2555 GdkColormap *colormap;
2557 GtkSheetChild *child;
2560 g_return_if_fail (widget != NULL);
2561 g_return_if_fail (GTK_IS_SHEET (widget));
2563 sheet = GTK_SHEET (widget);
2565 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2567 attributes.window_type = GDK_WINDOW_CHILD;
2568 attributes.x = widget->allocation.x;
2569 attributes.y = widget->allocation.y;
2570 attributes.width = widget->allocation.width;
2571 attributes.height = widget->allocation.height;
2572 attributes.wclass = GDK_INPUT_OUTPUT;
2574 attributes.visual = gtk_widget_get_visual (widget);
2575 attributes.colormap = gtk_widget_get_colormap (widget);
2577 attributes.event_mask = gtk_widget_get_events (widget);
2578 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2579 GDK_BUTTON_PRESS_MASK |
2580 GDK_BUTTON_RELEASE_MASK |
2581 GDK_KEY_PRESS_MASK |
2582 GDK_POINTER_MOTION_MASK |
2583 GDK_POINTER_MOTION_HINT_MASK);
2584 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2587 attributes.cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2590 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2592 gdk_window_set_user_data (widget->window, sheet);
2594 widget->style = gtk_style_attach (widget->style, widget->window);
2596 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2599 if (sheet->row_titles_visible)
2600 attributes.x = sheet->row_title_area.width;
2602 attributes.width = sheet->column_title_area.width;
2603 attributes.height = sheet->column_title_area.height;
2605 /* column - title window */
2606 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2607 gdk_window_set_user_data (sheet->column_title_window, sheet);
2608 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2612 if (sheet->column_titles_visible)
2613 attributes.y = sheet->column_title_area.height;
2614 attributes.width = sheet->row_title_area.width;
2615 attributes.height = sheet->row_title_area.height;
2617 /* row - title window */
2618 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2619 gdk_window_set_user_data (sheet->row_title_window, sheet);
2620 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2622 /* sheet - window */
2623 attributes.cursor = gdk_cursor_new (GDK_PLUS);
2627 attributes.width = sheet->sheet_window_width,
2628 attributes.height = sheet->sheet_window_height;
2630 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2631 gdk_window_set_user_data (sheet->sheet_window, sheet);
2633 gdk_cursor_unref (attributes.cursor);
2635 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2636 gdk_window_show (sheet->sheet_window);
2638 /* backing_pixmap */
2639 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
2643 gdk_gc_unref (sheet->fg_gc);
2645 gdk_gc_unref (sheet->bg_gc);
2646 sheet->fg_gc = gdk_gc_new (widget->window);
2647 sheet->bg_gc = gdk_gc_new (widget->window);
2649 colormap = gtk_widget_get_colormap (widget);
2651 gdk_color_white (colormap, &widget->style->white);
2652 gdk_color_black (colormap, &widget->style->black);
2654 gdk_gc_get_values (sheet->fg_gc, &auxvalues);
2656 values.foreground = widget->style->white;
2657 values.function = GDK_INVERT;
2658 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2660 gdk_gc_unref (sheet->xor_gc);
2661 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2667 if (sheet->sheet_entry->parent)
2669 gtk_widget_ref (sheet->sheet_entry);
2670 gtk_widget_unparent (sheet->sheet_entry);
2672 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2673 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
2675 if (sheet->button && sheet->button->parent)
2677 gtk_widget_ref (sheet->button);
2678 gtk_widget_unparent (sheet->button);
2680 gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
2681 gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
2683 if (!sheet->cursor_drag)
2684 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2686 if (sheet->column_titles_visible)
2687 gdk_window_show (sheet->column_title_window);
2688 if (sheet->row_titles_visible)
2689 gdk_window_show (sheet->row_title_window);
2691 size_allocate_row_title_buttons (sheet);
2692 size_allocate_column_title_buttons (sheet);
2694 name = g_strdup (sheet->name);
2695 gtk_sheet_set_title (sheet, name);
2699 children = sheet->children;
2702 child = children->data;
2703 children = children->next;
2705 gtk_sheet_realize_child (sheet, child);
2708 gtk_sheet_update_primary_selection (sheet);
2712 create_global_button (GtkSheet *sheet)
2714 sheet->button = gtk_button_new_with_label (" ");
2716 g_signal_connect (G_OBJECT (sheet->button),
2718 G_CALLBACK (global_button_clicked),
2723 size_allocate_global_button (GtkSheet *sheet)
2725 GtkAllocation allocation;
2727 if (!sheet->column_titles_visible) return;
2728 if (!sheet->row_titles_visible) return;
2730 gtk_widget_size_request (sheet->button, NULL);
2734 allocation.width = sheet->row_title_area.width;
2735 allocation.height = sheet->column_title_area.height;
2737 gtk_widget_size_allocate (sheet->button, &allocation);
2738 gtk_widget_show (sheet->button);
2742 global_button_clicked (GtkWidget *widget, gpointer data)
2746 gtk_sheet_click_cell (GTK_SHEET (data), - 1, - 1, &veto);
2747 gtk_widget_grab_focus (GTK_WIDGET (data));
2752 gtk_sheet_unrealize (GtkWidget * widget)
2756 g_return_if_fail (widget != NULL);
2757 g_return_if_fail (GTK_IS_SHEET (widget));
2759 sheet = GTK_SHEET (widget);
2761 gdk_cursor_destroy (sheet->cursor_drag);
2763 gdk_gc_destroy (sheet->xor_gc);
2764 gdk_gc_destroy (sheet->fg_gc);
2765 gdk_gc_destroy (sheet->bg_gc);
2767 gdk_window_destroy (sheet->sheet_window);
2768 gdk_window_destroy (sheet->column_title_window);
2769 gdk_window_destroy (sheet->row_title_window);
2773 g_object_unref (sheet->pixmap);
2774 sheet->pixmap = NULL;
2777 sheet->column_title_window = NULL;
2778 sheet->sheet_window = NULL;
2779 sheet->cursor_drag = NULL;
2780 sheet->xor_gc = NULL;
2781 sheet->fg_gc = NULL;
2782 sheet->bg_gc = NULL;
2784 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2785 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2789 gtk_sheet_map (GtkWidget * widget)
2792 GtkSheetChild *child;
2795 g_return_if_fail (widget != NULL);
2796 g_return_if_fail (GTK_IS_SHEET (widget));
2798 sheet = GTK_SHEET (widget);
2800 if (!GTK_WIDGET_MAPPED (widget))
2802 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2804 if (!sheet->cursor_drag) sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2806 gdk_window_show (widget->window);
2808 gdk_window_show (sheet->sheet_window);
2810 if (sheet->column_titles_visible)
2812 size_allocate_column_title_buttons (sheet);
2813 gdk_window_show (sheet->column_title_window);
2815 if (sheet->row_titles_visible)
2817 size_allocate_row_title_buttons (sheet);
2818 gdk_window_show (sheet->row_title_window);
2821 if (!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2822 && ! gtk_sheet_locked (sheet)
2823 && sheet->active_cell.row >= 0
2824 && sheet->active_cell.col >= 0 )
2826 gtk_widget_show (sheet->sheet_entry);
2827 gtk_widget_map (sheet->sheet_entry);
2830 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2831 !GTK_WIDGET_MAPPED (sheet->button))
2833 gtk_widget_show (sheet->button);
2834 gtk_widget_map (sheet->button);
2837 if (GTK_BIN (sheet->button)->child)
2838 if (GTK_WIDGET_VISIBLE (GTK_BIN (sheet->button)->child) &&
2839 !GTK_WIDGET_MAPPED (GTK_BIN (sheet->button)->child))
2840 gtk_widget_map (GTK_BIN (sheet->button)->child);
2842 gtk_sheet_range_draw (sheet, NULL);
2843 gtk_sheet_activate_cell (sheet,
2844 sheet->active_cell.row,
2845 sheet->active_cell.col);
2847 children = sheet->children;
2850 child = children->data;
2851 children = children->next;
2853 if (GTK_WIDGET_VISIBLE (child->widget) &&
2854 !GTK_WIDGET_MAPPED (child->widget))
2856 gtk_widget_map (child->widget);
2857 gtk_sheet_position_child (sheet, child);
2865 gtk_sheet_unmap (GtkWidget * widget)
2868 GtkSheetChild *child;
2871 g_return_if_fail (widget != NULL);
2872 g_return_if_fail (GTK_IS_SHEET (widget));
2874 sheet = GTK_SHEET (widget);
2876 if (GTK_WIDGET_MAPPED (widget))
2878 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2880 gdk_window_hide (sheet->sheet_window);
2881 if (sheet->column_titles_visible)
2882 gdk_window_hide (sheet->column_title_window);
2883 if (sheet->row_titles_visible)
2884 gdk_window_hide (sheet->row_title_window);
2885 gdk_window_hide (widget->window);
2887 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2888 gtk_widget_unmap (sheet->sheet_entry);
2890 if (GTK_WIDGET_MAPPED (sheet->button))
2891 gtk_widget_unmap (sheet->button);
2893 children = sheet->children;
2896 child = children->data;
2897 children = children->next;
2899 if (GTK_WIDGET_VISIBLE (child->widget) &&
2900 GTK_WIDGET_MAPPED (child->widget))
2902 gtk_widget_unmap (child->widget);
2911 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2914 GdkGC *fg_gc, *bg_gc;
2915 GtkSheetCellAttr attributes;
2918 g_return_if_fail (sheet != NULL);
2920 /* bail now if we arn't drawable yet */
2921 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2923 if (row < 0 || row >= yyy_row_count (sheet)) return;
2924 if (col < 0 || col >= xxx_column_count (sheet)) return;
2925 if (! xxx_column_is_visible (sheet, col)) return;
2926 if (! yyy_row_is_visible (sheet, row)) return;
2928 widget = GTK_WIDGET (sheet);
2930 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2932 /* select GC for background rectangle */
2933 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2934 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2936 fg_gc = sheet->fg_gc;
2937 bg_gc = sheet->bg_gc;
2939 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
2940 area.y = ROW_TOP_YPIXEL (sheet, row);
2941 area.width= xxx_column_width (sheet, col);
2942 area.height = yyy_row_height (sheet, row);
2944 gdk_draw_rectangle (sheet->pixmap,
2952 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
2954 if (sheet->show_grid)
2956 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
2958 gdk_draw_rectangle (sheet->pixmap,
2962 area.width, area.height);
2967 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
2972 gint text_width, text_height, y;
2974 gint size, sizel, sizer;
2975 GdkGC *fg_gc, *bg_gc;
2976 GtkSheetCellAttr attributes;
2977 PangoLayout *layout;
2978 PangoRectangle rect;
2979 PangoRectangle logical_rect;
2980 PangoLayoutLine *line;
2981 PangoFontMetrics *metrics;
2982 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (sheet));
2983 gint ascent, descent, y_pos;
2987 g_return_if_fail (sheet != NULL);
2989 /* bail now if we aren't drawable yet */
2990 if (!GTK_WIDGET_DRAWABLE (sheet))
2993 label = gtk_sheet_cell_get_text (sheet, row, col);
2997 if (row < 0 || row >= yyy_row_count (sheet)) return;
2998 if (col < 0 || col >= xxx_column_count (sheet)) return;
2999 if (! xxx_column_is_visible (sheet, col)) return;
3000 if (!yyy_row_is_visible (sheet, row)) return;
3003 widget = GTK_WIDGET (sheet);
3005 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3007 /* select GC for background rectangle */
3008 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3009 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3011 fg_gc = sheet->fg_gc;
3012 bg_gc = sheet->bg_gc;
3014 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
3015 area.y = ROW_TOP_YPIXEL (sheet, row);
3016 area.width = xxx_column_width (sheet, col);
3017 area.height = yyy_row_height (sheet, row);
3020 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
3021 dispose_string (sheet, label);
3022 pango_layout_set_font_description (layout, attributes.font_desc);
3024 pango_layout_get_pixel_extents (layout, NULL, &rect);
3026 line = pango_layout_get_lines (layout)->data;
3027 pango_layout_line_get_extents (line, NULL, &logical_rect);
3029 metrics = pango_context_get_metrics (context,
3030 attributes.font_desc,
3031 pango_context_get_language (context));
3033 ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
3034 descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
3036 pango_font_metrics_unref (metrics);
3038 /* Align primarily for locale's ascent / descent */
3040 logical_rect.height /= PANGO_SCALE;
3041 logical_rect.y /= PANGO_SCALE;
3042 y_pos = area.height - logical_rect.height;
3044 if (logical_rect.height > area.height)
3045 y_pos = (logical_rect.height - area.height - 2 * CELLOFFSET) / 2;
3048 else if (y_pos + logical_rect.height > area.height)
3049 y_pos = area.height - logical_rect.height;
3051 text_width = rect.width;
3052 text_height = rect.height;
3053 y = area.y + y_pos - CELLOFFSET;
3055 switch (attributes.justification)
3057 case GTK_JUSTIFY_RIGHT:
3059 area.x +=area.width;
3061 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3063 if ( !gtk_sheet_cell_empty (sheet, row, i)) break;
3064 if (size >= text_width + CELLOFFSET) break;
3065 size +=xxx_column_width (sheet, i);
3066 xxx_column_set_right_column (sheet, i,
3068 xxx_column_right_column (sheet, i)));
3073 xoffset += area.width - text_width - 2 * CELLOFFSET -
3074 attributes.border.width / 2;
3076 case GTK_JUSTIFY_CENTER:
3077 sizel = area.width / 2;
3078 sizer = area.width / 2;
3079 area.x += area.width / 2;
3081 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3083 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3084 if (sizer >= text_width / 2) break;
3085 sizer += xxx_column_width (sheet, i);
3086 xxx_column_set_left_column (sheet, i,
3089 xxx_column_left_column (sheet, i)));
3091 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3093 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3094 if (sizel >= text_width / 2) break;
3095 sizel +=xxx_column_width (sheet, i);
3096 xxx_column_set_right_column (sheet, i,
3098 xxx_column_right_column (sheet, i)));
3100 size = MIN (sizel, sizer);
3103 xoffset += sizel - text_width / 2 - CELLOFFSET;
3104 area.width = sizel + sizer;
3106 case GTK_JUSTIFY_LEFT:
3110 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3112 if (! gtk_sheet_cell_empty (sheet, row, i)) break;
3113 if (size >= text_width + CELLOFFSET) break;
3114 size +=xxx_column_width (sheet, i);
3115 xxx_column_set_left_column (sheet, i,
3118 xxx_column_left_column (sheet, i)));
3123 xoffset += attributes.border.width / 2;
3127 gdk_gc_set_clip_rectangle (fg_gc, &area);
3130 gdk_draw_layout (sheet->pixmap, fg_gc,
3131 area.x + xoffset + CELLOFFSET,
3135 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3136 g_object_unref (G_OBJECT (layout));
3138 gdk_draw_pixmap (sheet->sheet_window,
3139 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3151 gtk_sheet_range_draw (GtkSheet *sheet, const GtkSheetRange *range)
3154 GtkSheetRange drawing_range;
3157 g_return_if_fail (sheet != NULL);
3158 g_return_if_fail (GTK_SHEET (sheet));
3160 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3161 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3162 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
3166 drawing_range.row0 = MIN_VISIBLE_ROW (sheet);
3167 drawing_range.col0 = MIN_VISIBLE_COLUMN (sheet);
3168 drawing_range.rowi = MIN (MAX_VISIBLE_ROW (sheet),
3169 yyy_row_count (sheet) - 1);
3170 drawing_range.coli = MAX_VISIBLE_COLUMN (sheet);
3173 gdk_draw_rectangle (sheet->pixmap,
3174 GTK_WIDGET (sheet)->style->white_gc,
3177 sheet->sheet_window_width,
3178 sheet->sheet_window_height);
3182 drawing_range.row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
3183 drawing_range.col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
3184 drawing_range.rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
3185 drawing_range.coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
3188 if (drawing_range.coli == xxx_column_count (sheet) - 1)
3190 area.x = COLUMN_LEFT_XPIXEL (sheet,
3191 xxx_column_count (sheet) - 1) +
3192 xxx_column_width (sheet, xxx_column_count (sheet) - 1) + 1;
3196 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3198 gdk_draw_rectangle (sheet->pixmap,
3202 sheet->sheet_window_width - area.x,
3203 sheet->sheet_window_height);
3205 gdk_draw_pixmap (sheet->sheet_window,
3206 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3212 sheet->sheet_window_width - area.x,
3213 sheet->sheet_window_height);
3216 if (drawing_range.rowi == yyy_row_count (sheet) - 1)
3219 area.y = ROW_TOP_YPIXEL (sheet,
3220 yyy_row_count (sheet) - 1) +
3221 yyy_row_height (sheet, yyy_row_count (sheet) - 1) + 1;
3223 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3225 gdk_draw_rectangle (sheet->pixmap,
3229 sheet->sheet_window_width,
3230 sheet->sheet_window_height - area.y);
3232 gdk_draw_pixmap (sheet->sheet_window,
3233 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3239 sheet->sheet_window_width,
3240 sheet->sheet_window_height - area.y);
3243 for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
3244 for (j = drawing_range.col0; j <= drawing_range.coli; j++)
3246 gtk_sheet_cell_draw_default (sheet, i, j);
3247 gtk_sheet_cell_draw_label (sheet, i, j);
3250 gtk_sheet_draw_backing_pixmap (sheet, drawing_range);
3252 if (sheet->state != GTK_SHEET_NORMAL &&
3253 gtk_sheet_range_isvisible (sheet, sheet->range))
3254 gtk_sheet_range_draw_selection (sheet, drawing_range);
3256 if (sheet->state == GTK_STATE_NORMAL &&
3257 sheet->active_cell.row >= drawing_range.row0 &&
3258 sheet->active_cell.row <= drawing_range.rowi &&
3259 sheet->active_cell.col >= drawing_range.col0 &&
3260 sheet->active_cell.col <= drawing_range.coli)
3261 gtk_sheet_show_active_cell (sheet);
3265 gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
3271 if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3272 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3275 if (!gtk_sheet_range_isvisible (sheet, range)) return;
3276 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3280 range.col0 = MAX (sheet->range.col0, range.col0);
3281 range.coli = MIN (sheet->range.coli, range.coli);
3282 range.row0 = MAX (sheet->range.row0, range.row0);
3283 range.rowi = MIN (sheet->range.rowi, range.rowi);
3285 range.col0 = MAX (range.col0, MIN_VISIBLE_COLUMN (sheet));
3286 range.coli = MIN (range.coli, MAX_VISIBLE_COLUMN (sheet));
3287 range.row0 = MAX (range.row0, MIN_VISIBLE_ROW (sheet));
3288 range.rowi = MIN (range.rowi, MAX_VISIBLE_ROW (sheet));
3290 for (i = range.row0; i <= range.rowi; i++)
3292 for (j = range.col0; j <= range.coli; j++)
3295 if (gtk_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED &&
3296 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
3299 area.x = COLUMN_LEFT_XPIXEL (sheet, j);
3300 area.y = ROW_TOP_YPIXEL (sheet, i);
3301 area.width= xxx_column_width (sheet, j);
3302 area.height = yyy_row_height (sheet, i);
3304 if (i == sheet->range.row0)
3306 area.y = area.y + 2;
3307 area.height = area.height - 2;
3309 if (i == sheet->range.rowi) area.height = area.height - 3;
3310 if (j == sheet->range.col0)
3312 area.x = area.x + 2;
3313 area.width = area.width - 2;
3315 if (j == sheet->range.coli) area.width = area.width - 3;
3317 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
3319 gdk_draw_rectangle (sheet->sheet_window,
3322 area.x + 1, area.y + 1,
3323 area.width, area.height);
3330 gtk_sheet_draw_border (sheet, sheet->range);
3334 gtk_sheet_draw_backing_pixmap (GtkSheet *sheet, GtkSheetRange range)
3336 gint x, y, width, height;
3338 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3340 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
3341 y = ROW_TOP_YPIXEL (sheet, range.row0);
3342 width = COLUMN_LEFT_XPIXEL (sheet, range.coli) - x +
3343 xxx_column_width (sheet, range.coli);
3345 height = ROW_TOP_YPIXEL (sheet, range.rowi)- y + yyy_row_height (sheet, range.rowi);
3347 if (range.row0 == sheet->range.row0)
3350 height = height + 5;
3352 if (range.rowi == sheet->range.rowi) height = height + 5;
3353 if (range.col0 == sheet->range.col0)
3358 if (range.coli == sheet->range.coli) width = width + 5;
3360 width = MIN (width, sheet->sheet_window_width - x);
3361 height = MIN (height, sheet->sheet_window_height - y);
3368 x = (sheet->row_titles_visible)
3369 ? MAX (x, sheet->row_title_area.width) : MAX (x, 0);
3370 y = (sheet->column_titles_visible)
3371 ? MAX (y, sheet->column_title_area.height) : MAX (y, 0);
3373 if (range.coli == xxx_column_count (sheet) - 1)
3374 width = sheet->sheet_window_width - x;
3375 if (range.rowi == yyy_row_count (sheet) - 1)
3376 height = sheet->sheet_window_height - y;
3378 gdk_draw_pixmap (sheet->sheet_window,
3379 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3391 gtk_sheet_set_cell_text (GtkSheet *sheet, gint row, gint col, const gchar *text)
3393 GtkSheetCellAttr attributes;
3395 g_return_if_fail (sheet != NULL);
3396 g_return_if_fail (GTK_IS_SHEET (sheet));
3397 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3398 if (col < 0 || row < 0) return;
3400 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3401 gtk_sheet_set_cell (sheet, row, col, attributes.justification, text);
3405 safe_strcmp (const gchar *s1, const gchar *s2)
3407 if ( !s1 && !s2) return 0;
3408 if ( !s1) return - 1;
3409 if ( !s2) return +1;
3410 return strcmp (s1, s2);
3414 gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
3415 GtkJustification justification,
3418 GSheetModel *model ;
3422 GtkSheetRange range;
3424 GtkSheetCellAttr attributes;
3426 g_return_if_fail (sheet != NULL);
3427 g_return_if_fail (GTK_IS_SHEET (sheet));
3428 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3429 if (col < 0 || row < 0) return;
3431 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3433 attributes.justification = justification;
3435 model = gtk_sheet_get_model (sheet);
3437 old_text = g_sheet_model_get_string (model, row, col);
3441 if (0 != safe_strcmp (old_text, text))
3442 changed = g_sheet_model_set_string (model, text, row, col);
3444 if ( g_sheet_model_free_strings (model))
3448 if (changed && attributes.is_visible)
3450 gchar *s = gtk_sheet_cell_get_text (sheet, row, col);
3452 if (s && strlen (s) > 0)
3454 text_width = STRING_WIDTH (GTK_WIDGET (sheet),
3455 attributes.font_desc, text);
3457 dispose_string (sheet, s);
3461 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3462 range.coli = MAX_VISIBLE_COLUMN (sheet);
3464 if (gtk_sheet_autoresize (sheet) &&
3465 text_width > xxx_column_width (sheet, col) -
3466 2 * CELLOFFSET- attributes.border.width)
3468 gtk_sheet_set_column_width (sheet, col, text_width + 2 * CELLOFFSET
3469 + attributes.border.width);
3470 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3473 if (!GTK_SHEET_IS_FROZEN (sheet))
3474 gtk_sheet_range_draw (sheet, &range);
3478 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, col);
3484 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3486 GtkSheetRange range;
3488 g_return_if_fail (sheet != NULL);
3489 g_return_if_fail (GTK_IS_SHEET (sheet));
3490 if (column >= xxx_column_count (sheet) ||
3491 row >= yyy_row_count (sheet)) return;
3493 if (column < 0 || row < 0) return;
3497 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3498 range.coli = MAX_VISIBLE_COLUMN (sheet);
3500 gtk_sheet_real_cell_clear (sheet, row, column);
3502 if (!GTK_SHEET_IS_FROZEN (sheet))
3504 gtk_sheet_range_draw (sheet, &range);
3509 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column)
3511 GSheetModel *model = gtk_sheet_get_model (sheet);
3513 gchar *old_text = gtk_sheet_cell_get_text (sheet, row, column);
3515 if (old_text && strlen (old_text) > 0 )
3517 g_sheet_model_datum_clear (model, row, column);
3519 if (GTK_IS_OBJECT (sheet) && G_OBJECT (sheet)->ref_count > 0)
3520 g_signal_emit (G_OBJECT (sheet), sheet_signals[CLEAR_CELL], 0,
3524 dispose_string (sheet, old_text);
3528 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3530 g_return_if_fail (sheet != NULL);
3531 g_return_if_fail (GTK_IS_SHEET (sheet));
3533 gtk_sheet_real_range_clear (sheet, range);
3537 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3540 GtkSheetRange clear;
3545 clear.rowi = yyy_row_count (sheet) - 1;
3547 clear.coli = xxx_column_count (sheet) - 1;
3552 clear.row0 = MAX (clear.row0, 0);
3553 clear.col0 = MAX (clear.col0, 0);
3554 clear.rowi = MIN (clear.rowi, yyy_row_count (sheet) - 1 );
3555 clear.coli = MIN (clear.coli, xxx_column_count (sheet) - 1 );
3557 for (i = clear.row0; i <= clear.rowi; i++)
3558 for (j = clear.col0; j <= clear.coli; j++)
3560 gtk_sheet_real_cell_clear (sheet, i, j);
3563 gtk_sheet_range_draw (sheet, NULL);
3568 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3571 char *text = gtk_sheet_cell_get_text (sheet, row, col);
3572 empty = (text == NULL );
3574 dispose_string (sheet, text);
3581 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3584 g_return_val_if_fail (sheet != NULL, NULL);
3585 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3587 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet))
3589 if (col < 0 || row < 0) return NULL;
3591 model = gtk_sheet_get_model (sheet);
3596 return g_sheet_model_get_string (model, row, col);
3601 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3604 GtkSheetRange *range;
3606 g_return_val_if_fail (sheet != NULL, 0);
3607 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3608 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return 0;
3609 if (col < 0 || row < 0) return 0;
3611 state = sheet->state;
3612 range = &sheet->range;
3616 case GTK_SHEET_NORMAL:
3617 return GTK_STATE_NORMAL;
3619 case GTK_SHEET_ROW_SELECTED:
3620 if (row >= range->row0 && row <= range->rowi)
3621 return GTK_STATE_SELECTED;
3623 case GTK_SHEET_COLUMN_SELECTED:
3624 if (col >= range->col0 && col <= range->coli)
3625 return GTK_STATE_SELECTED;
3627 case GTK_SHEET_RANGE_SELECTED:
3628 if (row >= range->row0 && row <= range->rowi && \
3629 col >= range->col0 && col <= range->coli)
3630 return GTK_STATE_SELECTED;
3633 return GTK_STATE_NORMAL;
3636 /* Convert X, Y (in pixels) to *ROW, *COLUMN (in cell coords)
3637 -1 indicates the title buttons.
3638 If the function returns FALSE, then the results will be unreliable.
3641 gtk_sheet_get_pixel_info (GtkSheet *sheet,
3649 *column = -G_MAXINT;
3651 g_return_val_if_fail (sheet != NULL, 0);
3652 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3654 /* bounds checking, return false if the user clicked
3662 if ( y < sheet->column_title_area.height + sheet->column_title_area.y)
3667 trow = ROW_FROM_YPIXEL (sheet, y);
3668 if (trow > yyy_row_count (sheet))
3674 if ( x < sheet->row_title_area.width + sheet->row_title_area.x)
3678 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3679 if (tcol > xxx_column_count (sheet))
3689 gtk_sheet_get_cell_area (GtkSheet * sheet,
3694 g_return_val_if_fail (sheet != NULL, 0);
3695 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3697 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3700 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL (sheet, column) -
3701 (sheet->row_titles_visible
3702 ? sheet->row_title_area.width
3704 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL (sheet, row) -
3705 (sheet->column_titles_visible
3706 ? sheet->column_title_area.height
3708 area->width= (column == -1) ? sheet->row_title_area.width
3709 : xxx_column_width (sheet, column);
3711 area->height= (row == -1) ? sheet->column_title_area.height
3712 : yyy_row_height (sheet, row);
3718 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3720 g_return_val_if_fail (sheet != NULL, 0);
3721 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3723 if (row < - 1 || column < - 1) return FALSE;
3724 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3727 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3729 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
3732 sheet->active_cell.row = row;
3733 sheet->active_cell.col = column;
3735 if ( row == -1 || column == -1)
3737 gtk_sheet_hide_active_cell (sheet);
3741 if (!gtk_sheet_activate_cell (sheet, row, column)) return FALSE;
3743 if (gtk_sheet_autoscroll (sheet))
3744 gtk_sheet_move_query (sheet, row, column);
3750 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3752 g_return_if_fail (sheet != NULL);
3753 g_return_if_fail (GTK_IS_SHEET (sheet));
3755 if ( row ) *row = sheet->active_cell.row;
3756 if (column) *column = sheet->active_cell.col;
3760 gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
3765 GtkJustification justification;
3766 GtkSheetCellAttr attributes;
3768 g_return_if_fail (data != NULL);
3769 g_return_if_fail (GTK_IS_SHEET (data));
3771 sheet = GTK_SHEET (data);
3773 if (!GTK_WIDGET_VISIBLE (widget)) return;
3774 if (sheet->state != GTK_STATE_NORMAL) return;
3776 row = sheet->active_cell.row;
3777 col = sheet->active_cell.col;
3779 if (row < 0 || col < 0) return;
3781 sheet->active_cell.row =- 1;
3782 sheet->active_cell.col =- 1;
3784 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3786 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3788 if (text && strlen (text) > 0)
3790 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3791 justification = attributes.justification;
3792 gtk_sheet_set_cell (sheet, row, col, justification, text);
3795 if (sheet->freeze_count == 0)
3796 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3798 sheet->active_cell.row = row;;
3799 sheet->active_cell.col = col;
3804 gtk_sheet_deactivate_cell (GtkSheet *sheet)
3806 gboolean veto = TRUE;
3808 g_return_val_if_fail (sheet != NULL, FALSE);
3809 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3811 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return FALSE;
3812 if (sheet->state != GTK_SHEET_NORMAL) return FALSE;
3814 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[DEACTIVATE],
3815 sheet->active_cell.row,
3816 sheet->active_cell.col, &veto);
3818 if (!veto) return FALSE;
3820 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3823 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_sheet_get_entry (sheet)),
3824 G_CALLBACK (gtk_sheet_entry_changed),
3827 gtk_sheet_hide_active_cell (sheet);
3828 sheet->active_cell.row = -1;
3829 sheet->active_cell.col = -1;
3831 if (GTK_SHEET_REDRAW_PENDING (sheet))
3833 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3834 gtk_sheet_range_draw (sheet, NULL);
3841 gtk_sheet_hide_active_cell (GtkSheet *sheet)
3845 GtkJustification justification;
3846 GtkSheetCellAttr attributes;
3848 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3850 row = sheet->active_cell.row;
3851 col = sheet->active_cell.col;
3853 if (row < 0 || col < 0) return;
3855 if (sheet->freeze_count == 0)
3856 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3858 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3860 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3861 justification = attributes.justification;
3863 if (text && strlen (text) != 0)
3865 gtk_sheet_set_cell (sheet, row, col, justification, text);
3866 g_signal_emit (G_OBJECT (sheet), sheet_signals[SET_CELL], 0, row, col);
3870 gtk_sheet_cell_clear (sheet, row, col);
3873 row = sheet->active_cell.row;
3874 col = sheet->active_cell.col;
3876 gtk_widget_hide (sheet->sheet_entry);
3877 gtk_widget_unmap (sheet->sheet_entry);
3879 if (row != -1 && col != -1)
3880 gdk_draw_pixmap (sheet->sheet_window,
3881 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3883 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3884 ROW_TOP_YPIXEL (sheet, row)- 1,
3885 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3886 ROW_TOP_YPIXEL (sheet, row)- 1,
3887 xxx_column_width (sheet, col) + 4,
3888 yyy_row_height (sheet, row)+4);
3890 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3892 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3897 gtk_sheet_activate_cell (GtkSheet *sheet, gint row, gint col)
3899 gboolean veto = TRUE;
3901 g_return_val_if_fail (sheet != NULL, FALSE);
3902 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3904 if (row < 0 || col < 0) return FALSE;
3905 if (row >= yyy_row_count (sheet) || col >= xxx_column_count (sheet))
3908 if (!veto) return FALSE;
3909 if (sheet->state != GTK_SHEET_NORMAL)
3911 sheet->state = GTK_SHEET_NORMAL;
3912 gtk_sheet_real_unselect_range (sheet, NULL);
3915 sheet->range.row0 = row;
3916 sheet->range.col0 = col;
3917 sheet->range.rowi = row;
3918 sheet->range.coli = col;
3919 sheet->active_cell.row = row;
3920 sheet->active_cell.col = col;
3921 sheet->selection_cell.row = row;
3922 sheet->selection_cell.col = col;
3924 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
3926 gtk_sheet_show_active_cell (sheet);
3929 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
3931 G_CALLBACK (gtk_sheet_entry_changed),
3934 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals [ACTIVATE], row, col, &veto);
3940 gtk_sheet_show_active_cell (GtkSheet *sheet)
3942 GtkEntry *sheet_entry;
3943 GtkSheetCellAttr attributes;
3945 const gchar *old_text;
3946 GtkJustification justification;
3949 g_return_if_fail (sheet != NULL);
3950 g_return_if_fail (GTK_IS_SHEET (sheet));
3952 row = sheet->active_cell.row;
3953 col = sheet->active_cell.col;
3955 /* Don't show the active cell, if there is no active cell: */
3956 if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
3959 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3960 if (sheet->state != GTK_SHEET_NORMAL) return;
3961 if (GTK_SHEET_IN_SELECTION (sheet)) return;
3963 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3965 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
3967 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3969 justification = GTK_JUSTIFY_LEFT;
3971 if (gtk_sheet_justify_entry (sheet))
3972 justification = attributes.justification;
3974 text = gtk_sheet_cell_get_text (sheet, row, col);
3976 text = g_strdup ("");
3978 gtk_entry_set_visibility (GTK_ENTRY (sheet_entry), attributes.is_visible);
3980 if (gtk_sheet_locked (sheet) || !attributes.is_editable)
3981 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), FALSE);
3983 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), TRUE);
3985 /*** Added by John Gotts. Mar 25, 2005 *********/
3986 old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
3987 if (strcmp (old_text, text) != 0)
3989 if (!GTK_IS_ITEM_ENTRY (sheet_entry))
3990 gtk_entry_set_text (GTK_ENTRY (sheet_entry), text);
3992 gtk_item_entry_set_text (GTK_ITEM_ENTRY (sheet_entry), text, justification);
3995 gtk_sheet_entry_set_max_size (sheet);
3996 gtk_sheet_size_allocate_entry (sheet);
3998 gtk_widget_map (sheet->sheet_entry);
4000 gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
4002 dispose_string (sheet, text);
4006 gtk_sheet_draw_active_cell (GtkSheet *sheet)
4009 GtkSheetRange range;
4011 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
4012 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4014 row = sheet->active_cell.row;
4015 col = sheet->active_cell.col;
4017 if (row < 0 || col < 0) return;
4019 if (!gtk_sheet_cell_isvisible (sheet, row, col)) return;
4021 range.col0 = range.coli = col;
4022 range.row0 = range.rowi = row;
4024 gtk_sheet_draw_border (sheet, range);
4029 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4031 gint pixmap_width, pixmap_height;
4033 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4035 if (width == 0 && height == 0)
4037 width = sheet->sheet_window_width + 80;
4038 height = sheet->sheet_window_height + 80;
4044 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4047 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4051 /* reallocate if sizes don't match */
4052 gdk_window_get_size (sheet->pixmap,
4053 &pixmap_width, &pixmap_height);
4054 if ( (pixmap_width != width) || (pixmap_height != height))
4056 g_object_unref (sheet->pixmap);
4057 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4060 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4066 gtk_sheet_new_selection (GtkSheet *sheet, GtkSheetRange *range)
4068 gint i, j, mask1, mask2;
4069 gint state, selected;
4070 gint x, y, width, height;
4071 GtkSheetRange new_range, aux_range;
4073 g_return_if_fail (sheet != NULL);
4075 if (range == NULL) range=&sheet->range;
4079 range->row0 = MIN (range->row0, sheet->range.row0);
4080 range->rowi = MAX (range->rowi, sheet->range.rowi);
4081 range->col0 = MIN (range->col0, sheet->range.col0);
4082 range->coli = MAX (range->coli, sheet->range.coli);
4084 range->row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
4085 range->rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
4086 range->col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
4087 range->coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
4089 aux_range.row0 = MAX (new_range.row0, MIN_VISIBLE_ROW (sheet));
4090 aux_range.rowi = MIN (new_range.rowi, MAX_VISIBLE_ROW (sheet));
4091 aux_range.col0 = MAX (new_range.col0, MIN_VISIBLE_COLUMN (sheet));
4092 aux_range.coli = MIN (new_range.coli, MAX_VISIBLE_COLUMN (sheet));
4094 for (i = range->row0; i <= range->rowi; i++)
4096 for (j = range->col0; j <= range->coli; j++)
4099 state = gtk_sheet_cell_get_state (sheet, i, j);
4100 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4101 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4103 if (state == GTK_STATE_SELECTED && selected &&
4104 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4105 (i == sheet->range.row0 || i == sheet->range.rowi ||
4106 j == sheet->range.col0 || j == sheet->range.coli ||
4107 i == new_range.row0 || i == new_range.rowi ||
4108 j == new_range.col0 || j == new_range.coli))
4111 mask1 = i == sheet->range.row0 ? 1 : 0;
4112 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4113 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4114 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4116 mask2 = i == new_range.row0 ? 1 : 0;
4117 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4118 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4119 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4123 x = COLUMN_LEFT_XPIXEL (sheet, j);
4124 y = ROW_TOP_YPIXEL (sheet, i);
4125 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4126 xxx_column_width (sheet, j);
4127 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4129 if (i == sheet->range.row0)
4132 height = height + 3;
4134 if (i == sheet->range.rowi) height = height + 3;
4135 if (j == sheet->range.col0)
4140 if (j == sheet->range.coli) width = width + 3;
4142 gdk_draw_pixmap (sheet->sheet_window,
4143 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4152 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
4154 x = COLUMN_LEFT_XPIXEL (sheet, j);
4155 y = ROW_TOP_YPIXEL (sheet, i);
4156 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4157 xxx_column_width (sheet, j);
4159 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4161 if (i == new_range.row0)
4164 height = height - 2;
4166 if (i == new_range.rowi) height = height - 3;
4167 if (j == new_range.col0)
4172 if (j == new_range.coli) width = width - 3;
4174 gdk_draw_rectangle (sheet->sheet_window,
4185 for (i = range->row0; i <= range->rowi; i++)
4187 for (j = range->col0; j <= range->coli; j++)
4190 state = gtk_sheet_cell_get_state (sheet, i, j);
4191 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4192 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4194 if (state == GTK_STATE_SELECTED && !selected &&
4195 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4198 x = COLUMN_LEFT_XPIXEL (sheet, j);
4199 y = ROW_TOP_YPIXEL (sheet, i);
4200 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4201 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4203 if (i == sheet->range.row0)
4206 height = height + 3;
4208 if (i == sheet->range.rowi) height = height + 3;
4209 if (j == sheet->range.col0)
4214 if (j == sheet->range.coli) width = width + 3;
4216 gdk_draw_pixmap (sheet->sheet_window,
4217 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4229 for (i = range->row0; i <= range->rowi; i++)
4231 for (j = range->col0; j <= range->coli; j++)
4234 state = gtk_sheet_cell_get_state (sheet, i, j);
4235 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4236 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4238 if (state != GTK_STATE_SELECTED && selected &&
4239 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4240 (i != sheet->active_cell.row || j != sheet->active_cell.col))
4243 x = COLUMN_LEFT_XPIXEL (sheet, j);
4244 y = ROW_TOP_YPIXEL (sheet, i);
4245 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4246 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4248 if (i == new_range.row0)
4251 height = height - 2;
4253 if (i == new_range.rowi) height = height - 3;
4254 if (j == new_range.col0)
4259 if (j == new_range.coli) width = width - 3;
4261 gdk_draw_rectangle (sheet->sheet_window,
4272 for (i = aux_range.row0; i <= aux_range.rowi; i++)
4274 for (j = aux_range.col0; j <= aux_range.coli; j++)
4277 if (xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4280 state = gtk_sheet_cell_get_state (sheet, i, j);
4282 mask1 = i == sheet->range.row0 ? 1 : 0;
4283 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4284 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4285 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4287 mask2 = i == new_range.row0 ? 1 : 0;
4288 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4289 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4290 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4291 if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
4293 x = COLUMN_LEFT_XPIXEL (sheet, j);
4294 y = ROW_TOP_YPIXEL (sheet, i);
4295 width = xxx_column_width (sheet, j);
4296 height = yyy_row_height (sheet, i);
4298 gdk_draw_rectangle (sheet->sheet_window,
4306 gdk_draw_rectangle (sheet->sheet_window,
4309 x + 1, y + height - 1,
4313 gdk_draw_rectangle (sheet->sheet_window,
4321 gdk_draw_rectangle (sheet->sheet_window,
4324 x + width - 1, y + 1,
4338 gtk_sheet_draw_corners (sheet, new_range);
4343 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4348 gint x, y, width, height;
4350 widget = GTK_WIDGET (sheet);
4352 x = COLUMN_LEFT_XPIXEL (sheet, new_range.col0);
4353 y = ROW_TOP_YPIXEL (sheet, new_range.row0);
4354 width = COLUMN_LEFT_XPIXEL (sheet, new_range.coli) - x +
4355 xxx_column_width (sheet, new_range.coli);
4357 height = ROW_TOP_YPIXEL (sheet, new_range.rowi) - y +
4358 yyy_row_height (sheet, new_range.rowi);
4360 area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
4361 area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
4362 area.width = sheet->sheet_window_width;
4363 area.height = sheet->sheet_window_height;
4370 if (width > area.width) width = area.width + 10;
4373 height = height + y;
4376 if (height > area.height) height = area.height + 10;
4378 gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
4380 for (i =- 1; i <= 1; ++i)
4381 gdk_draw_rectangle (sheet->sheet_window,
4389 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
4392 gtk_sheet_draw_corners (sheet, new_range);
4396 gtk_sheet_draw_corners (GtkSheet *sheet, GtkSheetRange range)
4401 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.col0))
4403 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4404 y = ROW_TOP_YPIXEL (sheet, range.row0);
4405 gdk_draw_pixmap (sheet->sheet_window,
4406 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4414 gdk_draw_rectangle (sheet->sheet_window,
4421 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.coli) ||
4422 sheet->state == GTK_SHEET_COLUMN_SELECTED)
4424 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4425 xxx_column_width (sheet, range.coli);
4426 y = ROW_TOP_YPIXEL (sheet, range.row0);
4428 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4430 y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet))+3;
4433 gdk_draw_pixmap (sheet->sheet_window,
4434 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4442 gdk_draw_rectangle (sheet->sheet_window,
4445 x - width + width / 2, y - width + width / 2,
4446 2 + width, 2 + width);
4449 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.col0) ||
4450 sheet->state == GTK_SHEET_ROW_SELECTED)
4452 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4453 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4454 yyy_row_height (sheet, range.rowi);
4456 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4458 x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet))+3;
4461 gdk_draw_pixmap (sheet->sheet_window,
4462 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4470 gdk_draw_rectangle (sheet->sheet_window,
4473 x - width + width / 2, y - width + width / 2,
4474 2 + width, 2 + width);
4477 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.coli))
4479 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4480 xxx_column_width (sheet, range.coli);
4481 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4482 yyy_row_height (sheet, range.rowi);
4484 if (sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4485 if (sheet->state == GTK_SHEET_NORMAL) width = 3;
4486 gdk_draw_pixmap (sheet->sheet_window,
4487 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4495 gdk_draw_rectangle (sheet->sheet_window,
4498 x - width + width / 2, y - width + width / 2,
4499 2 + width, 2 + width);
4507 gtk_sheet_real_select_range (GtkSheet * sheet,
4508 const GtkSheetRange * range)
4512 g_return_if_fail (sheet != NULL);
4514 if (range == NULL) range = &sheet->range;
4516 memcpy (&sheet->range, range, sizeof (*range));
4518 if (range->row0 < 0 || range->rowi < 0) return;
4519 if (range->col0 < 0 || range->coli < 0) return;
4521 state = sheet->state;
4523 if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4524 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4526 gtk_sheet_new_selection (sheet, &sheet->range);
4530 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4531 gtk_sheet_range_draw_selection (sheet, sheet->range);
4534 gtk_sheet_update_primary_selection (sheet);
4536 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_RANGE], 0, &sheet->range);
4541 gtk_sheet_get_selected_range (GtkSheet *sheet,
4542 GtkSheetRange *range)
4544 g_return_if_fail (sheet != NULL);
4545 *range = sheet->range;
4550 gtk_sheet_select_range (GtkSheet * sheet, const GtkSheetRange *range)
4552 g_return_if_fail (sheet != NULL);
4554 if (range == NULL) range=&sheet->range;
4556 if (range->row0 < 0 || range->rowi < 0) return;
4557 if (range->col0 < 0 || range->coli < 0) return;
4560 if ( gtk_sheet_locked (sheet)) return ;
4562 if (sheet->state != GTK_SHEET_NORMAL)
4563 gtk_sheet_real_unselect_range (sheet, NULL);
4566 gboolean veto = TRUE;
4567 veto = gtk_sheet_deactivate_cell (sheet);
4571 sheet->range.row0 = range->row0;
4572 sheet->range.rowi = range->rowi;
4573 sheet->range.col0 = range->col0;
4574 sheet->range.coli = range->coli;
4575 sheet->active_cell.row = range->row0;
4576 sheet->active_cell.col = range->col0;
4577 sheet->selection_cell.row = range->rowi;
4578 sheet->selection_cell.col = range->coli;
4580 sheet->state = GTK_SHEET_RANGE_SELECTED;
4581 gtk_sheet_real_select_range (sheet, NULL);
4586 gtk_sheet_unselect_range (GtkSheet * sheet)
4588 gtk_sheet_real_unselect_range (sheet, NULL);
4589 sheet->state = GTK_STATE_NORMAL;
4591 gtk_sheet_activate_cell (sheet,
4592 sheet->active_cell.row, sheet->active_cell.col);
4597 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4598 const GtkSheetRange *range)
4600 g_return_if_fail (sheet != NULL);
4601 g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
4604 range = &sheet->range;
4606 if (range->row0 < 0 || range->rowi < 0) return;
4607 if (range->col0 < 0 || range->coli < 0) return;
4609 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, -1);
4610 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, -1);
4612 if (gtk_sheet_range_isvisible (sheet, *range))
4613 gtk_sheet_draw_backing_pixmap (sheet, *range);
4615 sheet->range.row0 = -1;
4616 sheet->range.rowi = -1;
4617 sheet->range.col0 = -1;
4618 sheet->range.coli = -1;
4620 gtk_sheet_position_children (sheet);
4625 gtk_sheet_expose (GtkWidget * widget,
4626 GdkEventExpose * event)
4629 GtkSheetRange range;
4631 g_return_val_if_fail (widget != NULL, FALSE);
4632 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4633 g_return_val_if_fail (event != NULL, FALSE);
4636 sheet = GTK_SHEET (widget);
4638 if (GTK_WIDGET_DRAWABLE (widget))
4640 range.row0 = ROW_FROM_YPIXEL (sheet, event->area.y);
4641 range.col0 = COLUMN_FROM_XPIXEL (sheet, event->area.x);
4642 range.rowi = ROW_FROM_YPIXEL (sheet, event->area.y + event->area.height);
4643 range.coli = COLUMN_FROM_XPIXEL (sheet, event->area.x + event->area.width);
4645 /* exposure events on the sheet */
4646 if (event->window == sheet->row_title_window &&
4647 sheet->row_titles_visible)
4650 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
4651 gtk_sheet_row_title_button_draw (sheet, i);
4654 if (event->window == sheet->column_title_window &&
4655 sheet->column_titles_visible)
4658 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
4659 gtk_sheet_column_title_button_draw (sheet, i);
4662 if (event->window == sheet->sheet_window)
4664 gtk_sheet_draw_backing_pixmap (sheet, range);
4666 if (sheet->state != GTK_SHEET_NORMAL)
4668 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4669 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4670 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4671 gtk_sheet_draw_backing_pixmap (sheet, sheet->drag_range);
4673 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4674 gtk_sheet_range_draw_selection (sheet, sheet->range);
4675 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4676 draw_xor_rectangle (sheet, sheet->drag_range);
4679 if ((!GTK_SHEET_IN_XDRAG (sheet)) && (!GTK_SHEET_IN_YDRAG (sheet)))
4681 if (sheet->state == GTK_SHEET_NORMAL)
4683 gtk_sheet_draw_active_cell (sheet);
4684 if (!GTK_SHEET_IN_SELECTION (sheet))
4685 gtk_widget_queue_draw (sheet->sheet_entry);
4691 if (sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
4692 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4694 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4701 gtk_sheet_button_press (GtkWidget * widget,
4702 GdkEventButton * event)
4705 GdkModifierType mods;
4706 gint x, y, row, column;
4709 g_return_val_if_fail (widget != NULL, FALSE);
4710 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4711 g_return_val_if_fail (event != NULL, FALSE);
4713 sheet = GTK_SHEET (widget);
4715 /* Cancel any pending tooltips */
4716 if (sheet->motion_timer)
4718 g_source_remove (sheet->motion_timer);
4719 sheet->motion_timer = 0;
4722 gtk_widget_get_pointer (widget, &x, &y);
4723 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4726 if (event->window == sheet->column_title_window)
4728 g_signal_emit (G_OBJECT (sheet),
4729 sheet_signals[BUTTON_EVENT_COLUMN], 0,
4732 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4733 g_signal_emit (G_OBJECT (sheet),
4734 sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
4737 else if (event->window == sheet->row_title_window)
4739 g_signal_emit (G_OBJECT (sheet),
4740 sheet_signals[BUTTON_EVENT_ROW], 0,
4743 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4744 g_signal_emit (G_OBJECT (sheet),
4745 sheet_signals[DOUBLE_CLICK_ROW], 0, row);
4749 gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
4751 if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
4754 /* press on resize windows */
4755 if (event->window == sheet->column_title_window &&
4756 gtk_sheet_columns_resizable (sheet))
4758 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4759 if (POSSIBLE_XDRAG (sheet, sheet->x_drag, &sheet->drag_cell.col))
4762 if (event->type == GDK_2BUTTON_PRESS)
4764 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4765 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4768 gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
4769 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4770 gdk_pointer_grab (sheet->column_title_window, FALSE,
4771 GDK_POINTER_MOTION_HINT_MASK |
4772 GDK_BUTTON1_MOTION_MASK |
4773 GDK_BUTTON_RELEASE_MASK,
4774 NULL, NULL, event->time);
4776 draw_xor_vline (sheet);
4781 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable (sheet))
4783 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4785 if (POSSIBLE_YDRAG (sheet, sheet->y_drag, &sheet->drag_cell.row))
4788 gtk_sheet_row_size_request (sheet, sheet->drag_cell.row, &req);
4789 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4790 gdk_pointer_grab (sheet->row_title_window, FALSE,
4791 GDK_POINTER_MOTION_HINT_MASK |
4792 GDK_BUTTON1_MOTION_MASK |
4793 GDK_BUTTON_RELEASE_MASK,
4794 NULL, NULL, event->time);
4796 draw_xor_hline (sheet);
4801 /* the sheet itself does not handle other than single click events */
4802 if (event->type != GDK_BUTTON_PRESS) return FALSE;
4804 /* selections on the sheet */
4805 if (event->window == sheet->sheet_window)
4807 gtk_widget_get_pointer (widget, &x, &y);
4808 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4809 gdk_pointer_grab (sheet->sheet_window, FALSE,
4810 GDK_POINTER_MOTION_HINT_MASK |
4811 GDK_BUTTON1_MOTION_MASK |
4812 GDK_BUTTON_RELEASE_MASK,
4813 NULL, NULL, event->time);
4814 gtk_grab_add (GTK_WIDGET (sheet));
4816 /* This seems to be a kludge to work around a problem where the sheet
4817 scrolls to another position. The timeout scrolls it back to its
4818 original posn. JMD 3 July 2007
4820 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4822 if (sheet->selection_mode != GTK_SELECTION_SINGLE &&
4823 sheet->selection_mode != GTK_SELECTION_NONE &&
4824 sheet->cursor_drag->type == GDK_SIZING &&
4825 !GTK_SHEET_IN_SELECTION (sheet) && !GTK_SHEET_IN_RESIZE (sheet))
4827 if (sheet->state == GTK_STATE_NORMAL)
4829 row = sheet->active_cell.row;
4830 column = sheet->active_cell.col;
4831 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4832 sheet->active_cell.row = row;
4833 sheet->active_cell.col = column;
4834 sheet->drag_range = sheet->range;
4835 sheet->state = GTK_SHEET_RANGE_SELECTED;
4836 gtk_sheet_select_range (sheet, &sheet->drag_range);
4840 if (row > sheet->range.rowi) row--;
4841 if (column > sheet->range.coli) column--;
4842 sheet->drag_cell.row = row;
4843 sheet->drag_cell.col = column;
4844 sheet->drag_range = sheet->range;
4845 draw_xor_rectangle (sheet, sheet->drag_range);
4846 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
4848 else if (sheet->cursor_drag->type == GDK_TOP_LEFT_ARROW &&
4849 !GTK_SHEET_IN_SELECTION (sheet)
4850 && ! GTK_SHEET_IN_DRAG (sheet)
4851 && ! gtk_sheet_locked (sheet)
4852 && sheet->active_cell.row >= 0
4853 && sheet->active_cell.col >= 0
4856 if (sheet->state == GTK_STATE_NORMAL)
4858 row = sheet->active_cell.row;
4859 column = sheet->active_cell.col;
4860 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4861 sheet->active_cell.row = row;
4862 sheet->active_cell.col = column;
4863 sheet->drag_range = sheet->range;
4864 sheet->state = GTK_SHEET_RANGE_SELECTED;
4865 gtk_sheet_select_range (sheet, &sheet->drag_range);
4869 if (row < sheet->range.row0) row++;
4870 if (row > sheet->range.rowi) row--;
4871 if (column < sheet->range.col0) column++;
4872 if (column > sheet->range.coli) column--;
4873 sheet->drag_cell.row = row;
4874 sheet->drag_cell.col = column;
4875 sheet->drag_range = sheet->range;
4876 draw_xor_rectangle (sheet, sheet->drag_range);
4877 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
4881 gtk_sheet_click_cell (sheet, row, column, &veto);
4882 if (veto) GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4886 if (event->window == sheet->column_title_window)
4888 gtk_widget_get_pointer (widget, &x, &y);
4889 column = COLUMN_FROM_XPIXEL (sheet, x);
4891 if (xxx_column_is_sensitive (sheet, column))
4893 gtk_sheet_click_cell (sheet, - 1, column, &veto);
4894 gtk_grab_add (GTK_WIDGET (sheet));
4895 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4896 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4900 if (event->window == sheet->row_title_window)
4902 gtk_widget_get_pointer (widget, &x, &y);
4903 row = ROW_FROM_YPIXEL (sheet, y);
4904 if (yyy_row_is_sensitive (sheet, row))
4906 gtk_sheet_click_cell (sheet, row, - 1, &veto);
4907 gtk_grab_add (GTK_WIDGET (sheet));
4908 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4909 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4918 gtk_sheet_scroll (gpointer data)
4921 gint x, y, row, column;
4924 sheet = GTK_SHEET (data);
4926 GDK_THREADS_ENTER ();
4928 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
4929 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4933 if (GTK_SHEET_IN_SELECTION (sheet))
4934 gtk_sheet_extend_selection (sheet, row, column);
4936 if (GTK_SHEET_IN_DRAG (sheet) || GTK_SHEET_IN_RESIZE (sheet))
4938 move = gtk_sheet_move_query (sheet, row, column);
4939 if (move) draw_xor_rectangle (sheet, sheet->drag_range);
4942 GDK_THREADS_LEAVE ();
4949 gtk_sheet_click_cell (GtkSheet *sheet, gint row, gint column, gboolean *veto)
4953 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
4959 if (column >= 0 && row >= 0)
4960 if (! xxx_column_is_visible (sheet, column) || !yyy_row_is_visible (sheet, row))
4966 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[TRAVERSE],
4967 sheet->active_cell.row, sheet->active_cell.col,
4968 &row, &column, veto);
4972 if (sheet->state == GTK_STATE_NORMAL) return;
4974 row = sheet->active_cell.row;
4975 column = sheet->active_cell.col;
4977 gtk_sheet_activate_cell (sheet, row, column);
4981 if (row == -1 && column >= 0)
4983 if (gtk_sheet_autoscroll (sheet))
4984 gtk_sheet_move_query (sheet, row, column);
4985 gtk_sheet_select_column (sheet, column);
4988 if (column == -1 && row >= 0)
4990 if (gtk_sheet_autoscroll (sheet))
4991 gtk_sheet_move_query (sheet, row, column);
4992 gtk_sheet_select_row (sheet, row);
4996 if (row == - 1 && column == - 1)
4998 sheet->range.row0 = 0;
4999 sheet->range.col0 = 0;
5000 sheet->range.rowi = yyy_row_count (sheet) - 1;
5001 sheet->range.coli = xxx_column_count (sheet) - 1;
5002 sheet->active_cell.row = 0;
5003 sheet->active_cell.col = 0;
5004 gtk_sheet_select_range (sheet, NULL);
5008 if (row != -1 && column != -1)
5010 if (sheet->state != GTK_SHEET_NORMAL)
5012 sheet->state = GTK_SHEET_NORMAL;
5013 gtk_sheet_real_unselect_range (sheet, NULL);
5017 if (!gtk_sheet_deactivate_cell (sheet))
5022 gtk_sheet_activate_cell (sheet, row, column);
5025 if (gtk_sheet_autoscroll (sheet))
5026 gtk_sheet_move_query (sheet, row, column);
5027 sheet->active_cell.row = row;
5028 sheet->active_cell.col = column;
5029 sheet->selection_cell.row = row;
5030 sheet->selection_cell.col = column;
5031 sheet->range.row0 = row;
5032 sheet->range.col0 = column;
5033 sheet->range.rowi = row;
5034 sheet->range.coli = column;
5035 sheet->state = GTK_SHEET_NORMAL;
5036 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5037 gtk_sheet_draw_active_cell (sheet);
5041 g_assert_not_reached ();
5042 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5043 sheet->active_cell.col);
5047 gtk_sheet_button_release (GtkWidget * widget,
5048 GdkEventButton * event)
5053 sheet = GTK_SHEET (widget);
5055 /* release on resize windows */
5056 if (GTK_SHEET_IN_XDRAG (sheet))
5058 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5059 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5060 gtk_widget_get_pointer (widget, &x, NULL);
5061 gdk_pointer_ungrab (event->time);
5062 draw_xor_vline (sheet);
5064 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col,
5065 new_column_width (sheet, sheet->drag_cell.col, &x));
5066 sheet->old_hadjustment = -1.;
5067 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "value_changed");
5071 if (GTK_SHEET_IN_YDRAG (sheet))
5073 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5074 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5075 gtk_widget_get_pointer (widget, NULL, &y);
5076 gdk_pointer_ungrab (event->time);
5077 draw_xor_hline (sheet);
5079 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5080 sheet->old_vadjustment = -1.;
5081 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "value_changed");
5086 if (GTK_SHEET_IN_DRAG (sheet))
5088 GtkSheetRange old_range;
5089 draw_xor_rectangle (sheet, sheet->drag_range);
5090 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
5091 gdk_pointer_ungrab (event->time);
5093 gtk_sheet_real_unselect_range (sheet, NULL);
5095 sheet->active_cell.row = sheet->active_cell.row +
5096 (sheet->drag_range.row0 - sheet->range.row0);
5097 sheet->active_cell.col = sheet->active_cell.col +
5098 (sheet->drag_range.col0 - sheet->range.col0);
5099 sheet->selection_cell.row = sheet->selection_cell.row +
5100 (sheet->drag_range.row0 - sheet->range.row0);
5101 sheet->selection_cell.col = sheet->selection_cell.col +
5102 (sheet->drag_range.col0 - sheet->range.col0);
5103 old_range = sheet->range;
5104 sheet->range = sheet->drag_range;
5105 sheet->drag_range = old_range;
5106 g_signal_emit (G_OBJECT (sheet), sheet_signals[MOVE_RANGE], 0,
5107 &sheet->drag_range, &sheet->range);
5108 gtk_sheet_select_range (sheet, &sheet->range);
5111 if (GTK_SHEET_IN_RESIZE (sheet))
5113 GtkSheetRange old_range;
5114 draw_xor_rectangle (sheet, sheet->drag_range);
5115 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
5116 gdk_pointer_ungrab (event->time);
5118 gtk_sheet_real_unselect_range (sheet, NULL);
5120 sheet->active_cell.row = sheet->active_cell.row +
5121 (sheet->drag_range.row0 - sheet->range.row0);
5122 sheet->active_cell.col = sheet->active_cell.col +
5123 (sheet->drag_range.col0 - sheet->range.col0);
5124 if (sheet->drag_range.row0 < sheet->range.row0)
5125 sheet->selection_cell.row = sheet->drag_range.row0;
5126 if (sheet->drag_range.rowi >= sheet->range.rowi)
5127 sheet->selection_cell.row = sheet->drag_range.rowi;
5128 if (sheet->drag_range.col0 < sheet->range.col0)
5129 sheet->selection_cell.col = sheet->drag_range.col0;
5130 if (sheet->drag_range.coli >= sheet->range.coli)
5131 sheet->selection_cell.col = sheet->drag_range.coli;
5132 old_range = sheet->range;
5133 sheet->range = sheet->drag_range;
5134 sheet->drag_range = old_range;
5136 if (sheet->state == GTK_STATE_NORMAL) sheet->state = GTK_SHEET_RANGE_SELECTED;
5137 g_signal_emit (G_OBJECT (sheet), sheet_signals[RESIZE_RANGE], 0,
5138 &sheet->drag_range, &sheet->range);
5139 gtk_sheet_select_range (sheet, &sheet->range);
5142 if (sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
5144 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5145 gdk_pointer_ungrab (event->time);
5146 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5147 sheet->active_cell.col);
5150 if (GTK_SHEET_IN_SELECTION)
5151 gdk_pointer_ungrab (event->time);
5152 gtk_grab_remove (GTK_WIDGET (sheet));
5154 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5159 /* Shamelessly lifted from gtktooltips */
5161 gtk_sheet_subtitle_paint_window (GtkWidget *tip_window)
5165 gtk_widget_size_request (tip_window, &req);
5166 gtk_paint_flat_box (tip_window->style, tip_window->window,
5167 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
5168 NULL, GTK_WIDGET(tip_window), "tooltip",
5169 0, 0, req.width, req.height);
5174 static GtkSheetHoverTitle *
5175 create_hover_window (void)
5177 GtkSheetHoverTitle *hw = malloc (sizeof (*hw));
5179 hw->window = gtk_window_new (GTK_WINDOW_POPUP);
5181 #if GTK_CHECK_VERSION (2, 9, 0)
5182 gtk_window_set_type_hint (GTK_WINDOW (hw->window),
5183 GDK_WINDOW_TYPE_HINT_TOOLTIP);
5186 gtk_widget_set_app_paintable (hw->window, TRUE);
5187 gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
5188 gtk_widget_set_name (hw->window, "gtk-tooltips");
5189 gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
5191 g_signal_connect (hw->window,
5193 G_CALLBACK (gtk_sheet_subtitle_paint_window),
5196 hw->label = gtk_label_new (NULL);
5199 gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
5200 gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
5202 gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
5204 gtk_widget_show (hw->label);
5206 g_signal_connect (hw->window,
5208 G_CALLBACK (gtk_widget_destroyed),
5214 #define HOVER_WINDOW_Y_OFFSET 2
5217 show_subtitle (GtkSheet *sheet, gint row, gint column, const gchar *subtitle)
5226 if ( ! sheet->hover_window)
5228 sheet->hover_window = create_hover_window ();
5229 gtk_widget_add_events (GTK_WIDGET (sheet), GDK_LEAVE_NOTIFY_MASK);
5231 g_signal_connect_swapped (sheet, "leave-notify-event",
5232 G_CALLBACK (gtk_widget_hide),
5233 sheet->hover_window->window);
5236 gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
5240 sheet->hover_window->row = row;
5241 sheet->hover_window->column = column;
5243 gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
5245 gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
5247 gtk_widget_show (sheet->hover_window->window);
5249 width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
5255 y += sheet->column_title_area.y;
5256 y += sheet->column_title_area.height;
5257 y += HOVER_WINDOW_Y_OFFSET;
5263 x += sheet->row_title_area.x;
5264 x += sheet->row_title_area.width * 2 / 3.0;
5267 gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
5272 motion_timeout_callback (gpointer data)
5274 GtkSheet *sheet = GTK_SHEET (data);
5277 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
5279 if ( gtk_sheet_get_pixel_info (sheet, x, y, &row, &column) )
5281 if ( column == -1 && row == -1 )
5286 GSheetRow *row_geo = sheet->row_geometry;
5289 text = g_sheet_row_get_subtitle (row_geo, row);
5291 show_subtitle (sheet, row, column, text);
5297 GSheetColumn *col_geo = sheet->column_geometry;
5300 text = g_sheet_column_get_subtitle (col_geo, column);
5302 show_subtitle (sheet, row, column, text );
5312 gtk_sheet_motion (GtkWidget * widget,
5313 GdkEventMotion * event)
5316 GdkModifierType mods;
5317 GdkCursorType new_cursor;
5321 g_return_val_if_fail (widget != NULL, FALSE);
5322 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5323 g_return_val_if_fail (event != NULL, FALSE);
5325 sheet = GTK_SHEET (widget);
5327 /* selections on the sheet */
5331 if (!sheet->hover_window || ! GTK_WIDGET_VISIBLE (sheet->hover_window->window))
5333 if ( sheet->motion_timer > 0 )
5334 g_source_remove (sheet->motion_timer);
5335 sheet->motion_timer = g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
5341 gtk_widget_get_pointer (widget, &wx, &wy);
5343 if ( gtk_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
5345 if ( row != sheet->hover_window->row || column != sheet->hover_window->column)
5347 gtk_widget_hide (sheet->hover_window->window);
5352 if (event->window == sheet->column_title_window &&
5353 gtk_sheet_columns_resizable (sheet))
5355 gtk_widget_get_pointer (widget, &x, &y);
5356 if (!GTK_SHEET_IN_SELECTION (sheet) &&
5357 POSSIBLE_XDRAG (sheet, x, &column))
5359 new_cursor = GDK_SB_H_DOUBLE_ARROW;
5360 if (new_cursor != sheet->cursor_drag->type)
5362 gdk_cursor_destroy (sheet->cursor_drag);
5363 sheet->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
5364 gdk_window_set_cursor (sheet->column_title_window,
5365 sheet->cursor_drag);
5370 new_cursor = GDK_TOP_LEFT_ARROW;
5371 if (!GTK_SHEET_IN_XDRAG (sheet) &&
5372 new_cursor != sheet->cursor_drag->type)
5374 gdk_cursor_destroy (sheet->cursor_drag);
5375 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5376 gdk_window_set_cursor (sheet->column_title_window,
5377 sheet->cursor_drag);
5382 if (event->window == sheet->row_title_window &&
5383 gtk_sheet_rows_resizable (sheet))
5385 gtk_widget_get_pointer (widget, &x, &y);
5386 if (!GTK_SHEET_IN_SELECTION (sheet) && POSSIBLE_YDRAG (sheet, y, &column))
5388 new_cursor = GDK_SB_V_DOUBLE_ARROW;
5389 if (new_cursor != sheet->cursor_drag->type)
5391 gdk_cursor_destroy (sheet->cursor_drag);
5392 sheet->cursor_drag = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
5393 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5398 new_cursor = GDK_TOP_LEFT_ARROW;
5399 if (!GTK_SHEET_IN_YDRAG (sheet) &&
5400 new_cursor != sheet->cursor_drag->type)
5402 gdk_cursor_destroy (sheet->cursor_drag);
5403 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5404 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5409 new_cursor = GDK_PLUS;
5410 if ( event->window == sheet->sheet_window &&
5411 !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
5412 !GTK_SHEET_IN_DRAG (sheet) &&
5413 !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
5414 !GTK_SHEET_IN_RESIZE (sheet) &&
5415 new_cursor != sheet->cursor_drag->type)
5417 gdk_cursor_destroy (sheet->cursor_drag);
5418 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
5419 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5422 new_cursor = GDK_TOP_LEFT_ARROW;
5423 if ( event->window == sheet->sheet_window &&
5424 ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) || GTK_SHEET_IN_RESIZE (sheet)) && (POSSIBLE_DRAG (sheet, x, y, &row, &column) || GTK_SHEET_IN_DRAG (sheet)) &&
5426 new_cursor != sheet->cursor_drag->type)
5428 gdk_cursor_destroy (sheet->cursor_drag);
5429 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5430 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5433 new_cursor = GDK_SIZING;
5434 if ( event->window == sheet->sheet_window &&
5435 sheet->selection_mode != GTK_SELECTION_NONE &&
5436 !GTK_SHEET_IN_DRAG (sheet) &&
5437 (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
5438 GTK_SHEET_IN_RESIZE (sheet)) &&
5439 new_cursor != sheet->cursor_drag->type)
5441 gdk_cursor_destroy (sheet->cursor_drag);
5442 sheet->cursor_drag = gdk_cursor_new (GDK_SIZING);
5443 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5447 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5448 if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
5450 if (GTK_SHEET_IN_XDRAG (sheet))
5452 if (event->is_hint || event->window != widget->window)
5453 gtk_widget_get_pointer (widget, &x, NULL);
5457 new_column_width (sheet, sheet->drag_cell.col, &x);
5458 if (x != sheet->x_drag)
5460 draw_xor_vline (sheet);
5462 draw_xor_vline (sheet);
5467 if (GTK_SHEET_IN_YDRAG (sheet))
5469 if (event->is_hint || event->window != widget->window)
5470 gtk_widget_get_pointer (widget, NULL, &y);
5474 new_row_height (sheet, sheet->drag_cell.row, &y);
5475 if (y != sheet->y_drag)
5477 draw_xor_hline (sheet);
5479 draw_xor_hline (sheet);
5484 if (GTK_SHEET_IN_DRAG (sheet))
5487 column = COLUMN_FROM_XPIXEL (sheet, x)- sheet->drag_cell.col;
5488 row = ROW_FROM_YPIXEL (sheet, y)- sheet->drag_cell.row;
5489 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5490 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5494 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5495 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5497 aux = sheet->drag_range;
5498 sheet->drag_range.row0 = sheet->range.row0 + row;
5499 sheet->drag_range.col0 = sheet->range.col0 + column;
5500 sheet->drag_range.rowi = sheet->range.rowi + row;
5501 sheet->drag_range.coli = sheet->range.coli + column;
5502 if (aux.row0 != sheet->drag_range.row0 ||
5503 aux.col0 != sheet->drag_range.col0)
5505 draw_xor_rectangle (sheet, aux);
5506 draw_xor_rectangle (sheet, sheet->drag_range);
5512 if (GTK_SHEET_IN_RESIZE (sheet))
5515 gint v_h, current_col, current_row, col_threshold, row_threshold;
5518 if (abs (x - COLUMN_LEFT_XPIXEL (sheet, sheet->drag_cell.col)) >
5519 abs (y - ROW_TOP_YPIXEL (sheet, sheet->drag_cell.row))) v_h = 2;
5521 current_col = COLUMN_FROM_XPIXEL (sheet, x);
5522 current_row = ROW_FROM_YPIXEL (sheet, y);
5523 column = current_col - sheet->drag_cell.col;
5524 row = current_row - sheet->drag_cell.row;
5526 /*use half of column width resp. row height as threshold to
5528 col_threshold = COLUMN_LEFT_XPIXEL (sheet, current_col) +
5529 xxx_column_width (sheet, current_col) / 2;
5532 if (x < col_threshold)
5535 else if (column < 0)
5537 if (x > col_threshold)
5540 row_threshold = ROW_TOP_YPIXEL (sheet, current_row) +
5541 yyy_row_height (sheet, current_row)/2;
5544 if (y < row_threshold)
5549 if (y > row_threshold)
5553 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5554 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5564 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5565 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5567 aux = sheet->drag_range;
5568 sheet->drag_range = sheet->range;
5570 if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
5571 if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
5572 if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
5573 if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
5575 if (aux.row0 != sheet->drag_range.row0 ||
5576 aux.rowi != sheet->drag_range.rowi ||
5577 aux.col0 != sheet->drag_range.col0 ||
5578 aux.coli != sheet->drag_range.coli)
5580 draw_xor_rectangle (sheet, aux);
5581 draw_xor_rectangle (sheet, sheet->drag_range);
5587 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5589 if (sheet->state == GTK_SHEET_NORMAL && row == sheet->active_cell.row &&
5590 column == sheet->active_cell.col) return TRUE;
5592 if (GTK_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
5593 gtk_sheet_extend_selection (sheet, row, column);
5599 gtk_sheet_move_query (GtkSheet *sheet, gint row, gint column)
5601 gint row_move, column_move;
5602 gfloat row_align, col_align;
5603 guint height, width;
5605 gint new_col = column;
5608 column_move = FALSE;
5612 height = sheet->sheet_window_height;
5613 width = sheet->sheet_window_width;
5615 if (row >= MAX_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5618 new_row = MIN (yyy_row_count (sheet), row + 1);
5620 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet) - 1 &&
5621 ROW_TOP_YPIXEL (sheet, yyy_row_count (sheet)- 1) +
5622 yyy_row_height (sheet, yyy_row_count (sheet)- 1) < height)
5628 if (row < MIN_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5633 if (column >= MAX_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5636 new_col = MIN (xxx_column_count (sheet) - 1, column + 1);
5638 if (MAX_VISIBLE_COLUMN (sheet) == (xxx_column_count (sheet) - 1) &&
5639 COLUMN_LEFT_XPIXEL (sheet, xxx_column_count (sheet) - 1) +
5640 xxx_column_width (sheet, xxx_column_count (sheet) - 1) < width)
5642 column_move = FALSE;
5646 if (column < MIN_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5652 if (row_move || column_move)
5654 gtk_sheet_moveto (sheet, new_row, new_col, row_align, col_align);
5657 return (row_move || column_move);
5661 gtk_sheet_extend_selection (GtkSheet *sheet, gint row, gint column)
5663 GtkSheetRange range;
5667 if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5670 if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5672 gtk_sheet_move_query (sheet, row, column);
5673 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5675 if (GTK_SHEET_IN_DRAG (sheet)) return;
5677 state = sheet->state;
5679 switch (sheet->state)
5681 case GTK_SHEET_ROW_SELECTED:
5682 column = xxx_column_count (sheet) - 1;
5684 case GTK_SHEET_COLUMN_SELECTED:
5685 row = yyy_row_count (sheet) - 1;
5687 case GTK_SHEET_NORMAL:
5688 sheet->state = GTK_SHEET_RANGE_SELECTED;
5689 r = sheet->active_cell.row;
5690 c = sheet->active_cell.col;
5691 sheet->range.col0 = c;
5692 sheet->range.row0 = r;
5693 sheet->range.coli = c;
5694 sheet->range.rowi = r;
5695 gdk_draw_pixmap (sheet->sheet_window,
5696 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
5698 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5699 ROW_TOP_YPIXEL (sheet, r)- 1,
5700 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5701 ROW_TOP_YPIXEL (sheet, r)- 1,
5702 xxx_column_width (sheet, c)+4,
5703 yyy_row_height (sheet, r)+4);
5704 gtk_sheet_range_draw_selection (sheet, sheet->range);
5705 case GTK_SHEET_RANGE_SELECTED:
5706 sheet->state = GTK_SHEET_RANGE_SELECTED;
5709 sheet->selection_cell.row = row;
5710 sheet->selection_cell.col = column;
5712 range.col0 = MIN (column, sheet->active_cell.col);
5713 range.coli = MAX (column, sheet->active_cell.col);
5714 range.row0 = MIN (row, sheet->active_cell.row);
5715 range.rowi = MAX (row, sheet->active_cell.row);
5717 if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5718 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5719 state == GTK_SHEET_NORMAL)
5720 gtk_sheet_real_select_range (sheet, &range);
5725 gtk_sheet_entry_key_press (GtkWidget *widget,
5729 g_signal_emit_by_name (G_OBJECT (widget), "key_press_event", key, &focus);
5734 gtk_sheet_key_press (GtkWidget *widget,
5740 gboolean extend_selection = FALSE;
5741 gboolean force_move = FALSE;
5742 gboolean in_selection = FALSE;
5743 gboolean veto = TRUE;
5746 sheet = GTK_SHEET (widget);
5748 if (key->state & GDK_CONTROL_MASK || key->keyval == GDK_Control_L ||
5749 key->keyval == GDK_Control_R) return FALSE;
5751 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval == GDK_Shift_L
5752 || key->keyval == GDK_Shift_R;
5754 state = sheet->state;
5755 in_selection = GTK_SHEET_IN_SELECTION (sheet);
5756 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5758 switch (key->keyval)
5760 case GDK_Return: case GDK_KP_Enter:
5761 if (sheet->state == GTK_SHEET_NORMAL &&
5762 !GTK_SHEET_IN_SELECTION (sheet))
5763 g_signal_stop_emission_by_name (gtk_sheet_get_entry (sheet),
5765 row = sheet->active_cell.row;
5766 col = sheet->active_cell.col;
5767 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5768 row = MIN_VISIBLE_ROW (sheet)- 1;
5769 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5770 col = MIN_VISIBLE_COLUMN (sheet);
5771 if (row < yyy_row_count (sheet) - 1)
5774 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1)
5777 gtk_sheet_click_cell (sheet, row, col, &veto);
5778 extend_selection = FALSE;
5780 case GDK_ISO_Left_Tab:
5781 row = sheet->active_cell.row;
5782 col = sheet->active_cell.col;
5783 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5784 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5785 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5786 row = MIN_VISIBLE_ROW (sheet);
5790 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5793 gtk_sheet_click_cell (sheet, row, col, &veto);
5794 extend_selection = FALSE;
5797 row = sheet->active_cell.row;
5798 col = sheet->active_cell.col;
5799 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5800 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5801 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5802 row = MIN_VISIBLE_ROW (sheet);
5803 if (col < xxx_column_count (sheet) - 1)
5806 while (! xxx_column_is_visible (sheet, col) &&
5807 col < xxx_column_count (sheet) - 1)
5810 gtk_sheet_click_cell (sheet, row, col, &veto);
5811 extend_selection = FALSE;
5814 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5816 if (extend_selection)
5818 if (state == GTK_STATE_NORMAL)
5820 row = sheet->active_cell.row;
5821 col = sheet->active_cell.col;
5822 gtk_sheet_click_cell (sheet, row, col, &veto);
5825 if (sheet->selection_cell.row > 0)
5827 row = sheet->selection_cell.row - scroll;
5828 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5830 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5834 col = sheet->active_cell.col;
5835 row = sheet->active_cell.row;
5836 if (state == GTK_SHEET_COLUMN_SELECTED)
5837 row = MIN_VISIBLE_ROW (sheet);
5838 if (state == GTK_SHEET_ROW_SELECTED)
5839 col = MIN_VISIBLE_COLUMN (sheet);
5841 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5843 gtk_sheet_click_cell (sheet, row, col, &veto);
5844 extend_selection = FALSE;
5847 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5849 if (extend_selection)
5851 if (state == GTK_STATE_NORMAL)
5853 row = sheet->active_cell.row;
5854 col = sheet->active_cell.col;
5855 gtk_sheet_click_cell (sheet, row, col, &veto);
5858 if (sheet->selection_cell.row < yyy_row_count (sheet)- 1)
5860 row = sheet->selection_cell.row + scroll;
5861 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5862 row = MIN (yyy_row_count (sheet)- 1, row);
5863 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5867 col = sheet->active_cell.col;
5868 row = sheet->active_cell.row;
5869 if (sheet->active_cell.row < yyy_row_count (sheet)- 1)
5871 if (state == GTK_SHEET_COLUMN_SELECTED)
5872 row = MIN_VISIBLE_ROW (sheet)- 1;
5873 if (state == GTK_SHEET_ROW_SELECTED)
5874 col = MIN_VISIBLE_COLUMN (sheet);
5876 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5877 row = MIN (yyy_row_count (sheet)- 1, row);
5879 gtk_sheet_click_cell (sheet, row, col, &veto);
5880 extend_selection = FALSE;
5883 if (extend_selection)
5885 if (state == GTK_STATE_NORMAL)
5887 row = sheet->active_cell.row;
5888 col = sheet->active_cell.col;
5889 gtk_sheet_click_cell (sheet, row, col, &veto);
5892 if (sheet->selection_cell.col < xxx_column_count (sheet) - 1)
5894 col = sheet->selection_cell.col + 1;
5895 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1)
5897 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5901 col = sheet->active_cell.col;
5902 row = sheet->active_cell.row;
5903 if (sheet->active_cell.col < xxx_column_count (sheet) - 1)
5906 if (state == GTK_SHEET_ROW_SELECTED)
5907 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5908 if (state == GTK_SHEET_COLUMN_SELECTED)
5909 row = MIN_VISIBLE_ROW (sheet);
5910 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1) col++;
5911 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5914 gtk_sheet_click_cell (sheet, row, col, &veto);
5919 extend_selection = FALSE;
5922 if (extend_selection)
5924 if (state == GTK_STATE_NORMAL)
5926 row = sheet->active_cell.row;
5927 col = sheet->active_cell.col;
5928 gtk_sheet_click_cell (sheet, row, col, &veto);
5931 if (sheet->selection_cell.col > 0)
5933 col = sheet->selection_cell.col - 1;
5934 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5935 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5939 col = sheet->active_cell.col - 1;
5940 row = sheet->active_cell.row;
5941 if (state == GTK_SHEET_ROW_SELECTED)
5942 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5943 if (state == GTK_SHEET_COLUMN_SELECTED)
5944 row = MIN_VISIBLE_ROW (sheet);
5945 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5948 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5951 gtk_sheet_click_cell (sheet, row, col, &veto);
5955 extend_selection = FALSE;
5959 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5960 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5961 extend_selection = FALSE;
5964 row = yyy_row_count (sheet)- 1;
5965 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5966 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5967 extend_selection = FALSE;
5972 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5973 if (extend_selection) return TRUE;
5975 if (state == GTK_SHEET_ROW_SELECTED)
5976 sheet->active_cell.col = MIN_VISIBLE_COLUMN (sheet);
5977 if (state == GTK_SHEET_COLUMN_SELECTED)
5978 sheet->active_cell.row = MIN_VISIBLE_ROW (sheet);
5982 if (extend_selection) return TRUE;
5984 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5985 sheet->active_cell.col);
5991 gtk_sheet_size_request (GtkWidget * widget,
5992 GtkRequisition * requisition)
5996 GtkSheetChild *child;
5997 GtkRequisition child_requisition;
5999 g_return_if_fail (widget != NULL);
6000 g_return_if_fail (GTK_IS_SHEET (widget));
6001 g_return_if_fail (requisition != NULL);
6003 sheet = GTK_SHEET (widget);
6005 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
6006 requisition->height = 3*DEFAULT_ROW_HEIGHT (widget);
6008 /* compute the size of the column title area */
6009 if (sheet->column_titles_visible)
6010 requisition->height += sheet->column_title_area.height;
6012 /* compute the size of the row title area */
6013 if (sheet->row_titles_visible)
6014 requisition->width += sheet->row_title_area.width;
6016 children = sheet->children;
6019 child = children->data;
6020 children = children->next;
6022 gtk_widget_size_request (child->widget, &child_requisition);
6028 gtk_sheet_size_allocate (GtkWidget * widget,
6029 GtkAllocation * allocation)
6032 GtkAllocation sheet_allocation;
6035 g_return_if_fail (widget != NULL);
6036 g_return_if_fail (GTK_IS_SHEET (widget));
6037 g_return_if_fail (allocation != NULL);
6039 sheet = GTK_SHEET (widget);
6040 widget->allocation = *allocation;
6041 border_width = GTK_CONTAINER (widget)->border_width;
6043 if (GTK_WIDGET_REALIZED (widget))
6044 gdk_window_move_resize (widget->window,
6045 allocation->x + border_width,
6046 allocation->y + border_width,
6047 allocation->width - 2 * border_width,
6048 allocation->height - 2 * border_width);
6050 /* use internal allocation structure for all the math
6051 * because it's easier than always subtracting the container
6053 sheet->internal_allocation.x = 0;
6054 sheet->internal_allocation.y = 0;
6055 sheet->internal_allocation.width = allocation->width - 2 * border_width;
6056 sheet->internal_allocation.height = allocation->height - 2 * border_width;
6058 sheet_allocation.x = 0;
6059 sheet_allocation.y = 0;
6060 sheet_allocation.width = allocation->width - 2 * border_width;
6061 sheet_allocation.height = allocation->height - 2 * border_width;
6063 sheet->sheet_window_width = sheet_allocation.width;
6064 sheet->sheet_window_height = sheet_allocation.height;
6066 if (GTK_WIDGET_REALIZED (widget))
6067 gdk_window_move_resize (sheet->sheet_window,
6070 sheet_allocation.width,
6071 sheet_allocation.height);
6073 /* position the window which holds the column title buttons */
6074 sheet->column_title_area.x = 0;
6075 sheet->column_title_area.y = 0;
6076 if (sheet->row_titles_visible)
6077 sheet->column_title_area.x = sheet->row_title_area.width;
6078 sheet->column_title_area.width = sheet_allocation.width -
6079 sheet->column_title_area.x;
6080 if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
6081 gdk_window_move_resize (sheet->column_title_window,
6082 sheet->column_title_area.x,
6083 sheet->column_title_area.y,
6084 sheet->column_title_area.width,
6085 sheet->column_title_area.height);
6087 sheet->sheet_window_width = sheet_allocation.width;
6088 sheet->sheet_window_height = sheet_allocation.height;
6090 /* column button allocation */
6091 size_allocate_column_title_buttons (sheet);
6093 /* position the window which holds the row title buttons */
6094 sheet->row_title_area.x = 0;
6095 sheet->row_title_area.y = 0;
6096 if (sheet->column_titles_visible)
6097 sheet->row_title_area.y = sheet->column_title_area.height;
6098 sheet->row_title_area.height = sheet_allocation.height -
6099 sheet->row_title_area.y;
6101 if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
6102 gdk_window_move_resize (sheet->row_title_window,
6103 sheet->row_title_area.x,
6104 sheet->row_title_area.y,
6105 sheet->row_title_area.width,
6106 sheet->row_title_area.height);
6109 /* row button allocation */
6110 size_allocate_row_title_buttons (sheet);
6111 size_allocate_column_title_buttons (sheet);
6113 /* re - scale backing pixmap */
6114 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
6115 gtk_sheet_position_children (sheet);
6117 /* set the scrollbars adjustments */
6118 adjust_scrollbars (sheet);
6122 size_allocate_column_title_buttons (GtkSheet * sheet)
6127 if (!sheet->column_titles_visible) return;
6128 if (!GTK_WIDGET_REALIZED (sheet))
6131 width = sheet->sheet_window_width;
6134 if (sheet->row_titles_visible)
6136 width -= sheet->row_title_area.width;
6137 x = sheet->row_title_area.width;
6140 if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6142 sheet->column_title_area.width = width;
6143 sheet->column_title_area.x = x;
6144 gdk_window_move_resize (sheet->column_title_window,
6145 sheet->column_title_area.x,
6146 sheet->column_title_area.y,
6147 sheet->column_title_area.width,
6148 sheet->column_title_area.height);
6152 if (MAX_VISIBLE_COLUMN (sheet) == xxx_column_count (sheet) - 1)
6153 gdk_window_clear_area (sheet->column_title_window,
6155 sheet->column_title_area.width,
6156 sheet->column_title_area.height);
6158 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6160 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
6161 gtk_sheet_column_title_button_draw (sheet, i);
6165 size_allocate_row_title_buttons (GtkSheet * sheet)
6170 if (!sheet->row_titles_visible) return;
6171 if (!GTK_WIDGET_REALIZED (sheet))
6174 height = sheet->sheet_window_height;
6177 if (sheet->column_titles_visible)
6179 height -= sheet->column_title_area.height;
6180 y = sheet->column_title_area.height;
6183 if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6185 sheet->row_title_area.y = y;
6186 sheet->row_title_area.height = height;
6187 gdk_window_move_resize (sheet->row_title_window,
6188 sheet->row_title_area.x,
6189 sheet->row_title_area.y,
6190 sheet->row_title_area.width,
6191 sheet->row_title_area.height);
6193 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet)- 1)
6194 gdk_window_clear_area (sheet->row_title_window,
6196 sheet->row_title_area.width,
6197 sheet->row_title_area.height);
6199 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6201 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
6203 if ( i >= yyy_row_count (sheet))
6205 gtk_sheet_row_title_button_draw (sheet, i);
6211 gtk_sheet_size_allocate_entry (GtkSheet *sheet)
6213 GtkAllocation shentry_allocation;
6214 GtkSheetCellAttr attributes = { 0 };
6215 GtkEntry *sheet_entry;
6216 GtkStyle *style = NULL, *previous_style = NULL;
6218 gint size, max_size, text_size, column_width;
6221 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6222 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
6224 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
6226 if ( ! gtk_sheet_get_attributes (sheet, sheet->active_cell.row,
6227 sheet->active_cell.col,
6231 if ( GTK_WIDGET_REALIZED (sheet->sheet_entry) )
6233 if (!GTK_WIDGET (sheet_entry)->style)
6234 gtk_widget_ensure_style (GTK_WIDGET (sheet_entry));
6236 previous_style = GTK_WIDGET (sheet_entry)->style;
6238 style = gtk_style_copy (previous_style);
6239 style->bg[GTK_STATE_NORMAL] = attributes.background;
6240 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6241 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6242 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6243 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6244 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6246 pango_font_description_free (style->font_desc);
6247 g_assert (attributes.font_desc);
6248 style->font_desc = pango_font_description_copy (attributes.font_desc);
6250 GTK_WIDGET (sheet_entry)->style = style;
6251 gtk_widget_size_request (sheet->sheet_entry, NULL);
6252 GTK_WIDGET (sheet_entry)->style = previous_style;
6254 if (style != previous_style)
6256 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6258 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6259 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6260 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6261 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6263 gtk_widget_set_style (GTK_WIDGET (sheet_entry), style);
6267 if (GTK_IS_ITEM_ENTRY (sheet_entry))
6268 max_size = GTK_ITEM_ENTRY (sheet_entry)->text_max_size;
6273 text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
6274 if (text && strlen (text) > 0)
6275 text_size = STRING_WIDTH (GTK_WIDGET (sheet), attributes.font_desc, text);
6277 column_width = xxx_column_width (sheet, sheet->active_cell.col);
6279 size = MIN (text_size, max_size);
6280 size = MAX (size, column_width - 2 * CELLOFFSET);
6282 row = sheet->active_cell.row;
6283 col = sheet->active_cell.col;
6285 shentry_allocation.x = COLUMN_LEFT_XPIXEL (sheet, sheet->active_cell.col);
6286 shentry_allocation.y = ROW_TOP_YPIXEL (sheet, sheet->active_cell.row);
6287 shentry_allocation.width = column_width;
6288 shentry_allocation.height = yyy_row_height (sheet, sheet->active_cell.row);
6290 if (GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6292 shentry_allocation.height -= 2 * CELLOFFSET;
6293 shentry_allocation.y += CELLOFFSET;
6294 shentry_allocation.width = size;
6296 switch (GTK_ITEM_ENTRY (sheet_entry)->justification)
6298 case GTK_JUSTIFY_CENTER:
6299 shentry_allocation.x += column_width / 2 - size / 2;
6301 case GTK_JUSTIFY_RIGHT:
6302 shentry_allocation.x += column_width - size - CELLOFFSET;
6304 case GTK_JUSTIFY_LEFT:
6305 case GTK_JUSTIFY_FILL:
6306 shentry_allocation.x += CELLOFFSET;
6311 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6313 shentry_allocation.x += 2;
6314 shentry_allocation.y += 2;
6315 shentry_allocation.width -= MIN (shentry_allocation.width, 3);
6316 shentry_allocation.height -= MIN (shentry_allocation.height, 3);
6319 gtk_widget_size_allocate (sheet->sheet_entry, &shentry_allocation);
6321 if (previous_style == style) g_object_unref (previous_style);
6325 gtk_sheet_entry_set_max_size (GtkSheet *sheet)
6329 gint sizel = 0, sizer = 0;
6331 GtkJustification justification;
6334 row = sheet->active_cell.row;
6335 col = sheet->active_cell.col;
6337 if ( ! GTK_IS_ITEM_ENTRY (sheet->sheet_entry) )
6340 justification = GTK_ITEM_ENTRY (sheet->sheet_entry)->justification;
6342 switch (justification)
6344 case GTK_JUSTIFY_FILL:
6345 case GTK_JUSTIFY_LEFT:
6346 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6348 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6353 size +=xxx_column_width (sheet, i);
6355 size = MIN (size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL (sheet, col));
6357 case GTK_JUSTIFY_RIGHT:
6358 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6360 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6365 size +=xxx_column_width (sheet, i);
6368 case GTK_JUSTIFY_CENTER:
6369 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6371 sizer += xxx_column_width (sheet, i);
6373 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6375 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6380 sizel +=xxx_column_width (sheet, i);
6382 size = 2 * MIN (sizel, sizer);
6387 size += xxx_column_width (sheet, col);
6388 GTK_ITEM_ENTRY (sheet->sheet_entry)->text_max_size = size;
6393 create_sheet_entry (GtkSheet *sheet)
6398 gint found_entry = FALSE;
6400 widget = GTK_WIDGET (sheet);
6402 if (sheet->sheet_entry)
6404 /* avoids warnings */
6405 gtk_widget_ref (sheet->sheet_entry);
6406 gtk_widget_unparent (sheet->sheet_entry);
6407 gtk_widget_destroy (sheet->sheet_entry);
6410 if (sheet->entry_type)
6412 if (!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY))
6414 parent = g_object_new (sheet->entry_type, NULL);
6416 sheet->sheet_entry = parent;
6418 entry = gtk_sheet_get_entry (sheet);
6419 if (GTK_IS_ENTRY (entry))
6424 parent = g_object_new (sheet->entry_type, NULL);
6431 g_warning ("Entry type must be GtkEntry subclass, using default");
6432 entry = gtk_item_entry_new ();
6433 sheet->sheet_entry = entry;
6436 sheet->sheet_entry = parent;
6440 entry = gtk_item_entry_new ();
6441 sheet->sheet_entry = entry;
6444 gtk_widget_size_request (sheet->sheet_entry, NULL);
6446 if (GTK_WIDGET_REALIZED (sheet))
6448 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6449 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
6450 gtk_widget_realize (sheet->sheet_entry);
6453 g_signal_connect_swapped (G_OBJECT (entry), "key_press_event",
6454 G_CALLBACK (gtk_sheet_entry_key_press),
6457 gtk_widget_show (sheet->sheet_entry);
6461 /* Finds the last child widget that happens to be of type GtkEntry */
6463 find_entry (GtkWidget *w, gpointer user_data)
6465 GtkWidget **entry = user_data;
6466 if ( GTK_IS_ENTRY (w))
6473 gtk_sheet_get_entry (GtkSheet *sheet)
6476 GtkWidget *entry = NULL;
6477 GtkTableChild *table_child;
6478 GtkBoxChild *box_child;
6479 GList *children = NULL;
6481 g_return_val_if_fail (sheet != NULL, NULL);
6482 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6483 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6485 if (GTK_IS_ENTRY (sheet->sheet_entry)) return (sheet->sheet_entry);
6487 parent = GTK_WIDGET (sheet->sheet_entry);
6489 if (GTK_IS_TABLE (parent)) children = GTK_TABLE (parent)->children;
6490 if (GTK_IS_BOX (parent)) children = GTK_BOX (parent)->children;
6492 if (GTK_IS_CONTAINER (parent))
6494 gtk_container_forall (GTK_CONTAINER (parent), find_entry, &entry);
6496 if (GTK_IS_ENTRY (entry))
6500 if (!children) return NULL;
6504 if (GTK_IS_TABLE (parent))
6506 table_child = children->data;
6507 entry = table_child->widget;
6509 if (GTK_IS_BOX (parent))
6511 box_child = children->data;
6512 entry = box_child->widget;
6515 if (GTK_IS_ENTRY (entry))
6517 children = children->next;
6521 if (!GTK_IS_ENTRY (entry)) return NULL;
6528 gtk_sheet_get_entry_widget (GtkSheet *sheet)
6530 g_return_val_if_fail (sheet != NULL, NULL);
6531 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6532 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6534 return (sheet->sheet_entry);
6539 gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
6540 GtkSheetButton *button, gboolean is_sensitive,
6541 GdkRectangle allocation)
6543 GtkShadowType shadow_type;
6544 gint text_width = 0, text_height = 0;
6545 GtkSheetChild *child = NULL;
6546 PangoAlignment align = PANGO_ALIGN_LEFT;
6554 g_return_if_fail (sheet != NULL);
6555 g_return_if_fail (button != NULL);
6557 rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
6559 gdk_window_clear_area (window,
6560 allocation.x, allocation.y,
6561 allocation.width, allocation.height);
6563 gtk_paint_box (sheet->button->style, window,
6564 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6565 &allocation, GTK_WIDGET (sheet->button),
6567 allocation.x, allocation.y,
6568 allocation.width, allocation.height);
6570 state = button->state;
6571 if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
6573 if (state == GTK_STATE_ACTIVE)
6574 shadow_type = GTK_SHADOW_IN;
6576 shadow_type = GTK_SHADOW_OUT;
6578 if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6579 gtk_paint_box (sheet->button->style, window,
6580 button->state, shadow_type,
6581 &allocation, GTK_WIDGET (sheet->button),
6583 allocation.x, allocation.y,
6584 allocation.width, allocation.height);
6586 if (button->label_visible)
6589 text_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))- 2 * CELLOFFSET;
6591 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6593 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, &allocation);
6595 allocation.y += 2 * sheet->button->style->ythickness;
6598 if (button->label && strlen (button->label)>0)
6601 PangoLayout *layout = NULL;
6602 gint real_x = allocation.x, real_y = allocation.y;
6604 words = button->label;
6605 line = g_new (gchar, 1);
6608 while (words && *words != '\0')
6612 len = strlen (line);
6613 line = g_realloc (line, len + 2);
6617 if (*words == '\n' || * (words + 1) == '\0')
6619 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
6621 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
6622 switch (button->justification)
6624 case GTK_JUSTIFY_LEFT:
6625 real_x = allocation.x + CELLOFFSET;
6626 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6628 case GTK_JUSTIFY_RIGHT:
6629 real_x = allocation.x + allocation.width - text_width - CELLOFFSET;
6630 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6632 case GTK_JUSTIFY_CENTER:
6634 real_x = allocation.x + (allocation.width - text_width)/2;
6635 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6636 pango_layout_set_justify (layout, TRUE);
6638 pango_layout_set_alignment (layout, align);
6639 gtk_paint_layout (GTK_WIDGET (sheet)->style,
6648 g_object_unref (G_OBJECT (layout));
6650 real_y += text_height + 2;
6653 line = g_new (gchar, 1);
6661 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6663 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
6667 if ((child = button->child) && (child->widget))
6669 child->x = allocation.x;
6670 child->y = allocation.y;
6672 child->x += (allocation.width - child->widget->requisition.width) / 2;
6673 child->y += (allocation.height - child->widget->requisition.height) / 2;
6674 allocation.x = child->x;
6675 allocation.y = child->y;
6676 allocation.width = child->widget->requisition.width;
6677 allocation.height = child->widget->requisition.height;
6679 allocation.x = child->x;
6680 allocation.y = child->y;
6682 gtk_widget_set_state (child->widget, button->state);
6684 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
6685 GTK_WIDGET_MAPPED (child->widget))
6687 gtk_widget_size_allocate (child->widget,
6689 gtk_widget_queue_draw (child->widget);
6693 gtk_sheet_button_free (button);
6697 /* COLUMN value of - 1 indicates that the area to the right of the rightmost
6698 button should be redrawn */
6700 gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
6702 GdkWindow *window = NULL;
6703 GdkRectangle allocation;
6704 GtkSheetButton *button = NULL;
6705 gboolean is_sensitive = FALSE;
6707 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6709 if (column >= 0 && ! xxx_column_is_visible (sheet, column)) return;
6710 if (column >= 0 && !sheet->column_titles_visible) return;
6711 if (column >= 0 && column < MIN_VISIBLE_COLUMN (sheet)) return;
6712 if (column >= 0 && column > MAX_VISIBLE_COLUMN (sheet)) return;
6714 window = sheet->column_title_window;
6716 allocation.height = sheet->column_title_area.height;
6720 const gint cols = xxx_column_count (sheet) ;
6721 allocation.x = COLUMN_LEFT_XPIXEL (sheet, cols - 1)
6723 allocation.width = sheet->column_title_area.width
6724 + sheet->column_title_area.x
6727 gdk_window_clear_area (window,
6728 allocation.x, allocation.y,
6729 allocation.width, allocation.height);
6733 button = xxx_column_button (sheet, column);
6734 allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
6735 if (sheet->row_titles_visible)
6736 allocation.x -= sheet->row_title_area.width;
6738 allocation.width = xxx_column_width (sheet, column);
6740 is_sensitive = xxx_column_is_sensitive (sheet, column);
6741 gtk_sheet_button_draw (sheet, window, button,
6742 is_sensitive, allocation);
6747 gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
6749 GdkWindow *window = NULL;
6750 GdkRectangle allocation;
6751 GtkSheetButton *button = NULL;
6752 gboolean is_sensitive = FALSE;
6755 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6757 if (row >= 0 && !yyy_row_is_visible (sheet, row)) return;
6758 if (row >= 0 && !sheet->row_titles_visible) return;
6759 if (row >= 0 && row < MIN_VISIBLE_ROW (sheet)) return;
6760 if (row >= 0 && row > MAX_VISIBLE_ROW (sheet)) return;
6763 window = sheet->row_title_window;
6764 button = yyy_row_button (sheet, row);
6766 allocation.y = ROW_TOP_YPIXEL (sheet, row) + CELL_SPACING;
6767 if (sheet->column_titles_visible)
6768 allocation.y -= sheet->column_title_area.height;
6769 allocation.width = sheet->row_title_area.width;
6770 allocation.height = yyy_row_height (sheet, row);
6771 is_sensitive = yyy_row_is_sensitive (sheet, row);
6773 gtk_sheet_button_draw (sheet, window, button, is_sensitive, allocation);
6780 * vadjustment_value_changed
6781 * hadjustment_value_changed */
6784 adjust_scrollbars (GtkSheet * sheet)
6786 if (sheet->vadjustment)
6788 sheet->vadjustment->page_size = sheet->sheet_window_height;
6789 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6790 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
6791 sheet->vadjustment->lower = 0;
6792 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6793 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "changed");
6797 if (sheet->hadjustment)
6799 sheet->hadjustment->page_size = sheet->sheet_window_width;
6800 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6801 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6802 sheet->hadjustment->lower = 0;
6803 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6804 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "changed");
6810 vadjustment_value_changed (GtkAdjustment * adjustment,
6814 gint diff, value, old_value;
6818 g_return_if_fail (adjustment != NULL);
6819 g_return_if_fail (data != NULL);
6820 g_return_if_fail (GTK_IS_SHEET (data));
6822 sheet = GTK_SHEET (data);
6824 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6826 row = ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + CELL_SPACING);
6827 if (!sheet->column_titles_visible)
6828 row = ROW_FROM_YPIXEL (sheet, CELL_SPACING);
6830 old_value = - sheet->voffset;
6832 new_row = g_sheet_row_pixel_to_row (sheet->row_geometry,
6833 adjustment->value, sheet);
6835 y = g_sheet_row_start_pixel (sheet->row_geometry, new_row, sheet);
6837 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6838 yyy_row_height (sheet, row) > sheet->vadjustment->step_increment)
6840 /* This avoids embarrassing twitching */
6841 if (row == new_row && row != yyy_row_count (sheet) - 1 &&
6842 adjustment->value - sheet->old_vadjustment >=
6843 sheet->vadjustment->step_increment &&
6844 new_row + 1 != MIN_VISIBLE_ROW (sheet))
6847 y = y+yyy_row_height (sheet, row);
6851 /* Negative old_adjustment enforces the redraw, otherwise avoid
6853 if (sheet->old_vadjustment >= 0. && row == new_row)
6855 sheet->old_vadjustment = sheet->vadjustment->value;
6859 sheet->old_vadjustment = sheet->vadjustment->value;
6860 adjustment->value = y;
6865 sheet->vadjustment->step_increment = yyy_row_height (sheet, 0);
6869 sheet->vadjustment->step_increment =
6870 MIN (yyy_row_height (sheet, new_row), yyy_row_height (sheet, new_row - 1));
6873 sheet->vadjustment->value = adjustment->value;
6875 value = adjustment->value;
6877 if (value >= - sheet->voffset)
6880 diff = value + sheet->voffset;
6885 diff = - sheet->voffset - value;
6888 sheet->voffset = - value;
6890 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
6891 sheet->state == GTK_SHEET_NORMAL &&
6892 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6893 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
6894 sheet->active_cell.col))
6898 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
6900 if (!text || strlen (text) == 0)
6901 gtk_sheet_cell_clear (sheet,
6902 sheet->active_cell.row,
6903 sheet->active_cell.col);
6904 gtk_widget_unmap (sheet->sheet_entry);
6907 gtk_sheet_position_children (sheet);
6909 gtk_sheet_range_draw (sheet, NULL);
6910 size_allocate_row_title_buttons (sheet);
6911 size_allocate_global_button (sheet);
6915 hadjustment_value_changed (GtkAdjustment * adjustment,
6919 gint i, diff, value, old_value;
6920 gint column, new_column;
6923 g_return_if_fail (adjustment != NULL);
6924 g_return_if_fail (data != NULL);
6925 g_return_if_fail (GTK_IS_SHEET (data));
6927 sheet = GTK_SHEET (data);
6929 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6931 column = COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + CELL_SPACING);
6932 if (!sheet->row_titles_visible)
6933 column = COLUMN_FROM_XPIXEL (sheet, CELL_SPACING);
6935 old_value = - sheet->hoffset;
6937 for (i = 0; i < xxx_column_count (sheet); i++)
6939 if (xxx_column_is_visible (sheet, i)) x += xxx_column_width (sheet, i);
6940 if (x > adjustment->value) break;
6942 x -= xxx_column_width (sheet, i);
6945 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6946 xxx_column_width (sheet, i) > sheet->hadjustment->step_increment)
6948 /* This avoids embarrassing twitching */
6949 if (column == new_column && column != xxx_column_count (sheet) - 1 &&
6950 adjustment->value - sheet->old_hadjustment >=
6951 sheet->hadjustment->step_increment &&
6952 new_column + 1 != MIN_VISIBLE_COLUMN (sheet))
6955 x += xxx_column_width (sheet, column);
6959 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6960 if (sheet->old_hadjustment >= 0. && new_column == column)
6962 sheet->old_hadjustment = sheet->hadjustment->value;
6966 sheet->old_hadjustment = sheet->hadjustment->value;
6967 adjustment->value = x;
6969 if (new_column == 0)
6971 sheet->hadjustment->step_increment = xxx_column_width (sheet, 0);
6975 sheet->hadjustment->step_increment =
6976 MIN (xxx_column_width (sheet, new_column), xxx_column_width (sheet, new_column - 1));
6980 sheet->hadjustment->value = adjustment->value;
6982 value = adjustment->value;
6984 if (value >= - sheet->hoffset)
6987 diff = value + sheet->hoffset;
6992 diff = - sheet->hoffset - value;
6995 sheet->hoffset = - value;
6996 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
6997 sheet->state == GTK_SHEET_NORMAL &&
6998 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6999 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
7000 sheet->active_cell.col))
7004 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
7005 if (!text || strlen (text) == 0)
7006 gtk_sheet_cell_clear (sheet,
7007 sheet->active_cell.row,
7008 sheet->active_cell.col);
7010 gtk_widget_unmap (sheet->sheet_entry);
7013 gtk_sheet_position_children (sheet);
7015 gtk_sheet_range_draw (sheet, NULL);
7016 size_allocate_column_title_buttons (sheet);
7020 /* COLUMN RESIZING */
7022 draw_xor_vline (GtkSheet * sheet)
7026 g_return_if_fail (sheet != NULL);
7028 widget = GTK_WIDGET (sheet);
7030 gdk_draw_line (widget->window, sheet->xor_gc,
7032 sheet->column_title_area.height,
7034 sheet->sheet_window_height + 1);
7039 draw_xor_hline (GtkSheet * sheet)
7043 g_return_if_fail (sheet != NULL);
7045 widget = GTK_WIDGET (sheet);
7047 gdk_draw_line (widget->window, sheet->xor_gc,
7048 sheet->row_title_area.width,
7051 sheet->sheet_window_width + 1,
7055 /* SELECTED RANGE */
7057 draw_xor_rectangle (GtkSheet *sheet, GtkSheetRange range)
7060 GdkRectangle clip_area, area;
7063 area.x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
7064 area.y = ROW_TOP_YPIXEL (sheet, range.row0);
7065 area.width = COLUMN_LEFT_XPIXEL (sheet, range.coli)- area.x+
7066 xxx_column_width (sheet, range.coli);
7067 area.height = ROW_TOP_YPIXEL (sheet, range.rowi)- area.y+
7068 yyy_row_height (sheet, range.rowi);
7070 clip_area.x = sheet->row_title_area.width;
7071 clip_area.y = sheet->column_title_area.height;
7072 clip_area.width = sheet->sheet_window_width;
7073 clip_area.height = sheet->sheet_window_height;
7075 if (!sheet->row_titles_visible) clip_area.x = 0;
7076 if (!sheet->column_titles_visible) clip_area.y = 0;
7080 area.width = area.width + area.x;
7083 if (area.width > clip_area.width) area.width = clip_area.width + 10;
7086 area.height = area.height + area.y;
7089 if (area.height > clip_area.height) area.height = clip_area.height + 10;
7093 clip_area.width += 3;
7094 clip_area.height += 3;
7096 gdk_gc_get_values (sheet->xor_gc, &values);
7098 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
7100 for (i =- 1; i <= 1; ++i)
7101 gdk_draw_rectangle (sheet->sheet_window,
7104 area.x + i, area.y + i,
7105 area.width - 2 * i, area.height - 2 * i);
7108 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
7110 gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
7115 /* this function returns the new width of the column being resized given
7116 * the column and x position of the cursor; the x cursor position is passed
7117 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7119 new_column_width (GtkSheet * sheet,
7128 min_width = sheet->column_requisition;
7130 /* you can't shrink a column to less than its minimum width */
7131 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7133 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7136 /* calculate new column width making sure it doesn't end up
7137 * less than the minimum width */
7138 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7139 if (width < min_width)
7142 xxx_set_column_width (sheet, column, width);
7143 size_allocate_column_title_buttons (sheet);
7148 /* this function returns the new height of the row being resized given
7149 * the row and y position of the cursor; the y cursor position is passed
7150 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7152 new_row_height (GtkSheet * sheet,
7160 min_height = sheet->row_requisition;
7162 /* you can't shrink a row to less than its minimum height */
7163 if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7166 *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7169 /* calculate new row height making sure it doesn't end up
7170 * less than the minimum height */
7171 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7172 if (height < min_height)
7173 height = min_height;
7175 yyy_set_row_height (sheet, row, height);
7176 size_allocate_row_title_buttons (sheet);
7182 gtk_sheet_set_column_width (GtkSheet * sheet,
7188 g_return_if_fail (sheet != NULL);
7189 g_return_if_fail (GTK_IS_SHEET (sheet));
7191 if (column < 0 || column >= xxx_column_count (sheet))
7194 gtk_sheet_column_size_request (sheet, column, &min_width);
7195 if (width < min_width) return;
7197 xxx_set_column_width (sheet, column, width);
7199 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7201 size_allocate_column_title_buttons (sheet);
7202 adjust_scrollbars (sheet);
7203 gtk_sheet_size_allocate_entry (sheet);
7204 gtk_sheet_range_draw (sheet, NULL);
7207 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, column);
7208 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_COL_WIDTH], 0,
7215 gtk_sheet_set_row_height (GtkSheet * sheet,
7221 g_return_if_fail (sheet != NULL);
7222 g_return_if_fail (GTK_IS_SHEET (sheet));
7224 if (row < 0 || row >= yyy_row_count (sheet))
7227 gtk_sheet_row_size_request (sheet, row, &min_height);
7228 if (height < min_height) return;
7230 yyy_set_row_height (sheet, row, height);
7232 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7234 size_allocate_row_title_buttons (sheet);
7235 adjust_scrollbars (sheet);
7236 gtk_sheet_size_allocate_entry (sheet);
7237 gtk_sheet_range_draw (sheet, NULL);
7240 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, - 1);
7241 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_ROW_HEIGHT], 0,
7248 gtk_sheet_get_attributes (const GtkSheet *sheet, gint row, gint col,
7249 GtkSheetCellAttr *attributes)
7251 const GdkColor *fg, *bg;
7252 const GtkJustification *j ;
7253 const PangoFontDescription *font_desc ;
7254 const GtkSheetCellBorder *border ;
7256 g_return_val_if_fail (sheet != NULL, FALSE);
7257 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7259 if (row < 0 || col < 0) return FALSE;
7261 init_attributes (sheet, col, attributes);
7266 attributes->is_editable = g_sheet_model_is_editable (sheet->model, row, col);
7267 attributes->is_visible = g_sheet_model_is_visible (sheet->model, row, col);
7269 fg = g_sheet_model_get_foreground (sheet->model, row, col);
7271 attributes->foreground = *fg;
7273 bg = g_sheet_model_get_background (sheet->model, row, col);
7275 attributes->background = *bg;
7277 j = g_sheet_model_get_justification (sheet->model, row, col);
7278 if (j) attributes->justification = *j;
7280 font_desc = g_sheet_model_get_font_desc (sheet->model, row, col);
7281 if ( font_desc ) attributes->font_desc = font_desc;
7283 border = g_sheet_model_get_cell_border (sheet->model, row, col);
7285 if ( border ) attributes->border = *border;
7291 init_attributes (const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7293 /* DEFAULT VALUES */
7294 attributes->foreground = GTK_WIDGET (sheet)->style->black;
7295 attributes->background = sheet->bg_color;
7296 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7298 GdkColormap *colormap;
7299 colormap = gdk_colormap_get_system ();
7300 gdk_color_black (colormap, &attributes->foreground);
7301 attributes->background = sheet->bg_color;
7303 attributes->justification = xxx_column_justification (sheet, col);
7304 attributes->border.width = 0;
7305 attributes->border.line_style = GDK_LINE_SOLID;
7306 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7307 attributes->border.join_style = GDK_JOIN_MITER;
7308 attributes->border.mask = 0;
7309 attributes->border.color = GTK_WIDGET (sheet)->style->black;
7310 attributes->is_editable = TRUE;
7311 attributes->is_visible = TRUE;
7312 attributes->font_desc = GTK_WIDGET (sheet)->style->font_desc;
7316 /********************************************************************
7317 * Container Functions:
7322 * gtk_sheet_move_child
7323 * gtk_sheet_position_child
7324 * gtk_sheet_position_children
7325 * gtk_sheet_realize_child
7326 * gtk_sheet_get_child_at
7327 ********************************************************************/
7330 gtk_sheet_put (GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7332 GtkRequisition child_requisition;
7333 GtkSheetChild *child_info;
7335 g_return_val_if_fail (sheet != NULL, NULL);
7336 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7337 g_return_val_if_fail (child != NULL, NULL);
7338 g_return_val_if_fail (child->parent == NULL, NULL);
7340 child_info = g_new (GtkSheetChild, 1);
7341 child_info->widget = child;
7344 child_info->attached_to_cell = FALSE;
7345 child_info->floating = TRUE;
7346 child_info->xpadding = child_info->ypadding = 0;
7347 child_info->xexpand = child_info->yexpand = FALSE;
7348 child_info->xshrink = child_info->yshrink = FALSE;
7349 child_info->xfill = child_info->yfill = FALSE;
7351 sheet->children = g_list_append (sheet->children, child_info);
7353 gtk_widget_set_parent (child, GTK_WIDGET (sheet));
7355 gtk_widget_size_request (child, &child_requisition);
7357 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7359 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7360 (!GTK_WIDGET_REALIZED (child) || GTK_WIDGET_NO_WINDOW (child)))
7361 gtk_sheet_realize_child (sheet, child_info);
7363 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7364 !GTK_WIDGET_MAPPED (child))
7365 gtk_widget_map (child);
7368 gtk_sheet_position_child (sheet, child_info);
7370 /* This will avoid drawing on the titles */
7372 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7374 if (sheet->row_titles_visible)
7375 gdk_window_show (sheet->row_title_window);
7376 if (sheet->column_titles_visible)
7377 gdk_window_show (sheet->column_title_window);
7380 return (child_info);
7384 gtk_sheet_attach_floating (GtkSheet *sheet,
7389 GtkSheetChild *child;
7391 if (row < 0 || col < 0)
7393 gtk_sheet_button_attach (sheet, widget, row, col);
7397 gtk_sheet_get_cell_area (sheet, row, col, &area);
7398 child = gtk_sheet_put (sheet, widget, area.x, area.y);
7399 child->attached_to_cell = TRUE;
7405 gtk_sheet_attach_default (GtkSheet *sheet,
7409 if (row < 0 || col < 0)
7411 gtk_sheet_button_attach (sheet, widget, row, col);
7415 gtk_sheet_attach (sheet, widget, row, col,
7416 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
7420 gtk_sheet_attach (GtkSheet *sheet,
7429 GtkSheetChild *child = NULL;
7431 if (row < 0 || col < 0)
7433 gtk_sheet_button_attach (sheet, widget, row, col);
7437 child = g_new0 (GtkSheetChild, 1);
7438 child->attached_to_cell = TRUE;
7439 child->floating = FALSE;
7440 child->widget = widget;
7443 child->xpadding = xpadding;
7444 child->ypadding = ypadding;
7445 child->xexpand = (xoptions & GTK_EXPAND) != 0;
7446 child->yexpand = (yoptions & GTK_EXPAND) != 0;
7447 child->xshrink = (xoptions & GTK_SHRINK) != 0;
7448 child->yshrink = (yoptions & GTK_SHRINK) != 0;
7449 child->xfill = (xoptions & GTK_FILL) != 0;
7450 child->yfill = (yoptions & GTK_FILL) != 0;
7452 sheet->children = g_list_append (sheet->children, child);
7454 gtk_sheet_get_cell_area (sheet, row, col, &area);
7456 child->x = area.x + child->xpadding;
7457 child->y = area.y + child->ypadding;
7459 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7461 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7462 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7463 gtk_sheet_realize_child (sheet, child);
7465 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7466 !GTK_WIDGET_MAPPED (widget))
7467 gtk_widget_map (widget);
7470 gtk_sheet_position_child (sheet, child);
7472 /* This will avoid drawing on the titles */
7474 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7476 if (GTK_SHEET_ROW_TITLES_VISIBLE (sheet))
7477 gdk_window_show (sheet->row_title_window);
7478 if (GTK_SHEET_COL_TITLES_VISIBLE (sheet))
7479 gdk_window_show (sheet->column_title_window);
7485 gtk_sheet_button_attach (GtkSheet *sheet,
7489 GtkSheetButton *button = 0;
7490 GtkSheetChild *child;
7491 GtkRequisition button_requisition;
7493 if (row >= 0 && col >= 0) return;
7494 if (row < 0 && col < 0) return;
7496 child = g_new (GtkSheetChild, 1);
7497 child->widget = widget;
7500 child->attached_to_cell = TRUE;
7501 child->floating = FALSE;
7504 child->xpadding = child->ypadding = 0;
7505 child->xshrink = child->yshrink = FALSE;
7506 child->xfill = child->yfill = FALSE;
7509 sheet->children = g_list_append (sheet->children, child);
7511 gtk_sheet_button_size_request (sheet, button, &button_requisition);
7514 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7516 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7517 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7518 gtk_sheet_realize_child (sheet, child);
7520 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7521 !GTK_WIDGET_MAPPED (widget))
7522 gtk_widget_map (widget);
7525 if (row == -1) size_allocate_column_title_buttons (sheet);
7526 if (col == -1) size_allocate_row_title_buttons (sheet);
7531 label_size_request (GtkSheet *sheet, gchar *label, GtkRequisition *req)
7536 gint row_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) - 2 * CELLOFFSET + 2;
7542 while (words && *words != '\0')
7544 if (*words == '\n' || * (words + 1) == '\0')
7546 req->height += row_height;
7549 req->width = MAX (req->width, STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, word));
7559 if (n > 0) req->height -= 2;
7563 gtk_sheet_button_size_request (GtkSheet *sheet,
7564 const GtkSheetButton *button,
7565 GtkRequisition *button_requisition)
7567 GtkRequisition requisition;
7568 GtkRequisition label_requisition;
7570 if (gtk_sheet_autoresize (sheet) && button->label && strlen (button->label) > 0)
7572 label_size_request (sheet, button->label, &label_requisition);
7573 label_requisition.width += 2 * CELLOFFSET;
7574 label_requisition.height += 2 * CELLOFFSET;
7578 label_requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7579 label_requisition.width = COLUMN_MIN_WIDTH;
7584 gtk_widget_size_request (button->child->widget, &requisition);
7585 requisition.width += 2 * button->child->xpadding;
7586 requisition.height += 2 * button->child->ypadding;
7587 requisition.width += 2 * sheet->button->style->xthickness;
7588 requisition.height += 2 * sheet->button->style->ythickness;
7592 requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7593 requisition.width = COLUMN_MIN_WIDTH;
7596 *button_requisition = requisition;
7597 button_requisition->width = MAX (requisition.width, label_requisition.width);
7598 button_requisition->height = MAX (requisition.height, label_requisition.height);
7603 gtk_sheet_row_size_request (GtkSheet *sheet,
7607 GtkRequisition button_requisition;
7610 gtk_sheet_button_size_request (sheet,
7611 yyy_row_button (sheet, row),
7612 &button_requisition);
7614 *requisition = button_requisition.height;
7616 children = sheet->children;
7619 GtkSheetChild *child = (GtkSheetChild *)children->data;
7620 GtkRequisition child_requisition;
7622 if (child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink)
7624 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7626 if (child_requisition.height + 2 * child->ypadding > *requisition)
7627 *requisition = child_requisition.height + 2 * child->ypadding;
7629 children = children->next;
7632 sheet->row_requisition = * requisition;
7636 gtk_sheet_column_size_request (GtkSheet *sheet,
7640 GtkRequisition button_requisition;
7643 gtk_sheet_button_size_request (sheet,
7644 xxx_column_button (sheet, col),
7645 &button_requisition);
7647 *requisition = button_requisition.width;
7649 children = sheet->children;
7652 GtkSheetChild *child = (GtkSheetChild *)children->data;
7653 GtkRequisition child_requisition;
7655 if (child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink)
7657 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7659 if (child_requisition.width + 2 * child->xpadding > *requisition)
7660 *requisition = child_requisition.width + 2 * child->xpadding;
7662 children = children->next;
7665 sheet->column_requisition = *requisition;
7669 gtk_sheet_move_child (GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7671 GtkSheetChild *child;
7674 g_return_if_fail (sheet != NULL);
7675 g_return_if_fail (GTK_IS_SHEET (sheet));
7677 children = sheet->children;
7680 child = children->data;
7682 if (child->widget == widget)
7686 child->row = ROW_FROM_YPIXEL (sheet, y);
7687 child->col = COLUMN_FROM_XPIXEL (sheet, x);
7688 gtk_sheet_position_child (sheet, child);
7692 children = children->next;
7695 g_warning ("Widget must be a GtkSheet child");
7700 gtk_sheet_position_child (GtkSheet *sheet, GtkSheetChild *child)
7702 GtkRequisition child_requisition;
7703 GtkAllocation child_allocation;
7709 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7711 if (sheet->column_titles_visible)
7712 yoffset = sheet->column_title_area.height;
7714 if (sheet->row_titles_visible)
7715 xoffset = sheet->row_title_area.width;
7717 if (child->attached_to_cell)
7719 gtk_sheet_get_cell_area (sheet, child->row, child->col, &area);
7720 child->x = area.x + child->xpadding;
7721 child->y = area.y + child->ypadding;
7723 if (!child->floating)
7725 if (child_requisition.width + 2 * child->xpadding <= xxx_column_width (sheet, child->col))
7729 child_requisition.width = child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7735 child->x = area.x + xxx_column_width (sheet, child->col) / 2 -
7736 child_requisition.width / 2;
7738 child_allocation.width = child_requisition.width;
7743 if (!child->xshrink)
7745 gtk_sheet_set_column_width (sheet, child->col, child_requisition.width + 2 * child->xpadding);
7747 child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7750 if (child_requisition.height +
7751 2 * child->ypadding <= yyy_row_height (sheet, child->row))
7755 child_requisition.height = child_allocation.height =
7756 yyy_row_height (sheet, child->row) - 2 * child->ypadding;
7762 child->y = area.y + yyy_row_height (sheet, child->row) / 2
7763 - child_requisition.height / 2;
7765 child_allocation.height = child_requisition.height;
7770 if (!child->yshrink)
7772 gtk_sheet_set_row_height (sheet, child->row, child_requisition.height + 2 * child->ypadding);
7774 child_allocation.height = yyy_row_height (sheet, child->row) -
7775 2 * child->ypadding;
7780 child_allocation.width = child_requisition.width;
7781 child_allocation.height = child_requisition.height;
7784 x = child_allocation.x = child->x + xoffset;
7785 y = child_allocation.y = child->y + yoffset;
7789 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
7790 x = child_allocation.x = child->x + xoffset;
7791 y = child_allocation.y = child->y + sheet->voffset + yoffset;
7792 y = child_allocation.y = child->y + yoffset;
7793 child_allocation.width = child_requisition.width;
7794 child_allocation.height = child_requisition.height;
7797 gtk_widget_size_allocate (child->widget, &child_allocation);
7798 gtk_widget_queue_draw (child->widget);
7802 gtk_sheet_forall (GtkContainer *container,
7803 gboolean include_internals,
7804 GtkCallback callback,
7805 gpointer callback_data)
7808 GtkSheetChild *child;
7811 g_return_if_fail (GTK_IS_SHEET (container));
7812 g_return_if_fail (callback != NULL);
7814 sheet = GTK_SHEET (container);
7815 children = sheet->children;
7818 child = children->data;
7819 children = children->next;
7821 (* callback) (child->widget, callback_data);
7824 (* callback) (sheet->button, callback_data);
7825 if (sheet->sheet_entry)
7826 (* callback) (sheet->sheet_entry, callback_data);
7831 gtk_sheet_position_children (GtkSheet *sheet)
7834 GtkSheetChild *child;
7836 children = sheet->children;
7840 child = (GtkSheetChild *)children->data;
7842 if (child->col != -1 && child->row != -1)
7843 gtk_sheet_position_child (sheet, child);
7845 if (child->row == -1)
7847 if (child->col < MIN_VISIBLE_COLUMN (sheet) ||
7848 child->col > MAX_VISIBLE_COLUMN (sheet))
7849 gtk_sheet_child_hide (child);
7851 gtk_sheet_child_show (child);
7853 if (child->col == -1)
7855 if (child->row < MIN_VISIBLE_ROW (sheet) ||
7856 child->row > MAX_VISIBLE_ROW (sheet))
7857 gtk_sheet_child_hide (child);
7859 gtk_sheet_child_show (child);
7862 children = children->next;
7867 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7871 GtkSheetChild *child = 0;
7873 g_return_if_fail (container != NULL);
7874 g_return_if_fail (GTK_IS_SHEET (container));
7876 sheet = GTK_SHEET (container);
7878 children = sheet->children;
7882 child = (GtkSheetChild *)children->data;
7884 if (child->widget == widget) break;
7886 children = children->next;
7891 gtk_widget_unparent (widget);
7892 child->widget = NULL;
7894 sheet->children = g_list_remove_link (sheet->children, children);
7895 g_list_free_1 (children);
7902 gtk_sheet_realize_child (GtkSheet *sheet, GtkSheetChild *child)
7906 widget = GTK_WIDGET (sheet);
7908 if (GTK_WIDGET_REALIZED (widget))
7910 if (child->row == -1)
7911 gtk_widget_set_parent_window (child->widget, sheet->column_title_window);
7912 else if (child->col == -1)
7913 gtk_widget_set_parent_window (child->widget, sheet->row_title_window);
7915 gtk_widget_set_parent_window (child->widget, sheet->sheet_window);
7918 gtk_widget_set_parent (child->widget, widget);
7924 gtk_sheet_get_child_at (GtkSheet *sheet, gint row, gint col)
7927 GtkSheetChild *child = 0;
7929 g_return_val_if_fail (sheet != NULL, NULL);
7930 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7932 children = sheet->children;
7936 child = (GtkSheetChild *)children->data;
7938 if (child->attached_to_cell)
7939 if (child->row == row && child->col == col) break;
7941 children = children->next;
7944 if (children) return child;
7950 gtk_sheet_child_hide (GtkSheetChild *child)
7952 g_return_if_fail (child != NULL);
7953 gtk_widget_hide (child->widget);
7957 gtk_sheet_child_show (GtkSheetChild *child)
7959 g_return_if_fail (child != NULL);
7961 gtk_widget_show (child->widget);
7965 gtk_sheet_get_model (const GtkSheet *sheet)
7967 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7969 return sheet->model;
7974 gtk_sheet_button_new (void)
7976 GtkSheetButton *button = g_malloc (sizeof (GtkSheetButton));
7978 button->state = GTK_STATE_NORMAL;
7979 button->label = NULL;
7980 button->label_visible = TRUE;
7981 button->child = NULL;
7982 button->justification = GTK_JUSTIFY_FILL;
7989 gtk_sheet_button_free (GtkSheetButton *button)
7991 if (!button) return ;
7993 g_free (button->label);
7999 range_to_text (const GtkSheet *sheet)
8001 gchar *celltext = NULL;
8005 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
8008 string = g_string_sized_new (80);
8010 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
8012 for (c = sheet->range.col0; c < sheet->range.coli; ++c)
8014 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8015 g_string_append (string, celltext);
8016 g_string_append (string, "\t");
8019 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8020 g_string_append (string, celltext);
8021 if ( r < sheet->range.rowi)
8022 g_string_append (string, "\n");
8030 range_to_html (const GtkSheet *sheet)
8032 gchar *celltext = NULL;
8036 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
8039 string = g_string_sized_new (480);
8041 g_string_append (string, "<html>\n");
8042 g_string_append (string, "<body>\n");
8043 g_string_append (string, "<table>\n");
8044 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
8046 g_string_append (string, "<tr>\n");
8047 for (c = sheet->range.col0; c <= sheet->range.coli; ++c)
8049 g_string_append (string, "<td>");
8050 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8051 g_string_append (string, celltext);
8052 g_string_append (string, "</td>\n");
8055 g_string_append (string, "</tr>\n");
8057 g_string_append (string, "</table>\n");
8058 g_string_append (string, "</body>\n");
8059 g_string_append (string, "</html>\n");
8071 primary_get_cb (GtkClipboard *clipboard,
8072 GtkSelectionData *selection_data,
8076 GtkSheet *sheet = GTK_SHEET (data);
8077 GString *string = NULL;
8081 case SELECT_FMT_TEXT:
8082 string = range_to_text (sheet);
8084 case SELECT_FMT_HTML:
8085 string = range_to_html (sheet);
8088 g_assert_not_reached ();
8091 gtk_selection_data_set (selection_data, selection_data->target,
8093 (const guchar *) string->str, string->len);
8094 g_string_free (string, TRUE);
8098 primary_clear_cb (GtkClipboard *clipboard,
8101 GtkSheet *sheet = GTK_SHEET (data);
8102 gtk_sheet_real_unselect_range (sheet, NULL);
8106 gtk_sheet_update_primary_selection (GtkSheet *sheet)
8108 static const GtkTargetEntry targets[] = {
8109 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
8110 { "STRING", 0, SELECT_FMT_TEXT },
8111 { "TEXT", 0, SELECT_FMT_TEXT },
8112 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
8113 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
8114 { "text/plain", 0, SELECT_FMT_TEXT },
8115 { "text/html", 0, SELECT_FMT_HTML }
8118 GtkClipboard *clipboard;
8120 if (!GTK_WIDGET_REALIZED (sheet))
8123 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet),
8124 GDK_SELECTION_PRIMARY);
8126 if (gtk_sheet_range_isvisible (sheet, sheet->range))
8128 if (!gtk_clipboard_set_with_owner (clipboard, targets,
8129 G_N_ELEMENTS (targets),
8130 primary_get_cb, primary_clear_cb,
8132 primary_clear_cb (clipboard, sheet);
8136 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet))
8137 gtk_clipboard_clear (clipboard);