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_IN_CLIP = 1 << 7,
77 GTK_SHEET_REDRAW_PENDING = 1 << 8,
80 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
81 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
82 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~ (flag))
84 #define GTK_SHEET_IS_LOCKED(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_LOCKED)
87 #define GTK_SHEET_IS_FROZEN(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
88 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
89 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
90 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
91 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
92 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
93 #define GTK_SHEET_IN_CLIP(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_CLIP)
94 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
96 #define CELL_SPACING 1
98 #define TIMEOUT_FLASH 200
99 #define TIMEOUT_HOVER 300
100 #define TIME_INTERVAL 8
101 #define COLUMN_MIN_WIDTH 10
106 #define DEFAULT_COLUMN_WIDTH 80
109 static void gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column);
111 static void gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row);
114 static gboolean gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col);
117 void dispose_string (const GtkSheet *sheet, gchar *text)
119 GSheetModel *model = gtk_sheet_get_model (sheet);
124 if (g_sheet_model_free_strings (model))
129 guint DEFAULT_ROW_HEIGHT (GtkWidget *widget)
131 if (!widget->style->font_desc) return 24;
134 PangoContext *context = gtk_widget_get_pango_context (widget);
135 PangoFontMetrics *metrics =
136 pango_context_get_metrics (context,
137 widget->style->font_desc,
138 pango_context_get_language (context));
139 guint val = pango_font_metrics_get_descent (metrics) +
140 pango_font_metrics_get_ascent (metrics);
141 pango_font_metrics_unref (metrics);
142 return PANGO_PIXELS (val)+2 * CELLOFFSET;
147 guint DEFAULT_FONT_ASCENT (GtkWidget *widget)
149 if (!widget->style->font_desc) return 12;
152 PangoContext *context = gtk_widget_get_pango_context (widget);
153 PangoFontMetrics *metrics =
154 pango_context_get_metrics (context,
155 widget->style->font_desc,
156 pango_context_get_language (context));
157 guint val = pango_font_metrics_get_ascent (metrics);
158 pango_font_metrics_unref (metrics);
159 return PANGO_PIXELS (val);
164 guint STRING_WIDTH (GtkWidget *widget,
165 const PangoFontDescription *font, const gchar *text)
170 layout = gtk_widget_create_pango_layout (widget, text);
171 pango_layout_set_font_description (layout, font);
173 pango_layout_get_extents (layout, NULL, &rect);
175 g_object_unref (G_OBJECT (layout));
176 return PANGO_PIXELS (rect.width);
180 guint DEFAULT_FONT_DESCENT (GtkWidget *widget)
182 if (!widget->style->font_desc) return 12;
185 PangoContext *context = gtk_widget_get_pango_context (widget);
186 PangoFontMetrics *metrics =
187 pango_context_get_metrics (context,
188 widget->style->font_desc,
189 pango_context_get_language (context));
190 guint val = pango_font_metrics_get_descent (metrics);
191 pango_font_metrics_unref (metrics);
192 return PANGO_PIXELS (val);
198 yyy_row_is_visible (const GtkSheet *sheet, gint row)
200 GSheetRow *row_geo = sheet->row_geometry;
202 return g_sheet_row_get_visibility (row_geo, row, 0);
207 yyy_row_is_sensitive (const GtkSheet *sheet, gint row)
209 GSheetRow *row_geo = sheet->row_geometry;
211 return g_sheet_row_get_sensitivity (row_geo, row, 0);
217 yyy_row_count (const GtkSheet *sheet)
219 GSheetRow *row_geo = sheet->row_geometry;
221 return g_sheet_row_get_row_count (row_geo, 0);
225 yyy_row_height (const GtkSheet *sheet, gint row)
227 GSheetRow *row_geo = sheet->row_geometry;
229 return g_sheet_row_get_height (row_geo, row, 0);
233 yyy_row_top_ypixel (const GtkSheet *sheet, gint row)
235 GSheetRow *geo = sheet->row_geometry;
237 gint y = g_sheet_row_start_pixel (geo, row, 0);
239 if ( sheet->column_titles_visible )
240 y += sheet->column_title_area.height;
246 /* Return the row containing pixel Y */
248 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
250 GSheetRow *geo = sheet->row_geometry;
252 gint cy = sheet->voffset;
254 if (sheet->column_titles_visible)
255 cy += sheet->column_title_area.height;
257 if (y < cy) return 0;
259 return g_sheet_row_pixel_to_row (geo, y - cy, 0);
263 /* gives the top pixel of the given row in context of
264 * the sheet's voffset */
266 ROW_TOP_YPIXEL (const GtkSheet *sheet, gint row)
268 return (sheet->voffset + yyy_row_top_ypixel (sheet, row));
272 /* returns the row index from a y pixel location in the
273 * context of the sheet's voffset */
275 ROW_FROM_YPIXEL (const GtkSheet *sheet, gint y)
277 return (yyy_row_ypixel_to_row (sheet, y));
280 static inline GtkSheetButton *
281 xxx_column_button (const GtkSheet *sheet, gint col)
283 GSheetColumn *col_geo = sheet->column_geometry;
284 if ( col < 0 ) return NULL ;
286 return g_sheet_column_get_button (col_geo, col);
291 xxx_column_left_xpixel (const GtkSheet *sheet, gint col)
293 GSheetColumn *geo = sheet->column_geometry;
295 gint x = g_sheet_column_start_pixel (geo, col);
297 if ( sheet->row_titles_visible )
298 x += sheet->row_title_area.width;
304 xxx_column_width (const GtkSheet *sheet, gint col)
306 GSheetColumn *col_geo = sheet->column_geometry;
308 return g_sheet_column_get_width (col_geo, col);
313 xxx_set_column_width (GtkSheet *sheet, gint col, gint width)
315 if ( sheet->column_geometry )
316 g_sheet_column_set_width (sheet->column_geometry, col, width);
320 xxx_column_set_left_column (GtkSheet *sheet, gint col, gint i)
322 GSheetColumn *col_geo = sheet->column_geometry;
324 g_sheet_column_set_left_text_column (col_geo, col, i);
328 xxx_column_left_column (const GtkSheet *sheet, gint col)
330 GSheetColumn *col_geo = sheet->column_geometry;
332 return g_sheet_column_get_left_text_column (col_geo, col);
336 xxx_column_set_right_column (GtkSheet *sheet, gint col, gint i)
338 GSheetColumn *col_geo = sheet->column_geometry;
340 g_sheet_column_set_right_text_column (col_geo, col, i);
344 xxx_column_right_column (const GtkSheet *sheet, gint col)
346 GSheetColumn *col_geo = sheet->column_geometry;
348 return g_sheet_column_get_right_text_column (col_geo, col);
351 static inline GtkJustification
352 xxx_column_justification (const GtkSheet *sheet, gint col)
354 GSheetColumn *col_geo = sheet->column_geometry;
356 return g_sheet_column_get_justification (col_geo, col);
360 xxx_column_is_visible (const GtkSheet *sheet, gint col)
362 GSheetColumn *col_geo = sheet->column_geometry;
364 return g_sheet_column_get_visibility (col_geo, col);
369 xxx_column_is_sensitive (const GtkSheet *sheet, gint col)
371 GSheetColumn *col_geo = sheet->column_geometry;
373 return g_sheet_column_get_sensitivity (col_geo, col);
377 /* gives the left pixel of the given column in context of
378 * the sheet's hoffset */
380 COLUMN_LEFT_XPIXEL (const GtkSheet *sheet, gint ncol)
382 return (sheet->hoffset + xxx_column_left_xpixel (sheet, ncol));
386 xxx_column_count (const GtkSheet *sheet)
388 GSheetColumn *col_geo = sheet->column_geometry;
390 return g_sheet_column_get_column_count (col_geo);
393 /* returns the column index from a x pixel location in the
394 * context of the sheet's hoffset */
396 COLUMN_FROM_XPIXEL (const GtkSheet * sheet,
402 if ( sheet->row_titles_visible )
403 cx += sheet->row_title_area.width;
405 if (x < cx) return 0;
406 for (i = 0; i < xxx_column_count (sheet); i++)
408 if (x >= cx && x <= (cx + xxx_column_width (sheet, i)) &&
409 xxx_column_is_visible (sheet, i))
411 if ( xxx_column_is_visible (sheet, i))
412 cx += xxx_column_width (sheet, i);
416 return xxx_column_count (sheet) - 1;
419 /* returns the total height of the sheet */
420 static inline gint SHEET_HEIGHT (GtkSheet *sheet)
422 const gint n_rows = yyy_row_count (sheet);
424 return yyy_row_top_ypixel (sheet, n_rows - 1) +
425 yyy_row_height (sheet, n_rows - 1);
429 static inline GtkSheetButton *
430 yyy_row_button (GtkSheet *sheet, gint row)
432 GSheetRow *row_geo = sheet->row_geometry;
434 return g_sheet_row_get_button (row_geo, row, sheet);
441 yyy_set_row_height (GtkSheet *sheet, gint row, gint height)
443 if ( sheet->row_geometry )
444 g_sheet_row_set_height (sheet->row_geometry, row, height, sheet);
449 /* returns the total width of the sheet */
450 static inline gint SHEET_WIDTH (GtkSheet *sheet)
454 cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
456 for (i = 0; i < xxx_column_count (sheet); i++)
457 if (xxx_column_is_visible (sheet, i))
458 cx += xxx_column_width (sheet, i);
463 #define MIN_VISIBLE_ROW(sheet) \
464 ROW_FROM_YPIXEL (sheet, sheet->column_title_area.height + 1)
466 #define MAX_VISIBLE_ROW(sheet) \
467 ROW_FROM_YPIXEL (sheet, sheet->sheet_window_height - 1)
469 #define MIN_VISIBLE_COLUMN(sheet) \
470 COLUMN_FROM_XPIXEL (sheet, sheet->row_title_area.width + 1)
472 #define MAX_VISIBLE_COLUMN(sheet) \
473 COLUMN_FROM_XPIXEL (sheet, sheet->sheet_window_width)
477 static inline gboolean
478 POSSIBLE_XDRAG (const GtkSheet *sheet, gint x, gint *drag_column)
482 column = COLUMN_FROM_XPIXEL (sheet, x);
483 *drag_column = column;
485 xdrag = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
486 if (x <= xdrag + DRAG_WIDTH / 2 && column != 0)
488 while (! xxx_column_is_visible (sheet, column - 1) && column > 0) column--;
489 *drag_column = column - 1;
490 return xxx_column_is_sensitive (sheet, column - 1);
493 xdrag += xxx_column_width (sheet, column);
494 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
495 return xxx_column_is_sensitive (sheet, column);
500 static inline gboolean
501 POSSIBLE_YDRAG (const GtkSheet *sheet, gint y, gint *drag_row)
504 row = ROW_FROM_YPIXEL (sheet, y);
507 ydrag = ROW_TOP_YPIXEL (sheet,row)+CELL_SPACING;
508 if (y <= ydrag + DRAG_WIDTH / 2 && row != 0)
510 while (!yyy_row_is_visible (sheet, row - 1) && row > 0) row--;
512 return yyy_row_is_sensitive (sheet, row - 1);
515 ydrag +=yyy_row_height (sheet, row);
517 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
518 return yyy_row_is_sensitive (sheet, row);
524 static inline gboolean
525 POSSIBLE_DRAG (const GtkSheet *sheet, gint x, gint y,
526 gint *drag_row, gint *drag_column)
530 /* Can't drag if nothing is selected */
531 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
532 sheet->range.col0 < 0 || sheet->range.coli < 0 )
535 *drag_column = COLUMN_FROM_XPIXEL (sheet, x);
536 *drag_row = ROW_FROM_YPIXEL (sheet, y);
538 if (x >= COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0) - DRAG_WIDTH / 2 &&
539 x <= COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
540 xxx_column_width (sheet, sheet->range.coli) + DRAG_WIDTH / 2)
542 ydrag = ROW_TOP_YPIXEL (sheet,sheet->range.row0);
543 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
545 *drag_row = sheet->range.row0;
548 ydrag = ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
549 yyy_row_height (sheet, sheet->range.rowi);
550 if (y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2)
552 *drag_row = sheet->range.rowi;
557 if (y >= ROW_TOP_YPIXEL (sheet, sheet->range.row0) - DRAG_WIDTH / 2 &&
558 y <= ROW_TOP_YPIXEL (sheet, sheet->range.rowi) +
559 yyy_row_height (sheet, sheet->range.rowi) + DRAG_WIDTH / 2)
561 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.col0);
562 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
564 *drag_column = sheet->range.col0;
567 xdrag = COLUMN_LEFT_XPIXEL (sheet, sheet->range.coli) +
568 xxx_column_width (sheet, sheet->range.coli);
569 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2)
571 *drag_column = sheet->range.coli;
579 static inline gboolean
580 POSSIBLE_RESIZE (const GtkSheet *sheet, gint x, gint y,
581 gint *drag_row, gint *drag_column)
585 /* Can't drag if nothing is selected */
586 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
587 sheet->range.col0 < 0 || sheet->range.coli < 0 )
590 xdrag = COLUMN_LEFT_XPIXEL (sheet,sheet->range.coli)+
591 xxx_column_width (sheet, sheet->range.coli);
593 ydrag = ROW_TOP_YPIXEL (sheet,sheet->range.rowi)+
594 yyy_row_height (sheet, sheet->range.rowi);
596 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
597 ydrag = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
599 if (sheet->state == GTK_SHEET_ROW_SELECTED)
600 xdrag = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
602 *drag_column = COLUMN_FROM_XPIXEL (sheet,x);
603 *drag_row = ROW_FROM_YPIXEL (sheet,y);
605 if (x >= xdrag - DRAG_WIDTH / 2 && x <= xdrag + DRAG_WIDTH / 2 &&
606 y >= ydrag - DRAG_WIDTH / 2 && y <= ydrag + DRAG_WIDTH / 2) return TRUE;
611 static void gtk_sheet_class_init (GtkSheetClass * klass);
612 static void gtk_sheet_init (GtkSheet * sheet);
613 static void gtk_sheet_destroy (GtkObject * object);
614 static void gtk_sheet_finalize (GObject * object);
615 static void gtk_sheet_style_set (GtkWidget *widget,
616 GtkStyle *previous_style);
617 static void gtk_sheet_realize (GtkWidget * widget);
618 static void gtk_sheet_unrealize (GtkWidget * widget);
619 static void gtk_sheet_map (GtkWidget * widget);
620 static void gtk_sheet_unmap (GtkWidget * widget);
621 static gint gtk_sheet_expose (GtkWidget * widget,
622 GdkEventExpose * event);
623 static void gtk_sheet_forall (GtkContainer *container,
624 gboolean include_internals,
625 GtkCallback callback,
626 gpointer callback_data);
628 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
629 GtkAdjustment *hadjustment,
630 GtkAdjustment *vadjustment);
632 static gint gtk_sheet_button_press (GtkWidget * widget,
633 GdkEventButton * event);
634 static gint gtk_sheet_button_release (GtkWidget * widget,
635 GdkEventButton * event);
636 static gint gtk_sheet_motion (GtkWidget * widget,
637 GdkEventMotion * event);
638 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
640 static gint gtk_sheet_key_press (GtkWidget *widget,
642 static void gtk_sheet_size_request (GtkWidget * widget,
643 GtkRequisition * requisition);
644 static void gtk_sheet_size_allocate (GtkWidget * widget,
645 GtkAllocation * allocation);
649 static gint gtk_sheet_range_isvisible (GtkSheet * sheet,
650 GtkSheetRange range);
651 static gint gtk_sheet_cell_isvisible (GtkSheet * sheet,
652 gint row, gint column);
655 static gint gtk_sheet_flash (gpointer data);
657 /* Drawing Routines */
659 /* draw cell background and frame */
660 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
661 gint row, gint column);
663 /* draw cell contents */
664 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
665 gint row, gint column);
667 /* draw visible part of range. If range == NULL then draw the whole screen */
668 static void gtk_sheet_range_draw (GtkSheet *sheet,
669 const GtkSheetRange *range);
671 /* highlight the visible part of the selected range */
672 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
673 GtkSheetRange range);
677 static gboolean gtk_sheet_move_query (GtkSheet *sheet,
678 gint row, gint column);
679 static void gtk_sheet_real_select_range (GtkSheet * sheet,
680 const GtkSheetRange * range);
681 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
682 const GtkSheetRange * range);
683 static void gtk_sheet_extend_selection (GtkSheet *sheet,
684 gint row, gint column);
685 static void gtk_sheet_new_selection (GtkSheet *sheet,
686 GtkSheetRange *range);
687 static void gtk_sheet_draw_border (GtkSheet *sheet,
688 GtkSheetRange range);
689 static void gtk_sheet_draw_corners (GtkSheet *sheet,
690 GtkSheetRange range);
693 /* Active Cell handling */
695 static void gtk_sheet_entry_changed (GtkWidget *widget,
697 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
698 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
699 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
701 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
702 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
703 static void gtk_sheet_click_cell (GtkSheet *sheet,
710 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
711 guint width, guint height);
712 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
713 GtkSheetRange range);
716 static void adjust_scrollbars (GtkSheet * sheet);
717 static void vadjustment_value_changed (GtkAdjustment * adjustment,
719 static void hadjustment_value_changed (GtkAdjustment * adjustment,
723 static void draw_xor_vline (GtkSheet * sheet);
724 static void draw_xor_hline (GtkSheet * sheet);
725 static void draw_xor_rectangle (GtkSheet *sheet,
726 GtkSheetRange range);
727 static void gtk_sheet_draw_flashing_range (GtkSheet *sheet,
728 GtkSheetRange range);
729 static guint new_column_width (GtkSheet * sheet,
732 static guint new_row_height (GtkSheet * sheet,
737 static void create_global_button (GtkSheet *sheet);
738 static void global_button_clicked (GtkWidget *widget,
742 static void create_sheet_entry (GtkSheet *sheet);
743 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
744 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
746 /* Sheet button gadgets */
748 static void size_allocate_column_title_buttons (GtkSheet * sheet);
749 static void size_allocate_row_title_buttons (GtkSheet * sheet);
752 static void size_allocate_global_button (GtkSheet *sheet);
753 static void gtk_sheet_button_size_request (GtkSheet *sheet,
754 const GtkSheetButton *button,
755 GtkRequisition *requisition);
757 /* Attributes routines */
758 static void init_attributes (const GtkSheet *sheet, gint col,
759 GtkSheetCellAttr *attributes);
762 /* Memory allocation routines */
763 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
764 const GtkSheetRange *range);
766 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
771 /* Container Functions */
772 static void gtk_sheet_remove (GtkContainer *container,
774 static void gtk_sheet_realize_child (GtkSheet *sheet,
775 GtkSheetChild *child);
776 static void gtk_sheet_position_child (GtkSheet *sheet,
777 GtkSheetChild *child);
778 static void gtk_sheet_position_children (GtkSheet *sheet);
779 static void gtk_sheet_child_show (GtkSheetChild *child);
780 static void gtk_sheet_child_hide (GtkSheetChild *child);
781 static void gtk_sheet_column_size_request (GtkSheet *sheet,
784 static void gtk_sheet_row_size_request (GtkSheet *sheet,
792 _gtkextra_signal_emit (GtkObject *object, guint signal_id, ...);
817 static GtkContainerClass *parent_class = NULL;
818 static guint sheet_signals[LAST_SIGNAL] = { 0 };
822 gtk_sheet_get_type ()
824 static GType sheet_type = 0;
828 static const GTypeInfo sheet_info =
830 sizeof (GtkSheetClass),
833 (GClassInitFunc) gtk_sheet_class_init,
838 (GInstanceInitFunc) gtk_sheet_init,
842 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
848 static GtkSheetRange*
849 gtk_sheet_range_copy (const GtkSheetRange *range)
851 GtkSheetRange *new_range;
853 g_return_val_if_fail (range != NULL, NULL);
855 new_range = g_new (GtkSheetRange, 1);
863 gtk_sheet_range_free (GtkSheetRange *range)
865 g_return_if_fail (range != NULL);
871 gtk_sheet_range_get_type (void)
873 static GType sheet_range_type = 0;
875 if (!sheet_range_type)
878 g_boxed_type_register_static ("GtkSheetRange",
879 (GBoxedCopyFunc) gtk_sheet_range_copy,
880 (GBoxedFreeFunc) gtk_sheet_range_free);
883 return sheet_range_type;
887 gtk_sheet_class_init (GtkSheetClass * klass)
889 GtkObjectClass *object_class;
890 GtkWidgetClass *widget_class;
891 GtkContainerClass *container_class;
892 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
894 object_class = (GtkObjectClass *) klass;
895 widget_class = (GtkWidgetClass *) klass;
896 container_class = (GtkContainerClass *) klass;
898 parent_class = g_type_class_peek_parent (klass);
901 * GtkSheet::select-row
902 * @sheet: the sheet widget that emitted the signal
903 * @row: the newly selected row index
905 * A row has been selected.
907 sheet_signals[SELECT_ROW] =
908 g_signal_new ("select-row",
909 G_TYPE_FROM_CLASS (object_class),
911 offsetof (GtkSheetClass, select_row),
920 * GtkSheet::select - column
921 * @sheet: the sheet widget that emitted the signal
922 * @column: the newly selected column index
924 * A column has been selected.
926 sheet_signals[SELECT_COLUMN] =
927 g_signal_new ("select-column",
928 G_TYPE_FROM_CLASS (object_class),
930 offsetof (GtkSheetClass, select_column),
939 * GtkSheet::double-click-row
940 * @sheet: the sheet widget that emitted the signal
941 * @row: the row that was double clicked.
943 * A row's title button has been double clicked
945 sheet_signals[DOUBLE_CLICK_ROW] =
946 g_signal_new ("double-click-row",
947 G_TYPE_FROM_CLASS (object_class),
958 * GtkSheet::double-click-column
959 * @sheet: the sheet widget that emitted the signal
960 * @column: the column that was double clicked.
962 * A column's title button has been double clicked
964 sheet_signals[DOUBLE_CLICK_COLUMN] =
965 g_signal_new ("double-click-column",
966 G_TYPE_FROM_CLASS (object_class),
977 * GtkSheet::button-event-column
978 * @sheet: the sheet widget that emitted the signal
979 * @column: the column on which the event occured.
981 * A button event occured on a column title button
983 sheet_signals[BUTTON_EVENT_COLUMN] =
984 g_signal_new ("button-event-column",
985 G_TYPE_FROM_CLASS (object_class),
989 gtkextra_VOID__INT_POINTER,
998 * GtkSheet::button-event-row
999 * @sheet: the sheet widget that emitted the signal
1000 * @column: the column on which the event occured.
1002 * A button event occured on a row title button
1004 sheet_signals[BUTTON_EVENT_ROW] =
1005 g_signal_new ("button-event-row",
1006 G_TYPE_FROM_CLASS (object_class),
1010 gtkextra_VOID__INT_POINTER,
1018 sheet_signals[SELECT_RANGE] =
1019 g_signal_new ("select-range",
1020 G_TYPE_FROM_CLASS (object_class),
1022 offsetof (GtkSheetClass, select_range),
1024 gtkextra_VOID__BOXED,
1027 GTK_TYPE_SHEET_RANGE);
1030 sheet_signals[CLIP_RANGE] =
1031 g_signal_new ("clip-range",
1032 G_TYPE_FROM_CLASS (object_class),
1034 offsetof (GtkSheetClass, clip_range),
1036 gtkextra_VOID__BOXED,
1039 GTK_TYPE_SHEET_RANGE);
1041 sheet_signals[RESIZE_RANGE] =
1042 g_signal_new ("resize-range",
1043 G_TYPE_FROM_CLASS (object_class),
1045 offsetof (GtkSheetClass, resize_range),
1047 gtkextra_VOID__BOXED_BOXED,
1050 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1053 sheet_signals[MOVE_RANGE] =
1054 g_signal_new ("move-range",
1055 G_TYPE_FROM_CLASS (object_class),
1057 offsetof (GtkSheetClass, move_range),
1059 gtkextra_VOID__BOXED_BOXED,
1062 GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE
1065 sheet_signals[TRAVERSE] =
1066 g_signal_new ("traverse",
1067 G_TYPE_FROM_CLASS (object_class),
1069 offsetof (GtkSheetClass, traverse),
1071 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
1072 G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_INT,
1073 G_TYPE_POINTER, G_TYPE_POINTER);
1076 sheet_signals[DEACTIVATE] =
1077 g_signal_new ("deactivate",
1078 G_TYPE_FROM_CLASS (object_class),
1080 offsetof (GtkSheetClass, deactivate),
1082 gtkextra_BOOLEAN__INT_INT,
1083 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1085 sheet_signals[ACTIVATE] =
1086 g_signal_new ("activate",
1087 G_TYPE_FROM_CLASS (object_class),
1089 offsetof (GtkSheetClass, activate),
1091 gtkextra_BOOLEAN__INT_INT,
1092 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
1094 sheet_signals[SET_CELL] =
1095 g_signal_new ("set-cell",
1096 G_TYPE_FROM_CLASS (object_class),
1098 offsetof (GtkSheetClass, set_cell),
1100 gtkextra_VOID__INT_INT,
1101 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1104 sheet_signals[CLEAR_CELL] =
1105 g_signal_new ("clear-cell",
1106 G_TYPE_FROM_CLASS (object_class),
1108 offsetof (GtkSheetClass, clear_cell),
1110 gtkextra_VOID__INT_INT,
1111 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1113 sheet_signals[CHANGED] =
1114 g_signal_new ("changed",
1115 G_TYPE_FROM_CLASS (object_class),
1117 offsetof (GtkSheetClass, changed),
1119 gtkextra_VOID__INT_INT,
1120 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1122 sheet_signals[NEW_COL_WIDTH] =
1123 g_signal_new ("new-column-width",
1124 G_TYPE_FROM_CLASS (object_class),
1126 offsetof (GtkSheetClass, new_column_width), /*!!!! */
1128 gtkextra_VOID__INT_INT,
1129 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1131 sheet_signals[NEW_ROW_HEIGHT] =
1132 g_signal_new ("new-row-height",
1133 G_TYPE_FROM_CLASS (object_class),
1135 offsetof (GtkSheetClass, new_row_height), /*!!!! */
1137 gtkextra_VOID__INT_INT,
1138 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
1140 widget_class->set_scroll_adjustments_signal =
1141 g_signal_new ("set-scroll-adjustments",
1142 G_TYPE_FROM_CLASS (object_class),
1144 offsetof (GtkSheetClass, set_scroll_adjustments),
1146 gtkextra_VOID__OBJECT_OBJECT,
1147 G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1150 container_class->add = NULL;
1151 container_class->remove = gtk_sheet_remove;
1152 container_class->forall = gtk_sheet_forall;
1154 object_class->destroy = gtk_sheet_destroy;
1155 gobject_class->finalize = gtk_sheet_finalize;
1157 widget_class->realize = gtk_sheet_realize;
1158 widget_class->unrealize = gtk_sheet_unrealize;
1159 widget_class->map = gtk_sheet_map;
1160 widget_class->unmap = gtk_sheet_unmap;
1161 widget_class->style_set = gtk_sheet_style_set;
1162 widget_class->button_press_event = gtk_sheet_button_press;
1163 widget_class->button_release_event = gtk_sheet_button_release;
1164 widget_class->motion_notify_event = gtk_sheet_motion;
1165 widget_class->key_press_event = gtk_sheet_key_press;
1166 widget_class->expose_event = gtk_sheet_expose;
1167 widget_class->size_request = gtk_sheet_size_request;
1168 widget_class->size_allocate = gtk_sheet_size_allocate;
1169 widget_class->focus_in_event = NULL;
1170 widget_class->focus_out_event = NULL;
1172 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1173 klass->select_row = NULL;
1174 klass->select_column = NULL;
1175 klass->select_range = NULL;
1176 klass->clip_range = NULL;
1177 klass->resize_range = NULL;
1178 klass->move_range = NULL;
1179 klass->traverse = NULL;
1180 klass->deactivate = NULL;
1181 klass->activate = NULL;
1182 klass->set_cell = NULL;
1183 klass->clear_cell = NULL;
1184 klass->changed = NULL;
1188 gtk_sheet_init (GtkSheet *sheet)
1190 sheet->column_geometry = NULL;
1191 sheet->row_geometry = NULL;
1193 sheet->children = NULL;
1196 sheet->selection_mode = GTK_SELECTION_NONE;
1197 sheet->freeze_count = 0;
1198 sheet->state = GTK_SHEET_NORMAL;
1200 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1201 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1203 sheet->column_title_window = NULL;
1204 sheet->column_title_area.x = 0;
1205 sheet->column_title_area.y = 0;
1206 sheet->column_title_area.width = 0;
1207 sheet->column_title_area.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
1209 sheet->row_title_window = NULL;
1210 sheet->row_title_area.x = 0;
1211 sheet->row_title_area.y = 0;
1212 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1213 sheet->row_title_area.height = 0;
1216 sheet->active_cell.row = 0;
1217 sheet->active_cell.col = 0;
1218 sheet->selection_cell.row = 0;
1219 sheet->selection_cell.col = 0;
1221 sheet->sheet_entry = NULL;
1222 sheet->pixmap = NULL;
1224 sheet->range.row0 = 0;
1225 sheet->range.rowi = 0;
1226 sheet->range.col0 = 0;
1227 sheet->range.coli = 0;
1229 sheet->state = GTK_SHEET_NORMAL;
1231 sheet->sheet_window = NULL;
1232 sheet->sheet_window_width = 0;
1233 sheet->sheet_window_height = 0;
1234 sheet->sheet_entry = NULL;
1235 sheet->button = NULL;
1240 sheet->hadjustment = NULL;
1241 sheet->vadjustment = NULL;
1243 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
1244 sheet->xor_gc = NULL;
1245 sheet->fg_gc = NULL;
1246 sheet->bg_gc = NULL;
1250 gdk_color_parse ("white", &sheet->bg_color);
1251 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1252 gdk_color_parse ("gray", &sheet->grid_color);
1253 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1254 sheet->show_grid = TRUE;
1256 sheet->motion_timer = 0;
1260 /* Callback which occurs whenever columns are inserted / deleted in the model */
1262 columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
1267 GtkSheet *sheet = GTK_SHEET (data);
1269 GtkSheetRange range;
1270 gint model_columns = g_sheet_model_get_column_count (model);
1273 /* Need to update all the columns starting from the first column and onwards.
1274 * Previous column are unchanged, so don't need to be updated.
1276 range.col0 = first_column;
1278 range.coli = xxx_column_count (sheet) - 1;
1279 range.rowi = yyy_row_count (sheet) - 1;
1281 adjust_scrollbars (sheet);
1283 if (sheet->active_cell.col >= model_columns)
1284 gtk_sheet_activate_cell (sheet, sheet->active_cell.row, model_columns - 1);
1286 for (i = first_column; i <= MAX_VISIBLE_COLUMN (sheet); i++)
1287 gtk_sheet_column_title_button_draw (sheet, i);
1289 gtk_sheet_range_draw (sheet, &range);
1293 /* Callback which occurs whenever rows are inserted / deleted in the model */
1295 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
1296 gint n_rows, gpointer data)
1299 GtkSheet *sheet = GTK_SHEET (data);
1301 GtkSheetRange range;
1303 gint model_rows = g_sheet_model_get_row_count (model);
1305 /* Need to update all the rows starting from the first row and onwards.
1306 * Previous rows are unchanged, so don't need to be updated.
1308 range.row0 = first_row;
1310 range.rowi = yyy_row_count (sheet) - 1;
1311 range.coli = xxx_column_count (sheet) - 1;
1313 adjust_scrollbars (sheet);
1315 if (sheet->active_cell.row >= model_rows)
1316 gtk_sheet_activate_cell (sheet, model_rows - 1, sheet->active_cell.col);
1318 for (i = first_row; i <= MAX_VISIBLE_ROW (sheet); i++)
1319 gtk_sheet_row_title_button_draw (sheet, i);
1321 gtk_sheet_range_draw (sheet, &range);
1325 If row0 or rowi are negative, then all rows will be updated.
1326 If col0 or coli are negative, then all columns will be updated.
1329 range_update_callback (GSheetModel *m, gint row0, gint col0,
1330 gint rowi, gint coli, gpointer data)
1332 GtkSheet *sheet = GTK_SHEET (data);
1334 GtkSheetRange range;
1341 if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1344 gtk_sheet_range_draw (sheet, NULL);
1345 adjust_scrollbars (sheet);
1347 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
1348 gtk_sheet_row_title_button_draw (sheet, i);
1350 for (i = MIN_VISIBLE_COLUMN (sheet);
1351 i <= MAX_VISIBLE_COLUMN (sheet); i++)
1352 gtk_sheet_column_title_button_draw (sheet, i);
1356 else if ( row0 < 0 || rowi < 0 )
1358 range.row0 = MIN_VISIBLE_ROW (sheet);
1359 range.rowi = MAX_VISIBLE_ROW (sheet);
1361 else if ( col0 < 0 || coli < 0 )
1363 range.col0 = MIN_VISIBLE_COLUMN (sheet);
1364 range.coli = MAX_VISIBLE_COLUMN (sheet);
1367 gtk_sheet_range_draw (sheet, &range);
1371 static void gtk_sheet_construct (GtkSheet *sheet,
1374 const gchar *title);
1379 * @rows: initial number of rows
1380 * @columns: initial number of columns
1381 * @title: sheet title
1382 * @model: the model to use for the sheet data
1384 * Creates a new sheet widget with the given number of rows and columns.
1386 * Returns: the new sheet widget
1389 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1392 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1394 gtk_sheet_construct (GTK_SHEET (widget), vgeo, hgeo, title);
1397 gtk_sheet_set_model (GTK_SHEET (widget), model);
1405 * gtk_sheet_set_model
1406 * @sheet: the sheet to set the model for
1407 * @model: the model to use for the sheet data
1409 * Sets the model for a GtkSheet
1413 gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
1415 g_return_if_fail (GTK_IS_SHEET (sheet));
1416 g_return_if_fail (G_IS_SHEET_MODEL (model));
1418 sheet->model = model;
1420 g_signal_connect (model, "range_changed",
1421 G_CALLBACK (range_update_callback), sheet);
1423 g_signal_connect (model, "rows_inserted",
1424 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1426 g_signal_connect (model, "rows_deleted",
1427 G_CALLBACK (rows_inserted_deleted_callback), sheet);
1429 g_signal_connect (model, "columns_inserted",
1430 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1432 g_signal_connect (model, "columns_deleted",
1433 G_CALLBACK (columns_inserted_deleted_callback), sheet);
1438 /* Call back for when the column titles have changed.
1439 FIRST is the first column changed.
1440 N_COLUMNS is the number of columns which have changed, or - 1, which
1441 indicates that the column has changed to its right - most extremity
1444 column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
1446 GtkSheet *sheet = GTK_SHEET (data);
1447 gboolean extremity = FALSE;
1449 if ( n_columns == -1 )
1452 n_columns = xxx_column_count (sheet) - 1 ;
1455 if (!GTK_SHEET_IS_FROZEN (sheet))
1458 for ( i = first ; i <= first + n_columns ; ++i )
1460 gtk_sheet_column_title_button_draw (sheet, i);
1461 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, i);
1466 gtk_sheet_column_title_button_draw (sheet, -1);
1471 gtk_sheet_construct (GtkSheet *sheet,
1476 g_return_if_fail (G_IS_SHEET_COLUMN (hgeo));
1477 g_return_if_fail (G_IS_SHEET_ROW (vgeo));
1479 sheet->column_geometry = hgeo;
1480 sheet->row_geometry = vgeo;
1483 sheet->columns_resizable = TRUE;
1484 sheet->rows_resizable = TRUE;
1486 sheet->row_titles_visible = TRUE;
1487 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1489 sheet->column_titles_visible = TRUE;
1490 sheet->autoscroll = TRUE;
1491 sheet->justify_entry = TRUE;
1494 /* create sheet entry */
1495 sheet->entry_type = 0;
1496 create_sheet_entry (sheet);
1498 /* create global selection button */
1499 create_global_button (sheet);
1502 sheet->name = g_strdup (title);
1504 g_signal_connect (sheet->column_geometry, "columns_changed",
1505 G_CALLBACK (column_titles_changed), sheet);
1511 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns,
1512 const gchar *title, GtkType entry_type)
1514 GtkWidget *widget = g_object_new (GTK_TYPE_SHEET, NULL);
1516 gtk_sheet_construct_with_custom_entry (GTK_SHEET (widget),
1517 rows, columns, title, entry_type);
1523 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1529 gtk_sheet_construct (sheet, vgeo, hgeo, title);
1531 sheet->entry_type = entry_type;
1532 create_sheet_entry (sheet);
1538 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
1542 g_return_if_fail (sheet != NULL);
1543 g_return_if_fail (GTK_IS_SHEET (sheet));
1545 state = sheet->state;
1547 if (sheet->state == GTK_SHEET_NORMAL)
1548 gtk_sheet_hide_active_cell (sheet);
1550 sheet->entry_type = entry_type;
1552 create_sheet_entry (sheet);
1554 if (state == GTK_SHEET_NORMAL)
1556 gtk_sheet_show_active_cell (sheet);
1557 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
1559 G_CALLBACK (gtk_sheet_entry_changed),
1565 gtk_sheet_show_grid (GtkSheet *sheet, gboolean show)
1567 g_return_if_fail (sheet != NULL);
1568 g_return_if_fail (GTK_IS_SHEET (sheet));
1570 if (show == sheet->show_grid) return;
1572 sheet->show_grid = show;
1574 if (!GTK_SHEET_IS_FROZEN (sheet))
1575 gtk_sheet_range_draw (sheet, NULL);
1579 gtk_sheet_grid_visible (GtkSheet *sheet)
1581 g_return_val_if_fail (sheet != NULL, 0);
1582 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1584 return sheet->show_grid;
1588 gtk_sheet_set_background (GtkSheet *sheet, GdkColor *color)
1590 g_return_if_fail (sheet != NULL);
1591 g_return_if_fail (GTK_IS_SHEET (sheet));
1595 gdk_color_parse ("white", &sheet->bg_color);
1596 gdk_color_alloc (gdk_colormap_get_system (), &sheet->bg_color);
1599 sheet->bg_color = *color;
1601 if (!GTK_SHEET_IS_FROZEN (sheet))
1602 gtk_sheet_range_draw (sheet, NULL);
1606 gtk_sheet_set_grid (GtkSheet *sheet, GdkColor *color)
1608 g_return_if_fail (sheet != NULL);
1609 g_return_if_fail (GTK_IS_SHEET (sheet));
1613 gdk_color_parse ("black", &sheet->grid_color);
1614 gdk_color_alloc (gdk_colormap_get_system (), &sheet->grid_color);
1617 sheet->grid_color = *color;
1619 if (!GTK_SHEET_IS_FROZEN (sheet))
1620 gtk_sheet_range_draw (sheet, NULL);
1624 gtk_sheet_get_columns_count (GtkSheet *sheet)
1626 g_return_val_if_fail (sheet != NULL, 0);
1627 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1629 return xxx_column_count (sheet);
1633 gtk_sheet_get_rows_count (GtkSheet *sheet)
1635 g_return_val_if_fail (sheet != NULL, 0);
1636 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1638 return yyy_row_count (sheet);
1642 gtk_sheet_get_state (GtkSheet *sheet)
1644 g_return_val_if_fail (sheet != NULL, 0);
1645 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1647 return (sheet->state);
1651 gtk_sheet_set_selection_mode (GtkSheet *sheet, gint mode)
1653 g_return_if_fail (sheet != NULL);
1654 g_return_if_fail (GTK_IS_SHEET (sheet));
1656 if (GTK_WIDGET_REALIZED (sheet))
1657 gtk_sheet_real_unselect_range (sheet, NULL);
1659 sheet->selection_mode = mode;
1663 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1665 g_return_if_fail (sheet != NULL);
1666 g_return_if_fail (GTK_IS_SHEET (sheet));
1668 sheet->autoresize = autoresize;
1672 gtk_sheet_autoresize (GtkSheet *sheet)
1674 g_return_val_if_fail (sheet != NULL, FALSE);
1675 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1677 return sheet->autoresize;
1681 gtk_sheet_set_column_width (GtkSheet * sheet,
1687 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1689 gint text_width = 0;
1692 g_return_if_fail (sheet != NULL);
1693 g_return_if_fail (GTK_IS_SHEET (sheet));
1694 if (column >= xxx_column_count (sheet) || column < 0) return;
1696 for (row = 0; row < yyy_row_count (sheet); row++)
1698 gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
1699 if (text && strlen (text) > 0)
1701 GtkSheetCellAttr attributes;
1703 gtk_sheet_get_attributes (sheet, row, column, &attributes);
1704 if (attributes.is_visible)
1706 gint width = STRING_WIDTH (GTK_WIDGET (sheet),
1707 attributes.font_desc,
1709 + 2 * CELLOFFSET + attributes.border.width;
1710 text_width = MAX (text_width, width);
1713 dispose_string (sheet, text);
1716 if (text_width > xxx_column_width (sheet, column) )
1718 gtk_sheet_set_column_width (sheet, column, text_width);
1719 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
1725 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1727 g_return_if_fail (sheet != NULL);
1728 g_return_if_fail (GTK_IS_SHEET (sheet));
1730 sheet->autoscroll = autoscroll;
1734 gtk_sheet_autoscroll (GtkSheet *sheet)
1736 g_return_val_if_fail (sheet != NULL, FALSE);
1737 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1739 return sheet->autoscroll;
1743 gtk_sheet_set_clip_text (GtkSheet *sheet, gboolean clip_text)
1745 g_return_if_fail (sheet != NULL);
1746 g_return_if_fail (GTK_IS_SHEET (sheet));
1748 sheet->clip_text = clip_text;
1752 gtk_sheet_clip_text (GtkSheet *sheet)
1754 g_return_val_if_fail (sheet != NULL, FALSE);
1755 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1757 return sheet->clip_text;
1761 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1763 g_return_if_fail (sheet != NULL);
1764 g_return_if_fail (GTK_IS_SHEET (sheet));
1766 sheet->justify_entry = justify;
1770 gtk_sheet_justify_entry (GtkSheet *sheet)
1772 g_return_val_if_fail (sheet != NULL, FALSE);
1773 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1775 return sheet->justify_entry;
1779 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1781 g_return_if_fail (sheet != NULL);
1782 g_return_if_fail (GTK_IS_SHEET (sheet));
1786 GTK_SHEET_SET_FLAGS (sheet,GTK_SHEET_IS_LOCKED);
1787 gtk_widget_hide (sheet->sheet_entry);
1788 gtk_widget_unmap (sheet->sheet_entry);
1792 GTK_SHEET_UNSET_FLAGS (sheet,GTK_SHEET_IS_LOCKED);
1793 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)))
1795 gtk_widget_show (sheet->sheet_entry);
1796 gtk_widget_map (sheet->sheet_entry);
1800 gtk_editable_set_editable (GTK_EDITABLE (sheet->sheet_entry), locked);
1805 gtk_sheet_locked (const GtkSheet *sheet)
1807 g_return_val_if_fail (sheet != NULL, FALSE);
1808 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1810 return GTK_SHEET_IS_LOCKED (sheet);
1813 /* This routine has problems with gtk+- 1.2 related with the
1814 label / button drawing - I think it's a bug in gtk+- 1.2 */
1816 gtk_sheet_set_title (GtkSheet *sheet, const gchar *title)
1820 g_return_if_fail (sheet != NULL);
1821 g_return_if_fail (title != NULL);
1822 g_return_if_fail (GTK_IS_SHEET (sheet));
1825 g_free (sheet->name);
1827 sheet->name = g_strdup (title);
1829 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) || !title) return;
1831 if (GTK_BIN (sheet->button)->child)
1832 label = GTK_BIN (sheet->button)->child;
1834 size_allocate_global_button (sheet);
1838 gtk_sheet_freeze (GtkSheet *sheet)
1840 g_return_if_fail (sheet != NULL);
1841 g_return_if_fail (GTK_IS_SHEET (sheet));
1843 sheet->freeze_count++;
1844 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1848 gtk_sheet_thaw (GtkSheet *sheet)
1850 g_return_if_fail (sheet != NULL);
1851 g_return_if_fail (GTK_IS_SHEET (sheet));
1853 if (sheet->freeze_count == 0) return;
1855 sheet->freeze_count--;
1856 if (sheet->freeze_count > 0) return;
1858 adjust_scrollbars (sheet);
1860 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
1862 sheet->old_vadjustment = -1.;
1863 sheet->old_hadjustment = -1.;
1865 if (sheet->hadjustment)
1866 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1868 if (sheet->vadjustment)
1869 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1872 if (sheet->state == GTK_STATE_NORMAL)
1873 if (sheet->sheet_entry && GTK_WIDGET_MAPPED (sheet->sheet_entry))
1875 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
1876 sheet->active_cell.col);
1882 gtk_sheet_set_row_titles_width (GtkSheet *sheet, guint width)
1884 if (width < COLUMN_MIN_WIDTH) return;
1886 sheet->row_title_area.width = width;
1888 adjust_scrollbars (sheet);
1890 sheet->old_hadjustment = -1.;
1891 if (sheet->hadjustment)
1892 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1894 size_allocate_global_button (sheet);
1898 gtk_sheet_set_column_titles_height (GtkSheet *sheet, guint height)
1900 if (height < DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))) return;
1902 sheet->column_title_area.height = height;
1904 adjust_scrollbars (sheet);
1906 sheet->old_vadjustment = -1.;
1907 if (sheet->vadjustment)
1908 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1910 size_allocate_global_button (sheet);
1914 gtk_sheet_show_column_titles (GtkSheet *sheet)
1918 if (sheet->column_titles_visible) return;
1920 sheet->column_titles_visible = TRUE;
1923 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1925 gdk_window_show (sheet->column_title_window);
1926 gdk_window_move_resize (sheet->column_title_window,
1927 sheet->column_title_area.x,
1928 sheet->column_title_area.y,
1929 sheet->column_title_area.width,
1930 sheet->column_title_area.height);
1932 for (col = MIN_VISIBLE_COLUMN (sheet);
1933 col <= MAX_VISIBLE_COLUMN (sheet);
1936 GtkSheetButton *button = xxx_column_button (sheet, col);
1937 GtkSheetChild *child = button->child;
1939 gtk_sheet_child_show (child);
1940 gtk_sheet_button_free (button);
1942 adjust_scrollbars (sheet);
1945 sheet->old_vadjustment = -1.;
1946 if (sheet->vadjustment)
1947 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
1949 size_allocate_global_button (sheet);
1954 gtk_sheet_show_row_titles (GtkSheet *sheet)
1958 if (sheet->row_titles_visible) return;
1960 sheet->row_titles_visible = TRUE;
1963 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
1965 gdk_window_show (sheet->row_title_window);
1966 gdk_window_move_resize (sheet->row_title_window,
1967 sheet->row_title_area.x,
1968 sheet->row_title_area.y,
1969 sheet->row_title_area.width,
1970 sheet->row_title_area.height);
1972 for (row = MIN_VISIBLE_ROW (sheet);
1973 row <= MAX_VISIBLE_ROW (sheet);
1976 const GtkSheetButton *button = yyy_row_button (sheet, row);
1977 GtkSheetChild *child = button->child;
1981 gtk_sheet_child_show (child);
1984 adjust_scrollbars (sheet);
1987 sheet->old_hadjustment = -1.;
1988 if (sheet->hadjustment)
1989 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
1991 size_allocate_global_button (sheet);
1995 gtk_sheet_hide_column_titles (GtkSheet *sheet)
1999 if (!sheet->column_titles_visible) return;
2001 sheet->column_titles_visible = FALSE;
2003 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
2005 if (sheet->column_title_window)
2006 gdk_window_hide (sheet->column_title_window);
2007 if (GTK_WIDGET_VISIBLE (sheet->button))
2008 gtk_widget_hide (sheet->button);
2010 for (col = MIN_VISIBLE_COLUMN (sheet);
2011 col <= MAX_VISIBLE_COLUMN (sheet);
2014 GtkSheetButton *button = xxx_column_button (sheet, col);
2015 GtkSheetChild *child = button->child;
2017 gtk_sheet_child_hide (child);
2018 gtk_sheet_button_free (button);
2020 adjust_scrollbars (sheet);
2023 sheet->old_vadjustment = -1.;
2024 if (sheet->vadjustment)
2025 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2030 gtk_sheet_hide_row_titles (GtkSheet *sheet)
2034 if (!sheet->row_titles_visible) return;
2036 sheet->row_titles_visible = FALSE;
2039 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
2041 if (sheet->row_title_window)
2042 gdk_window_hide (sheet->row_title_window);
2043 if (GTK_WIDGET_VISIBLE (sheet->button))
2044 gtk_widget_hide (sheet->button);
2045 for (row = MIN_VISIBLE_ROW (sheet);
2046 row <= MAX_VISIBLE_ROW (sheet);
2049 const GtkSheetButton *button = yyy_row_button (sheet, row);
2050 GtkSheetChild *child = button->child;
2053 gtk_sheet_child_hide (child);
2055 adjust_scrollbars (sheet);
2058 sheet->old_hadjustment = -1.;
2059 if (sheet->hadjustment)
2060 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2065 gtk_sheet_column_titles_visible (GtkSheet *sheet)
2067 g_return_val_if_fail (sheet != NULL, FALSE);
2068 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2069 return sheet->column_titles_visible;
2073 gtk_sheet_row_titles_visible (GtkSheet *sheet)
2075 g_return_val_if_fail (sheet != NULL, FALSE);
2076 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2077 return sheet->row_titles_visible;
2081 gtk_sheet_moveto (GtkSheet *sheet,
2088 guint width, height;
2090 gint min_row, min_col;
2092 g_return_if_fail (sheet != NULL);
2093 g_return_if_fail (GTK_IS_SHEET (sheet));
2094 g_return_if_fail (sheet->hadjustment != NULL);
2095 g_return_if_fail (sheet->vadjustment != NULL);
2097 if (row < 0 || row >= yyy_row_count (sheet))
2099 if (column < 0 || column >= xxx_column_count (sheet))
2102 height = sheet->sheet_window_height;
2103 width = sheet->sheet_window_width;
2105 /* adjust vertical scrollbar */
2106 if (row >= 0 && row_align >= 0.)
2108 y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
2109 - (gint) ( row_align*height + (1. - row_align)
2110 * yyy_row_height (sheet, row));
2112 /* This forces the sheet to scroll when you don't see the entire cell */
2115 if (row_align == 1.)
2117 while (min_row >= 0 && min_row > MIN_VISIBLE_ROW (sheet))
2119 if (yyy_row_is_visible (sheet, min_row))
2120 adjust += yyy_row_height (sheet, min_row);
2121 if (adjust >= height)
2127 min_row = MAX (min_row, 0);
2128 y = ROW_TOP_YPIXEL (sheet, min_row) - sheet->voffset +
2129 yyy_row_height (sheet, min_row) - 1;
2133 sheet->vadjustment->value = 0.0;
2135 sheet->vadjustment->value = y;
2137 sheet->old_vadjustment = -1.;
2138 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment),
2143 /* adjust horizontal scrollbar */
2144 if (column >= 0 && col_align >= 0.)
2146 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2147 - (gint) ( col_align*width + (1.- col_align)*
2148 xxx_column_width (sheet, column));
2151 /* This forces the sheet to scroll when you don't see the entire cell */
2154 if (col_align == 1.)
2156 while (min_col >= 0 && min_col > MIN_VISIBLE_COLUMN (sheet))
2158 if (xxx_column_is_visible (sheet, min_col))
2159 adjust += xxx_column_width (sheet, min_col);
2161 if (adjust >= width)
2167 min_col = MAX (min_col, 0);
2168 x = COLUMN_LEFT_XPIXEL (sheet, min_col) - sheet->hoffset +
2169 xxx_column_width (sheet, min_col) - 1;
2173 sheet->hadjustment->value = 0.0;
2175 sheet->hadjustment->value = x;
2177 sheet->old_vadjustment = -1.;
2178 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment),
2186 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2188 g_return_if_fail (sheet != NULL);
2189 g_return_if_fail (GTK_IS_SHEET (sheet));
2191 sheet->columns_resizable = resizable;
2195 gtk_sheet_columns_resizable (GtkSheet *sheet)
2197 g_return_val_if_fail (sheet != NULL, FALSE);
2198 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2200 return sheet->columns_resizable;
2205 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2207 g_return_if_fail (sheet != NULL);
2208 g_return_if_fail (GTK_IS_SHEET (sheet));
2210 sheet->rows_resizable = resizable;
2214 gtk_sheet_rows_resizable (GtkSheet *sheet)
2216 g_return_val_if_fail (sheet != NULL, FALSE);
2217 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2219 return sheet->rows_resizable;
2224 gtk_sheet_select_row (GtkSheet * sheet,
2227 g_return_if_fail (sheet != NULL);
2228 g_return_if_fail (GTK_IS_SHEET (sheet));
2230 if (row < 0 || row >= yyy_row_count (sheet))
2233 if (sheet->state != GTK_SHEET_NORMAL)
2234 gtk_sheet_real_unselect_range (sheet, NULL);
2237 gboolean veto = TRUE;
2238 veto = gtk_sheet_deactivate_cell (sheet);
2242 sheet->state = GTK_SHEET_ROW_SELECTED;
2243 sheet->range.row0 = row;
2244 sheet->range.col0 = 0;
2245 sheet->range.rowi = row;
2246 sheet->range.coli = xxx_column_count (sheet) - 1;
2247 sheet->active_cell.row = row;
2248 sheet->active_cell.col = 0;
2250 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, row);
2251 gtk_sheet_real_select_range (sheet, NULL);
2256 gtk_sheet_select_column (GtkSheet * sheet, gint column)
2258 g_return_if_fail (sheet != NULL);
2259 g_return_if_fail (GTK_IS_SHEET (sheet));
2261 if (column < 0 || column >= xxx_column_count (sheet))
2264 if (sheet->state != GTK_SHEET_NORMAL)
2265 gtk_sheet_real_unselect_range (sheet, NULL);
2268 gboolean veto = TRUE;
2269 veto = gtk_sheet_deactivate_cell (sheet);
2273 sheet->state = GTK_SHEET_COLUMN_SELECTED;
2274 sheet->range.row0 = 0;
2275 sheet->range.col0 = column;
2276 sheet->range.rowi = yyy_row_count (sheet) - 1;
2277 sheet->range.coli = column;
2278 sheet->active_cell.row = 0;
2279 sheet->active_cell.col = column;
2281 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, column);
2282 gtk_sheet_real_select_range (sheet, NULL);
2288 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2291 g_return_if_fail (sheet != NULL);
2292 g_return_if_fail (GTK_IS_SHEET (sheet));
2294 if (GTK_SHEET_IN_CLIP (sheet)) return;
2296 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_CLIP);
2299 sheet->clip_range = sheet->range;
2301 sheet->clip_range=*range;
2303 sheet->interval = 0;
2304 sheet->clip_timer = g_timeout_add (TIMEOUT_FLASH, gtk_sheet_flash, sheet);
2306 g_signal_emit (G_OBJECT (sheet), sheet_signals[CLIP_RANGE], 0,
2307 &sheet->clip_range);
2311 gtk_sheet_unclip_range (GtkSheet *sheet)
2314 g_return_if_fail (sheet != NULL);
2315 g_return_if_fail (GTK_IS_SHEET (sheet));
2317 if (!GTK_SHEET_IN_CLIP (sheet)) return;
2319 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_CLIP);
2321 g_source_remove (sheet->clip_timer);
2322 gtk_sheet_range_draw (sheet, &sheet->clip_range);
2324 if (gtk_sheet_range_isvisible (sheet, sheet->range))
2325 gtk_sheet_range_draw (sheet, &sheet->range);
2329 gtk_sheet_in_clip (GtkSheet *sheet)
2331 g_return_val_if_fail (sheet != NULL, FALSE);
2332 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2334 return GTK_SHEET_IN_CLIP (sheet);
2338 gtk_sheet_flash (gpointer data)
2341 gint x,y,width,height;
2342 GdkRectangle clip_area;
2344 sheet = GTK_SHEET (data);
2346 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return TRUE;
2347 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return TRUE;
2348 if (!gtk_sheet_range_isvisible (sheet, sheet->clip_range)) return TRUE;
2349 if (GTK_SHEET_IN_XDRAG (sheet)) return TRUE;
2350 if (GTK_SHEET_IN_YDRAG (sheet)) return TRUE;
2352 GDK_THREADS_ENTER ();
2354 x = COLUMN_LEFT_XPIXEL (sheet,sheet->clip_range.col0)+1;
2355 y = ROW_TOP_YPIXEL (sheet,sheet->clip_range.row0)+1;
2356 width = COLUMN_LEFT_XPIXEL (sheet,sheet->clip_range.coli)- x+
2357 xxx_column_width (sheet, sheet->clip_range.coli) - 1;
2358 height = ROW_TOP_YPIXEL (sheet,sheet->clip_range.rowi)- y+
2359 yyy_row_height (sheet, sheet->clip_range.rowi)- 1;
2361 clip_area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
2362 clip_area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
2363 clip_area.width = sheet->sheet_window_width;
2364 clip_area.height = sheet->sheet_window_height;
2371 if (width > clip_area.width) width = clip_area.width + 10;
2377 if (height > clip_area.height) height = clip_area.height + 10;
2379 gdk_draw_pixmap (sheet->sheet_window,
2380 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
2386 gdk_draw_pixmap (sheet->sheet_window,
2387 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
2393 gdk_draw_pixmap (sheet->sheet_window,
2394 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
2400 gdk_draw_pixmap (sheet->sheet_window,
2401 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
2408 sheet->interval = sheet->interval + 1;
2409 if (sheet->interval == TIME_INTERVAL) sheet->interval = 0;
2411 gdk_gc_set_dashes (sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2412 gtk_sheet_draw_flashing_range (sheet,sheet->clip_range);
2413 gdk_gc_set_dashes (sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2415 GDK_THREADS_LEAVE ();
2421 gtk_sheet_draw_flashing_range (GtkSheet *sheet, GtkSheetRange range)
2423 GdkRectangle clip_area;
2424 gint x,y,width,height;
2426 if (!gtk_sheet_range_isvisible (sheet, sheet->clip_range)) return;
2428 clip_area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
2429 clip_area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
2430 clip_area.width = sheet->sheet_window_width;
2431 clip_area.height = sheet->sheet_window_height;
2433 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
2435 x = COLUMN_LEFT_XPIXEL (sheet,sheet->clip_range.col0)+1;
2436 y = ROW_TOP_YPIXEL (sheet,sheet->clip_range.row0)+1;
2437 width = COLUMN_LEFT_XPIXEL (sheet,sheet->clip_range.coli)- x+
2438 xxx_column_width (sheet, sheet->clip_range.coli) - 1;
2439 height = ROW_TOP_YPIXEL (sheet,sheet->clip_range.rowi)- y+
2440 yyy_row_height (sheet, sheet->clip_range.rowi)- 1;
2447 if (width > clip_area.width) width = clip_area.width + 10;
2453 if (height > clip_area.height) height = clip_area.height + 10;
2455 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 1, 0, 0 );
2457 gdk_draw_rectangle (sheet->sheet_window, sheet->xor_gc, FALSE,
2461 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2463 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
2467 gtk_sheet_range_isvisible (GtkSheet * sheet,
2468 GtkSheetRange range)
2470 g_return_val_if_fail (sheet != NULL, FALSE);
2472 if (range.row0 < 0 || range.row0 >= yyy_row_count (sheet))
2475 if (range.rowi < 0 || range.rowi >= yyy_row_count (sheet))
2478 if (range.col0 < 0 || range.col0 >= xxx_column_count (sheet))
2481 if (range.coli < 0 || range.coli >= xxx_column_count (sheet))
2484 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2487 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2490 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2493 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2500 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2501 gint row, gint column)
2503 GtkSheetRange range;
2506 range.col0 = column;
2508 range.coli = column;
2510 return gtk_sheet_range_isvisible (sheet, range);
2514 gtk_sheet_get_visible_range (GtkSheet *sheet, GtkSheetRange *range)
2516 g_return_if_fail (sheet != NULL);
2517 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2518 g_return_if_fail (range != NULL);
2520 range->row0 = MIN_VISIBLE_ROW (sheet);
2521 range->col0 = MIN_VISIBLE_COLUMN (sheet);
2522 range->rowi = MAX_VISIBLE_ROW (sheet);
2523 range->coli = MAX_VISIBLE_COLUMN (sheet);
2527 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2529 g_return_val_if_fail (sheet != NULL, NULL);
2530 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2532 return sheet->vadjustment;
2536 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2538 g_return_val_if_fail (sheet != NULL, NULL);
2539 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2541 return sheet->hadjustment;
2545 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2546 GtkAdjustment *adjustment)
2548 GtkAdjustment *old_adjustment;
2550 g_return_if_fail (sheet != NULL);
2551 g_return_if_fail (GTK_IS_SHEET (sheet));
2553 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2555 if (sheet->vadjustment == adjustment)
2558 old_adjustment = sheet->vadjustment;
2560 if (sheet->vadjustment)
2562 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2563 G_SIGNAL_MATCH_DATA,
2566 g_object_unref (G_OBJECT (sheet->vadjustment));
2569 sheet->vadjustment = adjustment;
2571 if (sheet->vadjustment)
2573 g_object_ref (G_OBJECT (sheet->vadjustment));
2574 g_object_ref_sink (G_OBJECT (sheet->vadjustment));
2576 g_signal_connect (G_OBJECT (sheet->vadjustment), "value_changed",
2577 G_CALLBACK (vadjustment_value_changed),
2581 if (!sheet->vadjustment || !old_adjustment)
2583 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2587 sheet->old_vadjustment = sheet->vadjustment->value;
2591 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2592 GtkAdjustment *adjustment)
2594 GtkAdjustment *old_adjustment;
2596 g_return_if_fail (sheet != NULL);
2597 g_return_if_fail (GTK_IS_SHEET (sheet));
2599 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2601 if (sheet->hadjustment == adjustment)
2604 old_adjustment = sheet->hadjustment;
2606 if (sheet->hadjustment)
2608 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2609 G_SIGNAL_MATCH_DATA,
2612 g_object_unref (G_OBJECT (sheet->hadjustment));
2615 sheet->hadjustment = adjustment;
2617 if (sheet->hadjustment)
2619 g_object_ref (G_OBJECT (sheet->hadjustment));
2620 g_object_ref_sink (G_OBJECT (sheet->hadjustment));
2622 g_signal_connect (G_OBJECT (sheet->hadjustment), "value_changed",
2623 G_CALLBACK (hadjustment_value_changed),
2627 if (!sheet->hadjustment || !old_adjustment)
2629 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2633 sheet->old_hadjustment = sheet->hadjustment->value;
2637 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2638 GtkAdjustment *hadjustment,
2639 GtkAdjustment *vadjustment)
2641 if (sheet->hadjustment != hadjustment)
2642 gtk_sheet_set_hadjustment (sheet, hadjustment);
2644 if (sheet->vadjustment != vadjustment)
2645 gtk_sheet_set_vadjustment (sheet, vadjustment);
2649 gtk_sheet_finalize (GObject * object)
2653 g_return_if_fail (object != NULL);
2654 g_return_if_fail (GTK_IS_SHEET (object));
2656 sheet = GTK_SHEET (object);
2660 g_free (sheet->name);
2664 if (G_OBJECT_CLASS (parent_class)->finalize)
2665 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2669 gtk_sheet_destroy (GtkObject * object)
2674 g_return_if_fail (object != NULL);
2675 g_return_if_fail (GTK_IS_SHEET (object));
2677 sheet = GTK_SHEET (object);
2679 /* destroy the entry */
2680 if (sheet->sheet_entry && GTK_IS_WIDGET (sheet->sheet_entry))
2682 gtk_widget_destroy (sheet->sheet_entry);
2683 sheet->sheet_entry = NULL;
2686 /* destroy the global selection button */
2687 if (sheet->button && GTK_IS_WIDGET (sheet->button))
2689 gtk_widget_destroy (sheet->button);
2690 sheet->button = NULL;
2693 if (sheet->clip_timer)
2695 g_source_remove (sheet->clip_timer);
2696 sheet->clip_timer = 0;
2699 /* unref adjustments */
2700 if (sheet->hadjustment)
2702 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->hadjustment),
2703 G_SIGNAL_MATCH_DATA,
2707 g_object_unref (G_OBJECT (sheet->hadjustment));
2708 sheet->hadjustment = NULL;
2711 if (sheet->vadjustment)
2713 g_signal_handlers_disconnect_matched (G_OBJECT (sheet->vadjustment),
2714 G_SIGNAL_MATCH_DATA,
2718 g_object_unref (G_OBJECT (sheet->vadjustment));
2720 sheet->vadjustment = NULL;
2723 children = sheet->children;
2726 GtkSheetChild *child = (GtkSheetChild *)children->data;
2727 if (child && child->widget)
2728 gtk_sheet_remove (GTK_CONTAINER (sheet), child->widget);
2729 children = sheet->children;
2731 sheet->children = NULL;
2733 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2734 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2738 gtk_sheet_style_set (GtkWidget *widget,
2739 GtkStyle *previous_style)
2743 g_return_if_fail (widget != NULL);
2744 g_return_if_fail (GTK_IS_SHEET (widget));
2746 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2747 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2749 sheet = GTK_SHEET (widget);
2751 if (GTK_WIDGET_REALIZED (widget))
2753 gtk_style_set_background (widget->style, widget->window, widget->state);
2759 gtk_sheet_realize (GtkWidget * widget)
2762 GdkWindowAttr attributes;
2763 gint attributes_mask;
2764 GdkGCValues values, auxvalues;
2765 GdkColormap *colormap;
2767 GtkSheetChild *child;
2770 g_return_if_fail (widget != NULL);
2771 g_return_if_fail (GTK_IS_SHEET (widget));
2773 sheet = GTK_SHEET (widget);
2775 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2777 attributes.window_type = GDK_WINDOW_CHILD;
2778 attributes.x = widget->allocation.x;
2779 attributes.y = widget->allocation.y;
2780 attributes.width = widget->allocation.width;
2781 attributes.height = widget->allocation.height;
2782 attributes.wclass = GDK_INPUT_OUTPUT;
2784 attributes.visual = gtk_widget_get_visual (widget);
2785 attributes.colormap = gtk_widget_get_colormap (widget);
2787 attributes.event_mask = gtk_widget_get_events (widget);
2788 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2789 GDK_BUTTON_PRESS_MASK |
2790 GDK_BUTTON_RELEASE_MASK |
2791 GDK_KEY_PRESS_MASK |
2792 GDK_POINTER_MOTION_MASK |
2793 GDK_POINTER_MOTION_HINT_MASK);
2794 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2797 attributes.cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
2800 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2802 gdk_window_set_user_data (widget->window, sheet);
2804 widget->style = gtk_style_attach (widget->style, widget->window);
2806 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2809 if (sheet->row_titles_visible)
2810 attributes.x = sheet->row_title_area.width;
2812 attributes.width = sheet->column_title_area.width;
2813 attributes.height = sheet->column_title_area.height;
2815 /* column - title window */
2816 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2817 gdk_window_set_user_data (sheet->column_title_window, sheet);
2818 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2822 if (sheet->column_titles_visible)
2823 attributes.y = sheet->column_title_area.height;
2824 attributes.width = sheet->row_title_area.width;
2825 attributes.height = sheet->row_title_area.height;
2827 /* row - title window */
2828 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2829 gdk_window_set_user_data (sheet->row_title_window, sheet);
2830 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2832 /* sheet - window */
2833 attributes.cursor = gdk_cursor_new (GDK_PLUS);
2837 attributes.width = sheet->sheet_window_width,
2838 attributes.height = sheet->sheet_window_height;
2840 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2841 gdk_window_set_user_data (sheet->sheet_window, sheet);
2843 gdk_cursor_unref (attributes.cursor);
2845 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2846 gdk_window_show (sheet->sheet_window);
2848 /* backing_pixmap */
2849 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
2853 gdk_gc_unref (sheet->fg_gc);
2855 gdk_gc_unref (sheet->bg_gc);
2856 sheet->fg_gc = gdk_gc_new (widget->window);
2857 sheet->bg_gc = gdk_gc_new (widget->window);
2859 colormap = gtk_widget_get_colormap (widget);
2861 gdk_color_white (colormap, &widget->style->white);
2862 gdk_color_black (colormap, &widget->style->black);
2864 gdk_gc_get_values (sheet->fg_gc, &auxvalues);
2866 values.foreground = widget->style->white;
2867 values.function = GDK_INVERT;
2868 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2870 gdk_gc_unref (sheet->xor_gc);
2871 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2877 if (sheet->sheet_entry->parent)
2879 gtk_widget_ref (sheet->sheet_entry);
2880 gtk_widget_unparent (sheet->sheet_entry);
2882 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2883 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
2885 if (sheet->button && sheet->button->parent)
2887 gtk_widget_ref (sheet->button);
2888 gtk_widget_unparent (sheet->button);
2890 gtk_widget_set_parent_window (sheet->button, sheet->sheet_window);
2891 gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
2893 if (!sheet->cursor_drag)
2894 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
2896 if (sheet->column_titles_visible)
2897 gdk_window_show (sheet->column_title_window);
2898 if (sheet->row_titles_visible)
2899 gdk_window_show (sheet->row_title_window);
2901 size_allocate_row_title_buttons (sheet);
2902 size_allocate_column_title_buttons (sheet);
2904 name = g_strdup (sheet->name);
2905 gtk_sheet_set_title (sheet, name);
2909 children = sheet->children;
2912 child = children->data;
2913 children = children->next;
2915 gtk_sheet_realize_child (sheet, child);
2920 create_global_button (GtkSheet *sheet)
2922 sheet->button = gtk_button_new_with_label (" ");
2924 g_signal_connect (G_OBJECT (sheet->button),
2926 G_CALLBACK (global_button_clicked),
2931 size_allocate_global_button (GtkSheet *sheet)
2933 GtkAllocation allocation;
2935 if (!sheet->column_titles_visible) return;
2936 if (!sheet->row_titles_visible) return;
2938 gtk_widget_size_request (sheet->button, NULL);
2942 allocation.width = sheet->row_title_area.width;
2943 allocation.height = sheet->column_title_area.height;
2945 gtk_widget_size_allocate (sheet->button, &allocation);
2946 gtk_widget_show (sheet->button);
2950 global_button_clicked (GtkWidget *widget, gpointer data)
2954 gtk_sheet_click_cell (GTK_SHEET (data), - 1, - 1, &veto);
2955 gtk_widget_grab_focus (GTK_WIDGET (data));
2960 gtk_sheet_unrealize (GtkWidget * widget)
2964 g_return_if_fail (widget != NULL);
2965 g_return_if_fail (GTK_IS_SHEET (widget));
2967 sheet = GTK_SHEET (widget);
2969 gdk_cursor_destroy (sheet->cursor_drag);
2971 gdk_gc_destroy (sheet->xor_gc);
2972 gdk_gc_destroy (sheet->fg_gc);
2973 gdk_gc_destroy (sheet->bg_gc);
2975 gdk_window_destroy (sheet->sheet_window);
2976 gdk_window_destroy (sheet->column_title_window);
2977 gdk_window_destroy (sheet->row_title_window);
2981 g_object_unref (sheet->pixmap);
2982 sheet->pixmap = NULL;
2985 sheet->column_title_window = NULL;
2986 sheet->sheet_window = NULL;
2987 sheet->cursor_drag = NULL;
2988 sheet->xor_gc = NULL;
2989 sheet->fg_gc = NULL;
2990 sheet->bg_gc = NULL;
2992 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2993 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2997 gtk_sheet_map (GtkWidget * widget)
3000 GtkSheetChild *child;
3003 g_return_if_fail (widget != NULL);
3004 g_return_if_fail (GTK_IS_SHEET (widget));
3006 sheet = GTK_SHEET (widget);
3008 if (!GTK_WIDGET_MAPPED (widget))
3010 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
3012 if (!sheet->cursor_drag) sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
3014 gdk_window_show (widget->window);
3016 gdk_window_show (sheet->sheet_window);
3018 if (sheet->column_titles_visible)
3020 size_allocate_column_title_buttons (sheet);
3021 gdk_window_show (sheet->column_title_window);
3023 if (sheet->row_titles_visible)
3025 size_allocate_row_title_buttons (sheet);
3026 gdk_window_show (sheet->row_title_window);
3029 if (!GTK_WIDGET_MAPPED (sheet->sheet_entry)
3030 && ! gtk_sheet_locked (sheet)
3031 && sheet->active_cell.row >= 0
3032 && sheet->active_cell.col >= 0 )
3034 gtk_widget_show (sheet->sheet_entry);
3035 gtk_widget_map (sheet->sheet_entry);
3038 if (GTK_WIDGET_VISIBLE (sheet->button) &&
3039 !GTK_WIDGET_MAPPED (sheet->button))
3041 gtk_widget_show (sheet->button);
3042 gtk_widget_map (sheet->button);
3045 if (GTK_BIN (sheet->button)->child)
3046 if (GTK_WIDGET_VISIBLE (GTK_BIN (sheet->button)->child) &&
3047 !GTK_WIDGET_MAPPED (GTK_BIN (sheet->button)->child))
3048 gtk_widget_map (GTK_BIN (sheet->button)->child);
3050 gtk_sheet_range_draw (sheet, NULL);
3051 gtk_sheet_activate_cell (sheet,
3052 sheet->active_cell.row,
3053 sheet->active_cell.col);
3055 children = sheet->children;
3058 child = children->data;
3059 children = children->next;
3061 if (GTK_WIDGET_VISIBLE (child->widget) &&
3062 !GTK_WIDGET_MAPPED (child->widget))
3064 gtk_widget_map (child->widget);
3065 gtk_sheet_position_child (sheet, child);
3073 gtk_sheet_unmap (GtkWidget * widget)
3076 GtkSheetChild *child;
3079 g_return_if_fail (widget != NULL);
3080 g_return_if_fail (GTK_IS_SHEET (widget));
3082 sheet = GTK_SHEET (widget);
3084 if (GTK_WIDGET_MAPPED (widget))
3086 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3088 gdk_window_hide (sheet->sheet_window);
3089 if (sheet->column_titles_visible)
3090 gdk_window_hide (sheet->column_title_window);
3091 if (sheet->row_titles_visible)
3092 gdk_window_hide (sheet->row_title_window);
3093 gdk_window_hide (widget->window);
3095 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
3096 gtk_widget_unmap (sheet->sheet_entry);
3098 if (GTK_WIDGET_MAPPED (sheet->button))
3099 gtk_widget_unmap (sheet->button);
3101 children = sheet->children;
3104 child = children->data;
3105 children = children->next;
3107 if (GTK_WIDGET_VISIBLE (child->widget) &&
3108 GTK_WIDGET_MAPPED (child->widget))
3110 gtk_widget_unmap (child->widget);
3119 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
3122 GdkGC *fg_gc, *bg_gc;
3123 GtkSheetCellAttr attributes;
3126 g_return_if_fail (sheet != NULL);
3128 /* bail now if we arn't drawable yet */
3129 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3131 if (row < 0 || row >= yyy_row_count (sheet)) return;
3132 if (col < 0 || col >= xxx_column_count (sheet)) return;
3133 if (! xxx_column_is_visible (sheet, col)) return;
3134 if (! yyy_row_is_visible (sheet, row)) return;
3136 widget = GTK_WIDGET (sheet);
3138 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3140 /* select GC for background rectangle */
3141 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3142 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3144 fg_gc = sheet->fg_gc;
3145 bg_gc = sheet->bg_gc;
3147 area.x = COLUMN_LEFT_XPIXEL (sheet,col);
3148 area.y = ROW_TOP_YPIXEL (sheet,row);
3149 area.width= xxx_column_width (sheet, col);
3150 area.height = yyy_row_height (sheet, row);
3152 gdk_draw_rectangle (sheet->pixmap,
3160 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3162 if (sheet->show_grid)
3164 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3166 gdk_draw_rectangle (sheet->pixmap,
3170 area.width, area.height);
3175 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3178 GdkRectangle area, clip_area;
3180 gint text_width, text_height, y;
3182 gint size, sizel, sizer;
3183 GdkGC *fg_gc, *bg_gc;
3184 GtkSheetCellAttr attributes;
3185 PangoLayout *layout;
3186 PangoRectangle rect;
3187 PangoRectangle logical_rect;
3188 PangoLayoutLine *line;
3189 PangoFontMetrics *metrics;
3190 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (sheet));
3191 gint ascent, descent, y_pos;
3195 g_return_if_fail (sheet != NULL);
3197 /* bail now if we aren't drawable yet */
3198 if (!GTK_WIDGET_DRAWABLE (sheet))
3201 label = gtk_sheet_cell_get_text (sheet, row, col);
3205 if (row < 0 || row >= yyy_row_count (sheet)) return;
3206 if (col < 0 || col >= xxx_column_count (sheet)) return;
3207 if (! xxx_column_is_visible (sheet, col)) return;
3208 if (!yyy_row_is_visible (sheet, row)) return;
3211 widget = GTK_WIDGET (sheet);
3213 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3215 /* select GC for background rectangle */
3216 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3217 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3219 fg_gc = sheet->fg_gc;
3220 bg_gc = sheet->bg_gc;
3222 area.x = COLUMN_LEFT_XPIXEL (sheet,col);
3223 area.y = ROW_TOP_YPIXEL (sheet,row);
3224 area.width = xxx_column_width (sheet, col);
3225 area.height = yyy_row_height (sheet, row);
3229 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), label);
3230 dispose_string (sheet, label);
3231 pango_layout_set_font_description (layout, attributes.font_desc);
3233 pango_layout_get_pixel_extents (layout, NULL, &rect);
3235 line = pango_layout_get_lines (layout)->data;
3236 pango_layout_line_get_extents (line, NULL, &logical_rect);
3238 metrics = pango_context_get_metrics (context,
3239 attributes.font_desc,
3240 pango_context_get_language (context));
3242 ascent = pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
3243 descent = pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
3245 pango_font_metrics_unref (metrics);
3247 /* Align primarily for locale's ascent / descent */
3249 logical_rect.height /= PANGO_SCALE;
3250 logical_rect.y /= PANGO_SCALE;
3251 y_pos = area.height - logical_rect.height;
3253 if (logical_rect.height > area.height)
3254 y_pos = (logical_rect.height - area.height - 2 * CELLOFFSET) / 2;
3257 else if (y_pos + logical_rect.height > area.height)
3258 y_pos = area.height - logical_rect.height;
3260 text_width = rect.width;
3261 text_height = rect.height;
3262 y = area.y + y_pos - CELLOFFSET;
3264 switch (attributes.justification)
3266 case GTK_JUSTIFY_RIGHT:
3268 area.x +=area.width;
3269 if (!gtk_sheet_clip_text (sheet))
3271 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3273 if ( !gtk_sheet_cell_empty (sheet, row, i)) break;
3274 if (size >= text_width + CELLOFFSET) break;
3275 size +=xxx_column_width (sheet, i);
3276 xxx_column_set_right_column (sheet, i,
3278 xxx_column_right_column (sheet, i)));
3283 xoffset += area.width - text_width - 2 * CELLOFFSET -
3284 attributes.border.width / 2;
3286 case GTK_JUSTIFY_CENTER:
3287 sizel = area.width / 2;
3288 sizer = area.width / 2;
3289 area.x += area.width / 2;
3290 if (!gtk_sheet_clip_text (sheet))
3292 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3294 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3295 if (sizer >= text_width / 2) break;
3296 sizer += xxx_column_width (sheet, i);
3297 xxx_column_set_left_column (sheet, i,
3300 xxx_column_left_column (sheet, i)));
3302 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
3304 if ( ! gtk_sheet_cell_empty (sheet, row, i)) break;
3305 if (sizel >= text_width / 2) break;
3306 sizel +=xxx_column_width (sheet, i);
3307 xxx_column_set_right_column (sheet, i,
3309 xxx_column_right_column (sheet, i)));
3311 size = MIN (sizel, sizer);
3314 xoffset += sizel - text_width / 2 - CELLOFFSET;
3315 area.width = sizel + sizer;
3317 case GTK_JUSTIFY_LEFT:
3320 if (!gtk_sheet_clip_text (sheet))
3322 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
3324 if (! gtk_sheet_cell_empty (sheet, row, i)) break;
3325 if (size >= text_width + CELLOFFSET) break;
3326 size +=xxx_column_width (sheet, i);
3327 xxx_column_set_left_column (sheet, i,
3330 xxx_column_left_column (sheet, i)));
3335 xoffset += attributes.border.width / 2;
3339 if (!gtk_sheet_clip_text (sheet)) clip_area = area;
3340 gdk_gc_set_clip_rectangle (fg_gc, &clip_area);
3343 gdk_draw_layout (sheet->pixmap, fg_gc,
3344 area.x + xoffset + CELLOFFSET,
3348 gdk_gc_set_clip_rectangle (fg_gc, NULL);
3349 g_object_unref (G_OBJECT (layout));
3351 gdk_draw_pixmap (sheet->sheet_window,
3352 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3364 gtk_sheet_range_draw (GtkSheet *sheet, const GtkSheetRange *range)
3367 GtkSheetRange drawing_range;
3370 g_return_if_fail (sheet != NULL);
3371 g_return_if_fail (GTK_SHEET (sheet));
3373 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
3374 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3375 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
3379 drawing_range.row0 = MIN_VISIBLE_ROW (sheet);
3380 drawing_range.col0 = MIN_VISIBLE_COLUMN (sheet);
3381 drawing_range.rowi = MIN (MAX_VISIBLE_ROW (sheet),
3382 yyy_row_count (sheet) - 1);
3383 drawing_range.coli = MAX_VISIBLE_COLUMN (sheet);
3386 gdk_draw_rectangle (sheet->pixmap,
3387 GTK_WIDGET (sheet)->style->white_gc,
3390 sheet->sheet_window_width,
3391 sheet->sheet_window_height);
3395 drawing_range.row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
3396 drawing_range.col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
3397 drawing_range.rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
3398 drawing_range.coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
3401 if (drawing_range.coli == xxx_column_count (sheet) - 1)
3403 area.x = COLUMN_LEFT_XPIXEL (sheet,
3404 xxx_column_count (sheet) - 1) +
3405 xxx_column_width (sheet, xxx_column_count (sheet) - 1) + 1;
3409 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3411 gdk_draw_rectangle (sheet->pixmap,
3415 sheet->sheet_window_width - area.x,
3416 sheet->sheet_window_height);
3418 gdk_draw_pixmap (sheet->sheet_window,
3419 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3425 sheet->sheet_window_width - area.x,
3426 sheet->sheet_window_height);
3429 if (drawing_range.rowi == yyy_row_count (sheet) - 1)
3432 area.y = ROW_TOP_YPIXEL (sheet,
3433 yyy_row_count (sheet) - 1) +
3434 yyy_row_height (sheet, yyy_row_count (sheet) - 1) + 1;
3436 gdk_gc_set_foreground (sheet->fg_gc, &sheet->bg_color);
3438 gdk_draw_rectangle (sheet->pixmap,
3442 sheet->sheet_window_width,
3443 sheet->sheet_window_height - area.y);
3445 gdk_draw_pixmap (sheet->sheet_window,
3446 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3452 sheet->sheet_window_width,
3453 sheet->sheet_window_height - area.y);
3456 for (i = drawing_range.row0; i <= drawing_range.rowi; i++)
3457 for (j = drawing_range.col0; j <= drawing_range.coli; j++)
3459 gtk_sheet_cell_draw_default (sheet, i, j);
3460 gtk_sheet_cell_draw_label (sheet, i, j);
3463 gtk_sheet_draw_backing_pixmap (sheet, drawing_range);
3465 if (sheet->state != GTK_SHEET_NORMAL &&
3466 gtk_sheet_range_isvisible (sheet, sheet->range))
3467 gtk_sheet_range_draw_selection (sheet, drawing_range);
3469 if (sheet->state == GTK_STATE_NORMAL &&
3470 sheet->active_cell.row >= drawing_range.row0 &&
3471 sheet->active_cell.row <= drawing_range.rowi &&
3472 sheet->active_cell.col >= drawing_range.col0 &&
3473 sheet->active_cell.col <= drawing_range.coli)
3474 gtk_sheet_show_active_cell (sheet);
3478 gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
3484 if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3485 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3488 if (!gtk_sheet_range_isvisible (sheet, range)) return;
3489 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3493 range.col0 = MAX (sheet->range.col0, range.col0);
3494 range.coli = MIN (sheet->range.coli, range.coli);
3495 range.row0 = MAX (sheet->range.row0, range.row0);
3496 range.rowi = MIN (sheet->range.rowi, range.rowi);
3498 range.col0 = MAX (range.col0, MIN_VISIBLE_COLUMN (sheet));
3499 range.coli = MIN (range.coli, MAX_VISIBLE_COLUMN (sheet));
3500 range.row0 = MAX (range.row0, MIN_VISIBLE_ROW (sheet));
3501 range.rowi = MIN (range.rowi, MAX_VISIBLE_ROW (sheet));
3503 for (i = range.row0; i <= range.rowi; i++)
3505 for (j = range.col0; j <= range.coli; j++)
3508 if (gtk_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED &&
3509 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
3512 area.x = COLUMN_LEFT_XPIXEL (sheet,j);
3513 area.y = ROW_TOP_YPIXEL (sheet,i);
3514 area.width= xxx_column_width (sheet, j);
3515 area.height = yyy_row_height (sheet, i);
3517 if (i == sheet->range.row0)
3519 area.y = area.y + 2;
3520 area.height = area.height - 2;
3522 if (i == sheet->range.rowi) area.height = area.height - 3;
3523 if (j == sheet->range.col0)
3525 area.x = area.x + 2;
3526 area.width = area.width - 2;
3528 if (j == sheet->range.coli) area.width = area.width - 3;
3530 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
3532 gdk_draw_rectangle (sheet->sheet_window,
3535 area.x + 1,area.y + 1,
3536 area.width,area.height);
3543 gtk_sheet_draw_border (sheet, sheet->range);
3547 gtk_sheet_draw_backing_pixmap (GtkSheet *sheet, GtkSheetRange range)
3549 gint x,y,width,height;
3551 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
3553 x = COLUMN_LEFT_XPIXEL (sheet,range.col0);
3554 y = ROW_TOP_YPIXEL (sheet, range.row0);
3555 width = COLUMN_LEFT_XPIXEL (sheet, range.coli) - x +
3556 xxx_column_width (sheet, range.coli);
3558 height = ROW_TOP_YPIXEL (sheet, range.rowi)- y + yyy_row_height (sheet, range.rowi);
3560 if (range.row0 == sheet->range.row0)
3563 height = height + 5;
3565 if (range.rowi == sheet->range.rowi) height = height + 5;
3566 if (range.col0 == sheet->range.col0)
3571 if (range.coli == sheet->range.coli) width = width + 5;
3573 width = MIN (width, sheet->sheet_window_width - x);
3574 height = MIN (height, sheet->sheet_window_height - y);
3581 x = (sheet->row_titles_visible)
3582 ? MAX (x, sheet->row_title_area.width) : MAX (x, 0);
3583 y = (sheet->column_titles_visible)
3584 ? MAX (y, sheet->column_title_area.height) : MAX (y, 0);
3586 if (range.coli == xxx_column_count (sheet) - 1)
3587 width = sheet->sheet_window_width - x;
3588 if (range.rowi == yyy_row_count (sheet) - 1)
3589 height = sheet->sheet_window_height - y;
3591 gdk_draw_pixmap (sheet->sheet_window,
3592 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
3604 gtk_sheet_set_cell_text (GtkSheet *sheet, gint row, gint col, const gchar *text)
3606 GtkSheetCellAttr attributes;
3608 g_return_if_fail (sheet != NULL);
3609 g_return_if_fail (GTK_IS_SHEET (sheet));
3610 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3611 if (col < 0 || row < 0) return;
3613 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3614 gtk_sheet_set_cell (sheet, row, col, attributes.justification, text);
3618 safe_strcmp (const gchar *s1, const gchar *s2)
3620 if ( !s1 && !s2) return 0;
3621 if ( !s1) return - 1;
3622 if ( !s2) return +1;
3623 return strcmp (s1, s2);
3627 gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
3628 GtkJustification justification,
3631 GSheetModel *model ;
3635 GtkSheetRange range;
3637 GtkSheetCellAttr attributes;
3639 g_return_if_fail (sheet != NULL);
3640 g_return_if_fail (GTK_IS_SHEET (sheet));
3641 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return;
3642 if (col < 0 || row < 0) return;
3644 gtk_sheet_get_attributes (sheet, row, col, &attributes);
3646 attributes.justification = justification;
3648 model = gtk_sheet_get_model (sheet);
3650 old_text = g_sheet_model_get_string (model, row, col);
3654 if (0 != safe_strcmp (old_text, text))
3655 changed = g_sheet_model_set_string (model, text, row, col);
3657 if ( g_sheet_model_free_strings (model))
3661 if (changed && attributes.is_visible)
3663 gchar *s = gtk_sheet_cell_get_text (sheet, row, col);
3665 if (s && strlen (s) > 0)
3667 text_width = STRING_WIDTH (GTK_WIDGET (sheet),
3668 attributes.font_desc, text);
3670 dispose_string (sheet, s);
3674 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3675 range.coli = MAX_VISIBLE_COLUMN (sheet);
3677 if (gtk_sheet_autoresize (sheet) &&
3678 text_width > xxx_column_width (sheet, col) -
3679 2 * CELLOFFSET- attributes.border.width)
3681 gtk_sheet_set_column_width (sheet, col, text_width + 2 * CELLOFFSET
3682 + attributes.border.width);
3683 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
3686 if (!GTK_SHEET_IS_FROZEN (sheet))
3687 gtk_sheet_range_draw (sheet, &range);
3691 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, col);
3697 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3699 GtkSheetRange range;
3701 g_return_if_fail (sheet != NULL);
3702 g_return_if_fail (GTK_IS_SHEET (sheet));
3703 if (column >= xxx_column_count (sheet) ||
3704 row >= yyy_row_count (sheet)) return;
3706 if (column < 0 || row < 0) return;
3710 range.col0 = MIN_VISIBLE_COLUMN (sheet);
3711 range.coli = MAX_VISIBLE_COLUMN (sheet);
3713 gtk_sheet_real_cell_clear (sheet, row, column);
3715 if (!GTK_SHEET_IS_FROZEN (sheet))
3717 gtk_sheet_range_draw (sheet, &range);
3722 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column)
3724 GSheetModel *model = gtk_sheet_get_model (sheet);
3726 gchar *old_text = gtk_sheet_cell_get_text (sheet, row, column);
3728 if (old_text && strlen (old_text) > 0 )
3730 g_sheet_model_datum_clear (model, row, column);
3732 if (GTK_IS_OBJECT (sheet) && G_OBJECT (sheet)->ref_count > 0)
3733 g_signal_emit (G_OBJECT (sheet), sheet_signals[CLEAR_CELL], 0,
3737 dispose_string (sheet, old_text);
3741 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3743 g_return_if_fail (sheet != NULL);
3744 g_return_if_fail (GTK_IS_SHEET (sheet));
3746 gtk_sheet_real_range_clear (sheet, range);
3750 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3753 GtkSheetRange clear;
3758 clear.rowi = yyy_row_count (sheet) - 1;
3760 clear.coli = xxx_column_count (sheet) - 1;
3765 clear.row0 = MAX (clear.row0, 0);
3766 clear.col0 = MAX (clear.col0, 0);
3767 clear.rowi = MIN (clear.rowi, yyy_row_count (sheet) - 1 );
3768 clear.coli = MIN (clear.coli, xxx_column_count (sheet) - 1 );
3770 for (i = clear.row0; i <= clear.rowi; i++)
3771 for (j = clear.col0; j <= clear.coli; j++)
3773 gtk_sheet_real_cell_clear (sheet, i, j);
3776 gtk_sheet_range_draw (sheet, NULL);
3781 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3784 char *text = gtk_sheet_cell_get_text (sheet, row, col);
3785 empty = (text == NULL );
3787 dispose_string (sheet, text);
3794 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3797 g_return_val_if_fail (sheet != NULL, NULL);
3798 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3800 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet))
3802 if (col < 0 || row < 0) return NULL;
3804 model = gtk_sheet_get_model (sheet);
3809 return g_sheet_model_get_string (model, row, col);
3814 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3817 GtkSheetRange *range;
3819 g_return_val_if_fail (sheet != NULL, 0);
3820 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3821 if (col >= xxx_column_count (sheet) || row >= yyy_row_count (sheet)) return 0;
3822 if (col < 0 || row < 0) return 0;
3824 state = sheet->state;
3825 range = &sheet->range;
3829 case GTK_SHEET_NORMAL:
3830 return GTK_STATE_NORMAL;
3832 case GTK_SHEET_ROW_SELECTED:
3833 if (row >= range->row0 && row <= range->rowi)
3834 return GTK_STATE_SELECTED;
3836 case GTK_SHEET_COLUMN_SELECTED:
3837 if (col >= range->col0 && col <= range->coli)
3838 return GTK_STATE_SELECTED;
3840 case GTK_SHEET_RANGE_SELECTED:
3841 if (row >= range->row0 && row <= range->rowi && \
3842 col >= range->col0 && col <= range->coli)
3843 return GTK_STATE_SELECTED;
3846 return GTK_STATE_NORMAL;
3849 /* Convert X, Y (in pixels) to *ROW, *COLUMN (in cell coords)
3850 -1 indicates the title buttons.
3851 If the function returns FALSE, then the results will be unreliable.
3854 gtk_sheet_get_pixel_info (GtkSheet *sheet,
3862 *column = -G_MAXINT;
3864 g_return_val_if_fail (sheet != NULL, 0);
3865 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3867 /* bounds checking, return false if the user clicked
3875 if ( y < sheet->column_title_area.height + sheet->column_title_area.y)
3880 trow = ROW_FROM_YPIXEL (sheet, y);
3881 if (trow > yyy_row_count (sheet))
3887 if ( x < sheet->row_title_area.width + sheet->row_title_area.x)
3891 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3892 if (tcol > xxx_column_count (sheet))
3902 gtk_sheet_get_cell_area (GtkSheet * sheet,
3907 g_return_val_if_fail (sheet != NULL, 0);
3908 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3910 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3913 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL (sheet, column) -
3914 (sheet->row_titles_visible
3915 ? sheet->row_title_area.width
3917 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL (sheet, row) -
3918 (sheet->column_titles_visible
3919 ? sheet->column_title_area.height
3921 area->width= (column == -1) ? sheet->row_title_area.width
3922 : xxx_column_width (sheet, column);
3924 area->height= (row == -1) ? sheet->column_title_area.height
3925 : yyy_row_height (sheet, row);
3931 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3933 g_return_val_if_fail (sheet != NULL, 0);
3934 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3936 if (row < - 1 || column < - 1) return FALSE;
3937 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
3940 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
3942 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
3945 sheet->active_cell.row = row;
3946 sheet->active_cell.col = column;
3948 if ( row == -1 || column == -1)
3950 gtk_sheet_hide_active_cell (sheet);
3954 if (!gtk_sheet_activate_cell (sheet, row, column)) return FALSE;
3956 if (gtk_sheet_autoscroll (sheet))
3957 gtk_sheet_move_query (sheet, row, column);
3963 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3965 g_return_if_fail (sheet != NULL);
3966 g_return_if_fail (GTK_IS_SHEET (sheet));
3968 if ( row ) *row = sheet->active_cell.row;
3969 if (column) *column = sheet->active_cell.col;
3973 gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
3978 GtkJustification justification;
3979 GtkSheetCellAttr attributes;
3981 g_return_if_fail (data != NULL);
3982 g_return_if_fail (GTK_IS_SHEET (data));
3984 sheet = GTK_SHEET (data);
3986 if (!GTK_WIDGET_VISIBLE (widget)) return;
3987 if (sheet->state != GTK_STATE_NORMAL) return;
3989 row = sheet->active_cell.row;
3990 col = sheet->active_cell.col;
3992 if (row < 0 || col < 0) return;
3994 sheet->active_cell.row =- 1;
3995 sheet->active_cell.col =- 1;
3997 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
3999 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
4001 if (text && strlen (text) > 0)
4003 gtk_sheet_get_attributes (sheet, row, col, &attributes);
4004 justification = attributes.justification;
4005 gtk_sheet_set_cell (sheet, row, col, justification, text);
4008 if (sheet->freeze_count == 0)
4009 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
4011 sheet->active_cell.row = row;;
4012 sheet->active_cell.col = col;
4017 gtk_sheet_deactivate_cell (GtkSheet *sheet)
4019 gboolean veto = TRUE;
4021 g_return_val_if_fail (sheet != NULL, FALSE);
4022 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4024 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return FALSE;
4025 if (sheet->state != GTK_SHEET_NORMAL) return FALSE;
4027 _gtkextra_signal_emit (GTK_OBJECT (sheet),sheet_signals[DEACTIVATE],
4028 sheet->active_cell.row,
4029 sheet->active_cell.col, &veto);
4031 if (!veto) return FALSE;
4033 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
4036 g_signal_handlers_disconnect_by_func (G_OBJECT (gtk_sheet_get_entry (sheet)),
4037 G_CALLBACK (gtk_sheet_entry_changed),
4040 gtk_sheet_hide_active_cell (sheet);
4041 sheet->active_cell.row = -1;
4042 sheet->active_cell.col = -1;
4044 if (GTK_SHEET_REDRAW_PENDING (sheet))
4046 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_REDRAW_PENDING);
4047 gtk_sheet_range_draw (sheet, NULL);
4054 gtk_sheet_hide_active_cell (GtkSheet *sheet)
4058 GtkJustification justification;
4059 GtkSheetCellAttr attributes;
4061 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4063 row = sheet->active_cell.row;
4064 col = sheet->active_cell.col;
4066 if (row < 0 || col < 0) return;
4068 if (sheet->freeze_count == 0)
4069 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IS_FROZEN);
4071 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
4073 gtk_sheet_get_attributes (sheet, row, col, &attributes);
4074 justification = attributes.justification;
4076 if (text && strlen (text) != 0)
4078 gtk_sheet_set_cell (sheet, row, col, justification, text);
4079 g_signal_emit (G_OBJECT (sheet),sheet_signals[SET_CELL], 0, row, col);
4083 gtk_sheet_cell_clear (sheet, row, col);
4086 row = sheet->active_cell.row;
4087 col = sheet->active_cell.col;
4089 gtk_widget_hide (sheet->sheet_entry);
4090 gtk_widget_unmap (sheet->sheet_entry);
4092 if (row != -1 && col != -1)
4093 gdk_draw_pixmap (sheet->sheet_window,
4094 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4096 COLUMN_LEFT_XPIXEL (sheet,col)- 1,
4097 ROW_TOP_YPIXEL (sheet,row)- 1,
4098 COLUMN_LEFT_XPIXEL (sheet,col)- 1,
4099 ROW_TOP_YPIXEL (sheet,row)- 1,
4100 xxx_column_width (sheet, col) + 4,
4101 yyy_row_height (sheet, row)+4);
4103 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4105 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
4110 gtk_sheet_activate_cell (GtkSheet *sheet, gint row, gint col)
4112 gboolean veto = TRUE;
4114 g_return_val_if_fail (sheet != NULL, FALSE);
4115 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4117 if (row < 0 || col < 0) return FALSE;
4118 if (row >= yyy_row_count (sheet) || col >= xxx_column_count (sheet))
4121 /* _gtkextra_signal_emit (GTK_OBJECT (sheet),sheet_signals[ACTIVATE], row, col, &veto);
4122 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return veto;
4125 if (!veto) return FALSE;
4126 if (sheet->state != GTK_SHEET_NORMAL)
4128 sheet->state = GTK_SHEET_NORMAL;
4129 gtk_sheet_real_unselect_range (sheet, NULL);
4132 sheet->range.row0 = row;
4133 sheet->range.col0 = col;
4134 sheet->range.rowi = row;
4135 sheet->range.coli = col;
4136 sheet->active_cell.row = row;
4137 sheet->active_cell.col = col;
4138 sheet->selection_cell.row = row;
4139 sheet->selection_cell.col = col;
4141 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4143 gtk_sheet_show_active_cell (sheet);
4146 g_signal_connect (G_OBJECT (gtk_sheet_get_entry (sheet)),
4148 G_CALLBACK (gtk_sheet_entry_changed),
4151 _gtkextra_signal_emit (GTK_OBJECT (sheet),sheet_signals[ACTIVATE], row, col, &veto);
4157 gtk_sheet_show_active_cell (GtkSheet *sheet)
4159 GtkEntry *sheet_entry;
4160 GtkSheetCellAttr attributes;
4162 const gchar *old_text;
4163 GtkJustification justification;
4166 g_return_if_fail (sheet != NULL);
4167 g_return_if_fail (GTK_IS_SHEET (sheet));
4169 row = sheet->active_cell.row;
4170 col = sheet->active_cell.col;
4172 /* Don't show the active cell, if there is no active cell: */
4173 if (! (row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4176 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4177 if (sheet->state != GTK_SHEET_NORMAL) return;
4178 if (GTK_SHEET_IN_SELECTION (sheet)) return;
4180 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (sheet->sheet_entry), GTK_VISIBLE);
4182 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
4184 gtk_sheet_get_attributes (sheet, row, col, &attributes);
4186 justification = GTK_JUSTIFY_LEFT;
4188 if (gtk_sheet_justify_entry (sheet))
4189 justification = attributes.justification;
4191 text = gtk_sheet_cell_get_text (sheet, row, col);
4193 text = g_strdup ("");
4195 gtk_entry_set_visibility (GTK_ENTRY (sheet_entry), attributes.is_visible);
4197 if (gtk_sheet_locked (sheet) || !attributes.is_editable)
4198 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), FALSE);
4200 gtk_editable_set_editable (GTK_EDITABLE (sheet_entry), TRUE);
4202 /*** Added by John Gotts. Mar 25, 2005 *********/
4203 old_text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
4204 if (strcmp (old_text, text) != 0)
4206 if (!GTK_IS_ITEM_ENTRY (sheet_entry))
4207 gtk_entry_set_text (GTK_ENTRY (sheet_entry), text);
4209 gtk_item_entry_set_text (GTK_ITEM_ENTRY (sheet_entry), text, justification);
4212 gtk_sheet_entry_set_max_size (sheet);
4213 gtk_sheet_size_allocate_entry (sheet);
4215 gtk_widget_map (sheet->sheet_entry);
4217 gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
4219 dispose_string (sheet, text);
4223 gtk_sheet_draw_active_cell (GtkSheet *sheet)
4227 if (!GTK_WIDGET_DRAWABLE (GTK_WIDGET (sheet))) return;
4228 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4230 row = sheet->active_cell.row;
4231 col = sheet->active_cell.col;
4233 if (row < 0 || col < 0) return;
4235 if (!gtk_sheet_cell_isvisible (sheet, row, col)) return;
4237 gtk_sheet_draw_border (sheet, sheet->range);
4242 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4244 gint pixmap_width, pixmap_height;
4246 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
4248 if (width == 0 && height == 0)
4250 width = sheet->sheet_window_width + 80;
4251 height = sheet->sheet_window_height + 80;
4257 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4260 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4264 /* reallocate if sizes don't match */
4265 gdk_window_get_size (sheet->pixmap,
4266 &pixmap_width, &pixmap_height);
4267 if ( (pixmap_width != width) || (pixmap_height != height))
4269 g_object_unref (sheet->pixmap);
4270 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4273 if (!GTK_SHEET_IS_FROZEN (sheet)) gtk_sheet_range_draw (sheet, NULL);
4279 gtk_sheet_new_selection (GtkSheet *sheet, GtkSheetRange *range)
4281 gint i,j, mask1, mask2;
4282 gint state, selected;
4283 gint x,y,width,height;
4284 GtkSheetRange new_range, aux_range;
4286 g_return_if_fail (sheet != NULL);
4288 if (range == NULL) range=&sheet->range;
4292 range->row0 = MIN (range->row0, sheet->range.row0);
4293 range->rowi = MAX (range->rowi, sheet->range.rowi);
4294 range->col0 = MIN (range->col0, sheet->range.col0);
4295 range->coli = MAX (range->coli, sheet->range.coli);
4297 range->row0 = MAX (range->row0, MIN_VISIBLE_ROW (sheet));
4298 range->rowi = MIN (range->rowi, MAX_VISIBLE_ROW (sheet));
4299 range->col0 = MAX (range->col0, MIN_VISIBLE_COLUMN (sheet));
4300 range->coli = MIN (range->coli, MAX_VISIBLE_COLUMN (sheet));
4302 aux_range.row0 = MAX (new_range.row0, MIN_VISIBLE_ROW (sheet));
4303 aux_range.rowi = MIN (new_range.rowi, MAX_VISIBLE_ROW (sheet));
4304 aux_range.col0 = MAX (new_range.col0, MIN_VISIBLE_COLUMN (sheet));
4305 aux_range.coli = MIN (new_range.coli, MAX_VISIBLE_COLUMN (sheet));
4307 for (i = range->row0; i <= range->rowi; i++)
4309 for (j = range->col0; j <= range->coli; j++)
4312 state = gtk_sheet_cell_get_state (sheet, i, j);
4313 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4314 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4316 if (state == GTK_STATE_SELECTED && selected &&
4317 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4318 (i == sheet->range.row0 || i == sheet->range.rowi ||
4319 j == sheet->range.col0 || j == sheet->range.coli ||
4320 i == new_range.row0 || i == new_range.rowi ||
4321 j == new_range.col0 || j == new_range.coli))
4324 mask1 = i == sheet->range.row0 ? 1 : 0;
4325 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4326 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4327 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4329 mask2 = i == new_range.row0 ? 1 : 0;
4330 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4331 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4332 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4336 x = COLUMN_LEFT_XPIXEL (sheet,j);
4337 y = ROW_TOP_YPIXEL (sheet, i);
4338 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4339 xxx_column_width (sheet, j);
4340 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4342 if (i == sheet->range.row0)
4345 height = height + 3;
4347 if (i == sheet->range.rowi) height = height + 3;
4348 if (j == sheet->range.col0)
4353 if (j == sheet->range.coli) width = width + 3;
4355 gdk_draw_pixmap (sheet->sheet_window,
4356 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4365 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
4367 x = COLUMN_LEFT_XPIXEL (sheet,j);
4368 y = ROW_TOP_YPIXEL (sheet, i);
4369 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+
4370 xxx_column_width (sheet, j);
4372 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4374 if (i == new_range.row0)
4377 height = height - 2;
4379 if (i == new_range.rowi) height = height - 3;
4380 if (j == new_range.col0)
4385 if (j == new_range.coli) width = width - 3;
4387 gdk_draw_rectangle (sheet->sheet_window,
4398 for (i = range->row0; i <= range->rowi; i++)
4400 for (j = range->col0; j <= range->coli; j++)
4403 state = gtk_sheet_cell_get_state (sheet, i, j);
4404 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4405 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4407 if (state == GTK_STATE_SELECTED && !selected &&
4408 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4411 x = COLUMN_LEFT_XPIXEL (sheet,j);
4412 y = ROW_TOP_YPIXEL (sheet, i);
4413 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4414 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4416 if (i == sheet->range.row0)
4419 height = height + 3;
4421 if (i == sheet->range.rowi) height = height + 3;
4422 if (j == sheet->range.col0)
4427 if (j == sheet->range.coli) width = width + 3;
4429 gdk_draw_pixmap (sheet->sheet_window,
4430 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4442 for (i = range->row0; i <= range->rowi; i++)
4444 for (j = range->col0; j <= range->coli; j++)
4447 state = gtk_sheet_cell_get_state (sheet, i, j);
4448 selected= (i <= new_range.rowi && i >= new_range.row0 &&
4449 j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
4451 if (state != GTK_STATE_SELECTED && selected &&
4452 xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i) &&
4453 (i != sheet->active_cell.row || j != sheet->active_cell.col))
4456 x = COLUMN_LEFT_XPIXEL (sheet,j);
4457 y = ROW_TOP_YPIXEL (sheet, i);
4458 width = COLUMN_LEFT_XPIXEL (sheet, j)- x+ xxx_column_width (sheet, j);
4459 height = ROW_TOP_YPIXEL (sheet, i)- y + yyy_row_height (sheet, i);
4461 if (i == new_range.row0)
4464 height = height - 2;
4466 if (i == new_range.rowi) height = height - 3;
4467 if (j == new_range.col0)
4472 if (j == new_range.coli) width = width - 3;
4474 gdk_draw_rectangle (sheet->sheet_window,
4485 for (i = aux_range.row0; i <= aux_range.rowi; i++)
4487 for (j = aux_range.col0; j <= aux_range.coli; j++)
4490 if (xxx_column_is_visible (sheet, j) && yyy_row_is_visible (sheet, i))
4493 state = gtk_sheet_cell_get_state (sheet, i, j);
4495 mask1 = i == sheet->range.row0 ? 1 : 0;
4496 mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
4497 mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
4498 mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
4500 mask2 = i == new_range.row0 ? 1 : 0;
4501 mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
4502 mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
4503 mask2 = j == new_range.coli ? mask2 + 8 : mask2;
4504 if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
4506 x = COLUMN_LEFT_XPIXEL (sheet,j);
4507 y = ROW_TOP_YPIXEL (sheet, i);
4508 width = xxx_column_width (sheet, j);
4509 height = yyy_row_height (sheet, i);
4511 gdk_draw_rectangle (sheet->sheet_window,
4519 gdk_draw_rectangle (sheet->sheet_window,
4522 x + 1,y + height - 1,
4526 gdk_draw_rectangle (sheet->sheet_window,
4534 gdk_draw_rectangle (sheet->sheet_window,
4537 x + width - 1,y + 1,
4551 gtk_sheet_draw_corners (sheet, new_range);
4556 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4561 gint x, y, width, height;
4563 widget = GTK_WIDGET (sheet);
4565 x = COLUMN_LEFT_XPIXEL (sheet,new_range.col0);
4566 y = ROW_TOP_YPIXEL (sheet,new_range.row0);
4567 width = COLUMN_LEFT_XPIXEL (sheet, new_range.coli) - x +
4568 xxx_column_width (sheet, new_range.coli);
4570 height = ROW_TOP_YPIXEL (sheet, new_range.rowi) - y +
4571 yyy_row_height (sheet, new_range.rowi);
4573 area.x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet));
4574 area.y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet));
4575 area.width = sheet->sheet_window_width;
4576 area.height = sheet->sheet_window_height;
4583 if (width > area.width) width = area.width + 10;
4586 height = height + y;
4589 if (height > area.height) height = area.height + 10;
4591 gdk_gc_set_clip_rectangle (sheet->xor_gc, &area);
4593 for (i =- 1; i <= 1; ++i)
4594 gdk_draw_rectangle (sheet->sheet_window,
4602 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
4605 gtk_sheet_draw_corners (sheet, new_range);
4609 gtk_sheet_draw_corners (GtkSheet *sheet, GtkSheetRange range)
4614 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.col0))
4616 x = COLUMN_LEFT_XPIXEL (sheet,range.col0);
4617 y = ROW_TOP_YPIXEL (sheet,range.row0);
4618 gdk_draw_pixmap (sheet->sheet_window,
4619 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4627 gdk_draw_rectangle (sheet->sheet_window,
4634 if (gtk_sheet_cell_isvisible (sheet, range.row0, range.coli) ||
4635 sheet->state == GTK_SHEET_COLUMN_SELECTED)
4637 x = COLUMN_LEFT_XPIXEL (sheet,range.coli)+
4638 xxx_column_width (sheet, range.coli);
4639 y = ROW_TOP_YPIXEL (sheet,range.row0);
4641 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
4643 y = ROW_TOP_YPIXEL (sheet, MIN_VISIBLE_ROW (sheet))+3;
4646 gdk_draw_pixmap (sheet->sheet_window,
4647 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4655 gdk_draw_rectangle (sheet->sheet_window,
4658 x - width + width / 2,y - width + width / 2,
4659 2 + width,2 + width);
4662 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.col0) ||
4663 sheet->state == GTK_SHEET_ROW_SELECTED)
4665 x = COLUMN_LEFT_XPIXEL (sheet,range.col0);
4666 y = ROW_TOP_YPIXEL (sheet,range.rowi)+
4667 yyy_row_height (sheet, range.rowi);
4669 if (sheet->state == GTK_SHEET_ROW_SELECTED)
4671 x = COLUMN_LEFT_XPIXEL (sheet, MIN_VISIBLE_COLUMN (sheet))+3;
4674 gdk_draw_pixmap (sheet->sheet_window,
4675 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4683 gdk_draw_rectangle (sheet->sheet_window,
4686 x - width + width / 2,y - width + width / 2,
4687 2 + width,2 + width);
4690 if (gtk_sheet_cell_isvisible (sheet, range.rowi, range.coli))
4692 x = COLUMN_LEFT_XPIXEL (sheet,range.coli)+
4693 xxx_column_width (sheet, range.coli);
4694 y = ROW_TOP_YPIXEL (sheet,range.rowi)+
4695 yyy_row_height (sheet, range.rowi);
4697 if (sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4698 if (sheet->state == GTK_SHEET_NORMAL) width = 3;
4699 gdk_draw_pixmap (sheet->sheet_window,
4700 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
4708 gdk_draw_rectangle (sheet->sheet_window,
4711 x - width + width / 2,y - width + width / 2,
4712 2 + width,2 + width);
4720 gtk_sheet_real_select_range (GtkSheet * sheet,
4721 const GtkSheetRange * range)
4725 g_return_if_fail (sheet != NULL);
4727 if (range == NULL) range = &sheet->range;
4729 memcpy (&sheet->range, range, sizeof (*range));
4731 if (range->row0 < 0 || range->rowi < 0) return;
4732 if (range->col0 < 0 || range->coli < 0) return;
4734 state = sheet->state;
4736 if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4737 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4739 gtk_sheet_new_selection (sheet, &sheet->range);
4743 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4744 gtk_sheet_range_draw_selection (sheet, sheet->range);
4747 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_RANGE], 0, &sheet->range);
4752 gtk_sheet_get_selected_range (GtkSheet *sheet,
4753 GtkSheetRange *range)
4755 g_return_if_fail (sheet != NULL);
4756 *range = sheet->range;
4761 gtk_sheet_select_range (GtkSheet * sheet, const GtkSheetRange *range)
4763 g_return_if_fail (sheet != NULL);
4765 if (range == NULL) range=&sheet->range;
4767 if (range->row0 < 0 || range->rowi < 0) return;
4768 if (range->col0 < 0 || range->coli < 0) return;
4771 if ( gtk_sheet_locked (sheet)) return ;
4773 if (sheet->state != GTK_SHEET_NORMAL)
4774 gtk_sheet_real_unselect_range (sheet, NULL);
4777 gboolean veto = TRUE;
4778 veto = gtk_sheet_deactivate_cell (sheet);
4782 sheet->range.row0 = range->row0;
4783 sheet->range.rowi = range->rowi;
4784 sheet->range.col0 = range->col0;
4785 sheet->range.coli = range->coli;
4786 sheet->active_cell.row = range->row0;
4787 sheet->active_cell.col = range->col0;
4788 sheet->selection_cell.row = range->rowi;
4789 sheet->selection_cell.col = range->coli;
4791 sheet->state = GTK_SHEET_RANGE_SELECTED;
4792 gtk_sheet_real_select_range (sheet, NULL);
4797 gtk_sheet_unselect_range (GtkSheet * sheet)
4799 gtk_sheet_real_unselect_range (sheet, NULL);
4800 sheet->state = GTK_STATE_NORMAL;
4802 gtk_sheet_activate_cell (sheet,
4803 sheet->active_cell.row, sheet->active_cell.col);
4808 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4809 const GtkSheetRange *range)
4811 g_return_if_fail (sheet != NULL);
4812 g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
4815 range = &sheet->range;
4817 if (range->row0 < 0 || range->rowi < 0) return;
4818 if (range->col0 < 0 || range->coli < 0) return;
4820 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_COLUMN], 0, -1);
4821 g_signal_emit (G_OBJECT (sheet), sheet_signals[SELECT_ROW], 0, -1);
4823 if (gtk_sheet_range_isvisible (sheet, *range))
4824 gtk_sheet_draw_backing_pixmap (sheet, *range);
4826 sheet->range.row0 = -1;
4827 sheet->range.rowi = -1;
4828 sheet->range.col0 = -1;
4829 sheet->range.coli = -1;
4831 gtk_sheet_position_children (sheet);
4836 gtk_sheet_expose (GtkWidget * widget,
4837 GdkEventExpose * event)
4840 GtkSheetRange range;
4842 g_return_val_if_fail (widget != NULL, FALSE);
4843 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4844 g_return_val_if_fail (event != NULL, FALSE);
4847 sheet = GTK_SHEET (widget);
4849 if (GTK_WIDGET_DRAWABLE (widget))
4851 range.row0 = ROW_FROM_YPIXEL (sheet, event->area.y);
4852 range.col0 = COLUMN_FROM_XPIXEL (sheet, event->area.x);
4853 range.rowi = ROW_FROM_YPIXEL (sheet, event->area.y + event->area.height);
4854 range.coli = COLUMN_FROM_XPIXEL (sheet, event->area.x + event->area.width);
4856 /* exposure events on the sheet */
4857 if (event->window == sheet->row_title_window &&
4858 sheet->row_titles_visible)
4861 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
4862 gtk_sheet_row_title_button_draw (sheet, i);
4865 if (event->window == sheet->column_title_window &&
4866 sheet->column_titles_visible)
4869 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
4870 gtk_sheet_column_title_button_draw (sheet, i);
4873 if (event->window == sheet->sheet_window)
4875 gtk_sheet_draw_backing_pixmap (sheet, range);
4877 if (sheet->state != GTK_SHEET_NORMAL)
4879 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4880 gtk_sheet_draw_backing_pixmap (sheet, sheet->range);
4881 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4882 gtk_sheet_draw_backing_pixmap (sheet, sheet->drag_range);
4884 if (gtk_sheet_range_isvisible (sheet, sheet->range))
4885 gtk_sheet_range_draw_selection (sheet, sheet->range);
4886 if (GTK_SHEET_IN_RESIZE (sheet) || GTK_SHEET_IN_DRAG (sheet))
4887 draw_xor_rectangle (sheet, sheet->drag_range);
4890 if ((!GTK_SHEET_IN_XDRAG (sheet)) && (!GTK_SHEET_IN_YDRAG (sheet)))
4892 if (sheet->state == GTK_SHEET_NORMAL)
4894 gtk_sheet_draw_active_cell (sheet);
4895 if (!GTK_SHEET_IN_SELECTION (sheet))
4896 gtk_widget_queue_draw (sheet->sheet_entry);
4902 if (sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
4903 gtk_widget_grab_focus (GTK_WIDGET (sheet));
4905 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4912 gtk_sheet_button_press (GtkWidget * widget,
4913 GdkEventButton * event)
4916 GdkModifierType mods;
4917 gint x, y, row, column;
4920 g_return_val_if_fail (widget != NULL, FALSE);
4921 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4922 g_return_val_if_fail (event != NULL, FALSE);
4924 sheet = GTK_SHEET (widget);
4926 /* Cancel any pending tooltips */
4927 if (sheet->motion_timer)
4929 g_source_remove (sheet->motion_timer);
4930 sheet->motion_timer = 0;
4933 gtk_widget_get_pointer (widget, &x, &y);
4934 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4937 if (event->window == sheet->column_title_window)
4939 g_signal_emit (G_OBJECT (sheet),
4940 sheet_signals[BUTTON_EVENT_COLUMN], 0,
4943 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4944 g_signal_emit (G_OBJECT (sheet),
4945 sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
4948 else if (event->window == sheet->row_title_window)
4950 g_signal_emit (G_OBJECT (sheet),
4951 sheet_signals[BUTTON_EVENT_ROW], 0,
4954 if ( event->type == GDK_2BUTTON_PRESS && event->button == 1)
4955 g_signal_emit (G_OBJECT (sheet),
4956 sheet_signals[DOUBLE_CLICK_ROW], 0, row);
4960 gdk_window_get_pointer (widget->window, NULL, NULL, &mods);
4962 if (! (mods & GDK_BUTTON1_MASK)) return TRUE;
4965 /* press on resize windows */
4966 if (event->window == sheet->column_title_window &&
4967 gtk_sheet_columns_resizable (sheet))
4969 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4970 if (POSSIBLE_XDRAG (sheet, sheet->x_drag, &sheet->drag_cell.col))
4973 if (event->type == GDK_2BUTTON_PRESS)
4975 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4976 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4979 gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
4980 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4981 gdk_pointer_grab (sheet->column_title_window, FALSE,
4982 GDK_POINTER_MOTION_HINT_MASK |
4983 GDK_BUTTON1_MOTION_MASK |
4984 GDK_BUTTON_RELEASE_MASK,
4985 NULL, NULL, event->time);
4987 draw_xor_vline (sheet);
4992 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable (sheet))
4994 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4996 if (POSSIBLE_YDRAG (sheet, sheet->y_drag, &sheet->drag_cell.row))
4999 gtk_sheet_row_size_request (sheet, sheet->drag_cell.row, &req);
5000 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5001 gdk_pointer_grab (sheet->row_title_window, FALSE,
5002 GDK_POINTER_MOTION_HINT_MASK |
5003 GDK_BUTTON1_MOTION_MASK |
5004 GDK_BUTTON_RELEASE_MASK,
5005 NULL, NULL, event->time);
5007 draw_xor_hline (sheet);
5012 /* the sheet itself does not handle other than single click events */
5013 if (event->type != GDK_BUTTON_PRESS) return FALSE;
5015 /* selections on the sheet */
5016 if (event->window == sheet->sheet_window)
5018 gtk_widget_get_pointer (widget, &x, &y);
5019 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5020 gdk_pointer_grab (sheet->sheet_window, FALSE,
5021 GDK_POINTER_MOTION_HINT_MASK |
5022 GDK_BUTTON1_MOTION_MASK |
5023 GDK_BUTTON_RELEASE_MASK,
5024 NULL, NULL, event->time);
5025 gtk_grab_add (GTK_WIDGET (sheet));
5027 /* This seems to be a kludge to work around a problem where the sheet
5028 scrolls to another position. The timeout scrolls it back to its
5029 original posn. JMD 3 July 2007
5031 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5033 if (sheet->selection_mode != GTK_SELECTION_SINGLE &&
5034 sheet->selection_mode != GTK_SELECTION_NONE &&
5035 sheet->cursor_drag->type == GDK_SIZING &&
5036 !GTK_SHEET_IN_SELECTION (sheet) && !GTK_SHEET_IN_RESIZE (sheet))
5038 if (sheet->state == GTK_STATE_NORMAL)
5040 row = sheet->active_cell.row;
5041 column = sheet->active_cell.col;
5042 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
5043 sheet->active_cell.row = row;
5044 sheet->active_cell.col = column;
5045 sheet->drag_range = sheet->range;
5046 sheet->state = GTK_SHEET_RANGE_SELECTED;
5047 gtk_sheet_select_range (sheet, &sheet->drag_range);
5051 if (row > sheet->range.rowi) row--;
5052 if (column > sheet->range.coli) column--;
5053 sheet->drag_cell.row = row;
5054 sheet->drag_cell.col = column;
5055 sheet->drag_range = sheet->range;
5056 draw_xor_rectangle (sheet, sheet->drag_range);
5057 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
5059 else if (sheet->cursor_drag->type == GDK_TOP_LEFT_ARROW &&
5060 !GTK_SHEET_IN_SELECTION (sheet)
5061 && ! GTK_SHEET_IN_DRAG (sheet)
5062 && ! gtk_sheet_locked (sheet)
5063 && sheet->active_cell.row >= 0
5064 && sheet->active_cell.col >= 0
5067 if (sheet->state == GTK_STATE_NORMAL)
5069 row = sheet->active_cell.row;
5070 column = sheet->active_cell.col;
5071 if (!gtk_sheet_deactivate_cell (sheet)) return FALSE;
5072 sheet->active_cell.row = row;
5073 sheet->active_cell.col = column;
5074 sheet->drag_range = sheet->range;
5075 sheet->state = GTK_SHEET_RANGE_SELECTED;
5076 gtk_sheet_select_range (sheet, &sheet->drag_range);
5080 if (row < sheet->range.row0) row++;
5081 if (row > sheet->range.rowi) row--;
5082 if (column < sheet->range.col0) column++;
5083 if (column > sheet->range.coli) column--;
5084 sheet->drag_cell.row = row;
5085 sheet->drag_cell.col = column;
5086 sheet->drag_range = sheet->range;
5087 draw_xor_rectangle (sheet, sheet->drag_range);
5088 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
5092 gtk_sheet_click_cell (sheet, row, column, &veto);
5093 if (veto) GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5097 if (event->window == sheet->column_title_window)
5099 gtk_widget_get_pointer (widget, &x, &y);
5100 column = COLUMN_FROM_XPIXEL (sheet, x);
5102 if (xxx_column_is_sensitive (sheet, column))
5104 gtk_sheet_click_cell (sheet, - 1, column, &veto);
5105 gtk_grab_add (GTK_WIDGET (sheet));
5106 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5107 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5111 if (event->window == sheet->row_title_window)
5113 gtk_widget_get_pointer (widget, &x, &y);
5114 row = ROW_FROM_YPIXEL (sheet, y);
5115 if (yyy_row_is_sensitive (sheet, row))
5117 gtk_sheet_click_cell (sheet, row, - 1, &veto);
5118 gtk_grab_add (GTK_WIDGET (sheet));
5119 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5120 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5129 gtk_sheet_scroll (gpointer data)
5132 gint x,y,row,column;
5135 sheet = GTK_SHEET (data);
5137 GDK_THREADS_ENTER ();
5139 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
5140 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5144 if (GTK_SHEET_IN_SELECTION (sheet))
5145 gtk_sheet_extend_selection (sheet, row, column);
5147 if (GTK_SHEET_IN_DRAG (sheet) || GTK_SHEET_IN_RESIZE (sheet))
5149 move = gtk_sheet_move_query (sheet, row, column);
5150 if (move) draw_xor_rectangle (sheet, sheet->drag_range);
5153 GDK_THREADS_LEAVE ();
5160 gtk_sheet_click_cell (GtkSheet *sheet, gint row, gint column, gboolean *veto)
5164 if (row >= yyy_row_count (sheet) || column >= xxx_column_count (sheet))
5170 if (column >= 0 && row >= 0)
5171 if (! xxx_column_is_visible (sheet, column) || !yyy_row_is_visible (sheet, row))
5177 _gtkextra_signal_emit (GTK_OBJECT (sheet), sheet_signals[TRAVERSE],
5178 sheet->active_cell.row, sheet->active_cell.col,
5179 &row, &column, veto);
5183 if (sheet->state == GTK_STATE_NORMAL) return;
5185 row = sheet->active_cell.row;
5186 column = sheet->active_cell.col;
5188 gtk_sheet_activate_cell (sheet, row, column);
5192 if (row == -1 && column >= 0)
5194 if (gtk_sheet_autoscroll (sheet))
5195 gtk_sheet_move_query (sheet, row, column);
5196 gtk_sheet_select_column (sheet, column);
5199 if (column == -1 && row >= 0)
5201 if (gtk_sheet_autoscroll (sheet))
5202 gtk_sheet_move_query (sheet, row, column);
5203 gtk_sheet_select_row (sheet, row);
5207 if (row == - 1 && column == - 1)
5209 sheet->range.row0 = 0;
5210 sheet->range.col0 = 0;
5211 sheet->range.rowi = yyy_row_count (sheet) - 1;
5212 sheet->range.coli = xxx_column_count (sheet) - 1;
5213 sheet->active_cell.row = 0;
5214 sheet->active_cell.col = 0;
5215 gtk_sheet_select_range (sheet, NULL);
5219 if (row != -1 && column != -1)
5221 if (sheet->state != GTK_SHEET_NORMAL)
5223 sheet->state = GTK_SHEET_NORMAL;
5224 gtk_sheet_real_unselect_range (sheet, NULL);
5228 if (!gtk_sheet_deactivate_cell (sheet))
5235 if (gtk_sheet_autoscroll (sheet))
5236 gtk_sheet_move_query (sheet, row, column);
5237 sheet->active_cell.row = row;
5238 sheet->active_cell.col = column;
5239 sheet->selection_cell.row = row;
5240 sheet->selection_cell.col = column;
5241 sheet->range.row0 = row;
5242 sheet->range.col0 = column;
5243 sheet->range.rowi = row;
5244 sheet->range.coli = column;
5245 sheet->state = GTK_SHEET_NORMAL;
5246 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5247 gtk_sheet_draw_active_cell (sheet);
5251 g_assert_not_reached ();
5252 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5253 sheet->active_cell.col);
5257 gtk_sheet_button_release (GtkWidget * widget,
5258 GdkEventButton * event)
5263 sheet = GTK_SHEET (widget);
5265 /* release on resize windows */
5266 if (GTK_SHEET_IN_XDRAG (sheet))
5268 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5269 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5270 gtk_widget_get_pointer (widget, &x, NULL);
5271 gdk_pointer_ungrab (event->time);
5272 draw_xor_vline (sheet);
5274 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col,
5275 new_column_width (sheet, sheet->drag_cell.col, &x));
5276 sheet->old_hadjustment = -1.;
5277 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "value_changed");
5281 if (GTK_SHEET_IN_YDRAG (sheet))
5283 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5284 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5285 gtk_widget_get_pointer (widget, NULL, &y);
5286 gdk_pointer_ungrab (event->time);
5287 draw_xor_hline (sheet);
5289 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5290 sheet->old_vadjustment = -1.;
5291 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "value_changed");
5296 if (GTK_SHEET_IN_DRAG (sheet))
5298 GtkSheetRange old_range;
5299 draw_xor_rectangle (sheet, sheet->drag_range);
5300 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_DRAG);
5301 gdk_pointer_ungrab (event->time);
5303 gtk_sheet_real_unselect_range (sheet, NULL);
5305 sheet->active_cell.row = sheet->active_cell.row +
5306 (sheet->drag_range.row0 - sheet->range.row0);
5307 sheet->active_cell.col = sheet->active_cell.col +
5308 (sheet->drag_range.col0 - sheet->range.col0);
5309 sheet->selection_cell.row = sheet->selection_cell.row +
5310 (sheet->drag_range.row0 - sheet->range.row0);
5311 sheet->selection_cell.col = sheet->selection_cell.col +
5312 (sheet->drag_range.col0 - sheet->range.col0);
5313 old_range = sheet->range;
5314 sheet->range = sheet->drag_range;
5315 sheet->drag_range = old_range;
5316 g_signal_emit (G_OBJECT (sheet), sheet_signals[MOVE_RANGE], 0,
5317 &sheet->drag_range, &sheet->range);
5318 gtk_sheet_select_range (sheet, &sheet->range);
5321 if (GTK_SHEET_IN_RESIZE (sheet))
5323 GtkSheetRange old_range;
5324 draw_xor_rectangle (sheet, sheet->drag_range);
5325 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_RESIZE);
5326 gdk_pointer_ungrab (event->time);
5328 gtk_sheet_real_unselect_range (sheet, NULL);
5330 sheet->active_cell.row = sheet->active_cell.row +
5331 (sheet->drag_range.row0 - sheet->range.row0);
5332 sheet->active_cell.col = sheet->active_cell.col +
5333 (sheet->drag_range.col0 - sheet->range.col0);
5334 if (sheet->drag_range.row0 < sheet->range.row0)
5335 sheet->selection_cell.row = sheet->drag_range.row0;
5336 if (sheet->drag_range.rowi >= sheet->range.rowi)
5337 sheet->selection_cell.row = sheet->drag_range.rowi;
5338 if (sheet->drag_range.col0 < sheet->range.col0)
5339 sheet->selection_cell.col = sheet->drag_range.col0;
5340 if (sheet->drag_range.coli >= sheet->range.coli)
5341 sheet->selection_cell.col = sheet->drag_range.coli;
5342 old_range = sheet->range;
5343 sheet->range = sheet->drag_range;
5344 sheet->drag_range = old_range;
5346 if (sheet->state == GTK_STATE_NORMAL) sheet->state = GTK_SHEET_RANGE_SELECTED;
5347 g_signal_emit (G_OBJECT (sheet), sheet_signals[RESIZE_RANGE], 0,
5348 &sheet->drag_range, &sheet->range);
5349 gtk_sheet_select_range (sheet, &sheet->range);
5352 if (sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION (sheet))
5354 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5355 gdk_pointer_ungrab (event->time);
5356 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
5357 sheet->active_cell.col);
5360 if (GTK_SHEET_IN_SELECTION)
5361 gdk_pointer_ungrab (event->time);
5362 gtk_grab_remove (GTK_WIDGET (sheet));
5364 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5369 /* Shamelessly lifted from gtktooltips */
5371 gtk_sheet_subtitle_paint_window (GtkWidget *tip_window)
5375 gtk_widget_size_request (tip_window, &req);
5376 gtk_paint_flat_box (tip_window->style, tip_window->window,
5377 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
5378 NULL, GTK_WIDGET(tip_window), "tooltip",
5379 0, 0, req.width, req.height);
5384 static GtkSheetHoverTitle *
5385 create_hover_window (void)
5387 GtkSheetHoverTitle *hw = malloc (sizeof (*hw));
5389 hw->window = gtk_window_new (GTK_WINDOW_POPUP);
5391 #if GTK_CHECK_VERSION (2, 9, 0)
5392 gtk_window_set_type_hint (GTK_WINDOW (hw->window),
5393 GDK_WINDOW_TYPE_HINT_TOOLTIP);
5396 gtk_widget_set_app_paintable (hw->window, TRUE);
5397 gtk_window_set_resizable (GTK_WINDOW (hw->window), FALSE);
5398 gtk_widget_set_name (hw->window, "gtk-tooltips");
5399 gtk_container_set_border_width (GTK_CONTAINER (hw->window), 4);
5401 g_signal_connect (hw->window,
5403 G_CALLBACK (gtk_sheet_subtitle_paint_window),
5406 hw->label = gtk_label_new (NULL);
5409 gtk_label_set_line_wrap (GTK_LABEL (hw->label), TRUE);
5410 gtk_misc_set_alignment (GTK_MISC (hw->label), 0.5, 0.5);
5412 gtk_container_add (GTK_CONTAINER (hw->window), hw->label);
5414 gtk_widget_show (hw->label);
5416 g_signal_connect (hw->window,
5418 G_CALLBACK (gtk_widget_destroyed),
5424 #define HOVER_WINDOW_Y_OFFSET 2
5427 show_subtitle (GtkSheet *sheet, gint row, gint column, const gchar *subtitle)
5436 if ( ! sheet->hover_window)
5438 sheet->hover_window = create_hover_window ();
5439 gtk_widget_add_events (GTK_WIDGET (sheet), GDK_LEAVE_NOTIFY_MASK);
5441 g_signal_connect_swapped (sheet, "leave-notify-event",
5442 G_CALLBACK (gtk_widget_hide),
5443 sheet->hover_window->window);
5446 gtk_label_set_text (GTK_LABEL (sheet->hover_window->label),
5450 sheet->hover_window->row = row;
5451 sheet->hover_window->column = column;
5453 gdk_window_get_origin (GTK_WIDGET (sheet)->window, &x, &y);
5455 gtk_widget_get_pointer (GTK_WIDGET (sheet), &px, &py);
5457 gtk_widget_show (sheet->hover_window->window);
5459 width = GTK_WIDGET (sheet->hover_window->label)->allocation.width;
5465 y += sheet->column_title_area.y;
5466 y += sheet->column_title_area.height;
5467 y += HOVER_WINDOW_Y_OFFSET;
5473 x += sheet->row_title_area.x;
5474 x += sheet->row_title_area.width * 2 / 3.0;
5477 gtk_window_move (GTK_WINDOW (sheet->hover_window->window),
5482 motion_timeout_callback (gpointer data)
5484 GtkSheet *sheet = GTK_SHEET (data);
5487 gtk_widget_get_pointer (GTK_WIDGET (sheet), &x, &y);
5489 if ( gtk_sheet_get_pixel_info (sheet, x, y, &row, &column) )
5491 if ( column == -1 && row == -1 )
5496 GSheetRow *row_geo = sheet->row_geometry;
5499 text = g_sheet_row_get_subtitle (row_geo, row);
5501 show_subtitle (sheet, row, column, text);
5507 GSheetColumn *col_geo = sheet->column_geometry;
5510 text = g_sheet_column_get_subtitle (col_geo, column);
5512 show_subtitle (sheet, row, column, text );
5522 gtk_sheet_motion (GtkWidget * widget,
5523 GdkEventMotion * event)
5526 GdkModifierType mods;
5527 GdkCursorType new_cursor;
5531 g_return_val_if_fail (widget != NULL, FALSE);
5532 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5533 g_return_val_if_fail (event != NULL, FALSE);
5535 sheet = GTK_SHEET (widget);
5537 /* selections on the sheet */
5541 if (!sheet->hover_window || ! GTK_WIDGET_VISIBLE (sheet->hover_window->window))
5543 if ( sheet->motion_timer > 0 )
5544 g_source_remove (sheet->motion_timer);
5545 sheet->motion_timer = g_timeout_add (TIMEOUT_HOVER, motion_timeout_callback, sheet);
5551 gtk_widget_get_pointer (widget, &wx, &wy);
5553 if ( gtk_sheet_get_pixel_info (sheet, wx, wy, &row, &column) )
5555 if ( row != sheet->hover_window->row || column != sheet->hover_window->column)
5557 gtk_widget_hide (sheet->hover_window->window);
5562 if (event->window == sheet->column_title_window &&
5563 gtk_sheet_columns_resizable (sheet))
5565 gtk_widget_get_pointer (widget, &x, &y);
5566 if (!GTK_SHEET_IN_SELECTION (sheet) &&
5567 POSSIBLE_XDRAG (sheet, x, &column))
5569 new_cursor = GDK_SB_H_DOUBLE_ARROW;
5570 if (new_cursor != sheet->cursor_drag->type)
5572 gdk_cursor_destroy (sheet->cursor_drag);
5573 sheet->cursor_drag = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
5574 gdk_window_set_cursor (sheet->column_title_window,
5575 sheet->cursor_drag);
5580 new_cursor = GDK_TOP_LEFT_ARROW;
5581 if (!GTK_SHEET_IN_XDRAG (sheet) &&
5582 new_cursor != sheet->cursor_drag->type)
5584 gdk_cursor_destroy (sheet->cursor_drag);
5585 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5586 gdk_window_set_cursor (sheet->column_title_window,
5587 sheet->cursor_drag);
5592 if (event->window == sheet->row_title_window &&
5593 gtk_sheet_rows_resizable (sheet))
5595 gtk_widget_get_pointer (widget, &x, &y);
5596 if (!GTK_SHEET_IN_SELECTION (sheet) && POSSIBLE_YDRAG (sheet,y, &column))
5598 new_cursor = GDK_SB_V_DOUBLE_ARROW;
5599 if (new_cursor != sheet->cursor_drag->type)
5601 gdk_cursor_destroy (sheet->cursor_drag);
5602 sheet->cursor_drag = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
5603 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5608 new_cursor = GDK_TOP_LEFT_ARROW;
5609 if (!GTK_SHEET_IN_YDRAG (sheet) &&
5610 new_cursor != sheet->cursor_drag->type)
5612 gdk_cursor_destroy (sheet->cursor_drag);
5613 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5614 gdk_window_set_cursor (sheet->row_title_window, sheet->cursor_drag);
5619 new_cursor = GDK_PLUS;
5620 if ( event->window == sheet->sheet_window &&
5621 !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
5622 !GTK_SHEET_IN_DRAG (sheet) &&
5623 !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
5624 !GTK_SHEET_IN_RESIZE (sheet) &&
5625 new_cursor != sheet->cursor_drag->type)
5627 gdk_cursor_destroy (sheet->cursor_drag);
5628 sheet->cursor_drag = gdk_cursor_new (GDK_PLUS);
5629 gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
5632 new_cursor = GDK_TOP_LEFT_ARROW;
5633 if ( event->window == sheet->sheet_window &&
5634 ! (POSSIBLE_RESIZE (sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE (sheet)) && (POSSIBLE_DRAG (sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG (sheet)) &&
5636 new_cursor != sheet->cursor_drag->type)
5638 gdk_cursor_destroy (sheet->cursor_drag);
5639 sheet->cursor_drag = gdk_cursor_new (GDK_TOP_LEFT_ARROW);
5640 gdk_window_set_cursor (sheet->sheet_window,sheet->cursor_drag);
5643 new_cursor = GDK_SIZING;
5644 if ( event->window == sheet->sheet_window &&
5645 sheet->selection_mode != GTK_SELECTION_NONE &&
5646 !GTK_SHEET_IN_DRAG (sheet) &&
5647 (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
5648 GTK_SHEET_IN_RESIZE (sheet)) &&
5649 new_cursor != sheet->cursor_drag->type)
5651 gdk_cursor_destroy (sheet->cursor_drag);
5652 sheet->cursor_drag = gdk_cursor_new (GDK_SIZING);
5653 gdk_window_set_cursor (sheet->sheet_window,sheet->cursor_drag);
5657 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5658 if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
5660 if (GTK_SHEET_IN_XDRAG (sheet))
5662 if (event->is_hint || event->window != widget->window)
5663 gtk_widget_get_pointer (widget, &x, NULL);
5667 new_column_width (sheet, sheet->drag_cell.col, &x);
5668 if (x != sheet->x_drag)
5670 draw_xor_vline (sheet);
5672 draw_xor_vline (sheet);
5677 if (GTK_SHEET_IN_YDRAG (sheet))
5679 if (event->is_hint || event->window != widget->window)
5680 gtk_widget_get_pointer (widget, NULL, &y);
5684 new_row_height (sheet, sheet->drag_cell.row, &y);
5685 if (y != sheet->y_drag)
5687 draw_xor_hline (sheet);
5689 draw_xor_hline (sheet);
5694 if (GTK_SHEET_IN_DRAG (sheet))
5697 column = COLUMN_FROM_XPIXEL (sheet,x)- sheet->drag_cell.col;
5698 row = ROW_FROM_YPIXEL (sheet,y)- sheet->drag_cell.row;
5699 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5700 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5704 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5705 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5707 aux = sheet->drag_range;
5708 sheet->drag_range.row0 = sheet->range.row0 + row;
5709 sheet->drag_range.col0 = sheet->range.col0 + column;
5710 sheet->drag_range.rowi = sheet->range.rowi + row;
5711 sheet->drag_range.coli = sheet->range.coli + column;
5712 if (aux.row0 != sheet->drag_range.row0 ||
5713 aux.col0 != sheet->drag_range.col0)
5715 draw_xor_rectangle (sheet, aux);
5716 draw_xor_rectangle (sheet, sheet->drag_range);
5722 if (GTK_SHEET_IN_RESIZE (sheet))
5725 gint v_h, current_col, current_row, col_threshold, row_threshold;
5728 if (abs (x - COLUMN_LEFT_XPIXEL (sheet,sheet->drag_cell.col)) >
5729 abs (y - ROW_TOP_YPIXEL (sheet,sheet->drag_cell.row))) v_h = 2;
5731 current_col = COLUMN_FROM_XPIXEL (sheet,x);
5732 current_row = ROW_FROM_YPIXEL (sheet,y);
5733 column = current_col - sheet->drag_cell.col;
5734 row = current_row - sheet->drag_cell.row;
5736 /*use half of column width resp. row height as threshold to
5738 col_threshold = COLUMN_LEFT_XPIXEL (sheet,current_col) +
5739 xxx_column_width (sheet,current_col) / 2;
5742 if (x < col_threshold)
5745 else if (column < 0)
5747 if (x > col_threshold)
5750 row_threshold = ROW_TOP_YPIXEL (sheet,current_row) +
5751 yyy_row_height (sheet, current_row)/2;
5754 if (y < row_threshold)
5759 if (y > row_threshold)
5763 if (sheet->state == GTK_SHEET_COLUMN_SELECTED) row = 0;
5764 if (sheet->state == GTK_SHEET_ROW_SELECTED) column = 0;
5774 if (aux.row0 + row >= 0 && aux.rowi + row < yyy_row_count (sheet) &&
5775 aux.col0 + column >= 0 && aux.coli + column < xxx_column_count (sheet))
5777 aux = sheet->drag_range;
5778 sheet->drag_range = sheet->range;
5780 if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
5781 if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
5782 if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
5783 if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
5785 if (aux.row0 != sheet->drag_range.row0 ||
5786 aux.rowi != sheet->drag_range.rowi ||
5787 aux.col0 != sheet->drag_range.col0 ||
5788 aux.coli != sheet->drag_range.coli)
5790 draw_xor_rectangle (sheet, aux);
5791 draw_xor_rectangle (sheet, sheet->drag_range);
5797 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5799 if (sheet->state == GTK_SHEET_NORMAL && row == sheet->active_cell.row &&
5800 column == sheet->active_cell.col) return TRUE;
5802 if (GTK_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
5803 gtk_sheet_extend_selection (sheet, row, column);
5809 gtk_sheet_move_query (GtkSheet *sheet, gint row, gint column)
5811 gint row_move, column_move;
5812 gfloat row_align, col_align;
5813 guint height, width;
5815 gint new_col = column;
5818 column_move = FALSE;
5822 height = sheet->sheet_window_height;
5823 width = sheet->sheet_window_width;
5825 if (row >= MAX_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5828 new_row = MIN (yyy_row_count (sheet), row + 1);
5830 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet) - 1 &&
5831 ROW_TOP_YPIXEL (sheet, yyy_row_count (sheet)- 1) +
5832 yyy_row_height (sheet, yyy_row_count (sheet)- 1) < height)
5838 if (row < MIN_VISIBLE_ROW (sheet) && sheet->state != GTK_SHEET_COLUMN_SELECTED)
5843 if (column >= MAX_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5846 new_col = MIN (xxx_column_count (sheet) - 1, column + 1);
5848 if (MAX_VISIBLE_COLUMN (sheet) == (xxx_column_count (sheet) - 1) &&
5849 COLUMN_LEFT_XPIXEL (sheet, xxx_column_count (sheet) - 1) +
5850 xxx_column_width (sheet, xxx_column_count (sheet) - 1) < width)
5852 column_move = FALSE;
5856 if (column < MIN_VISIBLE_COLUMN (sheet) && sheet->state != GTK_SHEET_ROW_SELECTED)
5862 if (row_move || column_move)
5864 gtk_sheet_moveto (sheet, new_row, new_col, row_align, col_align);
5867 return (row_move || column_move);
5871 gtk_sheet_extend_selection (GtkSheet *sheet, gint row, gint column)
5873 GtkSheetRange range;
5877 if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5880 if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5882 gtk_sheet_move_query (sheet, row, column);
5883 gtk_widget_grab_focus (GTK_WIDGET (sheet));
5885 if (GTK_SHEET_IN_DRAG (sheet)) return;
5887 state = sheet->state;
5889 switch (sheet->state)
5891 case GTK_SHEET_ROW_SELECTED:
5892 column = xxx_column_count (sheet) - 1;
5894 case GTK_SHEET_COLUMN_SELECTED:
5895 row = yyy_row_count (sheet) - 1;
5897 case GTK_SHEET_NORMAL:
5898 sheet->state = GTK_SHEET_RANGE_SELECTED;
5899 r = sheet->active_cell.row;
5900 c = sheet->active_cell.col;
5901 sheet->range.col0 = c;
5902 sheet->range.row0 = r;
5903 sheet->range.coli = c;
5904 sheet->range.rowi = r;
5905 gdk_draw_pixmap (sheet->sheet_window,
5906 GTK_WIDGET (sheet)->style->fg_gc[GTK_STATE_NORMAL],
5908 COLUMN_LEFT_XPIXEL (sheet,c)- 1,
5909 ROW_TOP_YPIXEL (sheet,r)- 1,
5910 COLUMN_LEFT_XPIXEL (sheet,c)- 1,
5911 ROW_TOP_YPIXEL (sheet,r)- 1,
5912 xxx_column_width (sheet, c)+4,
5913 yyy_row_height (sheet, r)+4);
5914 gtk_sheet_range_draw_selection (sheet, sheet->range);
5915 case GTK_SHEET_RANGE_SELECTED:
5916 sheet->state = GTK_SHEET_RANGE_SELECTED;
5919 sheet->selection_cell.row = row;
5920 sheet->selection_cell.col = column;
5922 range.col0 = MIN (column,sheet->active_cell.col);
5923 range.coli = MAX (column,sheet->active_cell.col);
5924 range.row0 = MIN (row,sheet->active_cell.row);
5925 range.rowi = MAX (row,sheet->active_cell.row);
5927 if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5928 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5929 state == GTK_SHEET_NORMAL)
5930 gtk_sheet_real_select_range (sheet, &range);
5935 gtk_sheet_entry_key_press (GtkWidget *widget,
5939 g_signal_emit_by_name (G_OBJECT (widget), "key_press_event", key, &focus);
5944 gtk_sheet_key_press (GtkWidget *widget,
5950 gboolean extend_selection = FALSE;
5951 gboolean force_move = FALSE;
5952 gboolean in_selection = FALSE;
5953 gboolean veto = TRUE;
5956 sheet = GTK_SHEET (widget);
5958 if (key->state & GDK_CONTROL_MASK || key->keyval == GDK_Control_L ||
5959 key->keyval == GDK_Control_R) return FALSE;
5961 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval == GDK_Shift_L
5962 || key->keyval == GDK_Shift_R;
5964 state = sheet->state;
5965 in_selection = GTK_SHEET_IN_SELECTION (sheet);
5966 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5968 switch (key->keyval)
5970 case GDK_Return: case GDK_KP_Enter:
5971 if (sheet->state == GTK_SHEET_NORMAL &&
5972 !GTK_SHEET_IN_SELECTION (sheet))
5973 g_signal_stop_emission_by_name (gtk_sheet_get_entry (sheet),
5975 row = sheet->active_cell.row;
5976 col = sheet->active_cell.col;
5977 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5978 row = MIN_VISIBLE_ROW (sheet)- 1;
5979 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5980 col = MIN_VISIBLE_COLUMN (sheet);
5981 if (row < yyy_row_count (sheet) - 1)
5984 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1)
5987 gtk_sheet_click_cell (sheet, row, col, &veto);
5988 extend_selection = FALSE;
5990 case GDK_ISO_Left_Tab:
5991 row = sheet->active_cell.row;
5992 col = sheet->active_cell.col;
5993 if (sheet->state == GTK_SHEET_ROW_SELECTED)
5994 col = MIN_VISIBLE_COLUMN (sheet)- 1;
5995 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
5996 row = MIN_VISIBLE_ROW (sheet);
6000 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
6003 gtk_sheet_click_cell (sheet, row, col, &veto);
6004 extend_selection = FALSE;
6007 row = sheet->active_cell.row;
6008 col = sheet->active_cell.col;
6009 if (sheet->state == GTK_SHEET_ROW_SELECTED)
6010 col = MIN_VISIBLE_COLUMN (sheet)- 1;
6011 if (sheet->state == GTK_SHEET_COLUMN_SELECTED)
6012 row = MIN_VISIBLE_ROW (sheet);
6013 if (col < xxx_column_count (sheet) - 1)
6016 while (! xxx_column_is_visible (sheet, col) &&
6017 col < xxx_column_count (sheet) - 1)
6020 gtk_sheet_click_cell (sheet, row, col, &veto);
6021 extend_selection = FALSE;
6024 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
6026 if (extend_selection)
6028 if (state == GTK_STATE_NORMAL)
6030 row = sheet->active_cell.row;
6031 col = sheet->active_cell.col;
6032 gtk_sheet_click_cell (sheet, row, col, &veto);
6035 if (sheet->selection_cell.row > 0)
6037 row = sheet->selection_cell.row - scroll;
6038 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
6040 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
6044 col = sheet->active_cell.col;
6045 row = sheet->active_cell.row;
6046 if (state == GTK_SHEET_COLUMN_SELECTED)
6047 row = MIN_VISIBLE_ROW (sheet);
6048 if (state == GTK_SHEET_ROW_SELECTED)
6049 col = MIN_VISIBLE_COLUMN (sheet);
6051 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
6053 gtk_sheet_click_cell (sheet, row, col, &veto);
6054 extend_selection = FALSE;
6057 scroll = MAX_VISIBLE_ROW (sheet)- MIN_VISIBLE_ROW (sheet)+1;
6059 if (extend_selection)
6061 if (state == GTK_STATE_NORMAL)
6063 row = sheet->active_cell.row;
6064 col = sheet->active_cell.col;
6065 gtk_sheet_click_cell (sheet, row, col, &veto);
6068 if (sheet->selection_cell.row < yyy_row_count (sheet)- 1)
6070 row = sheet->selection_cell.row + scroll;
6071 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
6072 row = MIN (yyy_row_count (sheet)- 1, row);
6073 gtk_sheet_extend_selection (sheet, row, sheet->selection_cell.col);
6077 col = sheet->active_cell.col;
6078 row = sheet->active_cell.row;
6079 if (sheet->active_cell.row < yyy_row_count (sheet)- 1)
6081 if (state == GTK_SHEET_COLUMN_SELECTED)
6082 row = MIN_VISIBLE_ROW (sheet)- 1;
6083 if (state == GTK_SHEET_ROW_SELECTED)
6084 col = MIN_VISIBLE_COLUMN (sheet);
6086 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
6087 row = MIN (yyy_row_count (sheet)- 1, row);
6089 gtk_sheet_click_cell (sheet, row, col, &veto);
6090 extend_selection = FALSE;
6093 if (extend_selection)
6095 if (state == GTK_STATE_NORMAL)
6097 row = sheet->active_cell.row;
6098 col = sheet->active_cell.col;
6099 gtk_sheet_click_cell (sheet, row, col, &veto);
6102 if (sheet->selection_cell.col < xxx_column_count (sheet) - 1)
6104 col = sheet->selection_cell.col + 1;
6105 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1)
6107 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
6111 col = sheet->active_cell.col;
6112 row = sheet->active_cell.row;
6113 if (sheet->active_cell.col < xxx_column_count (sheet) - 1)
6116 if (state == GTK_SHEET_ROW_SELECTED)
6117 col = MIN_VISIBLE_COLUMN (sheet)- 1;
6118 if (state == GTK_SHEET_COLUMN_SELECTED)
6119 row = MIN_VISIBLE_ROW (sheet);
6120 while (! xxx_column_is_visible (sheet, col) && col < xxx_column_count (sheet) - 1) col++;
6121 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
6124 gtk_sheet_click_cell (sheet, row, col, &veto);
6129 extend_selection = FALSE;
6132 if (extend_selection)
6134 if (state == GTK_STATE_NORMAL)
6136 row = sheet->active_cell.row;
6137 col = sheet->active_cell.col;
6138 gtk_sheet_click_cell (sheet, row, col, &veto);
6141 if (sheet->selection_cell.col > 0)
6143 col = sheet->selection_cell.col - 1;
6144 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
6145 gtk_sheet_extend_selection (sheet, sheet->selection_cell.row, col);
6149 col = sheet->active_cell.col - 1;
6150 row = sheet->active_cell.row;
6151 if (state == GTK_SHEET_ROW_SELECTED)
6152 col = MIN_VISIBLE_COLUMN (sheet)- 1;
6153 if (state == GTK_SHEET_COLUMN_SELECTED)
6154 row = MIN_VISIBLE_ROW (sheet);
6155 while (! xxx_column_is_visible (sheet, col) && col > 0) col--;
6158 if (strlen (gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)))) == 0
6161 gtk_sheet_click_cell (sheet, row, col, &veto);
6165 extend_selection = FALSE;
6169 while (!yyy_row_is_visible (sheet, row) && row < yyy_row_count (sheet)- 1) row++;
6170 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
6171 extend_selection = FALSE;
6174 row = yyy_row_count (sheet)- 1;
6175 while (!yyy_row_is_visible (sheet, row) && row > 0) row--;
6176 gtk_sheet_click_cell (sheet, row, sheet->active_cell.col, &veto);
6177 extend_selection = FALSE;
6182 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
6183 if (extend_selection) return TRUE;
6185 if (state == GTK_SHEET_ROW_SELECTED)
6186 sheet->active_cell.col = MIN_VISIBLE_COLUMN (sheet);
6187 if (state == GTK_SHEET_COLUMN_SELECTED)
6188 sheet->active_cell.row = MIN_VISIBLE_ROW (sheet);
6192 if (extend_selection) return TRUE;
6194 gtk_sheet_activate_cell (sheet, sheet->active_cell.row,
6195 sheet->active_cell.col);
6201 gtk_sheet_size_request (GtkWidget * widget,
6202 GtkRequisition * requisition)
6206 GtkSheetChild *child;
6207 GtkRequisition child_requisition;
6209 g_return_if_fail (widget != NULL);
6210 g_return_if_fail (GTK_IS_SHEET (widget));
6211 g_return_if_fail (requisition != NULL);
6213 sheet = GTK_SHEET (widget);
6215 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
6216 requisition->height = 3*DEFAULT_ROW_HEIGHT (widget);
6218 /* compute the size of the column title area */
6219 if (sheet->column_titles_visible)
6220 requisition->height += sheet->column_title_area.height;
6222 /* compute the size of the row title area */
6223 if (sheet->row_titles_visible)
6224 requisition->width += sheet->row_title_area.width;
6226 children = sheet->children;
6229 child = children->data;
6230 children = children->next;
6232 gtk_widget_size_request (child->widget, &child_requisition);
6238 gtk_sheet_size_allocate (GtkWidget * widget,
6239 GtkAllocation * allocation)
6242 GtkAllocation sheet_allocation;
6245 g_return_if_fail (widget != NULL);
6246 g_return_if_fail (GTK_IS_SHEET (widget));
6247 g_return_if_fail (allocation != NULL);
6249 sheet = GTK_SHEET (widget);
6250 widget->allocation = *allocation;
6251 border_width = GTK_CONTAINER (widget)->border_width;
6253 if (GTK_WIDGET_REALIZED (widget))
6254 gdk_window_move_resize (widget->window,
6255 allocation->x + border_width,
6256 allocation->y + border_width,
6257 allocation->width - 2 * border_width,
6258 allocation->height - 2 * border_width);
6260 /* use internal allocation structure for all the math
6261 * because it's easier than always subtracting the container
6263 sheet->internal_allocation.x = 0;
6264 sheet->internal_allocation.y = 0;
6265 sheet->internal_allocation.width = allocation->width - 2 * border_width;
6266 sheet->internal_allocation.height = allocation->height - 2 * border_width;
6268 sheet_allocation.x = 0;
6269 sheet_allocation.y = 0;
6270 sheet_allocation.width = allocation->width - 2 * border_width;
6271 sheet_allocation.height = allocation->height - 2 * border_width;
6273 sheet->sheet_window_width = sheet_allocation.width;
6274 sheet->sheet_window_height = sheet_allocation.height;
6276 if (GTK_WIDGET_REALIZED (widget))
6277 gdk_window_move_resize (sheet->sheet_window,
6280 sheet_allocation.width,
6281 sheet_allocation.height);
6283 /* position the window which holds the column title buttons */
6284 sheet->column_title_area.x = 0;
6285 sheet->column_title_area.y = 0;
6286 if (sheet->row_titles_visible)
6287 sheet->column_title_area.x = sheet->row_title_area.width;
6288 sheet->column_title_area.width = sheet_allocation.width -
6289 sheet->column_title_area.x;
6290 if (GTK_WIDGET_REALIZED (widget) && sheet->column_titles_visible)
6291 gdk_window_move_resize (sheet->column_title_window,
6292 sheet->column_title_area.x,
6293 sheet->column_title_area.y,
6294 sheet->column_title_area.width,
6295 sheet->column_title_area.height);
6297 sheet->sheet_window_width = sheet_allocation.width;
6298 sheet->sheet_window_height = sheet_allocation.height;
6300 /* column button allocation */
6301 size_allocate_column_title_buttons (sheet);
6303 /* position the window which holds the row title buttons */
6304 sheet->row_title_area.x = 0;
6305 sheet->row_title_area.y = 0;
6306 if (sheet->column_titles_visible)
6307 sheet->row_title_area.y = sheet->column_title_area.height;
6308 sheet->row_title_area.height = sheet_allocation.height -
6309 sheet->row_title_area.y;
6311 if (GTK_WIDGET_REALIZED (widget) && sheet->row_titles_visible)
6312 gdk_window_move_resize (sheet->row_title_window,
6313 sheet->row_title_area.x,
6314 sheet->row_title_area.y,
6315 sheet->row_title_area.width,
6316 sheet->row_title_area.height);
6319 /* row button allocation */
6320 size_allocate_row_title_buttons (sheet);
6321 size_allocate_column_title_buttons (sheet);
6323 /* re - scale backing pixmap */
6324 gtk_sheet_make_backing_pixmap (sheet, 0, 0);
6325 gtk_sheet_position_children (sheet);
6327 /* set the scrollbars adjustments */
6328 adjust_scrollbars (sheet);
6332 size_allocate_column_title_buttons (GtkSheet * sheet)
6337 if (!sheet->column_titles_visible) return;
6338 if (!GTK_WIDGET_REALIZED (sheet))
6341 width = sheet->sheet_window_width;
6344 if (sheet->row_titles_visible)
6346 width -= sheet->row_title_area.width;
6347 x = sheet->row_title_area.width;
6350 if (sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6352 sheet->column_title_area.width = width;
6353 sheet->column_title_area.x = x;
6354 gdk_window_move_resize (sheet->column_title_window,
6355 sheet->column_title_area.x,
6356 sheet->column_title_area.y,
6357 sheet->column_title_area.width,
6358 sheet->column_title_area.height);
6362 if (MAX_VISIBLE_COLUMN (sheet) == xxx_column_count (sheet) - 1)
6363 gdk_window_clear_area (sheet->column_title_window,
6365 sheet->column_title_area.width,
6366 sheet->column_title_area.height);
6368 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6370 for (i = MIN_VISIBLE_COLUMN (sheet); i <= MAX_VISIBLE_COLUMN (sheet); i++)
6371 gtk_sheet_column_title_button_draw (sheet, i);
6375 size_allocate_row_title_buttons (GtkSheet * sheet)
6380 if (!sheet->row_titles_visible) return;
6381 if (!GTK_WIDGET_REALIZED (sheet))
6384 height = sheet->sheet_window_height;
6387 if (sheet->column_titles_visible)
6389 height -= sheet->column_title_area.height;
6390 y = sheet->column_title_area.height;
6393 if (sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6395 sheet->row_title_area.y = y;
6396 sheet->row_title_area.height = height;
6397 gdk_window_move_resize (sheet->row_title_window,
6398 sheet->row_title_area.x,
6399 sheet->row_title_area.y,
6400 sheet->row_title_area.width,
6401 sheet->row_title_area.height);
6403 if (MAX_VISIBLE_ROW (sheet) == yyy_row_count (sheet)- 1)
6404 gdk_window_clear_area (sheet->row_title_window,
6406 sheet->row_title_area.width,
6407 sheet->row_title_area.height);
6409 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
6411 for (i = MIN_VISIBLE_ROW (sheet); i <= MAX_VISIBLE_ROW (sheet); i++)
6413 if ( i >= yyy_row_count (sheet))
6415 gtk_sheet_row_title_button_draw (sheet, i);
6421 gtk_sheet_size_allocate_entry (GtkSheet *sheet)
6423 GtkAllocation shentry_allocation;
6424 GtkSheetCellAttr attributes = { 0 };
6425 GtkEntry *sheet_entry;
6426 GtkStyle *style = NULL, *previous_style = NULL;
6428 gint size, max_size, text_size, column_width;
6431 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6432 if (!GTK_WIDGET_MAPPED (GTK_WIDGET (sheet))) return;
6434 sheet_entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
6436 if ( ! gtk_sheet_get_attributes (sheet, sheet->active_cell.row,
6437 sheet->active_cell.col,
6441 if ( GTK_WIDGET_REALIZED (sheet->sheet_entry) )
6443 if (!GTK_WIDGET (sheet_entry)->style)
6444 gtk_widget_ensure_style (GTK_WIDGET (sheet_entry));
6446 previous_style = GTK_WIDGET (sheet_entry)->style;
6448 style = gtk_style_copy (previous_style);
6449 style->bg[GTK_STATE_NORMAL] = attributes.background;
6450 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6451 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6452 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6453 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6454 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6456 pango_font_description_free (style->font_desc);
6457 g_assert (attributes.font_desc);
6458 style->font_desc = pango_font_description_copy (attributes.font_desc);
6460 GTK_WIDGET (sheet_entry)->style = style;
6461 gtk_widget_size_request (sheet->sheet_entry, NULL);
6462 GTK_WIDGET (sheet_entry)->style = previous_style;
6464 if (style != previous_style)
6466 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6468 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6469 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6470 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6471 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6473 gtk_widget_set_style (GTK_WIDGET (sheet_entry), style);
6477 if (GTK_IS_ITEM_ENTRY (sheet_entry))
6478 max_size = GTK_ITEM_ENTRY (sheet_entry)->text_max_size;
6483 text = gtk_entry_get_text (GTK_ENTRY (sheet_entry));
6484 if (text && strlen (text) > 0)
6485 text_size = STRING_WIDTH (GTK_WIDGET (sheet), attributes.font_desc, text);
6487 column_width = xxx_column_width (sheet, sheet->active_cell.col);
6489 size = MIN (text_size, max_size);
6490 size = MAX (size,column_width - 2 * CELLOFFSET);
6492 row = sheet->active_cell.row;
6493 col = sheet->active_cell.col;
6495 shentry_allocation.x = COLUMN_LEFT_XPIXEL (sheet,sheet->active_cell.col);
6496 shentry_allocation.y = ROW_TOP_YPIXEL (sheet,sheet->active_cell.row);
6497 shentry_allocation.width = column_width;
6498 shentry_allocation.height = yyy_row_height (sheet, sheet->active_cell.row);
6500 if (GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6502 shentry_allocation.height -= 2 * CELLOFFSET;
6503 shentry_allocation.y += CELLOFFSET;
6504 if (gtk_sheet_clip_text (sheet))
6505 shentry_allocation.width = column_width - 2 * CELLOFFSET;
6507 shentry_allocation.width = size;
6509 switch (GTK_ITEM_ENTRY (sheet_entry)->justification)
6511 case GTK_JUSTIFY_CENTER:
6512 shentry_allocation.x += column_width / 2 - size / 2;
6514 case GTK_JUSTIFY_RIGHT:
6515 shentry_allocation.x += column_width - size - CELLOFFSET;
6517 case GTK_JUSTIFY_LEFT:
6518 case GTK_JUSTIFY_FILL:
6519 shentry_allocation.x += CELLOFFSET;
6524 if (!GTK_IS_ITEM_ENTRY (sheet->sheet_entry))
6526 shentry_allocation.x += 2;
6527 shentry_allocation.y += 2;
6528 shentry_allocation.width -= MIN (shentry_allocation.width, 3);
6529 shentry_allocation.height -= MIN (shentry_allocation.height, 3);
6532 gtk_widget_size_allocate (sheet->sheet_entry, &shentry_allocation);
6534 if (previous_style == style) g_object_unref (previous_style);
6538 gtk_sheet_entry_set_max_size (GtkSheet *sheet)
6542 gint sizel = 0, sizer = 0;
6544 GtkJustification justification;
6547 row = sheet->active_cell.row;
6548 col = sheet->active_cell.col;
6550 if ( ! GTK_IS_ITEM_ENTRY (sheet->sheet_entry) || gtk_sheet_clip_text (sheet))
6553 justification = GTK_ITEM_ENTRY (sheet->sheet_entry)->justification;
6555 switch (justification)
6557 case GTK_JUSTIFY_FILL:
6558 case GTK_JUSTIFY_LEFT:
6559 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6561 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6566 size +=xxx_column_width (sheet, i);
6568 size = MIN (size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL (sheet, col));
6570 case GTK_JUSTIFY_RIGHT:
6571 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6573 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6578 size +=xxx_column_width (sheet, i);
6581 case GTK_JUSTIFY_CENTER:
6582 for (i = col + 1; i <= MAX_VISIBLE_COLUMN (sheet); i++)
6584 sizer += xxx_column_width (sheet, i);
6586 for (i = col - 1; i >= MIN_VISIBLE_COLUMN (sheet); i--)
6588 if ((s = gtk_sheet_cell_get_text (sheet, row, i)))
6593 sizel +=xxx_column_width (sheet, i);
6595 size = 2 * MIN (sizel, sizer);
6600 size += xxx_column_width (sheet, col);
6601 GTK_ITEM_ENTRY (sheet->sheet_entry)->text_max_size = size;
6606 create_sheet_entry (GtkSheet *sheet)
6611 gint found_entry = FALSE;
6613 widget = GTK_WIDGET (sheet);
6615 if (sheet->sheet_entry)
6617 /* avoids warnings */
6618 gtk_widget_ref (sheet->sheet_entry);
6619 gtk_widget_unparent (sheet->sheet_entry);
6620 gtk_widget_destroy (sheet->sheet_entry);
6623 if (sheet->entry_type)
6625 if (!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY))
6627 parent = g_object_new (sheet->entry_type, NULL);
6629 sheet->sheet_entry = parent;
6631 entry = gtk_sheet_get_entry (sheet);
6632 if (GTK_IS_ENTRY (entry))
6637 parent = g_object_new (sheet->entry_type, NULL);
6644 g_warning ("Entry type must be GtkEntry subclass, using default");
6645 entry = gtk_item_entry_new ();
6646 sheet->sheet_entry = entry;
6649 sheet->sheet_entry = parent;
6653 entry = gtk_item_entry_new ();
6654 sheet->sheet_entry = entry;
6657 gtk_widget_size_request (sheet->sheet_entry, NULL);
6659 if (GTK_WIDGET_REALIZED (sheet))
6661 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6662 gtk_widget_set_parent (sheet->sheet_entry, GTK_WIDGET (sheet));
6663 gtk_widget_realize (sheet->sheet_entry);
6666 g_signal_connect_swapped (G_OBJECT (entry), "key_press_event",
6667 G_CALLBACK (gtk_sheet_entry_key_press),
6670 gtk_widget_show (sheet->sheet_entry);
6674 /* Finds the last child widget that happens to be of type GtkEntry */
6676 find_entry (GtkWidget *w, gpointer user_data)
6678 GtkWidget **entry = user_data;
6679 if ( GTK_IS_ENTRY (w))
6686 gtk_sheet_get_entry (GtkSheet *sheet)
6689 GtkWidget *entry = NULL;
6690 GtkTableChild *table_child;
6691 GtkBoxChild *box_child;
6692 GList *children = NULL;
6694 g_return_val_if_fail (sheet != NULL, NULL);
6695 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6696 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6698 if (GTK_IS_ENTRY (sheet->sheet_entry)) return (sheet->sheet_entry);
6700 parent = GTK_WIDGET (sheet->sheet_entry);
6702 if (GTK_IS_TABLE (parent)) children = GTK_TABLE (parent)->children;
6703 if (GTK_IS_BOX (parent)) children = GTK_BOX (parent)->children;
6705 if (GTK_IS_CONTAINER (parent))
6707 gtk_container_forall (GTK_CONTAINER (parent), find_entry, &entry);
6709 if (GTK_IS_ENTRY (entry))
6713 if (!children) return NULL;
6717 if (GTK_IS_TABLE (parent))
6719 table_child = children->data;
6720 entry = table_child->widget;
6722 if (GTK_IS_BOX (parent))
6724 box_child = children->data;
6725 entry = box_child->widget;
6728 if (GTK_IS_ENTRY (entry))
6730 children = children->next;
6734 if (!GTK_IS_ENTRY (entry)) return NULL;
6741 gtk_sheet_get_entry_widget (GtkSheet *sheet)
6743 g_return_val_if_fail (sheet != NULL, NULL);
6744 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6745 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6747 return (sheet->sheet_entry);
6752 gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
6753 GtkSheetButton *button, gboolean is_sensitive,
6754 GdkRectangle allocation)
6756 GtkShadowType shadow_type;
6757 gint text_width = 0, text_height = 0;
6758 GtkSheetChild *child = NULL;
6759 PangoAlignment align = PANGO_ALIGN_LEFT;
6767 g_return_if_fail (sheet != NULL);
6768 g_return_if_fail (button != NULL);
6770 rtl = gtk_widget_get_direction (GTK_WIDGET (sheet)) == GTK_TEXT_DIR_RTL;
6772 gdk_window_clear_area (window,
6773 allocation.x, allocation.y,
6774 allocation.width, allocation.height);
6776 gtk_paint_box (sheet->button->style, window,
6777 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6778 &allocation, GTK_WIDGET (sheet->button),
6780 allocation.x, allocation.y,
6781 allocation.width, allocation.height);
6783 state = button->state;
6784 if (!is_sensitive) state = GTK_STATE_INSENSITIVE;
6786 if (state == GTK_STATE_ACTIVE)
6787 shadow_type = GTK_SHADOW_IN;
6789 shadow_type = GTK_SHADOW_OUT;
6791 if (state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6792 gtk_paint_box (sheet->button->style, window,
6793 button->state, shadow_type,
6794 &allocation, GTK_WIDGET (sheet->button),
6796 allocation.x, allocation.y,
6797 allocation.width, allocation.height);
6799 if (button->label_visible)
6802 text_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet))- 2 * CELLOFFSET;
6804 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6806 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, &allocation);
6808 allocation.y += 2 * sheet->button->style->ythickness;
6811 if (button->label && strlen (button->label)>0)
6814 PangoLayout *layout = NULL;
6815 gint real_x = allocation.x, real_y = allocation.y;
6817 words = button->label;
6818 line = g_new (gchar, 1);
6821 while (words && *words != '\0')
6825 len = strlen (line);
6826 line = g_realloc (line, len + 2);
6830 if (*words == '\n' || * (words + 1) == '\0')
6832 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
6834 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
6835 switch (button->justification)
6837 case GTK_JUSTIFY_LEFT:
6838 real_x = allocation.x + CELLOFFSET;
6839 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6841 case GTK_JUSTIFY_RIGHT:
6842 real_x = allocation.x + allocation.width - text_width - CELLOFFSET;
6843 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6845 case GTK_JUSTIFY_CENTER:
6847 real_x = allocation.x + (allocation.width - text_width)/2;
6848 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6849 pango_layout_set_justify (layout, TRUE);
6851 pango_layout_set_alignment (layout, align);
6852 gtk_paint_layout (GTK_WIDGET (sheet)->style,
6861 g_object_unref (G_OBJECT (layout));
6863 real_y += text_height + 2;
6866 line = g_new (gchar, 1);
6874 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
6876 gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->white_gc, NULL);
6880 if ((child = button->child) && (child->widget))
6882 child->x = allocation.x;
6883 child->y = allocation.y;
6885 child->x += (allocation.width - child->widget->requisition.width) / 2;
6886 child->y += (allocation.height - child->widget->requisition.height) / 2;
6887 allocation.x = child->x;
6888 allocation.y = child->y;
6889 allocation.width = child->widget->requisition.width;
6890 allocation.height = child->widget->requisition.height;
6892 allocation.x = child->x;
6893 allocation.y = child->y;
6895 gtk_widget_set_state (child->widget, button->state);
6897 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
6898 GTK_WIDGET_MAPPED (child->widget))
6900 gtk_widget_size_allocate (child->widget,
6902 gtk_widget_queue_draw (child->widget);
6906 gtk_sheet_button_free (button);
6910 /* COLUMN value of - 1 indicates that the area to the right of the rightmost
6911 button should be redrawn */
6913 gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
6915 GdkWindow *window = NULL;
6916 GdkRectangle allocation;
6917 GtkSheetButton *button = NULL;
6918 gboolean is_sensitive = FALSE;
6920 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6922 if (column >= 0 && ! xxx_column_is_visible (sheet, column)) return;
6923 if (column >= 0 && !sheet->column_titles_visible) return;
6924 if (column >= 0 && column < MIN_VISIBLE_COLUMN (sheet)) return;
6925 if (column >= 0 && column > MAX_VISIBLE_COLUMN (sheet)) return;
6927 window = sheet->column_title_window;
6929 allocation.height = sheet->column_title_area.height;
6933 const gint cols = xxx_column_count (sheet) ;
6934 allocation.x = COLUMN_LEFT_XPIXEL (sheet, cols - 1)
6936 allocation.width = sheet->column_title_area.width
6937 + sheet->column_title_area.x
6940 gdk_window_clear_area (window,
6941 allocation.x, allocation.y,
6942 allocation.width, allocation.height);
6946 button = xxx_column_button (sheet, column);
6947 allocation.x = COLUMN_LEFT_XPIXEL (sheet, column) + CELL_SPACING;
6948 if (sheet->row_titles_visible)
6949 allocation.x -= sheet->row_title_area.width;
6951 allocation.width = xxx_column_width (sheet, column);
6953 is_sensitive = xxx_column_is_sensitive (sheet, column);
6954 gtk_sheet_button_draw (sheet, window, button,
6955 is_sensitive, allocation);
6960 gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
6962 GdkWindow *window = NULL;
6963 GdkRectangle allocation;
6964 GtkSheetButton *button = NULL;
6965 gboolean is_sensitive = FALSE;
6968 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
6970 if (row >= 0 && !yyy_row_is_visible (sheet, row)) return;
6971 if (row >= 0 && !sheet->row_titles_visible) return;
6972 if (row >= 0 && row < MIN_VISIBLE_ROW (sheet)) return;
6973 if (row >= 0 && row > MAX_VISIBLE_ROW (sheet)) return;
6976 window = sheet->row_title_window;
6977 button = yyy_row_button (sheet, row);
6979 allocation.y = ROW_TOP_YPIXEL (sheet, row) + CELL_SPACING;
6980 if (sheet->column_titles_visible)
6981 allocation.y -= sheet->column_title_area.height;
6982 allocation.width = sheet->row_title_area.width;
6983 allocation.height = yyy_row_height (sheet, row);
6984 is_sensitive = yyy_row_is_sensitive (sheet, row);
6986 gtk_sheet_button_draw (sheet, window, button, is_sensitive, allocation);
6993 * vadjustment_value_changed
6994 * hadjustment_value_changed */
6997 adjust_scrollbars (GtkSheet * sheet)
6999 if (sheet->vadjustment)
7001 sheet->vadjustment->page_size = sheet->sheet_window_height;
7002 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
7003 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7004 sheet->vadjustment->lower = 0;
7005 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
7006 g_signal_emit_by_name (G_OBJECT (sheet->vadjustment), "changed");
7010 if (sheet->hadjustment)
7012 sheet->hadjustment->page_size = sheet->sheet_window_width;
7013 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
7014 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
7015 sheet->hadjustment->lower = 0;
7016 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
7017 g_signal_emit_by_name (G_OBJECT (sheet->hadjustment), "changed");
7023 vadjustment_value_changed (GtkAdjustment * adjustment,
7027 gint diff, value, old_value;
7031 g_return_if_fail (adjustment != NULL);
7032 g_return_if_fail (data != NULL);
7033 g_return_if_fail (GTK_IS_SHEET (data));
7035 sheet = GTK_SHEET (data);
7037 if (GTK_SHEET_IS_FROZEN (sheet)) return;
7039 row = ROW_FROM_YPIXEL (sheet,sheet->column_title_area.height + CELL_SPACING);
7040 if (!sheet->column_titles_visible)
7041 row = ROW_FROM_YPIXEL (sheet, CELL_SPACING);
7043 old_value = - sheet->voffset;
7045 new_row = g_sheet_row_pixel_to_row (sheet->row_geometry,
7046 adjustment->value,sheet);
7048 y = g_sheet_row_start_pixel (sheet->row_geometry, new_row, sheet);
7050 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
7051 yyy_row_height (sheet, row) > sheet->vadjustment->step_increment)
7053 /* This avoids embarrassing twitching */
7054 if (row == new_row && row != yyy_row_count (sheet) - 1 &&
7055 adjustment->value - sheet->old_vadjustment >=
7056 sheet->vadjustment->step_increment &&
7057 new_row + 1 != MIN_VISIBLE_ROW (sheet))
7060 y = y+yyy_row_height (sheet, row);
7064 /* Negative old_adjustment enforces the redraw, otherwise avoid
7066 if (sheet->old_vadjustment >= 0. && row == new_row)
7068 sheet->old_vadjustment = sheet->vadjustment->value;
7072 sheet->old_vadjustment = sheet->vadjustment->value;
7073 adjustment->value = y;
7078 sheet->vadjustment->step_increment = yyy_row_height (sheet, 0);
7082 sheet->vadjustment->step_increment =
7083 MIN (yyy_row_height (sheet, new_row), yyy_row_height (sheet, new_row - 1));
7086 sheet->vadjustment->value = adjustment->value;
7088 value = adjustment->value;
7090 if (value >= - sheet->voffset)
7093 diff = value + sheet->voffset;
7098 diff = - sheet->voffset - value;
7101 sheet->voffset = - value;
7103 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
7104 sheet->state == GTK_SHEET_NORMAL &&
7105 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
7106 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
7107 sheet->active_cell.col))
7111 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
7113 if (!text || strlen (text) == 0)
7114 gtk_sheet_cell_clear (sheet,
7115 sheet->active_cell.row,
7116 sheet->active_cell.col);
7117 gtk_widget_unmap (sheet->sheet_entry);
7120 gtk_sheet_position_children (sheet);
7122 gtk_sheet_range_draw (sheet, NULL);
7123 size_allocate_row_title_buttons (sheet);
7124 size_allocate_global_button (sheet);
7128 hadjustment_value_changed (GtkAdjustment * adjustment,
7132 gint i, diff, value, old_value;
7133 gint column, new_column;
7136 g_return_if_fail (adjustment != NULL);
7137 g_return_if_fail (data != NULL);
7138 g_return_if_fail (GTK_IS_SHEET (data));
7140 sheet = GTK_SHEET (data);
7142 if (GTK_SHEET_IS_FROZEN (sheet)) return;
7144 column = COLUMN_FROM_XPIXEL (sheet,sheet->row_title_area.width + CELL_SPACING);
7145 if (!sheet->row_titles_visible)
7146 column = COLUMN_FROM_XPIXEL (sheet, CELL_SPACING);
7148 old_value = - sheet->hoffset;
7150 for (i = 0; i < xxx_column_count (sheet); i++)
7152 if (xxx_column_is_visible (sheet, i)) x += xxx_column_width (sheet, i);
7153 if (x > adjustment->value) break;
7155 x -= xxx_column_width (sheet, i);
7158 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
7159 xxx_column_width (sheet, i) > sheet->hadjustment->step_increment)
7161 /* This avoids embarrassing twitching */
7162 if (column == new_column && column != xxx_column_count (sheet) - 1 &&
7163 adjustment->value - sheet->old_hadjustment >=
7164 sheet->hadjustment->step_increment &&
7165 new_column + 1 != MIN_VISIBLE_COLUMN (sheet))
7168 x += xxx_column_width (sheet, column);
7172 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
7173 if (sheet->old_hadjustment >= 0. && new_column == column)
7175 sheet->old_hadjustment = sheet->hadjustment->value;
7179 sheet->old_hadjustment = sheet->hadjustment->value;
7180 adjustment->value = x;
7182 if (new_column == 0)
7184 sheet->hadjustment->step_increment = xxx_column_width (sheet, 0);
7188 sheet->hadjustment->step_increment =
7189 MIN (xxx_column_width (sheet, new_column), xxx_column_width (sheet, new_column - 1));
7193 sheet->hadjustment->value = adjustment->value;
7195 value = adjustment->value;
7197 if (value >= - sheet->hoffset)
7200 diff = value + sheet->hoffset;
7205 diff = - sheet->hoffset - value;
7208 sheet->hoffset = - value;
7209 if (GTK_WIDGET_REALIZED (sheet->sheet_entry) &&
7210 sheet->state == GTK_SHEET_NORMAL &&
7211 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
7212 !gtk_sheet_cell_isvisible (sheet, sheet->active_cell.row,
7213 sheet->active_cell.col))
7217 text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
7218 if (!text || strlen (text) == 0)
7219 gtk_sheet_cell_clear (sheet,
7220 sheet->active_cell.row,
7221 sheet->active_cell.col);
7223 gtk_widget_unmap (sheet->sheet_entry);
7226 gtk_sheet_position_children (sheet);
7228 gtk_sheet_range_draw (sheet, NULL);
7229 size_allocate_column_title_buttons (sheet);
7233 /* COLUMN RESIZING */
7235 draw_xor_vline (GtkSheet * sheet)
7239 g_return_if_fail (sheet != NULL);
7241 widget = GTK_WIDGET (sheet);
7243 gdk_draw_line (widget->window, sheet->xor_gc,
7245 sheet->column_title_area.height,
7247 sheet->sheet_window_height + 1);
7252 draw_xor_hline (GtkSheet * sheet)
7256 g_return_if_fail (sheet != NULL);
7258 widget = GTK_WIDGET (sheet);
7260 gdk_draw_line (widget->window, sheet->xor_gc,
7261 sheet->row_title_area.width,
7264 sheet->sheet_window_width + 1,
7268 /* SELECTED RANGE */
7270 draw_xor_rectangle (GtkSheet *sheet, GtkSheetRange range)
7273 GdkRectangle clip_area, area;
7276 area.x = COLUMN_LEFT_XPIXEL (sheet, range.col0);
7277 area.y = ROW_TOP_YPIXEL (sheet, range.row0);
7278 area.width = COLUMN_LEFT_XPIXEL (sheet, range.coli)- area.x+
7279 xxx_column_width (sheet, range.coli);
7280 area.height = ROW_TOP_YPIXEL (sheet, range.rowi)- area.y+
7281 yyy_row_height (sheet, range.rowi);
7283 clip_area.x = sheet->row_title_area.width;
7284 clip_area.y = sheet->column_title_area.height;
7285 clip_area.width = sheet->sheet_window_width;
7286 clip_area.height = sheet->sheet_window_height;
7288 if (!sheet->row_titles_visible) clip_area.x = 0;
7289 if (!sheet->column_titles_visible) clip_area.y = 0;
7293 area.width = area.width + area.x;
7296 if (area.width > clip_area.width) area.width = clip_area.width + 10;
7299 area.height = area.height + area.y;
7302 if (area.height > clip_area.height) area.height = clip_area.height + 10;
7306 clip_area.width += 3;
7307 clip_area.height += 3;
7309 gdk_gc_get_values (sheet->xor_gc, &values);
7311 gdk_gc_set_clip_rectangle (sheet->xor_gc, &clip_area);
7313 for (i =- 1; i <= 1; ++i)
7314 gdk_draw_rectangle (sheet->sheet_window,
7317 area.x + i, area.y + i,
7318 area.width - 2 * i, area.height - 2 * i);
7321 gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
7323 gdk_gc_set_foreground (sheet->xor_gc, &values.foreground);
7328 /* this function returns the new width of the column being resized given
7329 * the column and x position of the cursor; the x cursor position is passed
7330 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7332 new_column_width (GtkSheet * sheet,
7341 min_width = sheet->column_requisition;
7343 /* you can't shrink a column to less than its minimum width */
7344 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7346 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7349 /* calculate new column width making sure it doesn't end up
7350 * less than the minimum width */
7351 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7352 if (width < min_width)
7355 xxx_set_column_width (sheet, column, width);
7356 size_allocate_column_title_buttons (sheet);
7361 /* this function returns the new height of the row being resized given
7362 * the row and y position of the cursor; the y cursor position is passed
7363 * in as a pointer and automaticaly corrected if it's beyond min / max limits */
7365 new_row_height (GtkSheet * sheet,
7373 min_height = sheet->row_requisition;
7375 /* you can't shrink a row to less than its minimum height */
7376 if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7379 *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7382 /* calculate new row height making sure it doesn't end up
7383 * less than the minimum height */
7384 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7385 if (height < min_height)
7386 height = min_height;
7388 yyy_set_row_height (sheet, row, height);
7389 size_allocate_row_title_buttons (sheet);
7395 gtk_sheet_set_column_width (GtkSheet * sheet,
7401 g_return_if_fail (sheet != NULL);
7402 g_return_if_fail (GTK_IS_SHEET (sheet));
7404 if (column < 0 || column >= xxx_column_count (sheet))
7407 gtk_sheet_column_size_request (sheet, column, &min_width);
7408 if (width < min_width) return;
7410 xxx_set_column_width (sheet, column, width);
7412 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7414 size_allocate_column_title_buttons (sheet);
7415 adjust_scrollbars (sheet);
7416 gtk_sheet_size_allocate_entry (sheet);
7417 gtk_sheet_range_draw (sheet, NULL);
7420 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, -1, column);
7421 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_COL_WIDTH], 0,
7428 gtk_sheet_set_row_height (GtkSheet * sheet,
7434 g_return_if_fail (sheet != NULL);
7435 g_return_if_fail (GTK_IS_SHEET (sheet));
7437 if (row < 0 || row >= yyy_row_count (sheet))
7440 gtk_sheet_row_size_request (sheet, row, &min_height);
7441 if (height < min_height) return;
7443 yyy_set_row_height (sheet, row, height);
7445 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) && !GTK_SHEET_IS_FROZEN (sheet))
7447 size_allocate_row_title_buttons (sheet);
7448 adjust_scrollbars (sheet);
7449 gtk_sheet_size_allocate_entry (sheet);
7450 gtk_sheet_range_draw (sheet, NULL);
7453 g_signal_emit (G_OBJECT (sheet), sheet_signals[CHANGED], 0, row, - 1);
7454 g_signal_emit (G_OBJECT (sheet), sheet_signals[NEW_ROW_HEIGHT], 0,
7461 gtk_sheet_get_attributes (const GtkSheet *sheet, gint row, gint col,
7462 GtkSheetCellAttr *attributes)
7464 const GdkColor *fg, *bg;
7465 const GtkJustification *j ;
7466 const PangoFontDescription *font_desc ;
7467 const GtkSheetCellBorder *border ;
7469 g_return_val_if_fail (sheet != NULL, FALSE);
7470 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7472 if (row < 0 || col < 0) return FALSE;
7474 init_attributes (sheet, col, attributes);
7479 attributes->is_editable = g_sheet_model_is_editable (sheet->model, row, col);
7480 attributes->is_visible = g_sheet_model_is_visible (sheet->model, row, col);
7482 fg = g_sheet_model_get_foreground (sheet->model, row, col);
7484 attributes->foreground = *fg;
7486 bg = g_sheet_model_get_background (sheet->model, row, col);
7488 attributes->background = *bg;
7490 j = g_sheet_model_get_justification (sheet->model, row, col);
7491 if (j) attributes->justification = *j;
7493 font_desc = g_sheet_model_get_font_desc (sheet->model, row, col);
7494 if ( font_desc ) attributes->font_desc = font_desc;
7496 border = g_sheet_model_get_cell_border (sheet->model, row, col);
7498 if ( border ) attributes->border = *border;
7504 init_attributes (const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7506 /* DEFAULT VALUES */
7507 attributes->foreground = GTK_WIDGET (sheet)->style->black;
7508 attributes->background = sheet->bg_color;
7509 if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7511 GdkColormap *colormap;
7512 colormap = gdk_colormap_get_system ();
7513 gdk_color_black (colormap, &attributes->foreground);
7514 attributes->background = sheet->bg_color;
7516 attributes->justification = xxx_column_justification (sheet, col);
7517 attributes->border.width = 0;
7518 attributes->border.line_style = GDK_LINE_SOLID;
7519 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7520 attributes->border.join_style = GDK_JOIN_MITER;
7521 attributes->border.mask = 0;
7522 attributes->border.color = GTK_WIDGET (sheet)->style->black;
7523 attributes->is_editable = TRUE;
7524 attributes->is_visible = TRUE;
7525 attributes->font_desc = GTK_WIDGET (sheet)->style->font_desc;
7529 /********************************************************************
7530 * Container Functions:
7535 * gtk_sheet_move_child
7536 * gtk_sheet_position_child
7537 * gtk_sheet_position_children
7538 * gtk_sheet_realize_child
7539 * gtk_sheet_get_child_at
7540 ********************************************************************/
7543 gtk_sheet_put (GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7545 GtkRequisition child_requisition;
7546 GtkSheetChild *child_info;
7548 g_return_val_if_fail (sheet != NULL, NULL);
7549 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
7550 g_return_val_if_fail (child != NULL, NULL);
7551 g_return_val_if_fail (child->parent == NULL, NULL);
7553 child_info = g_new (GtkSheetChild, 1);
7554 child_info->widget = child;
7557 child_info->attached_to_cell = FALSE;
7558 child_info->floating = TRUE;
7559 child_info->xpadding = child_info->ypadding = 0;
7560 child_info->xexpand = child_info->yexpand = FALSE;
7561 child_info->xshrink = child_info->yshrink = FALSE;
7562 child_info->xfill = child_info->yfill = FALSE;
7564 sheet->children = g_list_append (sheet->children, child_info);
7566 gtk_widget_set_parent (child, GTK_WIDGET (sheet));
7568 gtk_widget_size_request (child, &child_requisition);
7570 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7572 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7573 (!GTK_WIDGET_REALIZED (child) || GTK_WIDGET_NO_WINDOW (child)))
7574 gtk_sheet_realize_child (sheet, child_info);
7576 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7577 !GTK_WIDGET_MAPPED (child))
7578 gtk_widget_map (child);
7581 gtk_sheet_position_child (sheet, child_info);
7583 /* This will avoid drawing on the titles */
7585 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7587 if (sheet->row_titles_visible)
7588 gdk_window_show (sheet->row_title_window);
7589 if (sheet->column_titles_visible)
7590 gdk_window_show (sheet->column_title_window);
7593 return (child_info);
7597 gtk_sheet_attach_floating (GtkSheet *sheet,
7602 GtkSheetChild *child;
7604 if (row < 0 || col < 0)
7606 gtk_sheet_button_attach (sheet, widget, row, col);
7610 gtk_sheet_get_cell_area (sheet, row, col, &area);
7611 child = gtk_sheet_put (sheet, widget, area.x, area.y);
7612 child->attached_to_cell = TRUE;
7618 gtk_sheet_attach_default (GtkSheet *sheet,
7622 if (row < 0 || col < 0)
7624 gtk_sheet_button_attach (sheet, widget, row, col);
7628 gtk_sheet_attach (sheet, widget, row, col,
7629 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
7633 gtk_sheet_attach (GtkSheet *sheet,
7642 GtkSheetChild *child = NULL;
7644 if (row < 0 || col < 0)
7646 gtk_sheet_button_attach (sheet, widget, row, col);
7650 child = g_new0 (GtkSheetChild, 1);
7651 child->attached_to_cell = TRUE;
7652 child->floating = FALSE;
7653 child->widget = widget;
7656 child->xpadding = xpadding;
7657 child->ypadding = ypadding;
7658 child->xexpand = (xoptions & GTK_EXPAND) != 0;
7659 child->yexpand = (yoptions & GTK_EXPAND) != 0;
7660 child->xshrink = (xoptions & GTK_SHRINK) != 0;
7661 child->yshrink = (yoptions & GTK_SHRINK) != 0;
7662 child->xfill = (xoptions & GTK_FILL) != 0;
7663 child->yfill = (yoptions & GTK_FILL) != 0;
7665 sheet->children = g_list_append (sheet->children, child);
7667 gtk_sheet_get_cell_area (sheet, row, col, &area);
7669 child->x = area.x + child->xpadding;
7670 child->y = area.y + child->ypadding;
7672 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7674 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7675 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7676 gtk_sheet_realize_child (sheet, child);
7678 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7679 !GTK_WIDGET_MAPPED (widget))
7680 gtk_widget_map (widget);
7683 gtk_sheet_position_child (sheet, child);
7685 /* This will avoid drawing on the titles */
7687 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
7689 if (GTK_SHEET_ROW_TITLES_VISIBLE (sheet))
7690 gdk_window_show (sheet->row_title_window);
7691 if (GTK_SHEET_COL_TITLES_VISIBLE (sheet))
7692 gdk_window_show (sheet->column_title_window);
7698 gtk_sheet_button_attach (GtkSheet *sheet,
7702 GtkSheetButton *button = 0;
7703 GtkSheetChild *child;
7704 GtkRequisition button_requisition;
7706 if (row >= 0 && col >= 0) return;
7707 if (row < 0 && col < 0) return;
7709 child = g_new (GtkSheetChild, 1);
7710 child->widget = widget;
7713 child->attached_to_cell = TRUE;
7714 child->floating = FALSE;
7717 child->xpadding = child->ypadding = 0;
7718 child->xshrink = child->yshrink = FALSE;
7719 child->xfill = child->yfill = FALSE;
7722 sheet->children = g_list_append (sheet->children, child);
7724 gtk_sheet_button_size_request (sheet, button, &button_requisition);
7727 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (sheet)))
7729 if (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)) &&
7730 (!GTK_WIDGET_REALIZED (widget) || GTK_WIDGET_NO_WINDOW (widget)))
7731 gtk_sheet_realize_child (sheet, child);
7733 if (GTK_WIDGET_MAPPED (GTK_WIDGET (sheet)) &&
7734 !GTK_WIDGET_MAPPED (widget))
7735 gtk_widget_map (widget);
7738 if (row == -1) size_allocate_column_title_buttons (sheet);
7739 if (col == -1) size_allocate_row_title_buttons (sheet);
7744 label_size_request (GtkSheet *sheet, gchar *label, GtkRequisition *req)
7749 gint row_height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet)) - 2 * CELLOFFSET + 2;
7755 while (words && *words != '\0')
7757 if (*words == '\n' || * (words + 1) == '\0')
7759 req->height += row_height;
7762 req->width = MAX (req->width, STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, word));
7772 if (n > 0) req->height -= 2;
7776 gtk_sheet_button_size_request (GtkSheet *sheet,
7777 const GtkSheetButton *button,
7778 GtkRequisition *button_requisition)
7780 GtkRequisition requisition;
7781 GtkRequisition label_requisition;
7783 if (gtk_sheet_autoresize (sheet) && button->label && strlen (button->label) > 0)
7785 label_size_request (sheet, button->label, &label_requisition);
7786 label_requisition.width += 2 * CELLOFFSET;
7787 label_requisition.height += 2 * CELLOFFSET;
7791 label_requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7792 label_requisition.width = COLUMN_MIN_WIDTH;
7797 gtk_widget_size_request (button->child->widget, &requisition);
7798 requisition.width += 2 * button->child->xpadding;
7799 requisition.height += 2 * button->child->ypadding;
7800 requisition.width += 2 * sheet->button->style->xthickness;
7801 requisition.height += 2 * sheet->button->style->ythickness;
7805 requisition.height = DEFAULT_ROW_HEIGHT (GTK_WIDGET (sheet));
7806 requisition.width = COLUMN_MIN_WIDTH;
7809 *button_requisition = requisition;
7810 button_requisition->width = MAX (requisition.width, label_requisition.width);
7811 button_requisition->height = MAX (requisition.height, label_requisition.height);
7816 gtk_sheet_row_size_request (GtkSheet *sheet,
7820 GtkRequisition button_requisition;
7823 gtk_sheet_button_size_request (sheet,
7824 yyy_row_button (sheet, row),
7825 &button_requisition);
7827 *requisition = button_requisition.height;
7829 children = sheet->children;
7832 GtkSheetChild *child = (GtkSheetChild *)children->data;
7833 GtkRequisition child_requisition;
7835 if (child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink)
7837 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7839 if (child_requisition.height + 2 * child->ypadding > *requisition)
7840 *requisition = child_requisition.height + 2 * child->ypadding;
7842 children = children->next;
7845 sheet->row_requisition = * requisition;
7849 gtk_sheet_column_size_request (GtkSheet *sheet,
7853 GtkRequisition button_requisition;
7856 gtk_sheet_button_size_request (sheet,
7857 xxx_column_button (sheet, col),
7858 &button_requisition);
7860 *requisition = button_requisition.width;
7862 children = sheet->children;
7865 GtkSheetChild *child = (GtkSheetChild *)children->data;
7866 GtkRequisition child_requisition;
7868 if (child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink)
7870 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7872 if (child_requisition.width + 2 * child->xpadding > *requisition)
7873 *requisition = child_requisition.width + 2 * child->xpadding;
7875 children = children->next;
7878 sheet->column_requisition = *requisition;
7882 gtk_sheet_move_child (GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7884 GtkSheetChild *child;
7887 g_return_if_fail (sheet != NULL);
7888 g_return_if_fail (GTK_IS_SHEET (sheet));
7890 children = sheet->children;
7893 child = children->data;
7895 if (child->widget == widget)
7899 child->row = ROW_FROM_YPIXEL (sheet, y);
7900 child->col = COLUMN_FROM_XPIXEL (sheet, x);
7901 gtk_sheet_position_child (sheet, child);
7905 children = children->next;
7908 g_warning ("Widget must be a GtkSheet child");
7913 gtk_sheet_position_child (GtkSheet *sheet, GtkSheetChild *child)
7915 GtkRequisition child_requisition;
7916 GtkAllocation child_allocation;
7922 gtk_widget_get_child_requisition (child->widget, &child_requisition);
7924 if (sheet->column_titles_visible)
7925 yoffset = sheet->column_title_area.height;
7927 if (sheet->row_titles_visible)
7928 xoffset = sheet->row_title_area.width;
7930 if (child->attached_to_cell)
7932 gtk_sheet_get_cell_area (sheet, child->row, child->col, &area);
7933 child->x = area.x + child->xpadding;
7934 child->y = area.y + child->ypadding;
7936 if (!child->floating)
7938 if (child_requisition.width + 2 * child->xpadding <= xxx_column_width (sheet, child->col))
7942 child_requisition.width = child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7948 child->x = area.x + xxx_column_width (sheet, child->col) / 2 -
7949 child_requisition.width / 2;
7951 child_allocation.width = child_requisition.width;
7956 if (!child->xshrink)
7958 gtk_sheet_set_column_width (sheet, child->col, child_requisition.width + 2 * child->xpadding);
7960 child_allocation.width = xxx_column_width (sheet, child->col) - 2 * child->xpadding;
7963 if (child_requisition.height +
7964 2 * child->ypadding <= yyy_row_height (sheet, child->row))
7968 child_requisition.height = child_allocation.height =
7969 yyy_row_height (sheet, child->row) - 2 * child->ypadding;
7975 child->y = area.y + yyy_row_height (sheet, child->row) / 2
7976 - child_requisition.height / 2;
7978 child_allocation.height = child_requisition.height;
7983 if (!child->yshrink)
7985 gtk_sheet_set_row_height (sheet, child->row, child_requisition.height + 2 * child->ypadding);
7987 child_allocation.height = yyy_row_height (sheet, child->row) -
7988 2 * child->ypadding;
7993 child_allocation.width = child_requisition.width;
7994 child_allocation.height = child_requisition.height;
7997 x = child_allocation.x = child->x + xoffset;
7998 y = child_allocation.y = child->y + yoffset;
8002 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
8003 x = child_allocation.x = child->x + xoffset;
8004 y = child_allocation.y = child->y + sheet->voffset + yoffset;
8005 y = child_allocation.y = child->y + yoffset;
8006 child_allocation.width = child_requisition.width;
8007 child_allocation.height = child_requisition.height;
8010 gtk_widget_size_allocate (child->widget, &child_allocation);
8011 gtk_widget_queue_draw (child->widget);
8015 gtk_sheet_forall (GtkContainer *container,
8016 gboolean include_internals,
8017 GtkCallback callback,
8018 gpointer callback_data)
8021 GtkSheetChild *child;
8024 g_return_if_fail (GTK_IS_SHEET (container));
8025 g_return_if_fail (callback != NULL);
8027 sheet = GTK_SHEET (container);
8028 children = sheet->children;
8031 child = children->data;
8032 children = children->next;
8034 (* callback) (child->widget, callback_data);
8037 (* callback) (sheet->button, callback_data);
8038 if (sheet->sheet_entry)
8039 (* callback) (sheet->sheet_entry, callback_data);
8044 gtk_sheet_position_children (GtkSheet *sheet)
8047 GtkSheetChild *child;
8049 children = sheet->children;
8053 child = (GtkSheetChild *)children->data;
8055 if (child->col != -1 && child->row != -1)
8056 gtk_sheet_position_child (sheet, child);
8058 if (child->row == -1)
8060 if (child->col < MIN_VISIBLE_COLUMN (sheet) ||
8061 child->col > MAX_VISIBLE_COLUMN (sheet))
8062 gtk_sheet_child_hide (child);
8064 gtk_sheet_child_show (child);
8066 if (child->col == -1)
8068 if (child->row < MIN_VISIBLE_ROW (sheet) ||
8069 child->row > MAX_VISIBLE_ROW (sheet))
8070 gtk_sheet_child_hide (child);
8072 gtk_sheet_child_show (child);
8075 children = children->next;
8080 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
8084 GtkSheetChild *child = 0;
8086 g_return_if_fail (container != NULL);
8087 g_return_if_fail (GTK_IS_SHEET (container));
8089 sheet = GTK_SHEET (container);
8091 children = sheet->children;
8095 child = (GtkSheetChild *)children->data;
8097 if (child->widget == widget) break;
8099 children = children->next;
8104 gtk_widget_unparent (widget);
8105 child->widget = NULL;
8107 sheet->children = g_list_remove_link (sheet->children, children);
8108 g_list_free_1 (children);
8115 gtk_sheet_realize_child (GtkSheet *sheet, GtkSheetChild *child)
8119 widget = GTK_WIDGET (sheet);
8121 if (GTK_WIDGET_REALIZED (widget))
8123 if (child->row == -1)
8124 gtk_widget_set_parent_window (child->widget, sheet->column_title_window);
8125 else if (child->col == -1)
8126 gtk_widget_set_parent_window (child->widget, sheet->row_title_window);
8128 gtk_widget_set_parent_window (child->widget, sheet->sheet_window);
8131 gtk_widget_set_parent (child->widget, widget);
8137 gtk_sheet_get_child_at (GtkSheet *sheet, gint row, gint col)
8140 GtkSheetChild *child = 0;
8142 g_return_val_if_fail (sheet != NULL, NULL);
8143 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
8145 children = sheet->children;
8149 child = (GtkSheetChild *)children->data;
8151 if (child->attached_to_cell)
8152 if (child->row == row && child->col == col) break;
8154 children = children->next;
8157 if (children) return child;
8163 gtk_sheet_child_hide (GtkSheetChild *child)
8165 g_return_if_fail (child != NULL);
8166 gtk_widget_hide (child->widget);
8170 gtk_sheet_child_show (GtkSheetChild *child)
8172 g_return_if_fail (child != NULL);
8174 gtk_widget_show (child->widget);
8178 gtk_sheet_get_model (const GtkSheet *sheet)
8180 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
8182 return sheet->model;
8187 gtk_sheet_button_new (void)
8189 GtkSheetButton *button = g_malloc (sizeof (GtkSheetButton));
8191 button->state = GTK_STATE_NORMAL;
8192 button->label = NULL;
8193 button->label_visible = TRUE;
8194 button->child = NULL;
8195 button->justification = GTK_JUSTIFY_FILL;
8202 gtk_sheet_button_free (GtkSheetButton *button)
8204 if (!button) return ;
8206 g_free (button->label);