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));
140 guint val = pango_font_metrics_get_descent (metrics) +
141 pango_font_metrics_get_ascent (metrics);
143 pango_font_metrics_unref (metrics);
145 return PANGO_PIXELS (val) + 2 * CELLOFFSET;
150 guint DEFAULT_FONT_ASCENT (GtkWidget *widget)
152 if (!widget->style->font_desc) return 12;
155 PangoContext *context = gtk_widget_get_pango_context (widget);
156 PangoFontMetrics *metrics =
157 pango_context_get_metrics (context,
158 widget->style->font_desc,
159 pango_context_get_language (context));
160 guint val = pango_font_metrics_get_ascent (metrics);
161 pango_font_metrics_unref (metrics);
162 return PANGO_PIXELS (val);
167 guint STRING_WIDTH (GtkWidget *widget,
168 const PangoFontDescription *font, const gchar *text)
173 layout = gtk_widget_create_pango_layout (widget, text);
174 pango_layout_set_font_description (layout, font);
176 pango_layout_get_extents (layout, NULL, &rect);
178 g_object_unref (G_OBJECT (layout));
179 return PANGO_PIXELS (rect.width);
183 guint DEFAULT_FONT_DESCENT (GtkWidget *widget)
185 if (!widget->style->font_desc) return 12;
188 PangoContext *context = gtk_widget_get_pango_context (widget);
189 PangoFontMetrics *metrics =
190 pango_context_get_metrics (context,
191 widget->style->font_desc,
192 pango_context_get_language (context));
193 guint val = pango_font_metrics_get_descent (metrics);
194 pango_font_metrics_unref (metrics);
195 return PANGO_PIXELS (val);
201 yyy_row_is_visible (const GtkSheet *sheet, gint row)
203 GSheetRow *row_geo = sheet->row_geometry;
205 return g_sheet_row_get_visibility (row_geo, row, 0);
210 yyy_row_is_sensitive (const GtkSheet *sheet, gint row)
212 GSheetRow *row_geo = sheet->row_geometry;
214 return g_sheet_row_get_sensitivity (row_geo, row, 0);
220 yyy_row_count (const GtkSheet *sheet)
222 GSheetRow *row_geo = sheet->row_geometry;
224 return g_sheet_row_get_row_count (row_geo, 0);
228 yyy_row_height (const GtkSheet *sheet, gint row)
230 GSheetRow *row_geo = sheet->row_geometry;
232 return g_sheet_row_get_height (row_geo, row, 0);
236 yyy_row_top_ypixel (const GtkSheet *sheet, gint row)
238 GSheetRow *geo = sheet->row_geometry;
240 gint y = g_sheet_row_start_pixel (geo, row, 0);
242 if ( sheet->column_titles_visible )
243 y += sheet->column_title_area.height;
249 /* Return the row containing pixel Y */
251 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
253 GSheetRow *geo = sheet->row_geometry;
255 gint cy = sheet->voffset;
257 if (sheet->column_titles_visible)
258 cy += sheet->column_title_area.height;
260 if (y < cy) return 0;
262 return g_sheet_row_pixel_to_row (geo, y - cy, 0);
266 /* gives the top pixel of the given row in context of
267 * the sheet's voffset */
269 ROW_TOP_YPIXEL (const GtkSheet *sheet, gint row)
271 return (sheet->voffset + yyy_row_top_ypixel (sheet, row));
275 /* returns the row index from a y pixel location in the
276 * context of the sheet's voffset */
278 ROW_FROM_YPIXEL (const GtkSheet *sheet, gint y)
280 return (yyy_row_ypixel_to_row (sheet, y));
283 static inline GtkSheetButton *
284 xxx_column_button (const GtkSheet *sheet, gint col)
286 GSheetColumn *col_geo = sheet->column_geometry;
287 if ( col < 0 ) return NULL ;
289 return g_sheet_column_get_button (col_geo, col);
294 xxx_column_left_xpixel (const GtkSheet *sheet, gint col)
296 GSheetColumn *geo = sheet->column_geometry;
298 gint x = g_sheet_column_start_pixel (geo, col);
300 if ( sheet->row_titles_visible )
301 x += sheet->row_title_area.width;
307 xxx_column_width (const GtkSheet *sheet, gint col)
309 GSheetColumn *col_geo = sheet->column_geometry;
311 return g_sheet_column_get_width (col_geo, col);
316 xxx_set_column_width (GtkSheet *sheet, gint col, gint width)
318 if ( sheet->column_geometry )
319 g_sheet_column_set_width (sheet->column_geometry, col, width);
323 xxx_column_set_left_column (GtkSheet *sheet, gint col, gint i)
325 GSheetColumn *col_geo = sheet->column_geometry;
327 g_sheet_column_set_left_text_column (col_geo, col, i);
331 xxx_column_left_column (const GtkSheet *sheet, gint col)
333 GSheetColumn *col_geo = sheet->column_geometry;
335 return g_sheet_column_get_left_text_column (col_geo, col);
339 xxx_column_set_right_column (GtkSheet *sheet, gint col, gint i)
341 GSheetColumn *col_geo = sheet->column_geometry;
343 g_sheet_column_set_right_text_column (col_geo, col, i);
347 xxx_column_right_column (const GtkSheet *sheet, gint col)
349 GSheetColumn *col_geo = sheet->column_geometry;
351 return g_sheet_column_get_right_text_column (col_geo, col);
354 static inline GtkJustification
355 xxx_column_justification (const GtkSheet *sheet, gint col)
357 GSheetColumn *col_geo = sheet->column_geometry;
359 return g_sheet_column_get_justification (col_geo, col);
363 xxx_column_is_visible (const GtkSheet *sheet, gint col)
365 GSheetColumn *col_geo = sheet->column_geometry;
367 return g_sheet_column_get_visibility (col_geo, col);
372 xxx_column_is_sensitive (const GtkSheet *sheet, gint col)
374 GSheetColumn *col_geo = sheet->column_geometry;
376 return g_sheet_column_get_sensitivity (col_geo, col);
380 /* gives the left pixel of the given column in context of
381 * the sheet's hoffset */
383 COLUMN_LEFT_XPIXEL (const GtkSheet *sheet, gint ncol)
385 return (sheet->hoffset + xxx_column_left_xpixel (sheet, ncol));
389 xxx_column_count (const GtkSheet *sheet)
391 GSheetColumn *col_geo = sheet->column_geometry;
393 return g_sheet_column_get_column_count (col_geo);
396 /* returns the column index from a x pixel location in the
397 * context of the sheet's hoffset */
399 COLUMN_FROM_XPIXEL (const GtkSheet * sheet,
405 if ( sheet->row_titles_visible )
406 cx += sheet->row_title_area.width;
408 if (x < cx) return 0;
409 for (i = 0; i < xxx_column_count (sheet); i++)
411 if (x >= cx && x <= (cx + xxx_column_width (sheet, i)) &&
412 xxx_column_is_visible (sheet, i))
414 if ( xxx_column_is_visible (sheet, i))
415 cx += xxx_column_width (sheet, i);
419 return xxx_column_count (sheet) - 1;
422 /* returns the total height of the sheet */
423 static inline gint SHEET_HEIGHT (GtkSheet *sheet)
425 const gint n_rows = yyy_row_count (sheet);
427 return yyy_row_top_ypixel (sheet, n_rows - 1) +
428 yyy_row_height (sheet, n_rows - 1);
432 static inline GtkSheetButton *
433 yyy_row_button (GtkSheet *sheet, gint row)
435 GSheetRow *row_geo = sheet->row_geometry;
437 return g_sheet_row_get_button (row_geo, row, sheet);
444 yyy_set_row_height (GtkSheet *sheet, gint row, gint height)
446 if ( sheet->row_geometry )
447 g_sheet_row_set_height (sheet->row_geometry, row, height, sheet);
452 /* returns the total width of the sheet */
453 static inline gint SHEET_WIDTH (GtkSheet *sheet)
457 cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
459 for (i = 0; i < xxx_column_count (sheet); i++)
460 if (xxx_column_is_visible (sheet, i))
461 cx += xxx_column_width (sheet, i);
466 #define MIN_VISIBLE_ROW(sheet) \
467 ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + 1)
469 #define MAX_VISIBLE_ROW(sheet) \
470 ROW_FROM_YPIXEL (sheet, sheet->sheet_window_height - 1)
472 #define MIN_VISIBLE_COLUMN(sheet) \
473 COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + 1)
475 #define MAX_VISIBLE_COLUMN(sheet) \
476 COLUMN_FROM_XPIXEL (sheet, sheet->sheet_window_width)
480 static inline gboolean
481 POSSIBLE_XDRAG (const GtkSheet *sheet, gint x, gint *drag_column)
485 column = COLUMN_FROM_XPIXEL (sheet, x);
486 *drag_column = column;
488 xdrag = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
489 if (x <= xdrag + DRAG_WIDTH / 2 && column != 0)
491 while (! xxx_column_is_visible (sheet, column - 1) && column > 0) column--;
492 *drag_column = column - 1;
493 return xxx_column_is_sensitive (sheet, column - 1);
496 xdrag += xxx_column_width (sheet, column);
497 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
498 return xxx_column_is_sensitive (sheet, column);
503 static inline gboolean
504 POSSIBLE_YDRAG (const GtkSheet *sheet, gint y, gint *drag_row)
507 row = ROW_FROM_YPIXEL (sheet, y);
510 ydrag = ROW_TOP_YPIXEL (sheet, row)+CELL_SPACING;
511 if (y <= ydrag + DRAG_WIDTH / 2 && row != 0)
513 while (!yyy_row_is_visible (sheet, row - 1) && row > 0) row--;
515 return yyy_row_is_sensitive (sheet, row - 1);
518 ydrag +=yyy_row_height (sheet, row);
520 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
521 return yyy_row_is_sensitive (sheet, row);
527 static inline gboolean
528 POSSIBLE_DRAG (const GtkSheet *sheet, gint x, gint y,
529 gint *drag_row, gint *drag_column)
533 /* Can't drag if nothing is selected */
534 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
535 sheet->range.col0 < 0 || sheet->range.coli < 0 )
538 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
539 *drag_row = ROW_FROM_YPIXEL (sheet, y);
541 if (x >= COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0) - DRAG_WIDTH / 2 &&
542 x <= COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
543 xxx_column_width (sheet, sheet->range.coli) + DRAG_WIDTH / 2)
545 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.row0);
546 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
548 *drag_row = sheet->range.row0;
551 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
552 yyy_row_height (sheet, sheet->range.rowi);
553 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
555 *drag_row = sheet->range.rowi;
560 if (y >= ROW_TOP_YPIXEL (sheet, sheet->range.row0) - DRAG_WIDTH / 2 &&
561 y <= ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
562 yyy_row_height (sheet, sheet->range.rowi) + DRAG_WIDTH / 2)
564 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0);
565 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
567 *drag_column = sheet->range.col0;
570 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
571 xxx_column_width (sheet, sheet->range.coli);
572 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
574 *drag_column = sheet->range.coli;
582 static inline gboolean
583 POSSIBLE_RESIZE (const GtkSheet *sheet, gint x, gint y,
584 gint *drag_row, gint *drag_column)
588 /* Can't drag if nothing is selected */
589 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
590 sheet->range.col0 < 0 || sheet->range.coli < 0 )
593 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli)+
594 xxx_column_width (sheet, sheet->range.coli);
596 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi)+
597 yyy_row_height (sheet, sheet->range.rowi);
599 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
600 ydrag = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
602 if (sheet->state == GTK_SHEET_ROW_SELECTED)
603 xdrag = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
605 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
606 *drag_row = ROW_FROM_YPIXEL (sheet, y);
608 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
609 y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
614 static void gtk_sheet_class_init (GtkSheetClass * klass);
615 static void gtk_sheet_init (GtkSheet * sheet);
616 static void gtk_sheet_destroy (GtkObject * object);
617 static void gtk_sheet_finalize (GObject * object);
618 static void gtk_sheet_style_set (GtkWidget *widget,
619 GtkStyle *previous_style);
620 static void gtk_sheet_realize (GtkWidget * widget);
621 static void gtk_sheet_unrealize (GtkWidget * widget);
622 static void gtk_sheet_map (GtkWidget * widget);
623 static void gtk_sheet_unmap (GtkWidget * widget);
624 static gint gtk_sheet_expose (GtkWidget * widget,
625 GdkEventExpose * event);
626 static void gtk_sheet_forall (GtkContainer *container,
627 gboolean include_internals,
628 GtkCallback callback,
629 gpointer callback_data);
631 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
632 GtkAdjustment *hadjustment,
633 GtkAdjustment *vadjustment);
635 static gint gtk_sheet_button_press (GtkWidget * widget,
636 GdkEventButton * event);
637 static gint gtk_sheet_button_release (GtkWidget * widget,
638 GdkEventButton * event);
639 static gint gtk_sheet_motion (GtkWidget * widget,
640 GdkEventMotion * event);
641 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
643 static gint gtk_sheet_key_press (GtkWidget *widget,
645 static void gtk_sheet_size_request (GtkWidget * widget,
646 GtkRequisition * requisition);
647 static void gtk_sheet_size_allocate (GtkWidget * widget,
648 GtkAllocation * allocation);
652 static gboolean gtk_sheet_range_isvisible (const GtkSheet * sheet,
653 GtkSheetRange range);
654 static gboolean gtk_sheet_cell_isvisible (GtkSheet * sheet,
655 gint row, gint column);
656 /* Drawing Routines */
658 /* draw cell background and frame */
659 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
660 gint row, gint column);
662 /* draw cell contents */
663 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
664 gint row, gint column);
666 /* draw visible part of range. If range == NULL then draw the whole screen */
667 static void gtk_sheet_range_draw (GtkSheet *sheet,
668 const GtkSheetRange *range);
670 /* highlight the visible part of the selected range */
671 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
672 GtkSheetRange range);
676 static gboolean gtk_sheet_move_query (GtkSheet *sheet,
677 gint row, gint column);
678 static void gtk_sheet_real_select_range (GtkSheet * sheet,
679 const GtkSheetRange * range);
680 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
681 const GtkSheetRange * range);
682 static void gtk_sheet_extend_selection (GtkSheet *sheet,
683 gint row, gint column);
684 static void gtk_sheet_new_selection (GtkSheet *sheet,
685 GtkSheetRange *range);
686 static void gtk_sheet_draw_border (GtkSheet *sheet,
687 GtkSheetRange range);
688 static void gtk_sheet_draw_corners (GtkSheet *sheet,
689 GtkSheetRange range);
692 /* Active Cell handling */
694 static void gtk_sheet_entry_changed (GtkWidget *widget,
696 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
697 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
698 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
700 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
701 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
702 static void gtk_sheet_click_cell (GtkSheet *sheet,
709 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
710 guint width, guint height);
711 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
712 GtkSheetRange range);
715 static void adjust_scrollbars (GtkSheet * sheet);
716 static void vadjustment_value_changed (GtkAdjustment * adjustment,
718 static void hadjustment_value_changed (GtkAdjustment * adjustment,
722 static void draw_xor_vline (GtkSheet * sheet);
723 static void draw_xor_hline (GtkSheet * sheet);
724 static void draw_xor_rectangle (GtkSheet *sheet,
725 GtkSheetRange range);
727 static guint new_column_width (GtkSheet * sheet,
730 static guint new_row_height (GtkSheet * sheet,
735 static void create_global_button (GtkSheet *sheet);
736 static void global_button_clicked (GtkWidget *widget,
740 static void create_sheet_entry (GtkSheet *sheet);
741 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
742 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
744 /* Sheet button gadgets */
746 static void size_allocate_column_title_buttons (GtkSheet * sheet);
747 static void size_allocate_row_title_buttons (GtkSheet * sheet);
750 static void size_allocate_global_button (GtkSheet *sheet);
751 static void gtk_sheet_button_size_request (GtkSheet *sheet,
752 const GtkSheetButton *button,
753 GtkRequisition *requisition);
755 /* Attributes routines */
756 static void init_attributes (const GtkSheet *sheet, gint col,
757 GtkSheetCellAttr *attributes);
760 /* Memory allocation routines */
761 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
762 const GtkSheetRange *range);
764 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
769 /* Container Functions */
770 static void gtk_sheet_remove (GtkContainer *container,
772 static void gtk_sheet_realize_child (GtkSheet *sheet,
773 GtkSheetChild *child);
774 static void gtk_sheet_position_child (GtkSheet *sheet,
775 GtkSheetChild *child);
776 static void gtk_sheet_position_children (GtkSheet *sheet);
777 static void gtk_sheet_child_show (GtkSheetChild *child);
778 static void gtk_sheet_child_hide (GtkSheetChild *child);
779 static void gtk_sheet_column_size_request (GtkSheet *sheet,
782 static void gtk_sheet_row_size_request (GtkSheet *sheet,
790 _gtkextra_signal_emit (GtkObject *object, guint signal_id, ...);
814 static GtkContainerClass *parent_class = NULL;
815 static guint sheet_signals[LAST_SIGNAL] = { 0 };
819 gtk_sheet_get_type ()
821 static GType sheet_type = 0;
825 static const GTypeInfo sheet_info =
827 sizeof (GtkSheetClass),
830 (GClassInitFunc) gtk_sheet_class_init,
835 (GInstanceInitFunc) gtk_sheet_init,
839 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
845 static GtkSheetRange*
846 gtk_sheet_range_copy (const GtkSheetRange *range)
848 GtkSheetRange *new_range;
850 g_return_val_if_fail (range != NULL, NULL);
852 new_range = g_new (GtkSheetRange, 1);
860 gtk_sheet_range_free (GtkSheetRange *range)
862 g_return_if_fail (range != NULL);
868 gtk_sheet_range_get_type (void)
870 static GType sheet_range_type = 0;
872 if (!sheet_range_type)
875 g_boxed_type_register_static ("GtkSheetRange",
876 (GBoxedCopyFunc) gtk_sheet_range_copy,
877 (GBoxedFreeFunc) gtk_sheet_range_free);
880 return sheet_range_type;
884 gtk_sheet_class_init (GtkSheetClass * klass)
886 GtkObjectClass *object_class;
887 GtkWidgetClass *widget_class;
888 GtkContainerClass *container_class;
889 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
891 object_class = (GtkObjectClass *) klass;
892 widget_class = (GtkWidgetClass *) klass;
893 container_class = (GtkContainerClass *) klass;
895 parent_class = g_type_class_peek_parent (klass);
898 * GtkSheet::select-row
899 * @sheet: the sheet widget that emitted the signal
900 * @row: the newly selected row index
902 * A row has been selected.
904 sheet_signals[SELECT_ROW] =
905 g_signal_new ("select-row",
906 G_TYPE_FROM_CLASS (object_class),
908 offsetof (GtkSheetClass, select_row),
917 * GtkSheet::select - column
918 * @sheet: the sheet widget that emitted the signal
919 * @column: the newly selected column index
921 * A column has been selected.
923 sheet_signals[SELECT_COLUMN] =
924 g_signal_new ("select-column",
925 G_TYPE_FROM_CLASS (object_class),
927 offsetof (GtkSheetClass, select_column),
936 * GtkSheet::double-click-row
937 * @sheet: the sheet widget that emitted the signal
938 * @row: the row that was double clicked.
940 * A row's title button has been double clicked
942 sheet_signals[DOUBLE_CLICK_ROW] =
943 g_signal_new ("double-click-row",
944 G_TYPE_FROM_CLASS (object_class),
955 * GtkSheet::double-click-column
956 * @sheet: the sheet widget that emitted the signal
957 * @column: the column that was double clicked.
959 * A column's title button has been double clicked
961 sheet_signals[DOUBLE_CLICK_COLUMN] =
962 g_signal_new ("double-click-column",
963 G_TYPE_FROM_CLASS (object_class),
974 * GtkSheet::button-event-column
975 * @sheet: the sheet widget that emitted the signal
976 * @column: the column on which the event occured.
978 * A button event occured on a column title button
980 sheet_signals[BUTTON_EVENT_COLUMN] =
981 g_signal_new ("button-event-column",
982 G_TYPE_FROM_CLASS (object_class),
986 gtkextra_VOID__INT_POINTER,
995 * GtkSheet::button-event-row
996 * @sheet: the sheet widget that emitted the signal
997 * @column: the column on which the event occured.
999 * A button event occured on a row title button
1001 sheet_signals[BUTTON_EVENT_ROW] =
1002 g_signal_new ("button-event-row",
1003 G_TYPE_FROM_CLASS (object_class),
1007 gtkextra_VOID__INT_POINTER,
1015 sheet_signals[SELECT_RANGE] =
1016 g_signal_new ("select-range",
1017 G_TYPE_FROM_CLASS (object_class),
1019 offsetof (GtkSheetClass, select_range),
1021 gtkextra_VOID__BOXED,
1024 GTK_TYPE_SHEET_RANGE);
1027 sheet_signals[RESIZE_RANGE] =
1028 g_signal_new ("resize-range",
1029 G_TYPE_FROM_CLASS (object_class),
1031 offsetof (GtkSheetClass, resize_range),
1033 gtkextra_VOID__BOXED_BOXED,
1036 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1039 sheet_signals[MOVE_RANGE] =
1040 g_signal_new ("move-range",
1041 G_TYPE_FROM_CLASS (object_class),
1043 offsetof (GtkSheetClass, move_range),
1045 gtkextra_VOID__BOXED_BOXED,
1048 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1051 sheet_signals[TRAVERSE] =
1052 g_signal_new ("traverse",
1053 G_TYPE_FROM_CLASS (object_class),
1055 offsetof (GtkSheetClass, traverse),
1057 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
1058 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT,
1059 G_TYPE_POINTER, G_TYPE_POINTER);
1062 sheet_signals[DEACTIVATE] =
1063 g_signal_new ("deactivate",
1064 G_TYPE_FROM_CLASS (object_class),
1066 offsetof (GtkSheetClass, deactivate),
1068 gtkextra_BOOLEAN__INT_INT,
1069 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1071 sheet_signals[ACTIVATE] =
1072 g_signal_new ("activate",
1073 G_TYPE_FROM_CLASS (object_class),
1075 offsetof (GtkSheetClass, activate),
1077 gtkextra_BOOLEAN__INT_INT,
1078 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1080 sheet_signals[SET_CELL] =
1081 g_signal_new ("set-cell",
1082 G_TYPE_FROM_CLASS (object_class),
1084 offsetof (GtkSheetClass, set_cell),
1086 gtkextra_VOID__INT_INT,
1087 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1090 sheet_signals[CLEAR_CELL] =
1091 g_signal_new ("clear-cell",
1092 G_TYPE_FROM_CLASS (object_class),
1094 offsetof (GtkSheetClass, clear_cell),
1096 gtkextra_VOID__INT_INT,
1097 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1099 sheet_signals[CHANGED] =
1100 g_signal_new ("changed",
1101 G_TYPE_FROM_CLASS (object_class),
1103 offsetof (GtkSheetClass, changed),
1105 gtkextra_VOID__INT_INT,
1106 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1108 sheet_signals[NEW_COL_WIDTH] =
1109 g_signal_new ("new-column-width",
1110 G_TYPE_FROM_CLASS (object_class),
1112 offsetof (GtkSheetClass, new_column_width), /*!!!! */
1114 gtkextra_VOID__INT_INT,
1115 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1117 sheet_signals[NEW_ROW_HEIGHT] =
1118 g_signal_new ("new-row-height",
1119 G_TYPE_FROM_CLASS (object_class),
1121 offsetof (GtkSheetClass, new_row_height), /*!!!! */
1123 gtkextra_VOID__INT_INT,
1124 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1126 widget_class->set_scroll_adjustments_signal =
1127 g_signal_new ("set-scroll-adjustments",
1128 G_TYPE_FROM_CLASS (object_class),
1130 offsetof (GtkSheetClass, set_scroll_adjustments),
1132 gtkextra_VOID__OBJECT_OBJECT,
1133 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1136 container_class->add = NULL;
1137 container_class->remove = gtk_sheet_remove;
1138 container_class->forall = gtk_sheet_forall;
1140 object_class->destroy = gtk_sheet_destroy;
1141 gobject_class->finalize = gtk_sheet_finalize;
1143 widget_class->realize = gtk_sheet_realize;
1144 widget_class->unrealize = gtk_sheet_unrealize;
1145 widget_class->map = gtk_sheet_map;
1146 widget_class->unmap = gtk_sheet_unmap;
1147 widget_class->style_set = gtk_sheet_style_set;
1148 widget_class->button_press_event = gtk_sheet_button_press;
1149 widget_class->button_release_event = gtk_sheet_button_release;
1150 widget_class->motion_notify_event = gtk_sheet_motion;
1151 widget_class->key_press_event = gtk_sheet_key_press;
1152 widget_class->expose_event = gtk_sheet_expose;
1153 widget_class->size_request = gtk_sheet_size_request;
1154 widget_class->size_allocate = gtk_sheet_size_allocate;
1155 widget_class->focus_in_event = NULL;
1156 widget_class->focus_out_event = NULL;
1158 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1159 klass->select_row = NULL;
1160 klass->select_column = NULL;
1161 klass->select_range = NULL;
1162 klass->resize_range = NULL;
1163 klass->move_range = NULL;
1164 klass->traverse = NULL;
1165 klass->deactivate = NULL;
1166 klass->activate = NULL;
1167 klass->set_cell = NULL;
1168 klass->clear_cell = NULL;
1169 klass->changed = NULL;
1173 gtk_sheet_init (GtkSheet *sheet)
1175 sheet->column_geometry = NULL;
1176 sheet->row_geometry = NULL;
1178 sheet->children = NULL;
1181 sheet->selection_mode = GTK_SELECTION_NONE;
1182 sheet->freeze_count = 0;
1183 sheet->state = GTK_SHEET_NORMAL;
1185 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1186 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1188 sheet->column_title_window = NULL;
1189 sheet->column_title_area.x = 0;
1190 sheet->column_title_area.y = 0;
1191 sheet->column_title_area.width = 0;
1192 sheet->column_title_area.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
1194 sheet->row_title_window = NULL;
1195 sheet->row_title_area.x = 0;
1196 sheet->row_title_area.y = 0;
1197 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1198 sheet->row_title_area.height = 0;
1201 sheet->active_cell.row = 0;
1202 sheet->active_cell.col = 0;
1203 sheet->selection_cell.row = 0;
1204 sheet->selection_cell.col = 0;
1206 sheet->sheet_entry = NULL;
1207 sheet->pixmap = NULL;
1209 sheet->range.row0 = 0;
1210 sheet->range.rowi = 0;
1211 sheet->range.col0 = 0;
1212 sheet->range.coli = 0;
1214 sheet->state = GTK_SHEET_NORMAL;
1216 sheet->sheet_window = NULL;
1217 sheet->sheet_window_width = 0;
1218 sheet->sheet_window_height = 0;
1219 sheet->sheet_entry = NULL;
1220 sheet->button = NULL;
1225 sheet->hadjustment = NULL;
1226 sheet->vadjustment = NULL;
1228 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
1229 sheet->xor_gc = NULL;
1230 sheet->fg_gc = NULL;
1231 sheet->bg_gc = NULL;
1235 gdk_color_parse ("white", &sheet->bg_color);
1236 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1237 gdk_color_parse ("gray", &sheet->grid_color);
1238 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1239 sheet->show_grid = TRUE;
1241 sheet->motion_timer = 0;
1245 /* Callback which occurs whenever columns are inserted / deleted in the model */
1247 columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
1252 GtkSheet *sheet = GTK_SHEET (data);
1254 GtkSheetRange range;
1255 gint model_columns = g_sheet_model_get_column_count (model);
1258 /* Need to update all the columns starting from the first column and onwards.
1259 * Previous column are unchanged, so don't need to be updated.
1261 range.col0 = first_column;
1263 range.coli = xxx_column_count (sheet) - 1;
1264 range.rowi = yyy_row_count (sheet) - 1;
1266 adjust_scrollbars (sheet);
1268 if (sheet->active_cell.col >= model_columns)
1269 gtk_sheet_activate_cell (sheet, sheet->active_cell.row, model_columns - 1);
1271 for (i = first_column; i <= MAX_VISIBLE_COLUMN (sheet); i++)
1272 gtk_sheet_column_title_button_draw (sheet, i);
1274 gtk_sheet_range_draw (sheet, &range);
1278 /* Callback which occurs whenever rows are inserted / deleted in the model */
1280 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
1281 gint n_rows, gpointer data)
1284 GtkSheet *sheet = GTK_SHEET (data);
1286 GtkSheetRange range;
1288 gint model_rows = g_sheet_model_get_row_count (model);
1290 /* Need to update all the rows starting from the first row and onwards.
1291 * Previous rows are unchanged, so don't need to be updated.
1293 range.row0 = first_row;
1295 range.rowi = yyy_row_count (sheet) - 1;
1296 range.coli = xxx_column_count (sheet) - 1;
1298 adjust_scrollbars (sheet);
1300 if (sheet->active_cell.row >= model_rows)
1301 gtk_sheet_activate_cell (sheet, model_rows - 1, sheet->active_cell.col);
1303 for (i = first_row; i <= MAX_VISIBLE_ROW (sheet); i++)
1304 gtk_sheet_row_title_button_draw (sheet, i);
1306 gtk_sheet_range_draw (sheet, &range);
1310 If row0 or rowi are negative, then all rows will be updated.
1311 If col0 or coli are negative, then all columns will be updated.
1314 range_update_callback (GSheetModel *m, gint row0, gint col0,
1315 gint rowi, gint coli, gpointer data)
1317 GtkSheet *sheet = GTK_SHEET (data);
1319 GtkSheetRange range;
1326 if ( MAX_VISIBLE_ROW (sheet) >
1327 g_sheet_model_get_row_count (sheet->model)
1329 MAX_VISIBLE_COLUMN (sheet) >
1330 g_sheet_model_get_column_count (sheet->model))
1332 gtk_sheet_move_query (sheet, 0, 0);
1335 if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1338 gtk_sheet_range_draw (sheet, NULL);
1339 adjust_scrollbars (sheet);
1341 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
1342 gtk_sheet_row_title_button_draw (sheet, i);
1344 for (i = MIN_VISIBLE_COLUMN (sheet);
1345 i <= MAX_VISIBLE_COLUMN (sheet); i++)
1346 gtk_sheet_column_title_button_draw (sheet, i);
1350 else if ( row0 < 0 || rowi < 0 )
1352 range.row0 = MIN_VISIBLE_ROW (sheet);
1353 range.rowi = MAX_VISIBLE_ROW (sheet);
1355 else if ( col0 < 0 || coli < 0 )
1357 range.col0 = MIN_VISIBLE_COLUMN (sheet);
1358 range.coli = MAX_VISIBLE_COLUMN (sheet);
1361 gtk_sheet_range_draw (sheet, &range);
1365 static void gtk_sheet_construct (GtkSheet *sheet,
1368 const gchar *title);
1373 * @rows: initial number of rows
1374 * @columns: initial number of columns
1375 * @title: sheet title
1376 * @model: the model to use for the sheet data
1378 * Creates a new sheet widget with the given number of rows and columns.
1380 * Returns: the new sheet widget
1383 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1386 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1388 gtk_sheet_construct (GTK_SHEET (widget), vgeo, hgeo, title);
1391 gtk_sheet_set_model (GTK_SHEET (widget), model);
1399 * gtk_sheet_set_model
1400 * @sheet: the sheet to set the model for
1401 * @model: the model to use for the sheet data
1403 * Sets the model for a GtkSheet
1407 gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
1409 g_return_if_fail (GTK_IS_SHEET (sheet));
1410 g_return_if_fail (G_IS_SHEET_MODEL (model));
1412 sheet->model = model;
1414 g_signal_connect (model, "range_changed",
1415 G_CALLBACK (range_update_callback), sheet);
1417 g_signal_connect (model, "rows_inserted",
1418 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1420 g_signal_connect (model, "rows_deleted",
1421 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1423 g_signal_connect (model, "columns_inserted",
1424 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1426 g_signal_connect (model, "columns_deleted",
1427 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1432 /* Call back for when the column titles have changed.
1433 FIRST is the first column changed.
1434 N_COLUMNS is the number of columns which have changed, or - 1, which
1435 indicates that the column has changed to its right - most extremity
1438 column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
1440 GtkSheet *sheet = GTK_SHEET (data);
1441 gboolean extremity = FALSE;
1443 if ( n_columns == -1 )
1446 n_columns = xxx_column_count (sheet) - 1 ;
1449 if (!GTK_SHEET_IS_FROZEN (sheet))
1452 for ( i = first ; i <= first + n_columns ; ++i )
1454 gtk_sheet_column_title_button_draw (sheet, i);
1455 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, i);
1460 gtk_sheet_column_title_button_draw (sheet, -1);
1465 gtk_sheet_construct (GtkSheet *sheet,
1470 g_return_if_fail (G_IS_SHEET_COLUMN (hgeo));
1471 g_return_if_fail (G_IS_SHEET_ROW (vgeo));
1473 sheet->column_geometry = hgeo;
1474 sheet->row_geometry = vgeo;
1477 sheet->columns_resizable = TRUE;
1478 sheet->rows_resizable = TRUE;
1480 sheet->row_titles_visible = TRUE;
1481 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1483 sheet->column_titles_visible = TRUE;
1484 sheet->autoscroll = TRUE;
1485 sheet->justify_entry = TRUE;
1488 /* create sheet entry */
1489 sheet->entry_type = 0;
1490 create_sheet_entry (sheet);
1492 /* create global selection button */
1493 create_global_button (sheet);
1496 sheet->name = g_strdup (title);
1498 g_signal_connect (sheet->column_geometry, "columns_changed",
1499 G_CALLBACK (column_titles_changed), sheet);
1505 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns,
1506 const gchar *title, GtkType entry_type)
1508 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1510 gtk_sheet_construct_with_custom_entry (GTK_SHEET (widget),
1511 rows, columns, title, entry_type);
1517 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1523 gtk_sheet_construct (sheet, vgeo, hgeo, title);
1525 sheet->entry_type = entry_type;
1526 create_sheet_entry (sheet);
1532 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
1536 g_return_if_fail (sheet != NULL);
1537 g_return_if_fail (GTK_IS_SHEET (sheet));
1539 state = sheet->state;
1541 if (sheet->state == GTK_SHEET_NORMAL)
1542 gtk_sheet_hide_active_cell (sheet);
1544 sheet->entry_type = entry_type;
1546 create_sheet_entry (sheet);
1548 if (state == GTK_SHEET_NORMAL)
1550 gtk_sheet_show_active_cell (sheet);
1551 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
1553 G_CALLBACK (gtk_sheet_entry_changed),
1559 gtk_sheet_show_grid (GtkSheet *sheet, gboolean show)
1561 g_return_if_fail (sheet != NULL);
1562 g_return_if_fail (GTK_IS_SHEET (sheet));
1564 if (show == sheet->show_grid) return;
1566 sheet->show_grid = show;
1568 if (!GTK_SHEET_IS_FROZEN (sheet))
1569 gtk_sheet_range_draw (sheet, NULL);
1573 gtk_sheet_grid_visible (GtkSheet *sheet)
1575 g_return_val_if_fail (sheet != NULL, 0);
1576 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1578 return sheet->show_grid;
1582 gtk_sheet_set_background (GtkSheet *sheet, GdkColor *color)
1584 g_return_if_fail (sheet != NULL);
1585 g_return_if_fail (GTK_IS_SHEET (sheet));
1589 gdk_color_parse ("white", &sheet->bg_color);
1590 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1593 sheet->bg_color = *color;
1595 if (!GTK_SHEET_IS_FROZEN (sheet))
1596 gtk_sheet_range_draw (sheet, NULL);
1600 gtk_sheet_set_grid (GtkSheet *sheet, GdkColor *color)
1602 g_return_if_fail (sheet != NULL);
1603 g_return_if_fail (GTK_IS_SHEET (sheet));
1607 gdk_color_parse ("black", &sheet->grid_color);
1608 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1611 sheet->grid_color = *color;
1613 if (!GTK_SHEET_IS_FROZEN (sheet))
1614 gtk_sheet_range_draw (sheet, NULL);
1618 gtk_sheet_get_columns_count (GtkSheet *sheet)
1620 g_return_val_if_fail (sheet != NULL, 0);
1621 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1623 return xxx_column_count (sheet);
1627 gtk_sheet_get_rows_count (GtkSheet *sheet)
1629 g_return_val_if_fail (sheet != NULL, 0);
1630 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1632 return yyy_row_count (sheet);
1636 gtk_sheet_get_state (GtkSheet *sheet)
1638 g_return_val_if_fail (sheet != NULL, 0);
1639 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1641 return (sheet->state);
1645 gtk_sheet_set_selection_mode (GtkSheet *sheet, gint mode)
1647 g_return_if_fail (sheet != NULL);
1648 g_return_if_fail (GTK_IS_SHEET (sheet));
1650 if (GTK_WIDGET_REALIZED (sheet))
1651 gtk_sheet_real_unselect_range (sheet, NULL);
1653 sheet->selection_mode = mode;
1657 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1659 g_return_if_fail (sheet != NULL);
1660 g_return_if_fail (GTK_IS_SHEET (sheet));
1662 sheet->autoresize = autoresize;
1666 gtk_sheet_autoresize (GtkSheet *sheet)
1668 g_return_val_if_fail (sheet != NULL, FALSE);
1669 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1671 return sheet->autoresize;
1675 gtk_sheet_set_column_width (GtkSheet * sheet,
1681 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1683 gint text_width = 0;
1686 g_return_if_fail (sheet != NULL);
1687 g_return_if_fail (GTK_IS_SHEET (sheet));
1688 if (column >= xxx_column_count (sheet) || column < 0) return;
1690 for (row = 0; row < yyy_row_count (sheet); row++)
1692 gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
1693 if (text && strlen (text) > 0)
1695 GtkSheetCellAttr attributes;
1697 gtk_sheet_get_attributes (sheet, row, column, &attributes);
1698 if (attributes.is_visible)
1700 gint width = STRING_WIDTH (GTK_WIDGET (sheet),
1701 attributes.font_desc,
1703 + 2 * CELLOFFSET + attributes.border.width;
1704 text_width = MAX (text_width, width);
1707 dispose_string (sheet, text);
1710 if (text_width > xxx_column_width (sheet, column) )
1712 gtk_sheet_set_column_width (sheet, column, text_width);
1713 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
1719 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1721 g_return_if_fail (sheet != NULL);
1722 g_return_if_fail (GTK_IS_SHEET (sheet));
1724 sheet->autoscroll = autoscroll;
1728 gtk_sheet_autoscroll (GtkSheet *sheet)
1730 g_return_val_if_fail (sheet != NULL, FALSE);
1731 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1733 return sheet->autoscroll;
1738 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1740 g_return_if_fail (sheet != NULL);
1741 g_return_if_fail (GTK_IS_SHEET (sheet));
1743 sheet->justify_entry = justify;
1747 gtk_sheet_justify_entry (GtkSheet *sheet)
1749 g_return_val_if_fail (sheet != NULL, FALSE);
1750 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1752 return sheet->justify_entry;
1756 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1758 g_return_if_fail (sheet != NULL);
1759 g_return_if_fail (GTK_IS_SHEET (sheet));
1763 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_LOCKED);
1764 gtk_widget_hide (sheet->sheet_entry);
1765 gtk_widget_unmap (sheet->sheet_entry);
1769 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_LOCKED);
1770 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)))
1772 gtk_widget_show (sheet->sheet_entry);
1773 gtk_widget_map (sheet->sheet_entry);
1777 gtk_editable_set_editable (GTK_EDITABLE (sheet->sheet_entry), locked);
1782 gtk_sheet_locked (const GtkSheet *sheet)
1784 g_return_val_if_fail (sheet != NULL, FALSE);
1785 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1787 return GTK_SHEET_IS_LOCKED (sheet);
1790 /* This routine has problems with gtk+- 1.2 related with the
1791 label / button drawing - I think it's a bug in gtk+- 1.2 */
1793 gtk_sheet_set_title (GtkSheet *sheet, const gchar *title)
1797 g_return_if_fail (sheet != NULL);
1798 g_return_if_fail (title != NULL);
1799 g_return_if_fail (GTK_IS_SHEET (sheet));
1802 g_free (sheet->name);
1804 sheet->name = g_strdup (title);
1806 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) || !title) return;
1808 if (GTK_BIN (sheet->button)->child)
1809 label = GTK_BIN (sheet->button)->child;
1811 size_allocate_global_button (sheet);
1815 gtk_sheet_freeze (GtkSheet *sheet)
1817 g_return_if_fail (sheet != NULL);
1818 g_return_if_fail (GTK_IS_SHEET (sheet));
1820 sheet->freeze_count++;
1821 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1825 gtk_sheet_thaw (GtkSheet *sheet)
1827 g_return_if_fail (sheet != NULL);
1828 g_return_if_fail (GTK_IS_SHEET (sheet));
1830 if (sheet->freeze_count == 0) return;
1832 sheet->freeze_count--;
1833 if (sheet->freeze_count > 0) return;
1835 adjust_scrollbars (sheet);
1837 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1839 sheet->old_vadjustment = -1.;
1840 sheet->old_hadjustment = -1.;
1842 if (sheet->hadjustment)
1843 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1845 if (sheet->vadjustment)
1846 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1849 if (sheet->state == GTK_STATE_NORMAL)
1850 if (sheet->sheet_entry && GTK_WIDGET_MAPPED (sheet->sheet_entry))
1852 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
1853 sheet->active_cell.col);
1859 gtk_sheet_set_row_titles_width (GtkSheet *sheet, guint width)
1861 if (width < COLUMN_MIN_WIDTH) return;
1863 sheet->row_title_area.width = width;
1865 adjust_scrollbars (sheet);
1867 sheet->old_hadjustment = -1.;
1868 if (sheet->hadjustment)
1869 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1871 size_allocate_global_button (sheet);
1875 gtk_sheet_set_column_titles_height (GtkSheet *sheet, guint height)
1877 if (height < DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))) return;
1879 sheet->column_title_area.height = height;
1881 adjust_scrollbars (sheet);
1883 sheet->old_vadjustment = -1.;
1884 if (sheet->vadjustment)
1885 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1887 size_allocate_global_button (sheet);
1891 gtk_sheet_show_column_titles (GtkSheet *sheet)
1895 if (sheet->column_titles_visible) return;
1897 sheet->column_titles_visible = TRUE;
1900 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1902 gdk_window_show (sheet->column_title_window);
1903 gdk_window_move_resize (sheet->column_title_window,
1904 sheet->column_title_area.x,
1905 sheet->column_title_area.y,
1906 sheet->column_title_area.width,
1907 sheet->column_title_area.height);
1909 for (col = MIN_VISIBLE_COLUMN (sheet);
1910 col <= MAX_VISIBLE_COLUMN (sheet);
1913 GtkSheetButton *button = xxx_column_button (sheet, col);
1914 GtkSheetChild *child = button->child;
1916 gtk_sheet_child_show (child);
1917 gtk_sheet_button_free (button);
1919 adjust_scrollbars (sheet);
1922 sheet->old_vadjustment = -1.;
1923 if (sheet->vadjustment)
1924 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1926 size_allocate_global_button (sheet);
1931 gtk_sheet_show_row_titles (GtkSheet *sheet)
1935 if (sheet->row_titles_visible) return;
1937 sheet->row_titles_visible = TRUE;
1940 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1942 gdk_window_show (sheet->row_title_window);
1943 gdk_window_move_resize (sheet->row_title_window,
1944 sheet->row_title_area.x,
1945 sheet->row_title_area.y,
1946 sheet->row_title_area.width,
1947 sheet->row_title_area.height);
1949 for (row = MIN_VISIBLE_ROW (sheet);
1950 row <= MAX_VISIBLE_ROW (sheet);
1953 const GtkSheetButton *button = yyy_row_button (sheet, row);
1954 GtkSheetChild *child = button->child;
1958 gtk_sheet_child_show (child);
1961 adjust_scrollbars (sheet);
1964 sheet->old_hadjustment = -1.;
1965 if (sheet->hadjustment)
1966 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1968 size_allocate_global_button (sheet);
1972 gtk_sheet_hide_column_titles (GtkSheet *sheet)
1976 if (!sheet->column_titles_visible) return;
1978 sheet->column_titles_visible = FALSE;
1980 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1982 if (sheet->column_title_window)
1983 gdk_window_hide (sheet->column_title_window);
1984 if (GTK_WIDGET_VISIBLE (sheet->button))
1985 gtk_widget_hide (sheet->button);
1987 for (col = MIN_VISIBLE_COLUMN (sheet);
1988 col <= MAX_VISIBLE_COLUMN (sheet);
1991 GtkSheetButton *button = xxx_column_button (sheet, col);
1992 GtkSheetChild *child = button->child;
1994 gtk_sheet_child_hide (child);
1995 gtk_sheet_button_free (button);
1997 adjust_scrollbars (sheet);
2000 sheet->old_vadjustment = -1.;
2001 if (sheet->vadjustment)
2002 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2007 gtk_sheet_hide_row_titles (GtkSheet *sheet)
2011 if (!sheet->row_titles_visible) return;
2013 sheet->row_titles_visible = FALSE;
2016 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
2018 if (sheet->row_title_window)
2019 gdk_window_hide (sheet->row_title_window);
2020 if (GTK_WIDGET_VISIBLE (sheet->button))
2021 gtk_widget_hide (sheet->button);
2022 for (row = MIN_VISIBLE_ROW (sheet);
2023 row <= MAX_VISIBLE_ROW (sheet);
2026 const GtkSheetButton *button = yyy_row_button (sheet, row);
2027 GtkSheetChild *child = button->child;
2030 gtk_sheet_child_hide (child);
2032 adjust_scrollbars (sheet);
2035 sheet->old_hadjustment = -1.;
2036 if (sheet->hadjustment)
2037 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2042 gtk_sheet_column_titles_visible (GtkSheet *sheet)
2044 g_return_val_if_fail (sheet != NULL, FALSE);
2045 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2046 return sheet->column_titles_visible;
2050 gtk_sheet_row_titles_visible (GtkSheet *sheet)
2052 g_return_val_if_fail (sheet != NULL, FALSE);
2053 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2054 return sheet->row_titles_visible;
2058 gtk_sheet_moveto (GtkSheet *sheet,
2065 guint width, height;
2067 gint min_row, min_col;
2069 g_return_if_fail (sheet != NULL);
2070 g_return_if_fail (GTK_IS_SHEET (sheet));
2071 g_return_if_fail (sheet->hadjustment != NULL);
2072 g_return_if_fail (sheet->vadjustment != NULL);
2074 if (row < 0 || row >= yyy_row_count (sheet))
2076 if (column < 0 || column >= xxx_column_count (sheet))
2079 height = sheet->sheet_window_height;
2080 width = sheet->sheet_window_width;
2082 /* adjust vertical scrollbar */
2083 if (row >= 0 && row_align >= 0.)
2085 y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
2086 - (gint) ( row_align*height + (1. - row_align)
2087 * yyy_row_height (sheet, row));
2089 /* This forces the sheet to scroll when you don't see the entire cell */
2092 if (row_align == 1.)
2094 while (min_row >= 0 && min_row > MIN_VISIBLE_ROW (sheet))
2096 if (yyy_row_is_visible (sheet, min_row))
2097 adjust += yyy_row_height (sheet, min_row);
2098 if (adjust >= height)
2104 min_row = MAX (min_row, 0);
2105 y = ROW_TOP_YPIXEL (sheet, min_row) - sheet->voffset +
2106 yyy_row_height (sheet, min_row) - 1;
2110 sheet->vadjustment->value = 0.0;
2112 sheet->vadjustment->value = y;
2114 sheet->old_vadjustment = -1.;
2115 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2120 /* adjust horizontal scrollbar */
2121 if (column >= 0 && col_align >= 0.)
2123 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2124 - (gint) ( col_align*width + (1.- col_align)*
2125 xxx_column_width (sheet, column));
2128 /* This forces the sheet to scroll when you don't see the entire cell */
2131 if (col_align == 1.)
2133 while (min_col >= 0 && min_col > MIN_VISIBLE_COLUMN (sheet))
2135 if (xxx_column_is_visible (sheet, min_col))
2136 adjust += xxx_column_width (sheet, min_col);
2138 if (adjust >= width)
2144 min_col = MAX (min_col, 0);
2145 x = COLUMN_LEFT_XPIXEL (sheet, min_col) - sheet->hoffset +
2146 xxx_column_width (sheet, min_col) - 1;
2150 sheet->hadjustment->value = 0.0;
2152 sheet->hadjustment->value = x;
2154 sheet->old_vadjustment = -1.;
2155 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2163 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2165 g_return_if_fail (sheet != NULL);
2166 g_return_if_fail (GTK_IS_SHEET (sheet));
2168 sheet->columns_resizable = resizable;
2172 gtk_sheet_columns_resizable (GtkSheet *sheet)
2174 g_return_val_if_fail (sheet != NULL, FALSE);
2175 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2177 return sheet->columns_resizable;
2182 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2184 g_return_if_fail (sheet != NULL);
2185 g_return_if_fail (GTK_IS_SHEET (sheet));
2187 sheet->rows_resizable = resizable;
2191 gtk_sheet_rows_resizable (GtkSheet *sheet)
2193 g_return_val_if_fail (sheet != NULL, FALSE);
2194 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2196 return sheet->rows_resizable;
2201 gtk_sheet_select_row (GtkSheet * sheet,
2204 g_return_if_fail (sheet != NULL);
2205 g_return_if_fail (GTK_IS_SHEET (sheet));
2207 if (row < 0 || row >= yyy_row_count (sheet))
2210 if (sheet->state != GTK_SHEET_NORMAL)
2211 gtk_sheet_real_unselect_range (sheet, NULL);
2214 gboolean veto = TRUE;
2215 veto = gtk_sheet_deactivate_cell (sheet);
2219 sheet->state = GTK_SHEET_ROW_SELECTED;
2220 sheet->range.row0 = row;
2221 sheet->range.col0 = 0;
2222 sheet->range.rowi = row;
2223 sheet->range.coli = xxx_column_count (sheet) - 1;
2224 sheet->active_cell.row = row;
2225 sheet->active_cell.col = 0;
2227 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, row);
2228 gtk_sheet_real_select_range (sheet, NULL);
2233 gtk_sheet_select_column (GtkSheet * sheet, gint column)
2235 g_return_if_fail (sheet != NULL);
2236 g_return_if_fail (GTK_IS_SHEET (sheet));
2238 if (column < 0 || column >= xxx_column_count (sheet))
2241 if (sheet->state != GTK_SHEET_NORMAL)
2242 gtk_sheet_real_unselect_range (sheet, NULL);
2245 gboolean veto = TRUE;
2246 veto = gtk_sheet_deactivate_cell (sheet);
2250 sheet->state = GTK_SHEET_COLUMN_SELECTED;
2251 sheet->range.row0 = 0;
2252 sheet->range.col0 = column;
2253 sheet->range.rowi = yyy_row_count (sheet) - 1;
2254 sheet->range.coli = column;
2255 sheet->active_cell.row = 0;
2256 sheet->active_cell.col = column;
2258 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, column);
2259 gtk_sheet_real_select_range (sheet, NULL);
2266 gtk_sheet_range_isvisible (const GtkSheet * sheet,
2267 GtkSheetRange range)
2269 g_return_val_if_fail (sheet != NULL, FALSE);
2271 if (range.row0 < 0 || range.row0 >= yyy_row_count (sheet))
2274 if (range.rowi < 0 || range.rowi >= yyy_row_count (sheet))
2277 if (range.col0 < 0 || range.col0 >= xxx_column_count (sheet))
2280 if (range.coli < 0 || range.coli >= xxx_column_count (sheet))
2283 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2286 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2289 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2292 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2299 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2300 gint row, gint column)
2302 GtkSheetRange range;
2305 range.col0 = column;
2307 range.coli = column;
2309 return gtk_sheet_range_isvisible (sheet, range);
2313 gtk_sheet_get_visible_range (GtkSheet *sheet, GtkSheetRange *range)
2315 g_return_if_fail (sheet != NULL);
2316 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2317 g_return_if_fail (range != NULL);
2319 range->row0 = MIN_VISIBLE_ROW (sheet);
2320 range->col0 = MIN_VISIBLE_COLUMN (sheet);
2321 range->rowi = MAX_VISIBLE_ROW (sheet);
2322 range->coli = MAX_VISIBLE_COLUMN (sheet);
2326 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2328 g_return_val_if_fail (sheet != NULL, NULL);
2329 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2331 return sheet->vadjustment;
2335 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2337 g_return_val_if_fail (sheet != NULL, NULL);
2338 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2340 return sheet->hadjustment;
2344 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2345 GtkAdjustment *adjustment)
2347 GtkAdjustment *old_adjustment;
2349 g_return_if_fail (sheet != NULL);
2350 g_return_if_fail (GTK_IS_SHEET (sheet));
2352 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2354 if (sheet->vadjustment == adjustment)
2357 old_adjustment = sheet->vadjustment;
2359 if (sheet->vadjustment)
2361 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2362 G_SIGNAL_MATCH_DATA,
2365 g_object_unref (G_OBJECT (sheet->vadjustment));
2368 sheet->vadjustment = adjustment;
2370 if (sheet->vadjustment)
2372 g_object_ref (G_OBJECT (sheet->vadjustment));
2373 g_object_ref_sink (G_OBJECT (sheet->vadjustment));
2375 g_signal_connect (G_OBJECT (sheet->vadjustment), "value_changed",
2376 G_CALLBACK (vadjustment_value_changed),
2380 if (!sheet->vadjustment || !old_adjustment)
2382 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2386 sheet->old_vadjustment = sheet->vadjustment->value;
2390 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2391 GtkAdjustment *adjustment)
2393 GtkAdjustment *old_adjustment;
2395 g_return_if_fail (sheet != NULL);
2396 g_return_if_fail (GTK_IS_SHEET (sheet));
2398 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2400 if (sheet->hadjustment == adjustment)
2403 old_adjustment = sheet->hadjustment;
2405 if (sheet->hadjustment)
2407 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2408 G_SIGNAL_MATCH_DATA,
2411 g_object_unref (G_OBJECT (sheet->hadjustment));
2414 sheet->hadjustment = adjustment;
2416 if (sheet->hadjustment)
2418 g_object_ref (G_OBJECT (sheet->hadjustment));
2419 g_object_ref_sink (G_OBJECT (sheet->hadjustment));
2421 g_signal_connect (G_OBJECT (sheet->hadjustment), "value_changed",
2422 G_CALLBACK (hadjustment_value_changed),
2426 if (!sheet->hadjustment || !old_adjustment)
2428 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2432 sheet->old_hadjustment = sheet->hadjustment->value;
2436 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2437 GtkAdjustment *hadjustment,
2438 GtkAdjustment *vadjustment)
2440 if (sheet->hadjustment != hadjustment)
2441 gtk_sheet_set_hadjustment (sheet, hadjustment);
2443 if (sheet->vadjustment != vadjustment)
2444 gtk_sheet_set_vadjustment (sheet, vadjustment);
2448 gtk_sheet_finalize (GObject * object)
2452 g_return_if_fail (object != NULL);
2453 g_return_if_fail (GTK_IS_SHEET (object));
2455 sheet = GTK_SHEET (object);
2459 g_free (sheet->name);
2463 if (G_OBJECT_CLASS (parent_class)->finalize)
2464 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2468 gtk_sheet_destroy (GtkObject * object)
2473 g_return_if_fail (object != NULL);
2474 g_return_if_fail (GTK_IS_SHEET (object));
2476 sheet = GTK_SHEET (object);
2478 /* destroy the entry */
2479 if (sheet->sheet_entry && GTK_IS_WIDGET (sheet->sheet_entry))
2481 gtk_widget_destroy (sheet->sheet_entry);
2482 sheet->sheet_entry = NULL;
2485 /* destroy the global selection button */
2486 if (sheet->button && GTK_IS_WIDGET (sheet->button))
2488 gtk_widget_destroy (sheet->button);
2489 sheet->button = NULL;
2492 /* unref adjustments */
2493 if (sheet->hadjustment)
2495 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2496 G_SIGNAL_MATCH_DATA,
2500 g_object_unref (G_OBJECT (sheet->hadjustment));
2501 sheet->hadjustment = NULL;
2504 if (sheet->vadjustment)
2506 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2507 G_SIGNAL_MATCH_DATA,
2511 g_object_unref (G_OBJECT (sheet->vadjustment));
2513 sheet->vadjustment = NULL;
2516 children = sheet->children;
2519 GtkSheetChild *child = (GtkSheetChild *)children->data;
2520 if (child && child->widget)
2521 gtk_sheet_remove (GTK_CONTAINER (sheet), child->widget);
2522 children = sheet->children;
2524 sheet->children = NULL;
2526 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2527 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2531 gtk_sheet_style_set (GtkWidget *widget,
2532 GtkStyle *previous_style)
2536 g_return_if_fail (widget != NULL);
2537 g_return_if_fail (GTK_IS_SHEET (widget));
2539 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2540 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2542 sheet = GTK_SHEET (widget);
2544 if (GTK_WIDGET_REALIZED (widget))
2546 gtk_style_set_background (widget->style, widget->window, widget->state);
2552 gtk_sheet_realize (GtkWidget * widget)
2555 GdkWindowAttr attributes;
2556 gint attributes_mask;
2557 GdkGCValues values, auxvalues;
2558 GdkColormap *colormap;
2560 GtkSheetChild *child;
2563 g_return_if_fail (widget != NULL);
2564 g_return_if_fail (GTK_IS_SHEET (widget));
2566 sheet = GTK_SHEET (widget);
2568 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2570 attributes.window_type = GDK_WINDOW_CHILD;
2571 attributes.x = widget->allocation.x;
2572 attributes.y = widget->allocation.y;
2573 attributes.width = widget->allocation.width;
2574 attributes.height = widget->allocation.height;
2575 attributes.wclass = GDK_INPUT_OUTPUT;
2577 attributes.visual = gtk_widget_get_visual (widget);
2578 attributes.colormap = gtk_widget_get_colormap (widget);
2580 attributes.event_mask = gtk_widget_get_events (widget);
2581 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2582 GDK_BUTTON_PRESS_MASK |
2583 GDK_BUTTON_RELEASE_MASK |
2584 GDK_KEY_PRESS_MASK |
2585 GDK_POINTER_MOTION_MASK |
2586 GDK_POINTER_MOTION_HINT_MASK);
2587 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2590 attributes.cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2593 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2595 gdk_window_set_user_data (widget->window, sheet);
2597 widget->style = gtk_style_attach (widget->style, widget->window);
2599 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2602 if (sheet->row_titles_visible)
2603 attributes.x = sheet->row_title_area.width;
2605 attributes.width = sheet->column_title_area.width;
2606 attributes.height = sheet->column_title_area.height;
2608 /* column - title window */
2609 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2610 gdk_window_set_user_data (sheet->column_title_window, sheet);
2611 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2615 if (sheet->column_titles_visible)
2616 attributes.y = sheet->column_title_area.height;
2617 attributes.width = sheet->row_title_area.width;
2618 attributes.height = sheet->row_title_area.height;
2620 /* row - title window */
2621 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2622 gdk_window_set_user_data (sheet->row_title_window, sheet);
2623 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2625 /* sheet - window */
2626 attributes.cursor = gdk_cursor_new (GDK_PLUS);
2630 attributes.width = sheet->sheet_window_width,
2631 attributes.height = sheet->sheet_window_height;
2633 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2634 gdk_window_set_user_data (sheet->sheet_window, sheet);
2636 gdk_cursor_unref (attributes.cursor);
2638 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2639 gdk_window_show (sheet->sheet_window);
2641 /* backing_pixmap */
2642 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
2646 gdk_gc_unref (sheet->fg_gc);
2648 gdk_gc_unref (sheet->bg_gc);
2649 sheet->fg_gc = gdk_gc_new (widget->window);
2650 sheet->bg_gc = gdk_gc_new (widget->window);
2652 colormap = gtk_widget_get_colormap (widget);
2654 gdk_color_white (colormap, &widget->style->white);
2655 gdk_color_black (colormap, &widget->style->black);
2657 gdk_gc_get_values (sheet->fg_gc, &auxvalues);
2659 values.foreground = widget->style->white;
2660 values.function = GDK_INVERT;
2661 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2663 gdk_gc_unref (sheet->xor_gc);
2664 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2670 if (sheet->sheet_entry->parent)
2672 gtk_widget_ref (sheet->sheet_entry);
2673 gtk_widget_unparent (sheet->sheet_entry);
2675 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2676 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
2678 if (sheet->button && sheet->button->parent)
2680 gtk_widget_ref (sheet->button);
2681 gtk_widget_unparent (sheet->button);
2683 gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
2684 gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
2686 if (!sheet->cursor_drag)
2687 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2689 if (sheet->column_titles_visible)
2690 gdk_window_show (sheet->column_title_window);
2691 if (sheet->row_titles_visible)
2692 gdk_window_show (sheet->row_title_window);
2694 size_allocate_row_title_buttons (sheet);
2695 size_allocate_column_title_buttons (sheet);
2697 name = g_strdup (sheet->name);
2698 gtk_sheet_set_title (sheet, name);
2702 children = sheet->children;
2705 child = children->data;
2706 children = children->next;
2708 gtk_sheet_realize_child (sheet, child);
2711 gtk_sheet_update_primary_selection (sheet);
2715 create_global_button (GtkSheet *sheet)
2717 sheet->button = gtk_button_new_with_label (" ");
2719 g_signal_connect (G_OBJECT (sheet->button),
2721 G_CALLBACK (global_button_clicked),
2726 size_allocate_global_button (GtkSheet *sheet)
2728 GtkAllocation allocation;
2730 if (!sheet->column_titles_visible) return;
2731 if (!sheet->row_titles_visible) return;
2733 gtk_widget_size_request (sheet->button, NULL);
2737 allocation.width = sheet->row_title_area.width;
2738 allocation.height = sheet->column_title_area.height;
2740 gtk_widget_size_allocate (sheet->button, &allocation);
2741 gtk_widget_show (sheet->button);
2745 global_button_clicked (GtkWidget *widget, gpointer data)
2749 gtk_sheet_click_cell (GTK_SHEET (data), - 1, - 1, &veto);
2750 gtk_widget_grab_focus (GTK_WIDGET (data));
2755 gtk_sheet_unrealize (GtkWidget * widget)
2759 g_return_if_fail (widget != NULL);
2760 g_return_if_fail (GTK_IS_SHEET (widget));
2762 sheet = GTK_SHEET (widget);
2764 gdk_cursor_destroy (sheet->cursor_drag);
2766 gdk_gc_destroy (sheet->xor_gc);
2767 gdk_gc_destroy (sheet->fg_gc);
2768 gdk_gc_destroy (sheet->bg_gc);
2770 gdk_window_destroy (sheet->sheet_window);
2771 gdk_window_destroy (sheet->column_title_window);
2772 gdk_window_destroy (sheet->row_title_window);
2776 g_object_unref (sheet->pixmap);
2777 sheet->pixmap = NULL;
2780 sheet->column_title_window = NULL;
2781 sheet->sheet_window = NULL;
2782 sheet->cursor_drag = NULL;
2783 sheet->xor_gc = NULL;
2784 sheet->fg_gc = NULL;
2785 sheet->bg_gc = NULL;
2787 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2788 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2792 gtk_sheet_map (GtkWidget * widget)
2795 GtkSheetChild *child;
2798 g_return_if_fail (widget != NULL);
2799 g_return_if_fail (GTK_IS_SHEET (widget));
2801 sheet = GTK_SHEET (widget);
2803 if (!GTK_WIDGET_MAPPED (widget))
2805 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2807 if (!sheet->cursor_drag) sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2809 gdk_window_show (widget->window);
2811 gdk_window_show (sheet->sheet_window);
2813 if (sheet->column_titles_visible)
2815 size_allocate_column_title_buttons (sheet);
2816 gdk_window_show (sheet->column_title_window);
2818 if (sheet->row_titles_visible)
2820 size_allocate_row_title_buttons (sheet);
2821 gdk_window_show (sheet->row_title_window);
2824 if (!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2825 && ! gtk_sheet_locked (sheet)
2826 && sheet->active_cell.row >= 0
2827 && sheet->active_cell.col >= 0 )
2829 gtk_widget_show (sheet->sheet_entry);
2830 gtk_widget_map (sheet->sheet_entry);
2833 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2834 !GTK_WIDGET_MAPPED (sheet->button))
2836 gtk_widget_show (sheet->button);
2837 gtk_widget_map (sheet->button);
2840 if (GTK_BIN (sheet->button)->child)
2841 if (GTK_WIDGET_VISIBLE (GTK_BIN (sheet->button)->child) &&
2842 !GTK_WIDGET_MAPPED (GTK_BIN (sheet->button)->child))
2843 gtk_widget_map (GTK_BIN (sheet->button)->child);
2845 gtk_sheet_range_draw (sheet, NULL);
2846 gtk_sheet_activate_cell (sheet,
2847 sheet->active_cell.row,
2848 sheet->active_cell.col);
2850 children = sheet->children;
2853 child = children->data;
2854 children = children->next;
2856 if (GTK_WIDGET_VISIBLE (child->widget) &&
2857 !GTK_WIDGET_MAPPED (child->widget))
2859 gtk_widget_map (child->widget);
2860 gtk_sheet_position_child (sheet, child);
2868 gtk_sheet_unmap (GtkWidget * widget)
2871 GtkSheetChild *child;
2874 g_return_if_fail (widget != NULL);
2875 g_return_if_fail (GTK_IS_SHEET (widget));
2877 sheet = GTK_SHEET (widget);
2879 if (GTK_WIDGET_MAPPED (widget))
2881 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2883 gdk_window_hide (sheet->sheet_window);
2884 if (sheet->column_titles_visible)
2885 gdk_window_hide (sheet->column_title_window);
2886 if (sheet->row_titles_visible)
2887 gdk_window_hide (sheet->row_title_window);
2888 gdk_window_hide (widget->window);
2890 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2891 gtk_widget_unmap (sheet->sheet_entry);
2893 if (GTK_WIDGET_MAPPED (sheet->button))
2894 gtk_widget_unmap (sheet->button);
2896 children = sheet->children;
2899 child = children->data;
2900 children = children->next;
2902 if (GTK_WIDGET_VISIBLE (child->widget) &&
2903 GTK_WIDGET_MAPPED (child->widget))
2905 gtk_widget_unmap (child->widget);
2914 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2917 GdkGC *fg_gc, *bg_gc;
2918 GtkSheetCellAttr attributes;
2921 g_return_if_fail (sheet != NULL);
2923 /* bail now if we arn't drawable yet */
2924 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2926 if (row < 0 || row >= yyy_row_count (sheet)) return;
2927 if (col < 0 || col >= xxx_column_count (sheet)) return;
2928 if (! xxx_column_is_visible (sheet, col)) return;
2929 if (! yyy_row_is_visible (sheet, row)) return;
2931 widget = GTK_WIDGET (sheet);
2933 gtk_sheet_get_attributes (sheet, row, col, &attributes);
2935 /* select GC for background rectangle */
2936 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2937 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2939 fg_gc = sheet->fg_gc;
2940 bg_gc = sheet->bg_gc;
2942 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
2943 area.y = ROW_TOP_YPIXEL (sheet, row);
2944 area.width= xxx_column_width (sheet, col);
2945 area.height = yyy_row_height (sheet, row);
2947 gdk_draw_rectangle (sheet->pixmap,
2955 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
2957 if (sheet->show_grid)
2959 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
2961 gdk_draw_rectangle (sheet->pixmap,
2965 area.width, area.height);
2970 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
2975 gint text_width, text_height, y;
2977 gint size, sizel, sizer;
2978 GdkGC *fg_gc, *bg_gc;
2979 GtkSheetCellAttr attributes;
2980 PangoLayout *layout;
2981 PangoRectangle rect;
2982 PangoRectangle logical_rect;
2983 PangoLayoutLine *line;
2984 PangoFontMetrics *metrics;
2985 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (sheet));
2986 gint ascent, descent, y_pos;
2990 g_return_if_fail (sheet != NULL);
2992 /* bail now if we aren't drawable yet */
2993 if (!GTK_WIDGET_DRAWABLE (sheet))
2996 label = gtk_sheet_cell_get_text (sheet, row, col);
3000 if (row < 0 || row >= yyy_row_count (sheet)) return;
3001 if (col < 0 || col >= xxx_column_count (sheet)) return;
3002 if (! xxx_column_is_visible (sheet, col)) return;
3003 if (!yyy_row_is_visible (sheet, row)) return;
3006 widget = GTK_WIDGET (sheet);
3008 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3010 /* select GC for background rectangle */
3011 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3012 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3014 fg_gc = sheet->fg_gc;
3015 bg_gc = sheet->bg_gc;
3017 area.x = COLUMN_LEFT_XPIXEL (sheet, col);
3018 area.y = ROW_TOP_YPIXEL (sheet, row);
3019 area.width = xxx_column_width (sheet, col);
3020 area.height = yyy_row_height (sheet, row);
3023 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
3024 dispose_string (sheet, label);
3025 pango_layout_set_font_description (layout, attributes.font_desc);
3027 pango_layout_get_pixel_extents (layout, NULL, &rect);
3029 line = pango_layout_get_lines (layout)->data;
3030 pango_layout_line_get_extents (line, NULL, &logical_rect);
3032 metrics = pango_context_get_metrics (context,
3033 attributes.font_desc,
3034 pango_context_get_language (context));
3036 ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
3037 descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
3039 pango_font_metrics_unref (metrics);
3041 /* Align primarily for locale's ascent / descent */
3043 logical_rect.height /= PANGO_SCALE;
3044 logical_rect.y /= PANGO_SCALE;
3045 y_pos = area.height - logical_rect.height;
3047 if (logical_rect.height > area.height)
3048 y_pos = (logical_rect.height - area.height - 2 * CELLOFFSET) / 2;
3051 else if (y_pos + logical_rect.height > area.height)
3052 y_pos = area.height - logical_rect.height;
3054 text_width = rect.width;
3055 text_height = rect.height;
3056 y = area.y + y_pos - CELLOFFSET;
3058 switch (attributes.justification)
3060 case GTK_JUSTIFY_RIGHT:
3062 area.x +=area.width;
3064 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3066 if ( !gtk_sheet_cell_empty (sheet, row, i)) break;
3067 if (size >= text_width + CELLOFFSET) break;
3068 size +=xxx_column_width (sheet, i);
3069 xxx_column_set_right_column (sheet, i,
3071 xxx_column_right_column (sheet, i)));
3076 xoffset += area.width - text_width - 2 * CELLOFFSET -
3077 attributes.border.width / 2;
3079 case GTK_JUSTIFY_CENTER:
3080 sizel = area.width / 2;
3081 sizer = area.width / 2;
3082 area.x += area.width / 2;
3084 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3086 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3087 if (sizer >= text_width / 2) break;
3088 sizer += xxx_column_width (sheet, i);
3089 xxx_column_set_left_column (sheet, i,
3092 xxx_column_left_column (sheet, i)));
3094 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3096 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3097 if (sizel >= text_width / 2) break;
3098 sizel +=xxx_column_width (sheet, i);
3099 xxx_column_set_right_column (sheet, i,
3101 xxx_column_right_column (sheet, i)));
3103 size = MIN (sizel, sizer);
3106 xoffset += sizel - text_width / 2 - CELLOFFSET;
3107 area.width = sizel + sizer;
3109 case GTK_JUSTIFY_LEFT:
3113 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3115 if (! gtk_sheet_cell_empty (sheet, row, i)) break;
3116 if (size >= text_width + CELLOFFSET) break;
3117 size +=xxx_column_width (sheet, i);
3118 xxx_column_set_left_column (sheet, i,
3121 xxx_column_left_column (sheet, i)));
3126 xoffset += attributes.border.width / 2;
3130 gdk_gc_set_clip_rectangle (fg_gc, &area);
3133 gdk_draw_layout (sheet->pixmap, fg_gc,
3134 area.x + xoffset + CELLOFFSET,
3138 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3139 g_object_unref (G_OBJECT (layout));
3141 gdk_draw_pixmap (sheet->sheet_window,
3142 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3154 gtk_sheet_range_draw (GtkSheet *sheet, const GtkSheetRange *range)
3157 GtkSheetRange drawing_range;
3160 g_return_if_fail (sheet != NULL);
3161 g_return_if_fail (GTK_SHEET (sheet));
3163 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3164 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3165 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
3169 drawing_range.row0 = MIN_VISIBLE_ROW (sheet);
3170 drawing_range.col0 = MIN_VISIBLE_COLUMN (sheet);
3171 drawing_range.rowi = MIN (MAX_VISIBLE_ROW (sheet),
3172 yyy_row_count (sheet) - 1);
3173 drawing_range.coli = MAX_VISIBLE_COLUMN (sheet);
3176 gdk_draw_rectangle (sheet->pixmap,
3177 GTK_WIDGET (sheet)->style->white_gc,
3180 sheet->sheet_window_width,
3181 sheet->sheet_window_height);
3185 drawing_range.row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
3186 drawing_range.col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
3187 drawing_range.rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
3188 drawing_range.coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
3191 if (drawing_range.coli == xxx_column_count (sheet) - 1)
3193 area.x = COLUMN_LEFT_XPIXEL (sheet,
3194 xxx_column_count (sheet) - 1) +
3195 xxx_column_width (sheet, xxx_column_count (sheet) - 1) + 1;
3199 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3201 gdk_draw_rectangle (sheet->pixmap,
3205 sheet->sheet_window_width - area.x,
3206 sheet->sheet_window_height);
3208 gdk_draw_pixmap (sheet->sheet_window,
3209 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3215 sheet->sheet_window_width - area.x,
3216 sheet->sheet_window_height);
3219 if (drawing_range.rowi == yyy_row_count (sheet) - 1)
3222 area.y = ROW_TOP_YPIXEL (sheet,
3223 yyy_row_count (sheet) - 1) +
3224 yyy_row_height (sheet, yyy_row_count (sheet) - 1) + 1;
3226 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3228 gdk_draw_rectangle (sheet->pixmap,
3232 sheet->sheet_window_width,
3233 sheet->sheet_window_height - area.y);
3235 gdk_draw_pixmap (sheet->sheet_window,
3236 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3242 sheet->sheet_window_width,
3243 sheet->sheet_window_height - area.y);
3246 for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
3247 for (j = drawing_range.col0; j <= drawing_range.coli; j++)
3249 gtk_sheet_cell_draw_default (sheet, i, j);
3250 gtk_sheet_cell_draw_label (sheet, i, j);
3253 gtk_sheet_draw_backing_pixmap (sheet, drawing_range);
3255 if (sheet->state != GTK_SHEET_NORMAL &&
3256 gtk_sheet_range_isvisible (sheet, sheet->range))
3257 gtk_sheet_range_draw_selection (sheet, drawing_range);
3259 if (sheet->state == GTK_STATE_NORMAL &&
3260 sheet->active_cell.row >= drawing_range.row0 &&
3261 sheet->active_cell.row <= drawing_range.rowi &&
3262 sheet->active_cell.col >= drawing_range.col0 &&
3263 sheet->active_cell.col <= drawing_range.coli)
3264 gtk_sheet_show_active_cell (sheet);
3268 gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
3274 if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3275 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3278 if (!gtk_sheet_range_isvisible (sheet, range)) return;
3279 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3283 range.col0 = MAX (sheet->range.col0, range.col0);
3284 range.coli = MIN (sheet->range.coli, range.coli);
3285 range.row0 = MAX (sheet->range.row0, range.row0);
3286 range.rowi = MIN (sheet->range.rowi, range.rowi);
3288 range.col0 = MAX (range.col0, MIN_VISIBLE_COLUMN (sheet));
3289 range.coli = MIN (range.coli, MAX_VISIBLE_COLUMN (sheet));
3290 range.row0 = MAX (range.row0, MIN_VISIBLE_ROW (sheet));
3291 range.rowi = MIN (range.rowi, MAX_VISIBLE_ROW (sheet));
3293 for (i = range.row0; i <= range.rowi; i++)
3295 for (j = range.col0; j <= range.coli; j++)
3298 if (gtk_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED &&
3299 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
3302 area.x = COLUMN_LEFT_XPIXEL (sheet, j);
3303 area.y = ROW_TOP_YPIXEL (sheet, i);
3304 area.width= xxx_column_width (sheet, j);
3305 area.height = yyy_row_height (sheet, i);
3307 if (i == sheet->range.row0)
3309 area.y = area.y + 2;
3310 area.height = area.height - 2;
3312 if (i == sheet->range.rowi) area.height = area.height - 3;
3313 if (j == sheet->range.col0)
3315 area.x = area.x + 2;
3316 area.width = area.width - 2;
3318 if (j == sheet->range.coli) area.width = area.width - 3;
3320 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
3322 gdk_draw_rectangle (sheet->sheet_window,
3325 area.x + 1, area.y + 1,
3326 area.width, area.height);
3333 gtk_sheet_draw_border (sheet, sheet->range);
3337 gtk_sheet_draw_backing_pixmap (GtkSheet *sheet, GtkSheetRange range)
3339 gint x, y, width, height;
3341 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3343 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
3344 y = ROW_TOP_YPIXEL (sheet, range.row0);
3345 width = COLUMN_LEFT_XPIXEL (sheet, range.coli) - x +
3346 xxx_column_width (sheet, range.coli);
3348 height = ROW_TOP_YPIXEL (sheet, range.rowi)- y + yyy_row_height (sheet, range.rowi);
3350 if (range.row0 == sheet->range.row0)
3353 height = height + 5;
3355 if (range.rowi == sheet->range.rowi) height = height + 5;
3356 if (range.col0 == sheet->range.col0)
3361 if (range.coli == sheet->range.coli) width = width + 5;
3363 width = MIN (width, sheet->sheet_window_width - x);
3364 height = MIN (height, sheet->sheet_window_height - y);
3371 x = (sheet->row_titles_visible)
3372 ? MAX (x, sheet->row_title_area.width) : MAX (x, 0);
3373 y = (sheet->column_titles_visible)
3374 ? MAX (y, sheet->column_title_area.height) : MAX (y, 0);
3376 if (range.coli == xxx_column_count (sheet) - 1)
3377 width = sheet->sheet_window_width - x;
3378 if (range.rowi == yyy_row_count (sheet) - 1)
3379 height = sheet->sheet_window_height - y;
3381 gdk_draw_pixmap (sheet->sheet_window,
3382 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3394 gtk_sheet_set_cell_text (GtkSheet *sheet, gint row, gint col, const gchar *text)
3396 GtkSheetCellAttr attributes;
3398 g_return_if_fail (sheet != NULL);
3399 g_return_if_fail (GTK_IS_SHEET (sheet));
3400 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3401 if (col < 0 || row < 0) return;
3403 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3404 gtk_sheet_set_cell (sheet, row, col, attributes.justification, text);
3408 safe_strcmp (const gchar *s1, const gchar *s2)
3410 if ( !s1 && !s2) return 0;
3411 if ( !s1) return - 1;
3412 if ( !s2) return +1;
3413 return strcmp (s1, s2);
3417 gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
3418 GtkJustification justification,
3421 GSheetModel *model ;
3425 GtkSheetRange range;
3427 GtkSheetCellAttr attributes;
3429 g_return_if_fail (sheet != NULL);
3430 g_return_if_fail (GTK_IS_SHEET (sheet));
3431 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3432 if (col < 0 || row < 0) return;
3434 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3436 attributes.justification = justification;
3438 model = gtk_sheet_get_model (sheet);
3440 old_text = g_sheet_model_get_string (model, row, col);
3444 if (0 != safe_strcmp (old_text, text))
3445 changed = g_sheet_model_set_string (model, text, row, col);
3447 if ( g_sheet_model_free_strings (model))
3451 if (changed && attributes.is_visible)
3453 gchar *s = gtk_sheet_cell_get_text (sheet, row, col);
3455 if (s && strlen (s) > 0)
3457 text_width = STRING_WIDTH (GTK_WIDGET (sheet),
3458 attributes.font_desc, text);
3460 dispose_string (sheet, s);
3464 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3465 range.coli = MAX_VISIBLE_COLUMN (sheet);
3467 if (gtk_sheet_autoresize (sheet) &&
3468 text_width > xxx_column_width (sheet, col) -
3469 2 * CELLOFFSET- attributes.border.width)
3471 gtk_sheet_set_column_width (sheet, col, text_width + 2 * CELLOFFSET
3472 + attributes.border.width);
3473 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3476 if (!GTK_SHEET_IS_FROZEN (sheet))
3477 gtk_sheet_range_draw (sheet, &range);
3481 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, col);
3487 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3489 GtkSheetRange range;
3491 g_return_if_fail (sheet != NULL);
3492 g_return_if_fail (GTK_IS_SHEET (sheet));
3493 if (column >= xxx_column_count (sheet) ||
3494 row >= yyy_row_count (sheet)) return;
3496 if (column < 0 || row < 0) return;
3500 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3501 range.coli = MAX_VISIBLE_COLUMN (sheet);
3503 gtk_sheet_real_cell_clear (sheet, row, column);
3505 if (!GTK_SHEET_IS_FROZEN (sheet))
3507 gtk_sheet_range_draw (sheet, &range);
3512 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column)
3514 GSheetModel *model = gtk_sheet_get_model (sheet);
3516 gchar *old_text = gtk_sheet_cell_get_text (sheet, row, column);
3518 if (old_text && strlen (old_text) > 0 )
3520 g_sheet_model_datum_clear (model, row, column);
3522 if (GTK_IS_OBJECT (sheet) && G_OBJECT (sheet)->ref_count > 0)
3523 g_signal_emit (G_OBJECT (sheet), sheet_signals[CLEAR_CELL], 0,
3527 dispose_string (sheet, old_text);
3531 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3533 g_return_if_fail (sheet != NULL);
3534 g_return_if_fail (GTK_IS_SHEET (sheet));
3536 gtk_sheet_real_range_clear (sheet, range);
3540 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3543 GtkSheetRange clear;
3548 clear.rowi = yyy_row_count (sheet) - 1;
3550 clear.coli = xxx_column_count (sheet) - 1;
3555 clear.row0 = MAX (clear.row0, 0);
3556 clear.col0 = MAX (clear.col0, 0);
3557 clear.rowi = MIN (clear.rowi, yyy_row_count (sheet) - 1 );
3558 clear.coli = MIN (clear.coli, xxx_column_count (sheet) - 1 );
3560 for (i = clear.row0; i <= clear.rowi; i++)
3561 for (j = clear.col0; j <= clear.coli; j++)
3563 gtk_sheet_real_cell_clear (sheet, i, j);
3566 gtk_sheet_range_draw (sheet, NULL);
3571 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3574 char *text = gtk_sheet_cell_get_text (sheet, row, col);
3575 empty = (text == NULL );
3577 dispose_string (sheet, text);
3584 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3587 g_return_val_if_fail (sheet != NULL, NULL);
3588 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3590 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet))
3592 if (col < 0 || row < 0) return NULL;
3594 model = gtk_sheet_get_model (sheet);
3599 return g_sheet_model_get_string (model, row, col);
3604 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3607 GtkSheetRange *range;
3609 g_return_val_if_fail (sheet != NULL, 0);
3610 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3611 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return 0;
3612 if (col < 0 || row < 0) return 0;
3614 state = sheet->state;
3615 range = &sheet->range;
3619 case GTK_SHEET_NORMAL:
3620 return GTK_STATE_NORMAL;
3622 case GTK_SHEET_ROW_SELECTED:
3623 if (row >= range->row0 && row <= range->rowi)
3624 return GTK_STATE_SELECTED;
3626 case GTK_SHEET_COLUMN_SELECTED:
3627 if (col >= range->col0 && col <= range->coli)
3628 return GTK_STATE_SELECTED;
3630 case GTK_SHEET_RANGE_SELECTED:
3631 if (row >= range->row0 && row <= range->rowi && \
3632 col >= range->col0 && col <= range->coli)
3633 return GTK_STATE_SELECTED;
3636 return GTK_STATE_NORMAL;
3639 /* Convert X, Y (in pixels) to *ROW, *COLUMN (in cell coords)
3640 -1 indicates the title buttons.
3641 If the function returns FALSE, then the results will be unreliable.
3644 gtk_sheet_get_pixel_info (GtkSheet *sheet,
3652 *column = -G_MAXINT;
3654 g_return_val_if_fail (sheet != NULL, 0);
3655 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3657 /* bounds checking, return false if the user clicked
3665 if ( y < sheet->column_title_area.height + sheet->column_title_area.y)
3670 trow = ROW_FROM_YPIXEL (sheet, y);
3671 if (trow > yyy_row_count (sheet))
3677 if ( x < sheet->row_title_area.width + sheet->row_title_area.x)
3681 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3682 if (tcol > xxx_column_count (sheet))
3692 gtk_sheet_get_cell_area (GtkSheet * sheet,
3697 g_return_val_if_fail (sheet != NULL, 0);
3698 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3700 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3703 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL (sheet, column) -
3704 (sheet->row_titles_visible
3705 ? sheet->row_title_area.width
3707 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL (sheet, row) -
3708 (sheet->column_titles_visible
3709 ? sheet->column_title_area.height
3711 area->width= (column == -1) ? sheet->row_title_area.width
3712 : xxx_column_width (sheet, column);
3714 area->height= (row == -1) ? sheet->column_title_area.height
3715 : yyy_row_height (sheet, row);
3721 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3723 g_return_val_if_fail (sheet != NULL, 0);
3724 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3726 if (row < - 1 || column < - 1) return FALSE;
3727 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3730 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3732 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
3735 sheet->active_cell.row = row;
3736 sheet->active_cell.col = column;
3738 if ( row == -1 || column == -1)
3740 gtk_sheet_hide_active_cell (sheet);
3744 if (!gtk_sheet_activate_cell (sheet, row, column)) return FALSE;
3746 if (gtk_sheet_autoscroll (sheet))
3747 gtk_sheet_move_query (sheet, row, column);
3753 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3755 g_return_if_fail (sheet != NULL);
3756 g_return_if_fail (GTK_IS_SHEET (sheet));
3758 if ( row ) *row = sheet->active_cell.row;
3759 if (column) *column = sheet->active_cell.col;
3763 gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
3768 GtkJustification justification;
3769 GtkSheetCellAttr attributes;
3771 g_return_if_fail (data != NULL);
3772 g_return_if_fail (GTK_IS_SHEET (data));
3774 sheet = GTK_SHEET (data);
3776 if (!GTK_WIDGET_VISIBLE (widget)) return;
3777 if (sheet->state != GTK_STATE_NORMAL) return;
3779 row = sheet->active_cell.row;
3780 col = sheet->active_cell.col;
3782 if (row < 0 || col < 0) return;
3784 sheet->active_cell.row =- 1;
3785 sheet->active_cell.col =- 1;
3787 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3789 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3791 if (text && strlen (text) > 0)
3793 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3794 justification = attributes.justification;
3795 gtk_sheet_set_cell (sheet, row, col, justification, text);
3798 if (sheet->freeze_count == 0)
3799 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3801 sheet->active_cell.row = row;;
3802 sheet->active_cell.col = col;
3807 gtk_sheet_deactivate_cell (GtkSheet *sheet)
3809 gboolean veto = TRUE;
3811 g_return_val_if_fail (sheet != NULL, FALSE);
3812 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3814 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return FALSE;
3815 if (sheet->state != GTK_SHEET_NORMAL) return FALSE;
3817 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[DEACTIVATE],
3818 sheet->active_cell.row,
3819 sheet->active_cell.col, &veto);
3821 if (!veto) return FALSE;
3823 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
3826 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_sheet_get_entry (sheet)),
3827 G_CALLBACK (gtk_sheet_entry_changed),
3830 gtk_sheet_hide_active_cell (sheet);
3831 sheet->active_cell.row = -1;
3832 sheet->active_cell.col = -1;
3834 if (GTK_SHEET_REDRAW_PENDING (sheet))
3836 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3837 gtk_sheet_range_draw (sheet, NULL);
3844 gtk_sheet_hide_active_cell (GtkSheet *sheet)
3848 GtkJustification justification;
3849 GtkSheetCellAttr attributes;
3851 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3853 row = sheet->active_cell.row;
3854 col = sheet->active_cell.col;
3856 if (row < 0 || col < 0) return;
3858 if (sheet->freeze_count == 0)
3859 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
3861 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3863 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3864 justification = attributes.justification;
3866 if (text && strlen (text) != 0)
3868 gtk_sheet_set_cell (sheet, row, col, justification, text);
3869 g_signal_emit (G_OBJECT (sheet), sheet_signals[SET_CELL], 0, row, col);
3873 gtk_sheet_cell_clear (sheet, row, col);
3876 row = sheet->active_cell.row;
3877 col = sheet->active_cell.col;
3879 gtk_widget_hide (sheet->sheet_entry);
3880 gtk_widget_unmap (sheet->sheet_entry);
3882 if (row != -1 && col != -1)
3883 gdk_draw_pixmap (sheet->sheet_window,
3884 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3886 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3887 ROW_TOP_YPIXEL (sheet, row)- 1,
3888 COLUMN_LEFT_XPIXEL (sheet, col)- 1,
3889 ROW_TOP_YPIXEL (sheet, row)- 1,
3890 xxx_column_width (sheet, col) + 4,
3891 yyy_row_height (sheet, row)+4);
3893 gtk_widget_grab_focus (GTK_WIDGET (sheet));
3895 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3900 gtk_sheet_activate_cell (GtkSheet *sheet, gint row, gint col)
3902 gboolean veto = TRUE;
3904 g_return_val_if_fail (sheet != NULL, FALSE);
3905 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3907 if (row < 0 || col < 0) return FALSE;
3908 if (row >= yyy_row_count (sheet) || col >= xxx_column_count (sheet))
3911 if (!veto) return FALSE;
3912 if (sheet->state != GTK_SHEET_NORMAL)
3914 sheet->state = GTK_SHEET_NORMAL;
3915 gtk_sheet_real_unselect_range (sheet, NULL);
3918 sheet->range.row0 = row;
3919 sheet->range.col0 = col;
3920 sheet->range.rowi = row;
3921 sheet->range.coli = col;
3922 sheet->active_cell.row = row;
3923 sheet->active_cell.col = col;
3924 sheet->selection_cell.row = row;
3925 sheet->selection_cell.col = col;
3927 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
3929 gtk_sheet_show_active_cell (sheet);
3932 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
3934 G_CALLBACK (gtk_sheet_entry_changed),
3937 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals [ACTIVATE], row, col, &veto);
3943 gtk_sheet_show_active_cell (GtkSheet *sheet)
3945 GtkEntry *sheet_entry;
3946 GtkSheetCellAttr attributes;
3948 const gchar *old_text;
3949 GtkJustification justification;
3952 g_return_if_fail (sheet != NULL);
3953 g_return_if_fail (GTK_IS_SHEET (sheet));
3955 row = sheet->active_cell.row;
3956 col = sheet->active_cell.col;
3958 /* Don't show the active cell, if there is no active cell: */
3959 if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
3962 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3963 if (sheet->state != GTK_SHEET_NORMAL) return;
3964 if (GTK_SHEET_IN_SELECTION (sheet)) return;
3966 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
3968 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
3970 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3972 justification = GTK_JUSTIFY_LEFT;
3974 if (gtk_sheet_justify_entry (sheet))
3975 justification = attributes.justification;
3977 text = gtk_sheet_cell_get_text (sheet, row, col);
3979 text = g_strdup ("");
3981 gtk_entry_set_visibility (GTK_ENTRY (sheet_entry), attributes.is_visible);
3983 if (gtk_sheet_locked (sheet) || !attributes.is_editable)
3984 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), FALSE);
3986 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), TRUE);
3988 /*** Added by John Gotts. Mar 25, 2005 *********/
3989 old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
3990 if (strcmp (old_text, text) != 0)
3992 if (!GTK_IS_ITEM_ENTRY (sheet_entry))
3993 gtk_entry_set_text (GTK_ENTRY (sheet_entry), text);
3995 gtk_item_entry_set_text (GTK_ITEM_ENTRY (sheet_entry), text, justification);
3998 gtk_sheet_entry_set_max_size (sheet);
3999 gtk_sheet_size_allocate_entry (sheet);
4001 gtk_widget_map (sheet->sheet_entry);
4003 gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
4005 dispose_string (sheet, text);
4009 gtk_sheet_draw_active_cell (GtkSheet *sheet)
4012 GtkSheetRange range;
4014 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
4015 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4017 row = sheet->active_cell.row;
4018 col = sheet->active_cell.col;
4020 if (row < 0 || col < 0) return;
4022 if (!gtk_sheet_cell_isvisible (sheet, row, col)) return;
4024 range.col0 = range.coli = col;
4025 range.row0 = range.rowi = row;
4027 gtk_sheet_draw_border (sheet, range);
4032 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4034 gint pixmap_width, pixmap_height;
4036 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4038 if (width == 0 && height == 0)
4040 width = sheet->sheet_window_width + 80;
4041 height = sheet->sheet_window_height + 80;
4047 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4050 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4054 /* reallocate if sizes don't match */
4055 gdk_window_get_size (sheet->pixmap,
4056 &pixmap_width, &pixmap_height);
4057 if ( (pixmap_width != width) || (pixmap_height != height))
4059 g_object_unref (sheet->pixmap);
4060 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4063 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4069 gtk_sheet_new_selection (GtkSheet *sheet, GtkSheetRange *range)
4071 gint i, j, mask1, mask2;
4072 gint state, selected;
4073 gint x, y, width, height;
4074 GtkSheetRange new_range, aux_range;
4076 g_return_if_fail (sheet != NULL);
4078 if (range == NULL) range=&sheet->range;
4082 range->row0 = MIN (range->row0, sheet->range.row0);
4083 range->rowi = MAX (range->rowi, sheet->range.rowi);
4084 range->col0 = MIN (range->col0, sheet->range.col0);
4085 range->coli = MAX (range->coli, sheet->range.coli);
4087 range->row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
4088 range->rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
4089 range->col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
4090 range->coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
4092 aux_range.row0 = MAX (new_range.row0, MIN_VISIBLE_ROW (sheet));
4093 aux_range.rowi = MIN (new_range.rowi, MAX_VISIBLE_ROW (sheet));
4094 aux_range.col0 = MAX (new_range.col0, MIN_VISIBLE_COLUMN (sheet));
4095 aux_range.coli = MIN (new_range.coli, MAX_VISIBLE_COLUMN (sheet));
4097 for (i = range->row0; i <= range->rowi; i++)
4099 for (j = range->col0; j <= range->coli; j++)
4102 state = gtk_sheet_cell_get_state (sheet, i, j);
4103 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4104 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4106 if (state == GTK_STATE_SELECTED && selected &&
4107 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4108 (i == sheet->range.row0 || i == sheet->range.rowi ||
4109 j == sheet->range.col0 || j == sheet->range.coli ||
4110 i == new_range.row0 || i == new_range.rowi ||
4111 j == new_range.col0 || j == new_range.coli))
4114 mask1 = i == sheet->range.row0 ? 1 : 0;
4115 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4116 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4117 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4119 mask2 = i == new_range.row0 ? 1 : 0;
4120 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4121 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4122 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4126 x = COLUMN_LEFT_XPIXEL (sheet, j);
4127 y = ROW_TOP_YPIXEL (sheet, i);
4128 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4129 xxx_column_width (sheet, j);
4130 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4132 if (i == sheet->range.row0)
4135 height = height + 3;
4137 if (i == sheet->range.rowi) height = height + 3;
4138 if (j == sheet->range.col0)
4143 if (j == sheet->range.coli) width = width + 3;
4145 gdk_draw_pixmap (sheet->sheet_window,
4146 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4155 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
4157 x = COLUMN_LEFT_XPIXEL (sheet, j);
4158 y = ROW_TOP_YPIXEL (sheet, i);
4159 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4160 xxx_column_width (sheet, j);
4162 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4164 if (i == new_range.row0)
4167 height = height - 2;
4169 if (i == new_range.rowi) height = height - 3;
4170 if (j == new_range.col0)
4175 if (j == new_range.coli) width = width - 3;
4177 gdk_draw_rectangle (sheet->sheet_window,
4188 for (i = range->row0; i <= range->rowi; i++)
4190 for (j = range->col0; j <= range->coli; j++)
4193 state = gtk_sheet_cell_get_state (sheet, i, j);
4194 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4195 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4197 if (state == GTK_STATE_SELECTED && !selected &&
4198 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4201 x = COLUMN_LEFT_XPIXEL (sheet, j);
4202 y = ROW_TOP_YPIXEL (sheet, i);
4203 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4204 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4206 if (i == sheet->range.row0)
4209 height = height + 3;
4211 if (i == sheet->range.rowi) height = height + 3;
4212 if (j == sheet->range.col0)
4217 if (j == sheet->range.coli) width = width + 3;
4219 gdk_draw_pixmap (sheet->sheet_window,
4220 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4232 for (i = range->row0; i <= range->rowi; i++)
4234 for (j = range->col0; j <= range->coli; j++)
4237 state = gtk_sheet_cell_get_state (sheet, i, j);
4238 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4239 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4241 if (state != GTK_STATE_SELECTED && selected &&
4242 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4243 (i != sheet->active_cell.row || j != sheet->active_cell.col))
4246 x = COLUMN_LEFT_XPIXEL (sheet, j);
4247 y = ROW_TOP_YPIXEL (sheet, i);
4248 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4249 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4251 if (i == new_range.row0)
4254 height = height - 2;
4256 if (i == new_range.rowi) height = height - 3;
4257 if (j == new_range.col0)
4262 if (j == new_range.coli) width = width - 3;
4264 gdk_draw_rectangle (sheet->sheet_window,
4275 for (i = aux_range.row0; i <= aux_range.rowi; i++)
4277 for (j = aux_range.col0; j <= aux_range.coli; j++)
4280 if (xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4283 state = gtk_sheet_cell_get_state (sheet, i, j);
4285 mask1 = i == sheet->range.row0 ? 1 : 0;
4286 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4287 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4288 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4290 mask2 = i == new_range.row0 ? 1 : 0;
4291 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4292 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4293 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4294 if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
4296 x = COLUMN_LEFT_XPIXEL (sheet, j);
4297 y = ROW_TOP_YPIXEL (sheet, i);
4298 width = xxx_column_width (sheet, j);
4299 height = yyy_row_height (sheet, i);
4301 gdk_draw_rectangle (sheet->sheet_window,
4309 gdk_draw_rectangle (sheet->sheet_window,
4312 x + 1, y + height - 1,
4316 gdk_draw_rectangle (sheet->sheet_window,
4324 gdk_draw_rectangle (sheet->sheet_window,
4327 x + width - 1, y + 1,
4341 gtk_sheet_draw_corners (sheet, new_range);
4346 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4351 gint x, y, width, height;
4353 widget = GTK_WIDGET (sheet);
4355 x = COLUMN_LEFT_XPIXEL (sheet, new_range.col0);
4356 y = ROW_TOP_YPIXEL (sheet, new_range.row0);
4357 width = COLUMN_LEFT_XPIXEL (sheet, new_range.coli) - x +
4358 xxx_column_width (sheet, new_range.coli);
4360 height = ROW_TOP_YPIXEL (sheet, new_range.rowi) - y +
4361 yyy_row_height (sheet, new_range.rowi);
4363 area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
4364 area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
4365 area.width = sheet->sheet_window_width;
4366 area.height = sheet->sheet_window_height;
4373 if (width > area.width) width = area.width + 10;
4376 height = height + y;
4379 if (height > area.height) height = area.height + 10;
4381 gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
4383 for (i =- 1; i <= 1; ++i)
4384 gdk_draw_rectangle (sheet->sheet_window,
4392 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
4395 gtk_sheet_draw_corners (sheet, new_range);
4399 gtk_sheet_draw_corners (GtkSheet *sheet, GtkSheetRange range)
4404 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.col0))
4406 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4407 y = ROW_TOP_YPIXEL (sheet, range.row0);
4408 gdk_draw_pixmap (sheet->sheet_window,
4409 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4417 gdk_draw_rectangle (sheet->sheet_window,
4424 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.coli) ||
4425 sheet->state == GTK_SHEET_COLUMN_SELECTED)
4427 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4428 xxx_column_width (sheet, range.coli);
4429 y = ROW_TOP_YPIXEL (sheet, range.row0);
4431 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4433 y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet))+3;
4436 gdk_draw_pixmap (sheet->sheet_window,
4437 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4445 gdk_draw_rectangle (sheet->sheet_window,
4448 x - width + width / 2, y - width + width / 2,
4449 2 + width, 2 + width);
4452 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.col0) ||
4453 sheet->state == GTK_SHEET_ROW_SELECTED)
4455 x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
4456 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4457 yyy_row_height (sheet, range.rowi);
4459 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4461 x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet))+3;
4464 gdk_draw_pixmap (sheet->sheet_window,
4465 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4473 gdk_draw_rectangle (sheet->sheet_window,
4476 x - width + width / 2, y - width + width / 2,
4477 2 + width, 2 + width);
4480 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.coli))
4482 x = COLUMN_LEFT_XPIXEL (sheet, range.coli)+
4483 xxx_column_width (sheet, range.coli);
4484 y = ROW_TOP_YPIXEL (sheet, range.rowi)+
4485 yyy_row_height (sheet, range.rowi);
4487 if (sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4488 if (sheet->state == GTK_SHEET_NORMAL) width = 3;
4489 gdk_draw_pixmap (sheet->sheet_window,
4490 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4498 gdk_draw_rectangle (sheet->sheet_window,
4501 x - width + width / 2, y - width + width / 2,
4502 2 + width, 2 + width);
4510 gtk_sheet_real_select_range (GtkSheet * sheet,
4511 const GtkSheetRange * range)
4515 g_return_if_fail (sheet != NULL);
4517 if (range == NULL) range = &sheet->range;
4519 memcpy (&sheet->range, range, sizeof (*range));
4521 if (range->row0 < 0 || range->rowi < 0) return;
4522 if (range->col0 < 0 || range->coli < 0) return;
4524 state = sheet->state;
4526 if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4527 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4529 gtk_sheet_new_selection (sheet, &sheet->range);
4533 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4534 gtk_sheet_range_draw_selection (sheet, sheet->range);
4537 gtk_sheet_update_primary_selection (sheet);
4539 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_RANGE], 0, &sheet->range);
4544 gtk_sheet_get_selected_range (GtkSheet *sheet,
4545 GtkSheetRange *range)
4547 g_return_if_fail (sheet != NULL);
4548 *range = sheet->range;
4553 gtk_sheet_select_range (GtkSheet * sheet, const GtkSheetRange *range)
4555 g_return_if_fail (sheet != NULL);
4557 if (range == NULL) range=&sheet->range;
4559 if (range->row0 < 0 || range->rowi < 0) return;
4560 if (range->col0 < 0 || range->coli < 0) return;
4563 if ( gtk_sheet_locked (sheet)) return ;
4565 if (sheet->state != GTK_SHEET_NORMAL)
4566 gtk_sheet_real_unselect_range (sheet, NULL);
4569 gboolean veto = TRUE;
4570 veto = gtk_sheet_deactivate_cell (sheet);
4574 sheet->range.row0 = range->row0;
4575 sheet->range.rowi = range->rowi;
4576 sheet->range.col0 = range->col0;
4577 sheet->range.coli = range->coli;
4578 sheet->active_cell.row = range->row0;
4579 sheet->active_cell.col = range->col0;
4580 sheet->selection_cell.row = range->rowi;
4581 sheet->selection_cell.col = range->coli;
4583 sheet->state = GTK_SHEET_RANGE_SELECTED;
4584 gtk_sheet_real_select_range (sheet, NULL);
4589 gtk_sheet_unselect_range (GtkSheet * sheet)
4591 gtk_sheet_real_unselect_range (sheet, NULL);
4592 sheet->state = GTK_STATE_NORMAL;
4594 gtk_sheet_activate_cell (sheet,
4595 sheet->active_cell.row, sheet->active_cell.col);
4600 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4601 const GtkSheetRange *range)
4603 g_return_if_fail (sheet != NULL);
4604 g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
4607 range = &sheet->range;
4609 if (range->row0 < 0 || range->rowi < 0) return;
4610 if (range->col0 < 0 || range->coli < 0) return;
4612 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, -1);
4613 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, -1);
4615 if (gtk_sheet_range_isvisible (sheet, *range))
4616 gtk_sheet_draw_backing_pixmap (sheet, *range);
4618 sheet->range.row0 = -1;
4619 sheet->range.rowi = -1;
4620 sheet->range.col0 = -1;
4621 sheet->range.coli = -1;
4623 gtk_sheet_position_children (sheet);
4628 gtk_sheet_expose (GtkWidget * widget,
4629 GdkEventExpose * event)
4632 GtkSheetRange range;
4634 g_return_val_if_fail (widget != NULL, FALSE);
4635 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4636 g_return_val_if_fail (event != NULL, FALSE);
4639 sheet = GTK_SHEET (widget);
4641 if (GTK_WIDGET_DRAWABLE (widget))
4643 range.row0 = ROW_FROM_YPIXEL (sheet, event->area.y);
4644 range.col0 = COLUMN_FROM_XPIXEL (sheet, event->area.x);
4645 range.rowi = ROW_FROM_YPIXEL (sheet, event->area.y + event->area.height);
4646 range.coli = COLUMN_FROM_XPIXEL (sheet, event->area.x + event->area.width);
4648 /* exposure events on the sheet */
4649 if (event->window == sheet->row_title_window &&
4650 sheet->row_titles_visible)
4653 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
4654 gtk_sheet_row_title_button_draw (sheet, i);
4657 if (event->window == sheet->column_title_window &&
4658 sheet->column_titles_visible)
4661 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
4662 gtk_sheet_column_title_button_draw (sheet, i);
4665 if (event->window == sheet->sheet_window)
4667 gtk_sheet_draw_backing_pixmap (sheet, range);
4669 if (sheet->state != GTK_SHEET_NORMAL)
4671 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4672 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4673 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4674 gtk_sheet_draw_backing_pixmap (sheet, sheet->drag_range);
4676 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4677 gtk_sheet_range_draw_selection (sheet, sheet->range);
4678 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4679 draw_xor_rectangle (sheet, sheet->drag_range);
4682 if ((!GTK_SHEET_IN_XDRAG (sheet)) && (!GTK_SHEET_IN_YDRAG (sheet)))
4684 if (sheet->state == GTK_SHEET_NORMAL)
4686 gtk_sheet_draw_active_cell (sheet);
4687 if (!GTK_SHEET_IN_SELECTION (sheet))
4688 gtk_widget_queue_draw (sheet->sheet_entry);
4694 if (sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
4695 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4697 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4704 gtk_sheet_button_press (GtkWidget * widget,
4705 GdkEventButton * event)
4708 GdkModifierType mods;
4709 gint x, y, row, column;
4712 g_return_val_if_fail (widget != NULL, FALSE);
4713 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4714 g_return_val_if_fail (event != NULL, FALSE);
4716 sheet = GTK_SHEET (widget);
4718 /* Cancel any pending tooltips */
4719 if (sheet->motion_timer)
4721 g_source_remove (sheet->motion_timer);
4722 sheet->motion_timer = 0;
4725 gtk_widget_get_pointer (widget, &x, &y);
4726 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4729 if (event->window == sheet->column_title_window)
4731 g_signal_emit (G_OBJECT (sheet),
4732 sheet_signals[BUTTON_EVENT_COLUMN], 0,
4735 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4736 g_signal_emit (G_OBJECT (sheet),
4737 sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
4740 else if (event->window == sheet->row_title_window)
4742 g_signal_emit (G_OBJECT (sheet),
4743 sheet_signals[BUTTON_EVENT_ROW], 0,
4746 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4747 g_signal_emit (G_OBJECT (sheet),
4748 sheet_signals[DOUBLE_CLICK_ROW], 0, row);
4752 gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
4754 if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
4757 /* press on resize windows */
4758 if (event->window == sheet->column_title_window &&
4759 gtk_sheet_columns_resizable (sheet))
4761 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4762 if (POSSIBLE_XDRAG (sheet, sheet->x_drag, &sheet->drag_cell.col))
4765 if (event->type == GDK_2BUTTON_PRESS)
4767 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4768 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4771 gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
4772 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4773 gdk_pointer_grab (sheet->column_title_window, FALSE,
4774 GDK_POINTER_MOTION_HINT_MASK |
4775 GDK_BUTTON1_MOTION_MASK |
4776 GDK_BUTTON_RELEASE_MASK,
4777 NULL, NULL, event->time);
4779 draw_xor_vline (sheet);
4784 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable (sheet))
4786 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4788 if (POSSIBLE_YDRAG (sheet, sheet->y_drag, &sheet->drag_cell.row))
4791 gtk_sheet_row_size_request (sheet, sheet->drag_cell.row, &req);
4792 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4793 gdk_pointer_grab (sheet->row_title_window, FALSE,
4794 GDK_POINTER_MOTION_HINT_MASK |
4795 GDK_BUTTON1_MOTION_MASK |
4796 GDK_BUTTON_RELEASE_MASK,
4797 NULL, NULL, event->time);
4799 draw_xor_hline (sheet);
4804 /* the sheet itself does not handle other than single click events */
4805 if (event->type != GDK_BUTTON_PRESS) return FALSE;
4807 /* selections on the sheet */
4808 if (event->window == sheet->sheet_window)
4810 gtk_widget_get_pointer (widget, &x, &y);
4811 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4812 gdk_pointer_grab (sheet->sheet_window, FALSE,
4813 GDK_POINTER_MOTION_HINT_MASK |
4814 GDK_BUTTON1_MOTION_MASK |
4815 GDK_BUTTON_RELEASE_MASK,
4816 NULL, NULL, event->time);
4817 gtk_grab_add (GTK_WIDGET (sheet));
4819 /* This seems to be a kludge to work around a problem where the sheet
4820 scrolls to another position. The timeout scrolls it back to its
4821 original posn. JMD 3 July 2007
4823 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4825 if (sheet->selection_mode != GTK_SELECTION_SINGLE &&
4826 sheet->selection_mode != GTK_SELECTION_NONE &&
4827 sheet->cursor_drag->type == GDK_SIZING &&
4828 !GTK_SHEET_IN_SELECTION (sheet) && !GTK_SHEET_IN_RESIZE (sheet))
4830 if (sheet->state == GTK_STATE_NORMAL)
4832 row = sheet->active_cell.row;
4833 column = sheet->active_cell.col;
4834 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4835 sheet->active_cell.row = row;
4836 sheet->active_cell.col = column;
4837 sheet->drag_range = sheet->range;
4838 sheet->state = GTK_SHEET_RANGE_SELECTED;
4839 gtk_sheet_select_range (sheet, &sheet->drag_range);
4843 if (row > sheet->range.rowi) row--;
4844 if (column > sheet->range.coli) column--;
4845 sheet->drag_cell.row = row;
4846 sheet->drag_cell.col = column;
4847 sheet->drag_range = sheet->range;
4848 draw_xor_rectangle (sheet, sheet->drag_range);
4849 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
4851 else if (sheet->cursor_drag->type == GDK_TOP_LEFT_ARROW &&
4852 !GTK_SHEET_IN_SELECTION (sheet)
4853 && ! GTK_SHEET_IN_DRAG (sheet)
4854 && ! gtk_sheet_locked (sheet)
4855 && sheet->active_cell.row >= 0
4856 && sheet->active_cell.col >= 0
4859 if (sheet->state == GTK_STATE_NORMAL)
4861 row = sheet->active_cell.row;
4862 column = sheet->active_cell.col;
4863 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
4864 sheet->active_cell.row = row;
4865 sheet->active_cell.col = column;
4866 sheet->drag_range = sheet->range;
4867 sheet->state = GTK_SHEET_RANGE_SELECTED;
4868 gtk_sheet_select_range (sheet, &sheet->drag_range);
4872 if (row < sheet->range.row0) row++;
4873 if (row > sheet->range.rowi) row--;
4874 if (column < sheet->range.col0) column++;
4875 if (column > sheet->range.coli) column--;
4876 sheet->drag_cell.row = row;
4877 sheet->drag_cell.col = column;
4878 sheet->drag_range = sheet->range;
4879 draw_xor_rectangle (sheet, sheet->drag_range);
4880 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
4884 gtk_sheet_click_cell (sheet, row, column, &veto);
4885 if (veto) GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4889 if (event->window == sheet->column_title_window)
4891 gtk_widget_get_pointer (widget, &x, &y);
4892 column = COLUMN_FROM_XPIXEL (sheet, x);
4894 if (xxx_column_is_sensitive (sheet, column))
4896 gtk_sheet_click_cell (sheet, - 1, column, &veto);
4897 gtk_grab_add (GTK_WIDGET (sheet));
4898 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4899 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4903 if (event->window == sheet->row_title_window)
4905 gtk_widget_get_pointer (widget, &x, &y);
4906 row = ROW_FROM_YPIXEL (sheet, y);
4907 if (yyy_row_is_sensitive (sheet, row))
4909 gtk_sheet_click_cell (sheet, row, - 1, &veto);
4910 gtk_grab_add (GTK_WIDGET (sheet));
4911 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4912 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4921 gtk_sheet_scroll (gpointer data)
4924 gint x, y, row, column;
4927 sheet = GTK_SHEET (data);
4929 GDK_THREADS_ENTER ();
4931 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
4932 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4936 if (GTK_SHEET_IN_SELECTION (sheet))
4937 gtk_sheet_extend_selection (sheet, row, column);
4939 if (GTK_SHEET_IN_DRAG (sheet) || GTK_SHEET_IN_RESIZE (sheet))
4941 move = gtk_sheet_move_query (sheet, row, column);
4942 if (move) draw_xor_rectangle (sheet, sheet->drag_range);
4945 GDK_THREADS_LEAVE ();
4952 gtk_sheet_click_cell (GtkSheet *sheet, gint row, gint column, gboolean *veto)
4956 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
4962 if (column >= 0 && row >= 0)
4963 if (! xxx_column_is_visible (sheet, column) || !yyy_row_is_visible (sheet, row))
4969 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[TRAVERSE],
4970 sheet->active_cell.row, sheet->active_cell.col,
4971 &row, &column, veto);
4975 if (sheet->state == GTK_STATE_NORMAL) return;
4977 row = sheet->active_cell.row;
4978 column = sheet->active_cell.col;
4980 gtk_sheet_activate_cell (sheet, row, column);
4984 if (row == -1 && column >= 0)
4986 if (gtk_sheet_autoscroll (sheet))
4987 gtk_sheet_move_query (sheet, row, column);
4988 gtk_sheet_select_column (sheet, column);
4991 if (column == -1 && row >= 0)
4993 if (gtk_sheet_autoscroll (sheet))
4994 gtk_sheet_move_query (sheet, row, column);
4995 gtk_sheet_select_row (sheet, row);
4999 if (row == - 1 && column == - 1)
5001 sheet->range.row0 = 0;
5002 sheet->range.col0 = 0;
5003 sheet->range.rowi = yyy_row_count (sheet) - 1;
5004 sheet->range.coli = xxx_column_count (sheet) - 1;
5005 sheet->active_cell.row = 0;
5006 sheet->active_cell.col = 0;
5007 gtk_sheet_select_range (sheet, NULL);
5011 if (row != -1 && column != -1)
5013 if (sheet->state != GTK_SHEET_NORMAL)
5015 sheet->state = GTK_SHEET_NORMAL;
5016 gtk_sheet_real_unselect_range (sheet, NULL);
5020 if (!gtk_sheet_deactivate_cell (sheet))
5025 gtk_sheet_activate_cell (sheet, row, column);
5028 if (gtk_sheet_autoscroll (sheet))
5029 gtk_sheet_move_query (sheet, row, column);
5030 sheet->active_cell.row = row;
5031 sheet->active_cell.col = column;
5032 sheet->selection_cell.row = row;
5033 sheet->selection_cell.col = column;
5034 sheet->range.row0 = row;
5035 sheet->range.col0 = column;
5036 sheet->range.rowi = row;
5037 sheet->range.coli = column;
5038 sheet->state = GTK_SHEET_NORMAL;
5039 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5040 gtk_sheet_draw_active_cell (sheet);
5044 g_assert_not_reached ();
5045 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5046 sheet->active_cell.col);
5050 gtk_sheet_button_release (GtkWidget * widget,
5051 GdkEventButton * event)
5056 sheet = GTK_SHEET (widget);
5058 /* release on resize windows */
5059 if (GTK_SHEET_IN_XDRAG (sheet))
5061 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5062 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5063 gtk_widget_get_pointer (widget, &x, NULL);
5064 gdk_pointer_ungrab (event->time);
5065 draw_xor_vline (sheet);
5067 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col,
5068 new_column_width (sheet, sheet->drag_cell.col, &x));
5069 sheet->old_hadjustment = -1.;
5070 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "value_changed");
5074 if (GTK_SHEET_IN_YDRAG (sheet))
5076 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5077 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5078 gtk_widget_get_pointer (widget, NULL, &y);
5079 gdk_pointer_ungrab (event->time);
5080 draw_xor_hline (sheet);
5082 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5083 sheet->old_vadjustment = -1.;
5084 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "value_changed");
5089 if (GTK_SHEET_IN_DRAG (sheet))
5091 GtkSheetRange old_range;
5092 draw_xor_rectangle (sheet, sheet->drag_range);
5093 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
5094 gdk_pointer_ungrab (event->time);
5096 gtk_sheet_real_unselect_range (sheet, NULL);
5098 sheet->active_cell.row = sheet->active_cell.row +
5099 (sheet->drag_range.row0 - sheet->range.row0);
5100 sheet->active_cell.col = sheet->active_cell.col +
5101 (sheet->drag_range.col0 - sheet->range.col0);
5102 sheet->selection_cell.row = sheet->selection_cell.row +
5103 (sheet->drag_range.row0 - sheet->range.row0);
5104 sheet->selection_cell.col = sheet->selection_cell.col +
5105 (sheet->drag_range.col0 - sheet->range.col0);
5106 old_range = sheet->range;
5107 sheet->range = sheet->drag_range;
5108 sheet->drag_range = old_range;
5109 g_signal_emit (G_OBJECT (sheet), sheet_signals[MOVE_RANGE], 0,
5110 &sheet->drag_range, &sheet->range);
5111 gtk_sheet_select_range (sheet, &sheet->range);
5114 if (GTK_SHEET_IN_RESIZE (sheet))
5116 GtkSheetRange old_range;
5117 draw_xor_rectangle (sheet, sheet->drag_range);
5118 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
5119 gdk_pointer_ungrab (event->time);
5121 gtk_sheet_real_unselect_range (sheet, NULL);
5123 sheet->active_cell.row = sheet->active_cell.row +
5124 (sheet->drag_range.row0 - sheet->range.row0);
5125 sheet->active_cell.col = sheet->active_cell.col +
5126 (sheet->drag_range.col0 - sheet->range.col0);
5127 if (sheet->drag_range.row0 < sheet->range.row0)
5128 sheet->selection_cell.row = sheet->drag_range.row0;
5129 if (sheet->drag_range.rowi >= sheet->range.rowi)
5130 sheet->selection_cell.row = sheet->drag_range.rowi;
5131 if (sheet->drag_range.col0 < sheet->range.col0)
5132 sheet->selection_cell.col = sheet->drag_range.col0;
5133 if (sheet->drag_range.coli >= sheet->range.coli)
5134 sheet->selection_cell.col = sheet->drag_range.coli;
5135 old_range = sheet->range;
5136 sheet->range = sheet->drag_range;
5137 sheet->drag_range = old_range;
5139 if (sheet->state == GTK_STATE_NORMAL) sheet->state = GTK_SHEET_RANGE_SELECTED;
5140 g_signal_emit (G_OBJECT (sheet), sheet_signals[RESIZE_RANGE], 0,
5141 &sheet->drag_range, &sheet->range);
5142 gtk_sheet_select_range (sheet, &sheet->range);
5145 if (sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
5147 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5148 gdk_pointer_ungrab (event->time);
5149 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5150 sheet->active_cell.col);
5153 if (GTK_SHEET_IN_SELECTION)
5154 gdk_pointer_ungrab (event->time);
5155 gtk_grab_remove (GTK_WIDGET (sheet));
5157 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5162 /* Shamelessly lifted from gtktooltips */
5164 gtk_sheet_subtitle_paint_window (GtkWidget *tip_window)
5168 gtk_widget_size_request (tip_window, &req);
5169 gtk_paint_flat_box (tip_window->style, tip_window->window,
5170 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
5171 NULL, GTK_WIDGET(tip_window), "tooltip",
5172 0, 0, req.width, req.height);
5177 static GtkSheetHoverTitle *
5178 create_hover_window (void)
5180 GtkSheetHoverTitle *hw = malloc (sizeof (*hw));
5182 hw->window = gtk_window_new (GTK_WINDOW_POPUP);
5184 #if GTK_CHECK_VERSION (2, 9, 0)
5185 gtk_window_set_type_hint (GTK_WINDOW (hw->window),
5186 GDK_WINDOW_TYPE_HINT_TOOLTIP);
5189 gtk_widget_set_app_paintable (hw->window, TRUE);
5190 gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
5191 gtk_widget_set_name (hw->window, "gtk-tooltips");
5192 gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
5194 g_signal_connect (hw->window,
5196 G_CALLBACK (gtk_sheet_subtitle_paint_window),
5199 hw->label = gtk_label_new (NULL);
5202 gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
5203 gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
5205 gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
5207 gtk_widget_show (hw->label);
5209 g_signal_connect (hw->window,
5211 G_CALLBACK (gtk_widget_destroyed),
5217 #define HOVER_WINDOW_Y_OFFSET 2
5220 show_subtitle (GtkSheet *sheet, gint row, gint column, const gchar *subtitle)
5229 if ( ! sheet->hover_window)
5231 sheet->hover_window = create_hover_window ();
5232 gtk_widget_add_events (GTK_WIDGET (sheet), GDK_LEAVE_NOTIFY_MASK);
5234 g_signal_connect_swapped (sheet, "leave-notify-event",
5235 G_CALLBACK (gtk_widget_hide),
5236 sheet->hover_window->window);
5239 gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
5243 sheet->hover_window->row = row;
5244 sheet->hover_window->column = column;
5246 gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
5248 gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
5250 gtk_widget_show (sheet->hover_window->window);
5252 width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
5258 y += sheet->column_title_area.y;
5259 y += sheet->column_title_area.height;
5260 y += HOVER_WINDOW_Y_OFFSET;
5266 x += sheet->row_title_area.x;
5267 x += sheet->row_title_area.width * 2 / 3.0;
5270 gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
5275 motion_timeout_callback (gpointer data)
5277 GtkSheet *sheet = GTK_SHEET (data);
5280 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
5282 if ( gtk_sheet_get_pixel_info (sheet, x, y, &row, &column) )
5284 if ( column == -1 && row == -1 )
5289 GSheetRow *row_geo = sheet->row_geometry;
5292 text = g_sheet_row_get_subtitle (row_geo, row);
5294 show_subtitle (sheet, row, column, text);
5300 GSheetColumn *col_geo = sheet->column_geometry;
5303 text = g_sheet_column_get_subtitle (col_geo, column);
5305 show_subtitle (sheet, row, column, text );
5315 gtk_sheet_motion (GtkWidget * widget,
5316 GdkEventMotion * event)
5319 GdkModifierType mods;
5320 GdkCursorType new_cursor;
5324 g_return_val_if_fail (widget != NULL, FALSE);
5325 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5326 g_return_val_if_fail (event != NULL, FALSE);
5328 sheet = GTK_SHEET (widget);
5330 /* selections on the sheet */
5334 if (!sheet->hover_window || ! GTK_WIDGET_VISIBLE (sheet->hover_window->window))
5336 if ( sheet->motion_timer > 0 )
5337 g_source_remove (sheet->motion_timer);
5338 sheet->motion_timer = g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
5344 gtk_widget_get_pointer (widget, &wx, &wy);
5346 if ( gtk_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
5348 if ( row != sheet->hover_window->row || column != sheet->hover_window->column)
5350 gtk_widget_hide (sheet->hover_window->window);
5355 if (event->window == sheet->column_title_window &&
5356 gtk_sheet_columns_resizable (sheet))
5358 gtk_widget_get_pointer (widget, &x, &y);
5359 if (!GTK_SHEET_IN_SELECTION (sheet) &&
5360 POSSIBLE_XDRAG (sheet, x, &column))
5362 new_cursor = GDK_SB_H_DOUBLE_ARROW;
5363 if (new_cursor != sheet->cursor_drag->type)
5365 gdk_cursor_destroy (sheet->cursor_drag);
5366 sheet->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
5367 gdk_window_set_cursor (sheet->column_title_window,
5368 sheet->cursor_drag);
5373 new_cursor = GDK_TOP_LEFT_ARROW;
5374 if (!GTK_SHEET_IN_XDRAG (sheet) &&
5375 new_cursor != sheet->cursor_drag->type)
5377 gdk_cursor_destroy (sheet->cursor_drag);
5378 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5379 gdk_window_set_cursor (sheet->column_title_window,
5380 sheet->cursor_drag);
5385 if (event->window == sheet->row_title_window &&
5386 gtk_sheet_rows_resizable (sheet))
5388 gtk_widget_get_pointer (widget, &x, &y);
5389 if (!GTK_SHEET_IN_SELECTION (sheet) && POSSIBLE_YDRAG (sheet, y, &column))
5391 new_cursor = GDK_SB_V_DOUBLE_ARROW;
5392 if (new_cursor != sheet->cursor_drag->type)
5394 gdk_cursor_destroy (sheet->cursor_drag);
5395 sheet->cursor_drag = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
5396 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5401 new_cursor = GDK_TOP_LEFT_ARROW;
5402 if (!GTK_SHEET_IN_YDRAG (sheet) &&
5403 new_cursor != sheet->cursor_drag->type)
5405 gdk_cursor_destroy (sheet->cursor_drag);
5406 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5407 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5412 new_cursor = GDK_PLUS;
5413 if ( event->window == sheet->sheet_window &&
5414 !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
5415 !GTK_SHEET_IN_DRAG (sheet) &&
5416 !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
5417 !GTK_SHEET_IN_RESIZE (sheet) &&
5418 new_cursor != sheet->cursor_drag->type)
5420 gdk_cursor_destroy (sheet->cursor_drag);
5421 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
5422 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5425 new_cursor = GDK_TOP_LEFT_ARROW;
5426 if ( event->window == sheet->sheet_window &&
5427 ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) || GTK_SHEET_IN_RESIZE (sheet)) && (POSSIBLE_DRAG (sheet, x, y, &row, &column) || GTK_SHEET_IN_DRAG (sheet)) &&
5429 new_cursor != sheet->cursor_drag->type)
5431 gdk_cursor_destroy (sheet->cursor_drag);
5432 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5433 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5436 new_cursor = GDK_SIZING;
5437 if ( event->window == sheet->sheet_window &&
5438 sheet->selection_mode != GTK_SELECTION_NONE &&
5439 !GTK_SHEET_IN_DRAG (sheet) &&
5440 (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
5441 GTK_SHEET_IN_RESIZE (sheet)) &&
5442 new_cursor != sheet->cursor_drag->type)
5444 gdk_cursor_destroy (sheet->cursor_drag);
5445 sheet->cursor_drag = gdk_cursor_new (GDK_SIZING);
5446 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5450 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5451 if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
5453 if (GTK_SHEET_IN_XDRAG (sheet))
5455 if (event->is_hint || event->window != widget->window)
5456 gtk_widget_get_pointer (widget, &x, NULL);
5460 new_column_width (sheet, sheet->drag_cell.col, &x);
5461 if (x != sheet->x_drag)
5463 draw_xor_vline (sheet);
5465 draw_xor_vline (sheet);
5470 if (GTK_SHEET_IN_YDRAG (sheet))
5472 if (event->is_hint || event->window != widget->window)
5473 gtk_widget_get_pointer (widget, NULL, &y);
5477 new_row_height (sheet, sheet->drag_cell.row, &y);
5478 if (y != sheet->y_drag)
5480 draw_xor_hline (sheet);
5482 draw_xor_hline (sheet);
5487 if (GTK_SHEET_IN_DRAG (sheet))
5490 column = COLUMN_FROM_XPIXEL (sheet, x)- sheet->drag_cell.col;
5491 row = ROW_FROM_YPIXEL (sheet, y)- sheet->drag_cell.row;
5492 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5493 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5497 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5498 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5500 aux = sheet->drag_range;
5501 sheet->drag_range.row0 = sheet->range.row0 + row;
5502 sheet->drag_range.col0 = sheet->range.col0 + column;
5503 sheet->drag_range.rowi = sheet->range.rowi + row;
5504 sheet->drag_range.coli = sheet->range.coli + column;
5505 if (aux.row0 != sheet->drag_range.row0 ||
5506 aux.col0 != sheet->drag_range.col0)
5508 draw_xor_rectangle (sheet, aux);
5509 draw_xor_rectangle (sheet, sheet->drag_range);
5515 if (GTK_SHEET_IN_RESIZE (sheet))
5518 gint v_h, current_col, current_row, col_threshold, row_threshold;
5521 if (abs (x - COLUMN_LEFT_XPIXEL (sheet, sheet->drag_cell.col)) >
5522 abs (y - ROW_TOP_YPIXEL (sheet, sheet->drag_cell.row))) v_h = 2;
5524 current_col = COLUMN_FROM_XPIXEL (sheet, x);
5525 current_row = ROW_FROM_YPIXEL (sheet, y);
5526 column = current_col - sheet->drag_cell.col;
5527 row = current_row - sheet->drag_cell.row;
5529 /*use half of column width resp. row height as threshold to
5531 col_threshold = COLUMN_LEFT_XPIXEL (sheet, current_col) +
5532 xxx_column_width (sheet, current_col) / 2;
5535 if (x < col_threshold)
5538 else if (column < 0)
5540 if (x > col_threshold)
5543 row_threshold = ROW_TOP_YPIXEL (sheet, current_row) +
5544 yyy_row_height (sheet, current_row)/2;
5547 if (y < row_threshold)
5552 if (y > row_threshold)
5556 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5557 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5567 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5568 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5570 aux = sheet->drag_range;
5571 sheet->drag_range = sheet->range;
5573 if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
5574 if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
5575 if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
5576 if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
5578 if (aux.row0 != sheet->drag_range.row0 ||
5579 aux.rowi != sheet->drag_range.rowi ||
5580 aux.col0 != sheet->drag_range.col0 ||
5581 aux.coli != sheet->drag_range.coli)
5583 draw_xor_rectangle (sheet, aux);
5584 draw_xor_rectangle (sheet, sheet->drag_range);
5590 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5592 if (sheet->state == GTK_SHEET_NORMAL && row == sheet->active_cell.row &&
5593 column == sheet->active_cell.col) return TRUE;
5595 if (GTK_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
5596 gtk_sheet_extend_selection (sheet, row, column);
5602 gtk_sheet_move_query (GtkSheet *sheet, gint row, gint column)
5604 gint row_move, column_move;
5605 gfloat row_align, col_align;
5606 guint height, width;
5608 gint new_col = column;
5611 column_move = FALSE;
5615 height = sheet->sheet_window_height;
5616 width = sheet->sheet_window_width;
5618 if (row >= MAX_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5621 new_row = MIN (yyy_row_count (sheet), row + 1);
5623 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet) - 1 &&
5624 ROW_TOP_YPIXEL (sheet, yyy_row_count (sheet)- 1) +
5625 yyy_row_height (sheet, yyy_row_count (sheet)- 1) < height)
5631 if (row < MIN_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5636 if (column >= MAX_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5639 new_col = MIN (xxx_column_count (sheet) - 1, column + 1);
5641 if (MAX_VISIBLE_COLUMN (sheet) == (xxx_column_count (sheet) - 1) &&
5642 COLUMN_LEFT_XPIXEL (sheet, xxx_column_count (sheet) - 1) +
5643 xxx_column_width (sheet, xxx_column_count (sheet) - 1) < width)
5645 column_move = FALSE;
5649 if (column < MIN_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5655 if (row_move || column_move)
5657 gtk_sheet_moveto (sheet, new_row, new_col, row_align, col_align);
5660 return (row_move || column_move);
5664 gtk_sheet_extend_selection (GtkSheet *sheet, gint row, gint column)
5666 GtkSheetRange range;
5670 if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5673 if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5675 gtk_sheet_move_query (sheet, row, column);
5676 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5678 if (GTK_SHEET_IN_DRAG (sheet)) return;
5680 state = sheet->state;
5682 switch (sheet->state)
5684 case GTK_SHEET_ROW_SELECTED:
5685 column = xxx_column_count (sheet) - 1;
5687 case GTK_SHEET_COLUMN_SELECTED:
5688 row = yyy_row_count (sheet) - 1;
5690 case GTK_SHEET_NORMAL:
5691 sheet->state = GTK_SHEET_RANGE_SELECTED;
5692 r = sheet->active_cell.row;
5693 c = sheet->active_cell.col;
5694 sheet->range.col0 = c;
5695 sheet->range.row0 = r;
5696 sheet->range.coli = c;
5697 sheet->range.rowi = r;
5698 gdk_draw_pixmap (sheet->sheet_window,
5699 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
5701 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5702 ROW_TOP_YPIXEL (sheet, r)- 1,
5703 COLUMN_LEFT_XPIXEL (sheet, c)- 1,
5704 ROW_TOP_YPIXEL (sheet, r)- 1,
5705 xxx_column_width (sheet, c)+4,
5706 yyy_row_height (sheet, r)+4);
5707 gtk_sheet_range_draw_selection (sheet, sheet->range);
5708 case GTK_SHEET_RANGE_SELECTED:
5709 sheet->state = GTK_SHEET_RANGE_SELECTED;
5712 sheet->selection_cell.row = row;
5713 sheet->selection_cell.col = column;
5715 range.col0 = MIN (column, sheet->active_cell.col);
5716 range.coli = MAX (column, sheet->active_cell.col);
5717 range.row0 = MIN (row, sheet->active_cell.row);
5718 range.rowi = MAX (row, sheet->active_cell.row);
5720 if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5721 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5722 state == GTK_SHEET_NORMAL)
5723 gtk_sheet_real_select_range (sheet, &range);
5728 gtk_sheet_entry_key_press (GtkWidget *widget,
5732 g_signal_emit_by_name (G_OBJECT (widget), "key_press_event", key, &focus);
5737 gtk_sheet_key_press (GtkWidget *widget,
5743 gboolean extend_selection = FALSE;
5744 gboolean force_move = FALSE;
5745 gboolean in_selection = FALSE;
5746 gboolean veto = TRUE;
5749 sheet = GTK_SHEET (widget);
5751 if (key->state & GDK_CONTROL_MASK || key->keyval == GDK_Control_L ||
5752 key->keyval == GDK_Control_R) return FALSE;
5754 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval == GDK_Shift_L
5755 || key->keyval == GDK_Shift_R;
5757 state = sheet->state;
5758 in_selection = GTK_SHEET_IN_SELECTION (sheet);
5759 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5761 switch (key->keyval)
5763 case GDK_Return: case GDK_KP_Enter:
5764 if (sheet->state == GTK_SHEET_NORMAL &&
5765 !GTK_SHEET_IN_SELECTION (sheet))
5766 g_signal_stop_emission_by_name (gtk_sheet_get_entry (sheet),
5768 row = sheet->active_cell.row;
5769 col = sheet->active_cell.col;
5770 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5771 row = MIN_VISIBLE_ROW (sheet)- 1;
5772 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5773 col = MIN_VISIBLE_COLUMN (sheet);
5774 if (row < yyy_row_count (sheet) - 1)
5777 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1)
5780 gtk_sheet_click_cell (sheet, row, col, &veto);
5781 extend_selection = FALSE;
5783 case GDK_ISO_Left_Tab:
5784 row = sheet->active_cell.row;
5785 col = sheet->active_cell.col;
5786 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5787 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5788 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5789 row = MIN_VISIBLE_ROW (sheet);
5793 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5796 gtk_sheet_click_cell (sheet, row, col, &veto);
5797 extend_selection = FALSE;
5800 row = sheet->active_cell.row;
5801 col = sheet->active_cell.col;
5802 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5803 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5804 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5805 row = MIN_VISIBLE_ROW (sheet);
5806 if (col < xxx_column_count (sheet) - 1)
5809 while (! xxx_column_is_visible (sheet, col) &&
5810 col < xxx_column_count (sheet) - 1)
5813 gtk_sheet_click_cell (sheet, row, col, &veto);
5814 extend_selection = FALSE;
5817 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5819 if (extend_selection)
5821 if (state == GTK_STATE_NORMAL)
5823 row = sheet->active_cell.row;
5824 col = sheet->active_cell.col;
5825 gtk_sheet_click_cell (sheet, row, col, &veto);
5828 if (sheet->selection_cell.row > 0)
5830 row = sheet->selection_cell.row - scroll;
5831 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5833 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5837 col = sheet->active_cell.col;
5838 row = sheet->active_cell.row;
5839 if (state == GTK_SHEET_COLUMN_SELECTED)
5840 row = MIN_VISIBLE_ROW (sheet);
5841 if (state == GTK_SHEET_ROW_SELECTED)
5842 col = MIN_VISIBLE_COLUMN (sheet);
5844 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5846 gtk_sheet_click_cell (sheet, row, col, &veto);
5847 extend_selection = FALSE;
5850 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
5852 if (extend_selection)
5854 if (state == GTK_STATE_NORMAL)
5856 row = sheet->active_cell.row;
5857 col = sheet->active_cell.col;
5858 gtk_sheet_click_cell (sheet, row, col, &veto);
5861 if (sheet->selection_cell.row < yyy_row_count (sheet)- 1)
5863 row = sheet->selection_cell.row + scroll;
5864 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5865 row = MIN (yyy_row_count (sheet)- 1, row);
5866 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
5870 col = sheet->active_cell.col;
5871 row = sheet->active_cell.row;
5872 if (sheet->active_cell.row < yyy_row_count (sheet)- 1)
5874 if (state == GTK_SHEET_COLUMN_SELECTED)
5875 row = MIN_VISIBLE_ROW (sheet)- 1;
5876 if (state == GTK_SHEET_ROW_SELECTED)
5877 col = MIN_VISIBLE_COLUMN (sheet);
5879 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5880 row = MIN (yyy_row_count (sheet)- 1, row);
5882 gtk_sheet_click_cell (sheet, row, col, &veto);
5883 extend_selection = FALSE;
5886 if (extend_selection)
5888 if (state == GTK_STATE_NORMAL)
5890 row = sheet->active_cell.row;
5891 col = sheet->active_cell.col;
5892 gtk_sheet_click_cell (sheet, row, col, &veto);
5895 if (sheet->selection_cell.col < xxx_column_count (sheet) - 1)
5897 col = sheet->selection_cell.col + 1;
5898 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1)
5900 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5904 col = sheet->active_cell.col;
5905 row = sheet->active_cell.row;
5906 if (sheet->active_cell.col < xxx_column_count (sheet) - 1)
5909 if (state == GTK_SHEET_ROW_SELECTED)
5910 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5911 if (state == GTK_SHEET_COLUMN_SELECTED)
5912 row = MIN_VISIBLE_ROW (sheet);
5913 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1) col++;
5914 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5917 gtk_sheet_click_cell (sheet, row, col, &veto);
5922 extend_selection = FALSE;
5925 if (extend_selection)
5927 if (state == GTK_STATE_NORMAL)
5929 row = sheet->active_cell.row;
5930 col = sheet->active_cell.col;
5931 gtk_sheet_click_cell (sheet, row, col, &veto);
5934 if (sheet->selection_cell.col > 0)
5936 col = sheet->selection_cell.col - 1;
5937 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5938 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
5942 col = sheet->active_cell.col - 1;
5943 row = sheet->active_cell.row;
5944 if (state == GTK_SHEET_ROW_SELECTED)
5945 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5946 if (state == GTK_SHEET_COLUMN_SELECTED)
5947 row = MIN_VISIBLE_ROW (sheet);
5948 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
5951 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
5954 gtk_sheet_click_cell (sheet, row, col, &veto);
5958 extend_selection = FALSE;
5962 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
5963 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5964 extend_selection = FALSE;
5967 row = yyy_row_count (sheet)- 1;
5968 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
5969 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
5970 extend_selection = FALSE;
5975 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5976 if (extend_selection) return TRUE;
5978 if (state == GTK_SHEET_ROW_SELECTED)
5979 sheet->active_cell.col = MIN_VISIBLE_COLUMN (sheet);
5980 if (state == GTK_SHEET_COLUMN_SELECTED)
5981 sheet->active_cell.row = MIN_VISIBLE_ROW (sheet);
5985 if (extend_selection) return TRUE;
5987 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5988 sheet->active_cell.col);
5994 gtk_sheet_size_request (GtkWidget * widget,
5995 GtkRequisition * requisition)
5999 GtkSheetChild *child;
6000 GtkRequisition child_requisition;
6002 g_return_if_fail (widget != NULL);
6003 g_return_if_fail (GTK_IS_SHEET (widget));
6004 g_return_if_fail (requisition != NULL);
6006 sheet = GTK_SHEET (widget);
6008 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
6009 requisition->height = 3*DEFAULT_ROW_HEIGHT (widget);
6011 /* compute the size of the column title area */
6012 if (sheet->column_titles_visible)
6013 requisition->height += sheet->column_title_area.height;
6015 /* compute the size of the row title area */
6016 if (sheet->row_titles_visible)
6017 requisition->width += sheet->row_title_area.width;
6019 children = sheet->children;
6022 child = children->data;
6023 children = children->next;
6025 gtk_widget_size_request (child->widget, &child_requisition);
6031 gtk_sheet_size_allocate (GtkWidget * widget,
6032 GtkAllocation * allocation)
6035 GtkAllocation sheet_allocation;
6038 g_return_if_fail (widget != NULL);
6039 g_return_if_fail (GTK_IS_SHEET (widget));
6040 g_return_if_fail (allocation != NULL);
6042 sheet = GTK_SHEET (widget);
6043 widget->allocation = *allocation;
6044 border_width = GTK_CONTAINER (widget)->border_width;
6046 if (GTK_WIDGET_REALIZED (widget))
6047 gdk_window_move_resize (widget->window,
6048 allocation->x + border_width,
6049 allocation->y + border_width,
6050 allocation->width - 2 * border_width,
6051 allocation->height - 2 * border_width);
6053 /* use internal allocation structure for all the math
6054 * because it's easier than always subtracting the container
6056 sheet->internal_allocation.x = 0;
6057 sheet->internal_allocation.y = 0;
6058 sheet->internal_allocation.width = allocation->width - 2 * border_width;
6059 sheet->internal_allocation.height = allocation->height - 2 * border_width;
6061 sheet_allocation.x = 0;
6062 sheet_allocation.y = 0;
6063 sheet_allocation.width = allocation->width - 2 * border_width;
6064 sheet_allocation.height = allocation->height - 2 * border_width;
6066 sheet->sheet_window_width = sheet_allocation.width;
6067 sheet->sheet_window_height = sheet_allocation.height;
6069 if (GTK_WIDGET_REALIZED (widget))
6070 gdk_window_move_resize (sheet->sheet_window,
6073 sheet_allocation.width,
6074 sheet_allocation.height);
6076 /* position the window which holds the column title buttons */
6077 sheet->column_title_area.x = 0;
6078 sheet->column_title_area.y = 0;
6079 if (sheet->row_titles_visible)
6080 sheet->column_title_area.x = sheet->row_title_area.width;
6081 sheet->column_title_area.width = sheet_allocation.width -
6082 sheet->column_title_area.x;
6083 if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
6084 gdk_window_move_resize (sheet->column_title_window,
6085 sheet->column_title_area.x,
6086 sheet->column_title_area.y,
6087 sheet->column_title_area.width,
6088 sheet->column_title_area.height);
6090 sheet->sheet_window_width = sheet_allocation.width;
6091 sheet->sheet_window_height = sheet_allocation.height;
6093 /* column button allocation */
6094 size_allocate_column_title_buttons (sheet);
6096 /* position the window which holds the row title buttons */
6097 sheet->row_title_area.x = 0;
6098 sheet->row_title_area.y = 0;
6099 if (sheet->column_titles_visible)
6100 sheet->row_title_area.y = sheet->column_title_area.height;
6101 sheet->row_title_area.height = sheet_allocation.height -
6102 sheet->row_title_area.y;
6104 if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
6105 gdk_window_move_resize (sheet->row_title_window,
6106 sheet->row_title_area.x,
6107 sheet->row_title_area.y,
6108 sheet->row_title_area.width,
6109 sheet->row_title_area.height);
6112 /* row button allocation */
6113 size_allocate_row_title_buttons (sheet);
6114 size_allocate_column_title_buttons (sheet);
6116 /* re - scale backing pixmap */
6117 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
6118 gtk_sheet_position_children (sheet);
6120 /* set the scrollbars adjustments */
6121 adjust_scrollbars (sheet);
6125 size_allocate_column_title_buttons (GtkSheet * sheet)
6130 if (!sheet->column_titles_visible) return;
6131 if (!GTK_WIDGET_REALIZED (sheet))
6134 width = sheet->sheet_window_width;
6137 if (sheet->row_titles_visible)
6139 width -= sheet->row_title_area.width;
6140 x = sheet->row_title_area.width;
6143 if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6145 sheet->column_title_area.width = width;
6146 sheet->column_title_area.x = x;
6147 gdk_window_move_resize (sheet->column_title_window,
6148 sheet->column_title_area.x,
6149 sheet->column_title_area.y,
6150 sheet->column_title_area.width,
6151 sheet->column_title_area.height);
6155 if (MAX_VISIBLE_COLUMN (sheet) == xxx_column_count (sheet) - 1)
6156 gdk_window_clear_area (sheet->column_title_window,
6158 sheet->column_title_area.width,
6159 sheet->column_title_area.height);
6161 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6163 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
6164 gtk_sheet_column_title_button_draw (sheet, i);
6168 size_allocate_row_title_buttons (GtkSheet * sheet)
6173 if (!sheet->row_titles_visible) return;
6174 if (!GTK_WIDGET_REALIZED (sheet))
6177 height = sheet->sheet_window_height;
6180 if (sheet->column_titles_visible)
6182 height -= sheet->column_title_area.height;
6183 y = sheet->column_title_area.height;
6186 if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6188 sheet->row_title_area.y = y;
6189 sheet->row_title_area.height = height;
6190 gdk_window_move_resize (sheet->row_title_window,
6191 sheet->row_title_area.x,
6192 sheet->row_title_area.y,
6193 sheet->row_title_area.width,
6194 sheet->row_title_area.height);
6196 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet)- 1)
6197 gdk_window_clear_area (sheet->row_title_window,
6199 sheet->row_title_area.width,
6200 sheet->row_title_area.height);
6202 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6204 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
6206 if ( i >= yyy_row_count (sheet))
6208 gtk_sheet_row_title_button_draw (sheet, i);
6214 gtk_sheet_size_allocate_entry (GtkSheet *sheet)
6216 GtkAllocation shentry_allocation;
6217 GtkSheetCellAttr attributes = { 0 };
6218 GtkEntry *sheet_entry;
6219 GtkStyle *style = NULL, *previous_style = NULL;
6221 gint size, max_size, text_size, column_width;
6224 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6225 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
6227 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
6229 if ( ! gtk_sheet_get_attributes (sheet, sheet->active_cell.row,
6230 sheet->active_cell.col,
6234 if ( GTK_WIDGET_REALIZED (sheet->sheet_entry) )
6236 if (!GTK_WIDGET (sheet_entry)->style)
6237 gtk_widget_ensure_style (GTK_WIDGET (sheet_entry));
6239 previous_style = GTK_WIDGET (sheet_entry)->style;
6241 style = gtk_style_copy (previous_style);
6242 style->bg[GTK_STATE_NORMAL] = attributes.background;
6243 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6244 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6245 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6246 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6247 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6249 pango_font_description_free (style->font_desc);
6250 g_assert (attributes.font_desc);
6251 style->font_desc = pango_font_description_copy (attributes.font_desc);
6253 GTK_WIDGET (sheet_entry)->style = style;
6254 gtk_widget_size_request (sheet->sheet_entry, NULL);
6255 GTK_WIDGET (sheet_entry)->style = previous_style;
6257 if (style != previous_style)
6259 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6261 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6262 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6263 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6264 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6266 gtk_widget_set_style (GTK_WIDGET (sheet_entry), style);
6267 g_object_unref (style);
6271 if (GTK_IS_ITEM_ENTRY (sheet_entry))
6272 max_size = GTK_ITEM_ENTRY (sheet_entry)->text_max_size;
6277 text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
6278 if (text && strlen (text) > 0)
6279 text_size = STRING_WIDTH (GTK_WIDGET (sheet), attributes.font_desc, text);
6281 column_width = xxx_column_width (sheet, sheet->active_cell.col);
6283 size = MIN (text_size, max_size);
6284 size = MAX (size, column_width - 2 * CELLOFFSET);
6286 row = sheet->active_cell.row;
6287 col = sheet->active_cell.col;
6289 shentry_allocation.x = COLUMN_LEFT_XPIXEL (sheet, sheet->active_cell.col);
6290 shentry_allocation.y = ROW_TOP_YPIXEL (sheet, sheet->active_cell.row);
6291 shentry_allocation.width = column_width;
6292 shentry_allocation.height = yyy_row_height (sheet, sheet->active_cell.row);
6294 if (GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6296 shentry_allocation.height -= 2 * CELLOFFSET;
6297 shentry_allocation.y += CELLOFFSET;
6298 shentry_allocation.width = size;
6300 switch (GTK_ITEM_ENTRY (sheet_entry)->justification)
6302 case GTK_JUSTIFY_CENTER:
6303 shentry_allocation.x += column_width / 2 - size / 2;
6305 case GTK_JUSTIFY_RIGHT:
6306 shentry_allocation.x += column_width - size - CELLOFFSET;
6308 case GTK_JUSTIFY_LEFT:
6309 case GTK_JUSTIFY_FILL:
6310 shentry_allocation.x += CELLOFFSET;
6315 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6317 shentry_allocation.x += 2;
6318 shentry_allocation.y += 2;
6319 shentry_allocation.width -= MIN (shentry_allocation.width, 3);
6320 shentry_allocation.height -= MIN (shentry_allocation.height, 3);
6323 gtk_widget_size_allocate (sheet->sheet_entry, &shentry_allocation);
6325 if (previous_style == style) g_object_unref (previous_style);
6329 gtk_sheet_entry_set_max_size (GtkSheet *sheet)
6333 gint sizel = 0, sizer = 0;
6335 GtkJustification justification;
6338 row = sheet->active_cell.row;
6339 col = sheet->active_cell.col;
6341 if ( ! GTK_IS_ITEM_ENTRY (sheet->sheet_entry) )
6344 justification = GTK_ITEM_ENTRY (sheet->sheet_entry)->justification;
6346 switch (justification)
6348 case GTK_JUSTIFY_FILL:
6349 case GTK_JUSTIFY_LEFT:
6350 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6352 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6357 size +=xxx_column_width (sheet, i);
6359 size = MIN (size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL (sheet, col));
6361 case GTK_JUSTIFY_RIGHT:
6362 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6364 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6369 size +=xxx_column_width (sheet, i);
6372 case GTK_JUSTIFY_CENTER:
6373 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6375 sizer += xxx_column_width (sheet, i);
6377 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6379 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6384 sizel +=xxx_column_width (sheet, i);
6386 size = 2 * MIN (sizel, sizer);
6391 size += xxx_column_width (sheet, col);
6392 GTK_ITEM_ENTRY (sheet->sheet_entry)->text_max_size = size;
6397 create_sheet_entry (GtkSheet *sheet)
6402 gint found_entry = FALSE;
6404 widget = GTK_WIDGET (sheet);
6406 if (sheet->sheet_entry)
6408 /* avoids warnings */
6409 gtk_widget_ref (sheet->sheet_entry);
6410 gtk_widget_unparent (sheet->sheet_entry);
6411 gtk_widget_destroy (sheet->sheet_entry);
6414 if (sheet->entry_type)
6416 if (!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY))
6418 parent = g_object_new (sheet->entry_type, NULL);
6420 sheet->sheet_entry = parent;
6422 entry = gtk_sheet_get_entry (sheet);
6423 if (GTK_IS_ENTRY (entry))
6428 parent = g_object_new (sheet->entry_type, NULL);
6435 g_warning ("Entry type must be GtkEntry subclass, using default");
6436 entry = gtk_item_entry_new ();
6437 sheet->sheet_entry = entry;
6440 sheet->sheet_entry = parent;
6444 entry = gtk_item_entry_new ();
6445 sheet->sheet_entry = entry;
6448 gtk_widget_size_request (sheet->sheet_entry, NULL);
6450 if (GTK_WIDGET_REALIZED (sheet))
6452 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6453 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
6454 gtk_widget_realize (sheet->sheet_entry);
6457 g_signal_connect_swapped (G_OBJECT (entry), "key_press_event",
6458 G_CALLBACK (gtk_sheet_entry_key_press),
6461 gtk_widget_show (sheet->sheet_entry);
6465 /* Finds the last child widget that happens to be of type GtkEntry */
6467 find_entry (GtkWidget *w, gpointer user_data)
6469 GtkWidget **entry = user_data;
6470 if ( GTK_IS_ENTRY (w))
6477 gtk_sheet_get_entry (GtkSheet *sheet)
6480 GtkWidget *entry = NULL;
6481 GtkTableChild *table_child;
6482 GtkBoxChild *box_child;
6483 GList *children = NULL;
6485 g_return_val_if_fail (sheet != NULL, NULL);
6486 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6487 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6489 if (GTK_IS_ENTRY (sheet->sheet_entry)) return (sheet->sheet_entry);
6491 parent = GTK_WIDGET (sheet->sheet_entry);
6493 if (GTK_IS_TABLE (parent)) children = GTK_TABLE (parent)->children;
6494 if (GTK_IS_BOX (parent)) children = GTK_BOX (parent)->children;
6496 if (GTK_IS_CONTAINER (parent))
6498 gtk_container_forall (GTK_CONTAINER (parent), find_entry, &entry);
6500 if (GTK_IS_ENTRY (entry))
6504 if (!children) return NULL;
6508 if (GTK_IS_TABLE (parent))
6510 table_child = children->data;
6511 entry = table_child->widget;
6513 if (GTK_IS_BOX (parent))
6515 box_child = children->data;
6516 entry = box_child->widget;
6519 if (GTK_IS_ENTRY (entry))
6521 children = children->next;
6525 if (!GTK_IS_ENTRY (entry)) return NULL;
6532 gtk_sheet_get_entry_widget (GtkSheet *sheet)
6534 g_return_val_if_fail (sheet != NULL, NULL);
6535 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6536 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6538 return (sheet->sheet_entry);
6543 gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
6544 GtkSheetButton *button, gboolean is_sensitive,
6545 GdkRectangle allocation)
6547 GtkShadowType shadow_type;
6548 gint text_width = 0, text_height = 0;
6549 GtkSheetChild *child = NULL;
6550 PangoAlignment align = PANGO_ALIGN_LEFT;
6558 g_return_if_fail (sheet != NULL);
6559 g_return_if_fail (button != NULL);
6561 rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
6563 gdk_window_clear_area (window,
6564 allocation.x, allocation.y,
6565 allocation.width, allocation.height);
6567 gtk_paint_box (sheet->button->style, window,
6568 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6569 &allocation, GTK_WIDGET (sheet->button),
6571 allocation.x, allocation.y,
6572 allocation.width, allocation.height);
6574 state = button->state;
6575 if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
6577 if (state == GTK_STATE_ACTIVE)
6578 shadow_type = GTK_SHADOW_IN;
6580 shadow_type = GTK_SHADOW_OUT;
6582 if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6583 gtk_paint_box (sheet->button->style, window,
6584 button->state, shadow_type,
6585 &allocation, GTK_WIDGET (sheet->button),
6587 allocation.x, allocation.y,
6588 allocation.width, allocation.height);
6590 if (button->label_visible)
6593 text_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))- 2 * CELLOFFSET;
6595 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6597 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, &allocation);
6599 allocation.y += 2 * sheet->button->style->ythickness;
6602 if (button->label && strlen (button->label)>0)
6605 PangoLayout *layout = NULL;
6606 gint real_x = allocation.x, real_y = allocation.y;
6608 words = button->label;
6609 line = g_new (gchar, 1);
6612 while (words && *words != '\0')
6616 len = strlen (line);
6617 line = g_realloc (line, len + 2);
6621 if (*words == '\n' || * (words + 1) == '\0')
6623 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
6625 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
6626 switch (button->justification)
6628 case GTK_JUSTIFY_LEFT:
6629 real_x = allocation.x + CELLOFFSET;
6630 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6632 case GTK_JUSTIFY_RIGHT:
6633 real_x = allocation.x + allocation.width - text_width - CELLOFFSET;
6634 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6636 case GTK_JUSTIFY_CENTER:
6638 real_x = allocation.x + (allocation.width - text_width)/2;
6639 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6640 pango_layout_set_justify (layout, TRUE);
6642 pango_layout_set_alignment (layout, align);
6643 gtk_paint_layout (GTK_WIDGET (sheet)->style,
6652 g_object_unref (G_OBJECT (layout));
6654 real_y += text_height + 2;
6657 line = g_new (gchar, 1);
6665 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6667 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
6671 if ((child = button->child) && (child->widget))
6673 child->x = allocation.x;
6674 child->y = allocation.y;
6676 child->x += (allocation.width - child->widget->requisition.width) / 2;
6677 child->y += (allocation.height - child->widget->requisition.height) / 2;
6678 allocation.x = child->x;
6679 allocation.y = child->y;
6680 allocation.width = child->widget->requisition.width;
6681 allocation.height = child->widget->requisition.height;
6683 allocation.x = child->x;
6684 allocation.y = child->y;
6686 gtk_widget_set_state (child->widget, button->state);
6688 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
6689 GTK_WIDGET_MAPPED (child->widget))
6691 gtk_widget_size_allocate (child->widget,
6693 gtk_widget_queue_draw (child->widget);
6697 gtk_sheet_button_free (button);
6701 /* COLUMN value of - 1 indicates that the area to the right of the rightmost
6702 button should be redrawn */
6704 gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
6706 GdkWindow *window = NULL;
6707 GdkRectangle allocation;
6709 gboolean is_sensitive = FALSE;
6711 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6713 if (column >= 0 && ! xxx_column_is_visible (sheet, column)) return;
6714 if (column >= 0 && !sheet->column_titles_visible) return;
6715 if (column >= 0 && column < MIN_VISIBLE_COLUMN (sheet)) return;
6716 if (column >= 0 && column > MAX_VISIBLE_COLUMN (sheet)) return;
6718 window = sheet->column_title_window;
6720 allocation.height = sheet->column_title_area.height;
6724 const gint cols = xxx_column_count (sheet) ;
6725 allocation.x = COLUMN_LEFT_XPIXEL (sheet, cols - 1)
6727 allocation.width = sheet->column_title_area.width
6728 + sheet->column_title_area.x
6731 gdk_window_clear_area (window,
6732 allocation.x, allocation.y,
6733 allocation.width, allocation.height);
6737 GtkSheetButton *button = xxx_column_button (sheet, column);
6738 allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
6739 if (sheet->row_titles_visible)
6740 allocation.x -= sheet->row_title_area.width;
6742 allocation.width = xxx_column_width (sheet, column);
6744 is_sensitive = xxx_column_is_sensitive (sheet, column);
6745 gtk_sheet_button_draw (sheet, window, button,
6746 is_sensitive, allocation);
6748 /* FIXME: Not freeing this button is correct (sort of),
6749 because in PSPP the model always returns a static copy */
6751 /* gtk_sheet_button_free (button); */
6757 gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
6759 GdkWindow *window = NULL;
6760 GdkRectangle allocation;
6761 GtkSheetButton *button = NULL;
6762 gboolean is_sensitive = FALSE;
6765 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6767 if (row >= 0 && !yyy_row_is_visible (sheet, row)) return;
6768 if (row >= 0 && !sheet->row_titles_visible) return;
6769 if (row >= 0 && row < MIN_VISIBLE_ROW (sheet)) return;
6770 if (row >= 0 && row > MAX_VISIBLE_ROW (sheet)) return;
6773 window = sheet->row_title_window;
6774 button = yyy_row_button (sheet, row);
6776 allocation.y = ROW_TOP_YPIXEL (sheet, row) + CELL_SPACING;
6777 if (sheet->column_titles_visible)
6778 allocation.y -= sheet->column_title_area.height;
6779 allocation.width = sheet->row_title_area.width;
6780 allocation.height = yyy_row_height (sheet, row);
6781 is_sensitive = yyy_row_is_sensitive (sheet, row);
6783 gtk_sheet_button_draw (sheet, window, button, is_sensitive, allocation);
6790 * vadjustment_value_changed
6791 * hadjustment_value_changed */
6794 adjust_scrollbars (GtkSheet * sheet)
6796 if (sheet->vadjustment)
6798 sheet->vadjustment->page_size = sheet->sheet_window_height;
6799 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6800 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
6801 sheet->vadjustment->lower = 0;
6802 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6803 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "changed");
6807 if (sheet->hadjustment)
6809 sheet->hadjustment->page_size = sheet->sheet_window_width;
6810 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6811 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6812 sheet->hadjustment->lower = 0;
6813 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6814 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "changed");
6820 vadjustment_value_changed (GtkAdjustment * adjustment,
6824 gint diff, value, old_value;
6828 g_return_if_fail (adjustment != NULL);
6829 g_return_if_fail (data != NULL);
6830 g_return_if_fail (GTK_IS_SHEET (data));
6832 sheet = GTK_SHEET (data);
6834 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6836 row = ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + CELL_SPACING);
6837 if (!sheet->column_titles_visible)
6838 row = ROW_FROM_YPIXEL (sheet, CELL_SPACING);
6840 old_value = - sheet->voffset;
6842 new_row = g_sheet_row_pixel_to_row (sheet->row_geometry,
6843 adjustment->value, sheet);
6845 y = g_sheet_row_start_pixel (sheet->row_geometry, new_row, sheet);
6847 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6848 yyy_row_height (sheet, row) > sheet->vadjustment->step_increment)
6850 /* This avoids embarrassing twitching */
6851 if (row == new_row && row != yyy_row_count (sheet) - 1 &&
6852 adjustment->value - sheet->old_vadjustment >=
6853 sheet->vadjustment->step_increment &&
6854 new_row + 1 != MIN_VISIBLE_ROW (sheet))
6857 y = y+yyy_row_height (sheet, row);
6861 /* Negative old_adjustment enforces the redraw, otherwise avoid
6863 if (sheet->old_vadjustment >= 0. && row == new_row)
6865 sheet->old_vadjustment = sheet->vadjustment->value;
6869 sheet->old_vadjustment = sheet->vadjustment->value;
6870 adjustment->value = y;
6875 sheet->vadjustment->step_increment = yyy_row_height (sheet, 0);
6879 sheet->vadjustment->step_increment =
6880 MIN (yyy_row_height (sheet, new_row), yyy_row_height (sheet, new_row - 1));
6883 sheet->vadjustment->value = adjustment->value;
6885 value = adjustment->value;
6887 if (value >= - sheet->voffset)
6890 diff = value + sheet->voffset;
6895 diff = - sheet->voffset - value;
6898 sheet->voffset = - value;
6900 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
6901 sheet->state == GTK_SHEET_NORMAL &&
6902 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6903 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
6904 sheet->active_cell.col))
6908 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
6910 if (!text || strlen (text) == 0)
6911 gtk_sheet_cell_clear (sheet,
6912 sheet->active_cell.row,
6913 sheet->active_cell.col);
6914 gtk_widget_unmap (sheet->sheet_entry);
6917 gtk_sheet_position_children (sheet);
6919 gtk_sheet_range_draw (sheet, NULL);
6920 size_allocate_row_title_buttons (sheet);
6921 size_allocate_global_button (sheet);
6925 hadjustment_value_changed (GtkAdjustment * adjustment,
6929 gint i, diff, value, old_value;
6930 gint column, new_column;
6933 g_return_if_fail (adjustment != NULL);
6934 g_return_if_fail (data != NULL);
6935 g_return_if_fail (GTK_IS_SHEET (data));
6937 sheet = GTK_SHEET (data);
6939 if (GTK_SHEET_IS_FROZEN (sheet)) return;
6941 column = COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + CELL_SPACING);
6942 if (!sheet->row_titles_visible)
6943 column = COLUMN_FROM_XPIXEL (sheet, CELL_SPACING);
6945 old_value = - sheet->hoffset;
6947 for (i = 0; i < xxx_column_count (sheet); i++)
6949 if (xxx_column_is_visible (sheet, i)) x += xxx_column_width (sheet, i);
6950 if (x > adjustment->value) break;
6952 x -= xxx_column_width (sheet, i);
6955 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6956 xxx_column_width (sheet, i) > sheet->hadjustment->step_increment)
6958 /* This avoids embarrassing twitching */
6959 if (column == new_column && column != xxx_column_count (sheet) - 1 &&
6960 adjustment->value - sheet->old_hadjustment >=
6961 sheet->hadjustment->step_increment &&
6962 new_column + 1 != MIN_VISIBLE_COLUMN (sheet))
6965 x += xxx_column_width (sheet, column);
6969 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6970 if (sheet->old_hadjustment >= 0. && new_column == column)
6972 sheet->old_hadjustment = sheet->hadjustment->value;
6976 sheet->old_hadjustment = sheet->hadjustment->value;
6977 adjustment->value = x;
6979 if (new_column == 0)
6981 sheet->hadjustment->step_increment = xxx_column_width (sheet, 0);
6985 sheet->hadjustment->step_increment =
6986 MIN (xxx_column_width (sheet, new_column), xxx_column_width (sheet, new_column - 1));
6990 sheet->hadjustment->value = adjustment->value;
6992 value = adjustment->value;
6994 if (value >= - sheet->hoffset)
6997 diff = value + sheet->hoffset;
7002 diff = - sheet->hoffset - value;
7005 sheet->hoffset = - value;
7006 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
7007 sheet->state == GTK_SHEET_NORMAL &&
7008 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
7009 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
7010 sheet->active_cell.col))
7014 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
7015 if (!text || strlen (text) == 0)
7016 gtk_sheet_cell_clear (sheet,
7017 sheet->active_cell.row,
7018 sheet->active_cell.col);
7020 gtk_widget_unmap (sheet->sheet_entry);
7023 gtk_sheet_position_children (sheet);
7025 gtk_sheet_range_draw (sheet, NULL);
7026 size_allocate_column_title_buttons (sheet);
7030 /* COLUMN RESIZING */
7032 draw_xor_vline (GtkSheet * sheet)
7036 g_return_if_fail (sheet != NULL);
7038 widget = GTK_WIDGET (sheet);
7040 gdk_draw_line (widget->window, sheet->xor_gc,
7042 sheet->column_title_area.height,
7044 sheet->sheet_window_height + 1);
7049 draw_xor_hline (GtkSheet * sheet)
7053 g_return_if_fail (sheet != NULL);
7055 widget = GTK_WIDGET (sheet);
7057 gdk_draw_line (widget->window, sheet->xor_gc,
7058 sheet->row_title_area.width,
7061 sheet->sheet_window_width + 1,
7065 /* SELECTED RANGE */
7067 draw_xor_rectangle (GtkSheet *sheet, GtkSheetRange range)
7070 GdkRectangle clip_area, area;
7073 area.x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
7074 area.y = ROW_TOP_YPIXEL (sheet, range.row0);
7075 area.width = COLUMN_LEFT_XPIXEL (sheet, range.coli)- area.x+
7076 xxx_column_width (sheet, range.coli);
7077 area.height = ROW_TOP_YPIXEL (sheet, range.rowi)- area.y+
7078 yyy_row_height (sheet, range.rowi);
7080 clip_area.x = sheet->row_title_area.width;
7081 clip_area.y = sheet->column_title_area.height;
7082 clip_area.width = sheet->sheet_window_width;
7083 clip_area.height = sheet->sheet_window_height;
7085 if (!sheet->row_titles_visible) clip_area.x = 0;
7086 if (!sheet->column_titles_visible) clip_area.y = 0;
7090 area.width = area.width + area.x;
7093 if (area.width > clip_area.width) area.width = clip_area.width + 10;
7096 area.height = area.height + area.y;
7099 if (area.height > clip_area.height) area.height = clip_area.height + 10;
7103 clip_area.width += 3;
7104 clip_area.height += 3;
7106 gdk_gc_get_values (sheet->xor_gc, &values);
7108 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
7110 for (i =- 1; i <= 1; ++i)
7111 gdk_draw_rectangle (sheet->sheet_window,
7114 area.x + i, area.y + i,
7115 area.width - 2 * i, area.height - 2 * i);
7118 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
7120 gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
7125 /* this function returns the new width of the column being resized given
7126 * the column and x position of the cursor; the x cursor position is passed
7127 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7129 new_column_width (GtkSheet * sheet,
7138 min_width = sheet->column_requisition;
7140 /* you can't shrink a column to less than its minimum width */
7141 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7143 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7146 /* calculate new column width making sure it doesn't end up
7147 * less than the minimum width */
7148 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7149 if (width < min_width)
7152 xxx_set_column_width (sheet, column, width);
7153 size_allocate_column_title_buttons (sheet);
7158 /* this function returns the new height of the row being resized given
7159 * the row and y position of the cursor; the y cursor position is passed
7160 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7162 new_row_height (GtkSheet * sheet,
7170 min_height = sheet->row_requisition;
7172 /* you can't shrink a row to less than its minimum height */
7173 if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7176 *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7179 /* calculate new row height making sure it doesn't end up
7180 * less than the minimum height */
7181 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7182 if (height < min_height)
7183 height = min_height;
7185 yyy_set_row_height (sheet, row, height);
7186 size_allocate_row_title_buttons (sheet);
7192 gtk_sheet_set_column_width (GtkSheet * sheet,
7198 g_return_if_fail (sheet != NULL);
7199 g_return_if_fail (GTK_IS_SHEET (sheet));
7201 if (column < 0 || column >= xxx_column_count (sheet))
7204 gtk_sheet_column_size_request (sheet, column, &min_width);
7205 if (width < min_width) return;
7207 xxx_set_column_width (sheet, column, width);
7209 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7211 size_allocate_column_title_buttons (sheet);
7212 adjust_scrollbars (sheet);
7213 gtk_sheet_size_allocate_entry (sheet);
7214 gtk_sheet_range_draw (sheet, NULL);
7217 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, column);
7218 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_COL_WIDTH], 0,
7225 gtk_sheet_set_row_height (GtkSheet * sheet,
7231 g_return_if_fail (sheet != NULL);
7232 g_return_if_fail (GTK_IS_SHEET (sheet));
7234 if (row < 0 || row >= yyy_row_count (sheet))
7237 gtk_sheet_row_size_request (sheet, row, &min_height);
7238 if (height < min_height) return;
7240 yyy_set_row_height (sheet, row, height);
7242 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7244 size_allocate_row_title_buttons (sheet);
7245 adjust_scrollbars (sheet);
7246 gtk_sheet_size_allocate_entry (sheet);
7247 gtk_sheet_range_draw (sheet, NULL);
7250 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, - 1);
7251 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_ROW_HEIGHT], 0,
7258 gtk_sheet_get_attributes (const GtkSheet *sheet, gint row, gint col,
7259 GtkSheetCellAttr *attributes)
7261 const GdkColor *fg, *bg;
7262 const GtkJustification *j ;
7263 const PangoFontDescription *font_desc ;
7264 const GtkSheetCellBorder *border ;
7266 g_return_val_if_fail (sheet != NULL, FALSE);
7267 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7269 if (row < 0 || col < 0) return FALSE;
7271 init_attributes (sheet, col, attributes);
7276 attributes->is_editable = g_sheet_model_is_editable (sheet->model, row, col);
7277 attributes->is_visible = g_sheet_model_is_visible (sheet->model, row, col);
7279 fg = g_sheet_model_get_foreground (sheet->model, row, col);
7281 attributes->foreground = *fg;
7283 bg = g_sheet_model_get_background (sheet->model, row, col);
7285 attributes->background = *bg;
7287 j = g_sheet_model_get_justification (sheet->model, row, col);
7288 if (j) attributes->justification = *j;
7290 font_desc = g_sheet_model_get_font_desc (sheet->model, row, col);
7291 if ( font_desc ) attributes->font_desc = font_desc;
7293 border = g_sheet_model_get_cell_border (sheet->model, row, col);
7295 if ( border ) attributes->border = *border;
7301 init_attributes (const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7303 /* DEFAULT VALUES */
7304 attributes->foreground = GTK_WIDGET (sheet)->style->black;
7305 attributes->background = sheet->bg_color;
7306 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7308 GdkColormap *colormap;
7309 colormap = gdk_colormap_get_system ();
7310 gdk_color_black (colormap, &attributes->foreground);
7311 attributes->background = sheet->bg_color;
7313 attributes->justification = xxx_column_justification (sheet, col);
7314 attributes->border.width = 0;
7315 attributes->border.line_style = GDK_LINE_SOLID;
7316 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7317 attributes->border.join_style = GDK_JOIN_MITER;
7318 attributes->border.mask = 0;
7319 attributes->border.color = GTK_WIDGET (sheet)->style->black;
7320 attributes->is_editable = TRUE;
7321 attributes->is_visible = TRUE;
7322 attributes->font_desc = GTK_WIDGET (sheet)->style->font_desc;
7326 /********************************************************************
7327 * Container Functions:
7332 * gtk_sheet_move_child
7333 * gtk_sheet_position_child
7334 * gtk_sheet_position_children
7335 * gtk_sheet_realize_child
7336 * gtk_sheet_get_child_at
7337 ********************************************************************/
7340 gtk_sheet_put (GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7342 GtkRequisition child_requisition;
7343 GtkSheetChild *child_info;
7345 g_return_val_if_fail (sheet != NULL, NULL);
7346 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7347 g_return_val_if_fail (child != NULL, NULL);
7348 g_return_val_if_fail (child->parent == NULL, NULL);
7350 child_info = g_new (GtkSheetChild, 1);
7351 child_info->widget = child;
7354 child_info->attached_to_cell = FALSE;
7355 child_info->floating = TRUE;
7356 child_info->xpadding = child_info->ypadding = 0;
7357 child_info->xexpand = child_info->yexpand = FALSE;
7358 child_info->xshrink = child_info->yshrink = FALSE;
7359 child_info->xfill = child_info->yfill = FALSE;
7361 sheet->children = g_list_append (sheet->children, child_info);
7363 gtk_widget_set_parent (child, GTK_WIDGET (sheet));
7365 gtk_widget_size_request (child, &child_requisition);
7367 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7369 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7370 (!GTK_WIDGET_REALIZED (child) || GTK_WIDGET_NO_WINDOW (child)))
7371 gtk_sheet_realize_child (sheet, child_info);
7373 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7374 !GTK_WIDGET_MAPPED (child))
7375 gtk_widget_map (child);
7378 gtk_sheet_position_child (sheet, child_info);
7380 /* This will avoid drawing on the titles */
7382 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7384 if (sheet->row_titles_visible)
7385 gdk_window_show (sheet->row_title_window);
7386 if (sheet->column_titles_visible)
7387 gdk_window_show (sheet->column_title_window);
7390 return (child_info);
7394 gtk_sheet_attach_floating (GtkSheet *sheet,
7399 GtkSheetChild *child;
7401 if (row < 0 || col < 0)
7403 gtk_sheet_button_attach (sheet, widget, row, col);
7407 gtk_sheet_get_cell_area (sheet, row, col, &area);
7408 child = gtk_sheet_put (sheet, widget, area.x, area.y);
7409 child->attached_to_cell = TRUE;
7415 gtk_sheet_attach_default (GtkSheet *sheet,
7419 if (row < 0 || col < 0)
7421 gtk_sheet_button_attach (sheet, widget, row, col);
7425 gtk_sheet_attach (sheet, widget, row, col,
7426 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
7430 gtk_sheet_attach (GtkSheet *sheet,
7439 GtkSheetChild *child = NULL;
7441 if (row < 0 || col < 0)
7443 gtk_sheet_button_attach (sheet, widget, row, col);
7447 child = g_new0 (GtkSheetChild, 1);
7448 child->attached_to_cell = TRUE;
7449 child->floating = FALSE;
7450 child->widget = widget;
7453 child->xpadding = xpadding;
7454 child->ypadding = ypadding;
7455 child->xexpand = (xoptions & GTK_EXPAND) != 0;
7456 child->yexpand = (yoptions & GTK_EXPAND) != 0;
7457 child->xshrink = (xoptions & GTK_SHRINK) != 0;
7458 child->yshrink = (yoptions & GTK_SHRINK) != 0;
7459 child->xfill = (xoptions & GTK_FILL) != 0;
7460 child->yfill = (yoptions & GTK_FILL) != 0;
7462 sheet->children = g_list_append (sheet->children, child);
7464 gtk_sheet_get_cell_area (sheet, row, col, &area);
7466 child->x = area.x + child->xpadding;
7467 child->y = area.y + child->ypadding;
7469 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7471 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7472 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7473 gtk_sheet_realize_child (sheet, child);
7475 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7476 !GTK_WIDGET_MAPPED (widget))
7477 gtk_widget_map (widget);
7480 gtk_sheet_position_child (sheet, child);
7482 /* This will avoid drawing on the titles */
7484 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7486 if (GTK_SHEET_ROW_TITLES_VISIBLE (sheet))
7487 gdk_window_show (sheet->row_title_window);
7488 if (GTK_SHEET_COL_TITLES_VISIBLE (sheet))
7489 gdk_window_show (sheet->column_title_window);
7495 gtk_sheet_button_attach (GtkSheet *sheet,
7499 GtkSheetButton *button = 0;
7500 GtkSheetChild *child;
7501 GtkRequisition button_requisition;
7503 if (row >= 0 && col >= 0) return;
7504 if (row < 0 && col < 0) return;
7506 child = g_new (GtkSheetChild, 1);
7507 child->widget = widget;
7510 child->attached_to_cell = TRUE;
7511 child->floating = FALSE;
7514 child->xpadding = child->ypadding = 0;
7515 child->xshrink = child->yshrink = FALSE;
7516 child->xfill = child->yfill = FALSE;
7519 sheet->children = g_list_append (sheet->children, child);
7521 gtk_sheet_button_size_request (sheet, button, &button_requisition);
7524 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7526 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7527 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7528 gtk_sheet_realize_child (sheet, child);
7530 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7531 !GTK_WIDGET_MAPPED (widget))
7532 gtk_widget_map (widget);
7535 if (row == -1) size_allocate_column_title_buttons (sheet);
7536 if (col == -1) size_allocate_row_title_buttons (sheet);
7541 label_size_request (GtkSheet *sheet, gchar *label, GtkRequisition *req)
7546 gint row_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) - 2 * CELLOFFSET + 2;
7552 while (words && *words != '\0')
7554 if (*words == '\n' || * (words + 1) == '\0')
7556 req->height += row_height;
7559 req->width = MAX (req->width, STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, word));
7569 if (n > 0) req->height -= 2;
7573 gtk_sheet_button_size_request (GtkSheet *sheet,
7574 const GtkSheetButton *button,
7575 GtkRequisition *button_requisition)
7577 GtkRequisition requisition;
7578 GtkRequisition label_requisition;
7580 if (gtk_sheet_autoresize (sheet) && button->label && strlen (button->label) > 0)
7582 label_size_request (sheet, button->label, &label_requisition);
7583 label_requisition.width += 2 * CELLOFFSET;
7584 label_requisition.height += 2 * CELLOFFSET;
7588 label_requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7589 label_requisition.width = COLUMN_MIN_WIDTH;
7594 gtk_widget_size_request (button->child->widget, &requisition);
7595 requisition.width += 2 * button->child->xpadding;
7596 requisition.height += 2 * button->child->ypadding;
7597 requisition.width += 2 * sheet->button->style->xthickness;
7598 requisition.height += 2 * sheet->button->style->ythickness;
7602 requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7603 requisition.width = COLUMN_MIN_WIDTH;
7606 *button_requisition = requisition;
7607 button_requisition->width = MAX (requisition.width, label_requisition.width);
7608 button_requisition->height = MAX (requisition.height, label_requisition.height);
7613 gtk_sheet_row_size_request (GtkSheet *sheet,
7617 GtkRequisition button_requisition;
7620 gtk_sheet_button_size_request (sheet,
7621 yyy_row_button (sheet, row),
7622 &button_requisition);
7624 *requisition = button_requisition.height;
7626 children = sheet->children;
7629 GtkSheetChild *child = (GtkSheetChild *)children->data;
7630 GtkRequisition child_requisition;
7632 if (child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink)
7634 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7636 if (child_requisition.height + 2 * child->ypadding > *requisition)
7637 *requisition = child_requisition.height + 2 * child->ypadding;
7639 children = children->next;
7642 sheet->row_requisition = * requisition;
7646 gtk_sheet_column_size_request (GtkSheet *sheet,
7650 GtkRequisition button_requisition;
7652 GtkSheetButton *button = xxx_column_button (sheet, col);
7654 gtk_sheet_button_size_request (sheet,
7656 &button_requisition);
7658 gtk_sheet_button_free (button);
7660 *requisition = button_requisition.width;
7662 children = sheet->children;
7665 GtkSheetChild *child = (GtkSheetChild *)children->data;
7666 GtkRequisition child_requisition;
7668 if (child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink)
7670 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7672 if (child_requisition.width + 2 * child->xpadding > *requisition)
7673 *requisition = child_requisition.width + 2 * child->xpadding;
7675 children = children->next;
7678 sheet->column_requisition = *requisition;
7682 gtk_sheet_move_child (GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7684 GtkSheetChild *child;
7687 g_return_if_fail (sheet != NULL);
7688 g_return_if_fail (GTK_IS_SHEET (sheet));
7690 children = sheet->children;
7693 child = children->data;
7695 if (child->widget == widget)
7699 child->row = ROW_FROM_YPIXEL (sheet, y);
7700 child->col = COLUMN_FROM_XPIXEL (sheet, x);
7701 gtk_sheet_position_child (sheet, child);
7705 children = children->next;
7708 g_warning ("Widget must be a GtkSheet child");
7713 gtk_sheet_position_child (GtkSheet *sheet, GtkSheetChild *child)
7715 GtkRequisition child_requisition;
7716 GtkAllocation child_allocation;
7722 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7724 if (sheet->column_titles_visible)
7725 yoffset = sheet->column_title_area.height;
7727 if (sheet->row_titles_visible)
7728 xoffset = sheet->row_title_area.width;
7730 if (child->attached_to_cell)
7732 gtk_sheet_get_cell_area (sheet, child->row, child->col, &area);
7733 child->x = area.x + child->xpadding;
7734 child->y = area.y + child->ypadding;
7736 if (!child->floating)
7738 if (child_requisition.width + 2 * child->xpadding <= xxx_column_width (sheet, child->col))
7742 child_requisition.width = child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7748 child->x = area.x + xxx_column_width (sheet, child->col) / 2 -
7749 child_requisition.width / 2;
7751 child_allocation.width = child_requisition.width;
7756 if (!child->xshrink)
7758 gtk_sheet_set_column_width (sheet, child->col, child_requisition.width + 2 * child->xpadding);
7760 child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7763 if (child_requisition.height +
7764 2 * child->ypadding <= yyy_row_height (sheet, child->row))
7768 child_requisition.height = child_allocation.height =
7769 yyy_row_height (sheet, child->row) - 2 * child->ypadding;
7775 child->y = area.y + yyy_row_height (sheet, child->row) / 2
7776 - child_requisition.height / 2;
7778 child_allocation.height = child_requisition.height;
7783 if (!child->yshrink)
7785 gtk_sheet_set_row_height (sheet, child->row, child_requisition.height + 2 * child->ypadding);
7787 child_allocation.height = yyy_row_height (sheet, child->row) -
7788 2 * child->ypadding;
7793 child_allocation.width = child_requisition.width;
7794 child_allocation.height = child_requisition.height;
7797 x = child_allocation.x = child->x + xoffset;
7798 y = child_allocation.y = child->y + yoffset;
7802 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
7803 x = child_allocation.x = child->x + xoffset;
7804 y = child_allocation.y = child->y + sheet->voffset + yoffset;
7805 y = child_allocation.y = child->y + yoffset;
7806 child_allocation.width = child_requisition.width;
7807 child_allocation.height = child_requisition.height;
7810 gtk_widget_size_allocate (child->widget, &child_allocation);
7811 gtk_widget_queue_draw (child->widget);
7815 gtk_sheet_forall (GtkContainer *container,
7816 gboolean include_internals,
7817 GtkCallback callback,
7818 gpointer callback_data)
7821 GtkSheetChild *child;
7824 g_return_if_fail (GTK_IS_SHEET (container));
7825 g_return_if_fail (callback != NULL);
7827 sheet = GTK_SHEET (container);
7828 children = sheet->children;
7831 child = children->data;
7832 children = children->next;
7834 (* callback) (child->widget, callback_data);
7837 (* callback) (sheet->button, callback_data);
7838 if (sheet->sheet_entry)
7839 (* callback) (sheet->sheet_entry, callback_data);
7844 gtk_sheet_position_children (GtkSheet *sheet)
7847 GtkSheetChild *child;
7849 children = sheet->children;
7853 child = (GtkSheetChild *)children->data;
7855 if (child->col != -1 && child->row != -1)
7856 gtk_sheet_position_child (sheet, child);
7858 if (child->row == -1)
7860 if (child->col < MIN_VISIBLE_COLUMN (sheet) ||
7861 child->col > MAX_VISIBLE_COLUMN (sheet))
7862 gtk_sheet_child_hide (child);
7864 gtk_sheet_child_show (child);
7866 if (child->col == -1)
7868 if (child->row < MIN_VISIBLE_ROW (sheet) ||
7869 child->row > MAX_VISIBLE_ROW (sheet))
7870 gtk_sheet_child_hide (child);
7872 gtk_sheet_child_show (child);
7875 children = children->next;
7880 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7884 GtkSheetChild *child = 0;
7886 g_return_if_fail (container != NULL);
7887 g_return_if_fail (GTK_IS_SHEET (container));
7889 sheet = GTK_SHEET (container);
7891 children = sheet->children;
7895 child = (GtkSheetChild *)children->data;
7897 if (child->widget == widget) break;
7899 children = children->next;
7904 gtk_widget_unparent (widget);
7905 child->widget = NULL;
7907 sheet->children = g_list_remove_link (sheet->children, children);
7908 g_list_free_1 (children);
7915 gtk_sheet_realize_child (GtkSheet *sheet, GtkSheetChild *child)
7919 widget = GTK_WIDGET (sheet);
7921 if (GTK_WIDGET_REALIZED (widget))
7923 if (child->row == -1)
7924 gtk_widget_set_parent_window (child->widget, sheet->column_title_window);
7925 else if (child->col == -1)
7926 gtk_widget_set_parent_window (child->widget, sheet->row_title_window);
7928 gtk_widget_set_parent_window (child->widget, sheet->sheet_window);
7931 gtk_widget_set_parent (child->widget, widget);
7937 gtk_sheet_get_child_at (GtkSheet *sheet, gint row, gint col)
7940 GtkSheetChild *child = 0;
7942 g_return_val_if_fail (sheet != NULL, NULL);
7943 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7945 children = sheet->children;
7949 child = (GtkSheetChild *)children->data;
7951 if (child->attached_to_cell)
7952 if (child->row == row && child->col == col) break;
7954 children = children->next;
7957 if (children) return child;
7963 gtk_sheet_child_hide (GtkSheetChild *child)
7965 g_return_if_fail (child != NULL);
7966 gtk_widget_hide (child->widget);
7970 gtk_sheet_child_show (GtkSheetChild *child)
7972 g_return_if_fail (child != NULL);
7974 gtk_widget_show (child->widget);
7978 gtk_sheet_get_model (const GtkSheet *sheet)
7980 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7982 return sheet->model;
7987 gtk_sheet_button_new (void)
7989 GtkSheetButton *button = g_malloc (sizeof (GtkSheetButton));
7991 button->state = GTK_STATE_NORMAL;
7992 button->label = NULL;
7993 button->label_visible = TRUE;
7994 button->child = NULL;
7995 button->justification = GTK_JUSTIFY_FILL;
8002 gtk_sheet_button_free (GtkSheetButton *button)
8004 if (!button) return ;
8006 g_free (button->label);
8012 range_to_text (const GtkSheet *sheet)
8014 gchar *celltext = NULL;
8018 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
8021 string = g_string_sized_new (80);
8023 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
8025 for (c = sheet->range.col0; c < sheet->range.coli; ++c)
8027 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8028 g_string_append (string, celltext);
8029 g_string_append (string, "\t");
8032 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8033 g_string_append (string, celltext);
8034 if ( r < sheet->range.rowi)
8035 g_string_append (string, "\n");
8043 range_to_html (const GtkSheet *sheet)
8045 gchar *celltext = NULL;
8049 if ( !gtk_sheet_range_isvisible (sheet, sheet->range))
8052 string = g_string_sized_new (480);
8054 g_string_append (string, "<html>\n");
8055 g_string_append (string, "<body>\n");
8056 g_string_append (string, "<table>\n");
8057 for (r = sheet->range.row0; r <= sheet->range.rowi; ++r)
8059 g_string_append (string, "<tr>\n");
8060 for (c = sheet->range.col0; c <= sheet->range.coli; ++c)
8062 g_string_append (string, "<td>");
8063 celltext = gtk_sheet_cell_get_text (sheet, r, c);
8064 g_string_append (string, celltext);
8065 g_string_append (string, "</td>\n");
8068 g_string_append (string, "</tr>\n");
8070 g_string_append (string, "</table>\n");
8071 g_string_append (string, "</body>\n");
8072 g_string_append (string, "</html>\n");
8084 primary_get_cb (GtkClipboard *clipboard,
8085 GtkSelectionData *selection_data,
8089 GtkSheet *sheet = GTK_SHEET (data);
8090 GString *string = NULL;
8094 case SELECT_FMT_TEXT:
8095 string = range_to_text (sheet);
8097 case SELECT_FMT_HTML:
8098 string = range_to_html (sheet);
8101 g_assert_not_reached ();
8104 gtk_selection_data_set (selection_data, selection_data->target,
8106 (const guchar *) string->str, string->len);
8107 g_string_free (string, TRUE);
8111 primary_clear_cb (GtkClipboard *clipboard,
8114 GtkSheet *sheet = GTK_SHEET (data);
8115 gtk_sheet_real_unselect_range (sheet, NULL);
8119 gtk_sheet_update_primary_selection (GtkSheet *sheet)
8121 static const GtkTargetEntry targets[] = {
8122 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
8123 { "STRING", 0, SELECT_FMT_TEXT },
8124 { "TEXT", 0, SELECT_FMT_TEXT },
8125 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
8126 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
8127 { "text/plain", 0, SELECT_FMT_TEXT },
8128 { "text/html", 0, SELECT_FMT_HTML }
8131 GtkClipboard *clipboard;
8133 if (!GTK_WIDGET_REALIZED (sheet))
8136 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (sheet),
8137 GDK_SELECTION_PRIMARY);
8139 if (gtk_sheet_range_isvisible (sheet, sheet->range))
8141 if (!gtk_clipboard_set_with_owner (clipboard, targets,
8142 G_N_ELEMENTS (targets),
8143 primary_get_cb, primary_clear_cb,
8145 primary_clear_cb (clipboard, sheet);
8149 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (sheet))
8150 gtk_clipboard_clear (clipboard);