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
26 * @short_description: spreadsheet widget for gtk2
28 * GtkSheet is a matrix widget for GTK+. It consists of an scrollable grid of
29 * cells where you can allocate text. Cell contents can be edited interactively
30 * through a specially designed entry, GtkItemEntry. It is also a container
31 * subclass, allowing you to display buttons, curves, pixmaps and any other
34 * You can also set many attributes as: border, foreground and background color,
35 * text justification, and more.
37 * The testgtksheet program shows how easy is to create a spreadsheet-like GUI
45 #include <gdk/gdkkeysyms.h>
46 #include <gtk/gtksignal.h>
47 #include <gtk/gtklabel.h>
48 #include <gtk/gtkbutton.h>
49 #include <gtk/gtkadjustment.h>
50 #include <gtk/gtktable.h>
51 #include <gtk/gtkbox.h>
52 #include <gtk/gtkmain.h>
53 #include <gtk/gtktypeutils.h>
54 #include <gtk/gtkentry.h>
55 #include <gtk/gtkcontainer.h>
56 #include <gtk/gtkpixmap.h>
57 #include <pango/pango.h>
58 #include "gtkitementry.h"
60 #include "gtkextra-marshal.h"
61 #include "gsheetmodel.h"
66 GTK_SHEET_IS_LOCKED = 1 << 0,
67 GTK_SHEET_IS_FROZEN = 1 << 1,
68 GTK_SHEET_IN_XDRAG = 1 << 2,
69 GTK_SHEET_IN_YDRAG = 1 << 3,
70 GTK_SHEET_IN_DRAG = 1 << 4,
71 GTK_SHEET_IN_SELECTION = 1 << 5,
72 GTK_SHEET_IN_RESIZE = 1 << 6,
73 GTK_SHEET_IN_CLIP = 1 << 7,
74 GTK_SHEET_REDRAW_PENDING = 1 << 8,
77 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
78 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
79 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~(flag))
81 #define GTK_SHEET_IS_LOCKED(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_LOCKED)
84 #define GTK_SHEET_IS_FROZEN(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
85 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
86 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
87 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
88 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
89 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
90 #define GTK_SHEET_IN_CLIP(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_CLIP)
91 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
93 #define CELL_SPACING 1
95 #define TIMEOUT_SCROLL 20
96 #define TIMEOUT_FLASH 200
97 #define TIME_INTERVAL 8
98 #define COLUMN_MIN_WIDTH 10
103 #define DEFAULT_COLUMN_WIDTH 80
106 static void gtk_sheet_column_title_button_draw(GtkSheet *sheet, gint column);
108 static void gtk_sheet_row_title_button_draw(GtkSheet *sheet, gint row);
111 static gboolean gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col);
114 void dispose_string (const GtkSheet *sheet, gchar *text)
116 GSheetModel *model = gtk_sheet_get_model(sheet);
121 if (g_sheet_model_free_strings(model))
126 guint DEFAULT_ROW_HEIGHT(GtkWidget *widget)
128 if(!widget->style->font_desc) return 24;
130 PangoContext *context = gtk_widget_get_pango_context(widget);
131 PangoFontMetrics *metrics = pango_context_get_metrics(context,
132 widget->style->font_desc,
133 pango_context_get_language(context));
134 guint val = pango_font_metrics_get_descent(metrics) +
135 pango_font_metrics_get_ascent(metrics);
136 pango_font_metrics_unref(metrics);
137 return PANGO_PIXELS(val)+2*CELLOFFSET;
140 static inline guint DEFAULT_FONT_ASCENT(GtkWidget *widget)
142 if(!widget->style->font_desc) return 12;
144 PangoContext *context = gtk_widget_get_pango_context(widget);
145 PangoFontMetrics *metrics = pango_context_get_metrics(context,
146 widget->style->font_desc,
147 pango_context_get_language(context));
148 guint val = pango_font_metrics_get_ascent(metrics);
149 pango_font_metrics_unref(metrics);
150 return PANGO_PIXELS(val);
153 static inline guint STRING_WIDTH(GtkWidget *widget,
154 const PangoFontDescription *font, const gchar *text)
159 layout = gtk_widget_create_pango_layout (widget, text);
160 pango_layout_set_font_description (layout, font);
162 pango_layout_get_extents (layout, NULL, &rect);
164 g_object_unref(G_OBJECT(layout));
165 return PANGO_PIXELS(rect.width);
168 static inline guint DEFAULT_FONT_DESCENT(GtkWidget *widget)
170 if(!widget->style->font_desc) return 12;
172 PangoContext *context = gtk_widget_get_pango_context(widget);
173 PangoFontMetrics *metrics = pango_context_get_metrics(context,
174 widget->style->font_desc,
175 pango_context_get_language(context));
176 guint val = pango_font_metrics_get_descent(metrics);
177 pango_font_metrics_unref(metrics);
178 return PANGO_PIXELS(val);
184 yyy_row_is_visible(const GtkSheet *sheet, gint row)
186 GSheetRow *row_geo = sheet->row_geometry;
188 return g_sheet_row_get_visibility(row_geo, row, 0);
193 yyy_row_is_sensitive(const GtkSheet *sheet, gint row)
195 GSheetRow *row_geo = sheet->row_geometry;
197 return g_sheet_row_get_sensitivity(row_geo, row, 0);
203 yyy_row_count(const GtkSheet *sheet)
205 GSheetRow *row_geo = sheet->row_geometry;
207 return g_sheet_row_get_row_count(row_geo, 0);
211 yyy_row_height(const GtkSheet *sheet, gint row)
213 GSheetRow *row_geo = sheet->row_geometry;
215 return g_sheet_row_get_height(row_geo, row, 0);
219 yyy_row_top_ypixel(const GtkSheet *sheet, gint row)
221 GSheetRow *geo = sheet->row_geometry;
223 gint y = g_sheet_row_start_pixel(geo, row, 0);
225 if ( sheet->column_titles_visible )
226 y += sheet->column_title_area.height;
232 /* Return the row containing pixel Y */
234 yyy_row_ypixel_to_row(const GtkSheet *sheet, gint y)
236 GSheetRow *geo = sheet->row_geometry;
238 gint cy = sheet->voffset;
240 if(sheet->column_titles_visible)
241 cy += sheet->column_title_area.height;
245 return g_sheet_row_pixel_to_row(geo, y - cy, 0);
249 /* gives the top pixel of the given row in context of
250 * the sheet's voffset */
252 ROW_TOP_YPIXEL(const GtkSheet *sheet, gint row)
254 return (sheet->voffset + yyy_row_top_ypixel(sheet, row));
258 /* returns the row index from a y pixel location in the
259 * context of the sheet's voffset */
261 ROW_FROM_YPIXEL(const GtkSheet *sheet, gint y)
263 return (yyy_row_ypixel_to_row(sheet, y));
266 static inline GtkSheetButton *
267 xxx_column_button(const GtkSheet *sheet, gint col)
269 GSheetColumn *col_geo = sheet->column_geometry;
270 if ( col < 0 ) return NULL ;
272 return g_sheet_column_get_button(col_geo, col);
277 xxx_column_left_xpixel(const GtkSheet *sheet, gint col)
279 GSheetColumn *geo = sheet->column_geometry;
281 gint x = g_sheet_column_start_pixel(geo, col);
283 if ( sheet->row_titles_visible )
284 x += sheet->row_title_area.width;
290 xxx_column_width(const GtkSheet *sheet, gint col)
292 GSheetColumn *col_geo = sheet->column_geometry;
294 return g_sheet_column_get_width(col_geo, col);
299 xxx_set_column_width(GtkSheet *sheet, gint col, gint width)
301 if ( sheet->column_geometry )
302 g_sheet_column_set_width(sheet->column_geometry, col, width);
306 xxx_column_set_left_column(GtkSheet *sheet, gint col, gint i)
308 GSheetColumn *col_geo = sheet->column_geometry;
310 g_sheet_column_set_left_text_column(col_geo, col, i);
314 xxx_column_left_column(const GtkSheet *sheet, gint col)
316 GSheetColumn *col_geo = sheet->column_geometry;
318 return g_sheet_column_get_left_text_column(col_geo, col);
322 xxx_column_set_right_column(GtkSheet *sheet, gint col, gint i)
324 GSheetColumn *col_geo = sheet->column_geometry;
326 g_sheet_column_set_right_text_column(col_geo, col, i);
330 xxx_column_right_column(const GtkSheet *sheet, gint col)
332 GSheetColumn *col_geo = sheet->column_geometry;
334 return g_sheet_column_get_right_text_column(col_geo, col);
337 static inline GtkJustification
338 xxx_column_justification(const GtkSheet *sheet, gint col)
340 GSheetColumn *col_geo = sheet->column_geometry;
342 return g_sheet_column_get_justification(col_geo, col);
346 xxx_column_is_visible(const GtkSheet *sheet, gint col)
348 GSheetColumn *col_geo = sheet->column_geometry;
350 return g_sheet_column_get_visibility(col_geo, col);
355 xxx_column_is_sensitive(const GtkSheet *sheet, gint col)
357 GSheetColumn *col_geo = sheet->column_geometry;
359 return g_sheet_column_get_sensitivity(col_geo, col);
363 /* gives the left pixel of the given column in context of
364 * the sheet's hoffset */
366 COLUMN_LEFT_XPIXEL(const GtkSheet *sheet, gint ncol)
368 return (sheet->hoffset + xxx_column_left_xpixel(sheet, ncol));
372 xxx_column_count(const GtkSheet *sheet)
374 GSheetColumn *col_geo = sheet->column_geometry;
376 return g_sheet_column_get_column_count(col_geo);
379 /* returns the column index from a x pixel location in the
380 * context of the sheet's hoffset */
382 COLUMN_FROM_XPIXEL (const GtkSheet * sheet,
388 if( sheet->row_titles_visible )
389 cx += sheet->row_title_area.width;
392 for (i = 0; i < xxx_column_count(sheet); i++)
394 if (x >= cx && x <= (cx + xxx_column_width(sheet, i)) &&
395 xxx_column_is_visible(sheet, i))
397 if( xxx_column_is_visible(sheet, i))
398 cx += xxx_column_width(sheet, i);
402 return xxx_column_count(sheet) - 1;
405 /* returns the total height of the sheet */
406 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
408 const gint n_rows = yyy_row_count(sheet);
410 return yyy_row_top_ypixel(sheet, n_rows - 1) +
411 yyy_row_height(sheet, n_rows - 1);
415 static inline GtkSheetButton *
416 yyy_row_button(GtkSheet *sheet, gint row)
418 GSheetRow *row_geo = sheet->row_geometry;
420 return g_sheet_row_get_button(row_geo, row, sheet);
427 yyy_set_row_height(GtkSheet *sheet, gint row, gint height)
429 if ( sheet->row_geometry )
430 g_sheet_row_set_height(sheet->row_geometry, row, height, sheet);
435 /* returns the total width of the sheet */
436 static inline gint SHEET_WIDTH(GtkSheet *sheet)
440 cx = ( sheet->row_titles_visible ? sheet->row_title_area.width : 0);
442 for (i=0; i < xxx_column_count(sheet); i++)
443 if(xxx_column_is_visible(sheet, i)) cx += xxx_column_width(sheet, i);
448 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
449 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
450 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
451 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
454 static inline gboolean
455 POSSIBLE_XDRAG(const GtkSheet *sheet, gint x, gint *drag_column)
459 column=COLUMN_FROM_XPIXEL(sheet, x);
462 xdrag = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
463 if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
464 while(! xxx_column_is_visible(sheet, column-1) && column>0) column--;
465 *drag_column=column-1;
466 return xxx_column_is_sensitive(sheet, column-1);
469 xdrag+= xxx_column_width(sheet, column);
470 if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
471 return xxx_column_is_sensitive(sheet, column);
476 static inline gboolean
477 POSSIBLE_YDRAG(const GtkSheet *sheet, gint y, gint *drag_row)
480 row=ROW_FROM_YPIXEL(sheet, y);
483 ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
484 if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
485 while(!yyy_row_is_visible(sheet, row-1) && row>0) row--;
487 return yyy_row_is_sensitive(sheet, row-1);
490 ydrag+=yyy_row_height(sheet, row);
492 if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
493 return yyy_row_is_sensitive(sheet, row);
499 static inline gboolean
500 POSSIBLE_DRAG(const GtkSheet *sheet, gint x, gint y,
501 gint *drag_row, gint *drag_column)
505 /* Can't drag if nothing is selected */
506 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
507 sheet->range.col0 < 0 || sheet->range.coli < 0 )
510 *drag_column = COLUMN_FROM_XPIXEL(sheet, x);
511 *drag_row = ROW_FROM_YPIXEL(sheet, y);
513 if(x >= COLUMN_LEFT_XPIXEL(sheet, sheet->range.col0) - DRAG_WIDTH/2 &&
514 x <= COLUMN_LEFT_XPIXEL(sheet, sheet->range.coli) +
515 xxx_column_width(sheet, sheet->range.coli) + DRAG_WIDTH/2)
517 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
518 if(y >= ydrag - DRAG_WIDTH/2 && y <= ydrag + DRAG_WIDTH/2)
520 *drag_row = sheet->range.row0;
523 ydrag = ROW_TOP_YPIXEL(sheet, sheet->range.rowi) +
524 yyy_row_height(sheet, sheet->range.rowi);
525 if(y >= ydrag - DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
527 *drag_row = sheet->range.rowi;
532 if(y >= ROW_TOP_YPIXEL(sheet, sheet->range.row0) - DRAG_WIDTH/2 &&
533 y <= ROW_TOP_YPIXEL(sheet, sheet->range.rowi) +
534 yyy_row_height(sheet, sheet->range.rowi) + DRAG_WIDTH/2)
536 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->range.col0);
537 if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag + DRAG_WIDTH/2)
539 *drag_column = sheet->range.col0;
542 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->range.coli) +
543 xxx_column_width(sheet, sheet->range.coli);
544 if(x >= xdrag - DRAG_WIDTH/2 && x <= xdrag + DRAG_WIDTH/2)
546 *drag_column = sheet->range.coli;
553 static inline gboolean
554 POSSIBLE_RESIZE(const GtkSheet *sheet, gint x, gint y,
555 gint *drag_row, gint *drag_column)
559 /* Can't drag if nothing is selected */
560 if ( sheet->range.row0 < 0 || sheet->range.rowi < 0 ||
561 sheet->range.col0 < 0 || sheet->range.coli < 0 )
564 xdrag = COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
565 xxx_column_width(sheet, sheet->range.coli);
567 ydrag = ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
568 yyy_row_height(sheet, sheet->range.rowi);
570 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
571 ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
573 if(sheet->state == GTK_SHEET_ROW_SELECTED)
574 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
576 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
577 *drag_row=ROW_FROM_YPIXEL(sheet,y);
579 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
580 y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
585 static void gtk_sheet_class_init (GtkSheetClass * klass);
586 static void gtk_sheet_init (GtkSheet * sheet);
587 static void gtk_sheet_destroy (GtkObject * object);
588 static void gtk_sheet_finalize (GObject * object);
589 static void gtk_sheet_style_set (GtkWidget *widget,
590 GtkStyle *previous_style);
591 static void gtk_sheet_realize (GtkWidget * widget);
592 static void gtk_sheet_unrealize (GtkWidget * widget);
593 static void gtk_sheet_map (GtkWidget * widget);
594 static void gtk_sheet_unmap (GtkWidget * widget);
595 static gint gtk_sheet_expose (GtkWidget * widget,
596 GdkEventExpose * event);
597 static void gtk_sheet_forall (GtkContainer *container,
598 gboolean include_internals,
599 GtkCallback callback,
600 gpointer callback_data);
602 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
603 GtkAdjustment *hadjustment,
604 GtkAdjustment *vadjustment);
606 static gint gtk_sheet_button_press (GtkWidget * widget,
607 GdkEventButton * event);
608 static gint gtk_sheet_button_release (GtkWidget * widget,
609 GdkEventButton * event);
610 static gint gtk_sheet_motion (GtkWidget * widget,
611 GdkEventMotion * event);
612 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
614 static gint gtk_sheet_key_press (GtkWidget *widget,
616 static void gtk_sheet_size_request (GtkWidget * widget,
617 GtkRequisition * requisition);
618 static void gtk_sheet_size_allocate (GtkWidget * widget,
619 GtkAllocation * allocation);
623 static gint gtk_sheet_range_isvisible (GtkSheet * sheet,
624 GtkSheetRange range);
625 static gint gtk_sheet_cell_isvisible (GtkSheet * sheet,
626 gint row, gint column);
629 static gint gtk_sheet_scroll (gpointer data);
630 static gint gtk_sheet_flash (gpointer data);
632 /* Drawing Routines */
634 /* draw cell background and frame */
635 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
636 gint row, gint column);
638 /* draw cell border */
639 static void gtk_sheet_cell_draw_border (GtkSheet *sheet,
640 gint row, gint column,
643 /* draw cell contents */
644 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
645 gint row, gint column);
647 /* draw visible part of range. If range==NULL then draw the whole screen */
648 static void gtk_sheet_range_draw (GtkSheet *sheet,
649 const GtkSheetRange *range);
651 /* highlight the visible part of the selected range */
652 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
653 GtkSheetRange range);
657 static gint gtk_sheet_move_query (GtkSheet *sheet,
658 gint row, gint column);
659 static void gtk_sheet_real_select_range (GtkSheet * sheet,
660 const GtkSheetRange * range);
661 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
662 const GtkSheetRange * range);
663 static void gtk_sheet_extend_selection (GtkSheet *sheet,
664 gint row, gint column);
665 static void gtk_sheet_new_selection (GtkSheet *sheet,
666 GtkSheetRange *range);
667 static void gtk_sheet_draw_border (GtkSheet *sheet,
668 GtkSheetRange range);
669 static void gtk_sheet_draw_corners (GtkSheet *sheet,
670 GtkSheetRange range);
673 /* Active Cell handling */
675 static void gtk_sheet_entry_changed (GtkWidget *widget,
677 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
678 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
679 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
681 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
682 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
683 static void gtk_sheet_click_cell (GtkSheet *sheet,
690 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
691 guint width, guint height);
692 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
693 GtkSheetRange range);
696 static void adjust_scrollbars (GtkSheet * sheet);
697 static void vadjustment_changed (GtkAdjustment * adjustment,
699 static void hadjustment_changed (GtkAdjustment * adjustment,
701 static void vadjustment_value_changed (GtkAdjustment * adjustment,
703 static void hadjustment_value_changed (GtkAdjustment * adjustment,
707 static void draw_xor_vline (GtkSheet * sheet);
708 static void draw_xor_hline (GtkSheet * sheet);
709 static void draw_xor_rectangle (GtkSheet *sheet,
710 GtkSheetRange range);
711 static void gtk_sheet_draw_flashing_range (GtkSheet *sheet,
712 GtkSheetRange range);
713 static guint new_column_width (GtkSheet * sheet,
716 static guint new_row_height (GtkSheet * sheet,
721 static void create_global_button (GtkSheet *sheet);
722 static void global_button_clicked (GtkWidget *widget,
726 static void create_sheet_entry (GtkSheet *sheet);
727 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
728 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
730 /* Sheet button gadgets */
732 static void size_allocate_column_title_buttons (GtkSheet * sheet);
733 static void size_allocate_row_title_buttons (GtkSheet * sheet);
736 static void size_allocate_global_button (GtkSheet *sheet);
737 static void gtk_sheet_button_size_request (GtkSheet *sheet,
738 const GtkSheetButton *button,
739 GtkRequisition *requisition);
741 /* Attributes routines */
742 static void init_attributes (const GtkSheet *sheet, gint col,
743 GtkSheetCellAttr *attributes);
746 /* Memory allocation routines */
747 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
748 const GtkSheetRange *range,
750 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
756 /* Container Functions */
757 static void gtk_sheet_remove (GtkContainer *container,
759 static void gtk_sheet_realize_child (GtkSheet *sheet,
760 GtkSheetChild *child);
761 static void gtk_sheet_position_child (GtkSheet *sheet,
762 GtkSheetChild *child);
763 static void gtk_sheet_position_children (GtkSheet *sheet);
764 static void gtk_sheet_child_show (GtkSheetChild *child);
765 static void gtk_sheet_child_hide (GtkSheetChild *child);
766 static void gtk_sheet_column_size_request (GtkSheet *sheet,
769 static void gtk_sheet_row_size_request (GtkSheet *sheet,
777 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...);
799 static GtkContainerClass *parent_class = NULL;
800 static guint sheet_signals[LAST_SIGNAL] = {0};
804 gtk_sheet_get_type ()
806 static GType sheet_type = 0;
810 static const GTypeInfo sheet_info =
812 sizeof (GtkSheetClass),
815 (GClassInitFunc) gtk_sheet_class_init,
820 (GInstanceInitFunc) gtk_sheet_init,
824 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
830 static GtkSheetRange*
831 gtk_sheet_range_copy (const GtkSheetRange *range)
833 GtkSheetRange *new_range;
835 g_return_val_if_fail (range != NULL, NULL);
837 new_range = g_new (GtkSheetRange, 1);
845 gtk_sheet_range_free (GtkSheetRange *range)
847 g_return_if_fail (range != NULL);
853 gtk_sheet_range_get_type (void)
855 static GType sheet_range_type=0;
857 if(!sheet_range_type)
859 sheet_range_type = g_boxed_type_register_static("GtkSheetRange", (GBoxedCopyFunc)gtk_sheet_range_copy, (GBoxedFreeFunc)gtk_sheet_range_free);
861 return sheet_range_type;
866 gtk_sheet_class_init (GtkSheetClass * klass)
868 GtkObjectClass *object_class;
869 GtkWidgetClass *widget_class;
870 GtkContainerClass *container_class;
871 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
873 object_class = (GtkObjectClass *) klass;
874 widget_class = (GtkWidgetClass *) klass;
875 container_class = (GtkContainerClass *) klass;
877 parent_class = g_type_class_peek_parent (klass);
880 * GtkSheet::select-row
881 * @sheet: the sheet widget that emitted the signal
882 * @row: the newly selected row index
884 * A row has been selected.
886 sheet_signals[SELECT_ROW] =
887 gtk_signal_new ("select-row",
889 GTK_CLASS_TYPE(object_class),
890 GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
892 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
895 * GtkSheet::select-column
896 * @sheet: the sheet widget that emitted the signal
897 * @column: the newly selected column index
899 * A column has been selected.
901 sheet_signals[SELECT_COLUMN] =
902 gtk_signal_new ("select-column",
904 GTK_CLASS_TYPE(object_class),
905 GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
907 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
911 * GtkSheet::double-click-row
912 * @sheet: the sheet widget that emitted the signal
913 * @row: the row that was double clicked.
915 * A row's title button has been double clicked
917 sheet_signals[DOUBLE_CLICK_ROW] =
918 gtk_signal_new ("double-click-row",
920 GTK_CLASS_TYPE(object_class),
923 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
927 * GtkSheet::double-click-column
928 * @sheet: the sheet widget that emitted the signal
929 * @column: the column that was double clicked.
931 * A column's title button has been double clicked
933 sheet_signals[DOUBLE_CLICK_COLUMN] =
934 gtk_signal_new ("double-click-column",
936 GTK_CLASS_TYPE(object_class),
939 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
941 sheet_signals[SELECT_RANGE] =
942 gtk_signal_new ("select-range",
944 GTK_CLASS_TYPE(object_class),
945 GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
946 gtkextra_VOID__BOXED,
947 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
949 sheet_signals[CLIP_RANGE] =
950 gtk_signal_new ("clip-range",
952 GTK_CLASS_TYPE(object_class),
953 GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
954 gtkextra_VOID__BOXED,
955 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
957 sheet_signals[RESIZE_RANGE] =
958 gtk_signal_new ("resize-range",
960 GTK_CLASS_TYPE(object_class),
961 GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
962 gtkextra_VOID__BOXED_BOXED,
963 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
964 sheet_signals[MOVE_RANGE] =
965 gtk_signal_new ("move-range",
967 GTK_CLASS_TYPE(object_class),
968 GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
969 gtkextra_VOID__BOXED_BOXED,
970 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
971 sheet_signals[TRAVERSE] =
972 gtk_signal_new ("traverse",
974 GTK_CLASS_TYPE(object_class),
975 GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
976 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
977 GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
978 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
980 sheet_signals[DEACTIVATE] =
981 gtk_signal_new ("deactivate",
983 GTK_CLASS_TYPE(object_class),
984 GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
985 gtkextra_BOOLEAN__INT_INT,
986 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
988 sheet_signals[ACTIVATE] =
989 gtk_signal_new ("activate",
991 GTK_CLASS_TYPE(object_class),
992 GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
993 gtkextra_BOOLEAN__INT_INT,
994 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
996 sheet_signals[SET_CELL] =
997 gtk_signal_new ("set-cell",
999 GTK_CLASS_TYPE(object_class),
1000 GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
1001 gtkextra_VOID__INT_INT,
1002 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1004 sheet_signals[CLEAR_CELL] =
1005 gtk_signal_new ("clear-cell",
1007 GTK_CLASS_TYPE(object_class),
1008 GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
1009 gtkextra_VOID__INT_INT,
1010 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1012 sheet_signals[CHANGED] =
1013 gtk_signal_new ("changed",
1015 GTK_CLASS_TYPE(object_class),
1016 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
1017 gtkextra_VOID__INT_INT,
1018 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1020 sheet_signals[NEW_COL_WIDTH] =
1021 gtk_signal_new ("new-column-width",
1023 GTK_CLASS_TYPE(object_class),
1024 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
1025 gtkextra_VOID__INT_INT,
1026 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1028 sheet_signals[NEW_ROW_HEIGHT] =
1029 gtk_signal_new ("new-row-height",
1031 GTK_CLASS_TYPE(object_class),
1032 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
1033 gtkextra_VOID__INT_INT,
1034 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
1036 widget_class->set_scroll_adjustments_signal =
1037 gtk_signal_new ("set-scroll-adjustments",
1039 GTK_CLASS_TYPE(object_class),
1040 GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
1041 gtkextra_VOID__OBJECT_OBJECT,
1042 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1045 container_class->add = NULL;
1046 container_class->remove = gtk_sheet_remove;
1047 container_class->forall = gtk_sheet_forall;
1049 object_class->destroy = gtk_sheet_destroy;
1050 gobject_class->finalize = gtk_sheet_finalize;
1052 widget_class->realize = gtk_sheet_realize;
1053 widget_class->unrealize = gtk_sheet_unrealize;
1054 widget_class->map = gtk_sheet_map;
1055 widget_class->unmap = gtk_sheet_unmap;
1056 widget_class->style_set = gtk_sheet_style_set;
1057 widget_class->button_press_event = gtk_sheet_button_press;
1058 widget_class->button_release_event = gtk_sheet_button_release;
1059 widget_class->motion_notify_event = gtk_sheet_motion;
1060 widget_class->key_press_event = gtk_sheet_key_press;
1061 widget_class->expose_event = gtk_sheet_expose;
1062 widget_class->size_request = gtk_sheet_size_request;
1063 widget_class->size_allocate = gtk_sheet_size_allocate;
1064 widget_class->focus_in_event = NULL;
1065 widget_class->focus_out_event = NULL;
1067 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
1068 klass->select_row = NULL;
1069 klass->select_column = NULL;
1070 klass->select_range = NULL;
1071 klass->clip_range = NULL;
1072 klass->resize_range = NULL;
1073 klass->move_range = NULL;
1074 klass->traverse = NULL;
1075 klass->deactivate = NULL;
1076 klass->activate = NULL;
1077 klass->set_cell = NULL;
1078 klass->clear_cell = NULL;
1079 klass->changed = NULL;
1084 gtk_sheet_init (GtkSheet *sheet)
1086 sheet->column_geometry = NULL;
1087 sheet->row_geometry = NULL;
1089 sheet->children = NULL;
1092 sheet->selection_mode = GTK_SELECTION_BROWSE;
1093 sheet->freeze_count = 0;
1094 sheet->state = GTK_SHEET_NORMAL;
1096 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
1097 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
1099 sheet->view.row0 = 0;
1100 sheet->view.col0 = 0;
1101 sheet->view.rowi = 0;
1102 sheet->view.coli = 0;
1104 sheet->column_title_window=NULL;
1105 sheet->column_title_area.x=0;
1106 sheet->column_title_area.y=0;
1107 sheet->column_title_area.width=0;
1108 sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
1110 sheet->row_title_window=NULL;
1111 sheet->row_title_area.x=0;
1112 sheet->row_title_area.y=0;
1113 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1114 sheet->row_title_area.height=0;
1117 sheet->active_cell.row=0;
1118 sheet->active_cell.col=0;
1119 sheet->selection_cell.row=0;
1120 sheet->selection_cell.col=0;
1122 sheet->sheet_entry=NULL;
1125 sheet->range.row0 = 0;
1126 sheet->range.rowi = 0;
1127 sheet->range.col0 = 0;
1128 sheet->range.coli = 0;
1130 sheet->state=GTK_SHEET_NORMAL;
1132 sheet->sheet_window = NULL;
1133 sheet->sheet_window_width = 0;
1134 sheet->sheet_window_height = 0;
1135 sheet->sheet_entry = NULL;
1136 sheet->button = NULL;
1141 sheet->hadjustment = NULL;
1142 sheet->vadjustment = NULL;
1144 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
1145 sheet->xor_gc = NULL;
1146 sheet->fg_gc = NULL;
1147 sheet->bg_gc = NULL;
1151 gdk_color_parse("white", &sheet->bg_color);
1152 gdk_color_alloc(gdk_colormap_get_system(), &sheet->bg_color);
1153 gdk_color_parse("gray", &sheet->grid_color);
1154 gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1155 sheet->show_grid = TRUE;
1159 /* Callback which occurs whenever columns are inserted/deleted in the model */
1161 columns_inserted_deleted_callback (GSheetModel *model, gint first_column, gint n_columns,
1165 GtkSheet *sheet = GTK_SHEET(data);
1167 GtkSheetRange range;
1168 gint model_columns = g_sheet_model_get_column_count(model);
1171 /* Need to update all the columns starting from the first column and onwards.
1172 * Previous column are unchanged, so don't need to be updated.
1174 range.col0 = first_column;
1176 range.coli = xxx_column_count(sheet) - 1;
1177 range.rowi = yyy_row_count(sheet) - 1;
1180 COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width + 1);
1183 COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1185 if ( sheet->view.coli > range.coli)
1186 sheet->view.coli = range.coli;
1188 adjust_scrollbars(sheet);
1190 if (sheet->active_cell.col >= model_columns)
1191 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, model_columns - 1);
1193 for(i = first_column; i <= MAX_VISIBLE_COLUMN(sheet); i++)
1194 gtk_sheet_column_title_button_draw(sheet, i);
1196 gtk_sheet_range_draw(sheet, &range);
1200 /* Callback which occurs whenever rows are inserted/deleted in the model */
1202 rows_inserted_deleted_callback (GSheetModel *model, gint first_row, gint n_rows,
1206 GtkSheet *sheet = GTK_SHEET(data);
1208 GtkSheetRange range;
1210 gint model_rows = g_sheet_model_get_row_count(model);
1212 /* Need to update all the rows starting from the first row and onwards.
1213 * Previous rows are unchanged, so don't need to be updated.
1215 range.row0 = first_row;
1217 range.rowi = yyy_row_count(sheet) - 1;
1218 range.coli = xxx_column_count(sheet) - 1;
1221 ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height + 1);
1223 ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height - 1);
1225 if ( sheet->view.rowi > range.rowi)
1226 sheet->view.rowi = range.rowi;
1228 adjust_scrollbars(sheet);
1230 if (sheet->active_cell.row >= model_rows)
1231 gtk_sheet_activate_cell(sheet, model_rows - 1, sheet->active_cell.col);
1233 for(i = first_row; i <= MAX_VISIBLE_ROW(sheet); i++)
1234 gtk_sheet_row_title_button_draw(sheet, i);
1236 gtk_sheet_range_draw(sheet, &range);
1240 If row0 or rowi are negative, then all rows will be updated.
1241 If col0 or coli are negative, then all columns will be updated.
1244 range_update_callback (GSheetModel *m, gint row0, gint col0,
1245 gint rowi, gint coli, gpointer data)
1247 GtkSheet *sheet = GTK_SHEET(data);
1249 GtkSheetRange range;
1256 if( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
1258 gtk_sheet_range_draw(sheet, NULL);
1261 else if ( row0 < 0 || rowi < 0 )
1263 range.row0=MIN_VISIBLE_ROW(sheet);
1264 range.rowi=MAX_VISIBLE_ROW(sheet);
1266 else if ( col0 < 0 || coli < 0 )
1268 range.col0=MIN_VISIBLE_COLUMN(sheet);
1269 range.coli=MAX_VISIBLE_COLUMN(sheet);
1272 gtk_sheet_range_draw(sheet, &range);
1276 static void gtk_sheet_construct (GtkSheet *sheet,
1279 const gchar *title);
1284 * @rows: initial number of rows
1285 * @columns: initial number of columns
1286 * @title: sheet title
1287 * @model: the model to use for the sheet data
1289 * Creates a new sheet widget with the given number of rows and columns.
1291 * Returns: the new sheet widget
1294 gtk_sheet_new (GSheetRow *vgeo, GSheetColumn *hgeo, const gchar *title,
1299 widget = gtk_type_new (gtk_sheet_get_type ());
1301 gtk_sheet_construct(GTK_SHEET(widget), vgeo, hgeo, title);
1304 gtk_sheet_set_model(GTK_SHEET(widget), model);
1312 * gtk_sheet_set_model
1313 * @sheet: the sheet to set the model for
1314 * @model: the model to use for the sheet data
1316 * Sets the model for a GtkSheet
1320 gtk_sheet_set_model(GtkSheet *sheet, GSheetModel *model)
1322 g_return_if_fail (GTK_IS_SHEET (sheet));
1323 g_return_if_fail (G_IS_SHEET_MODEL (model));
1325 sheet->model = model;
1327 g_signal_connect(model, "range_changed",
1328 G_CALLBACK(range_update_callback), sheet);
1330 g_signal_connect(model, "rows_inserted",
1331 G_CALLBACK(rows_inserted_deleted_callback), sheet);
1333 g_signal_connect(model, "rows_deleted",
1334 G_CALLBACK(rows_inserted_deleted_callback), sheet);
1336 g_signal_connect(model, "columns_inserted",
1337 G_CALLBACK(columns_inserted_deleted_callback), sheet);
1339 g_signal_connect(model, "columns_deleted",
1340 G_CALLBACK(columns_inserted_deleted_callback), sheet);
1345 /* Call back for when the column titles have changed.
1346 FIRST is the first column changed.
1347 N_COLUMNS is the number of columns which have changed, or -1, which
1348 indicates that the column has changed to its right-most extremity
1351 column_titles_changed(GtkWidget *w, gint first, gint n_columns, gpointer data)
1353 GtkSheet *sheet = GTK_SHEET(data);
1354 gboolean extremity = FALSE;
1356 if ( n_columns == -1 )
1359 n_columns = xxx_column_count(sheet) - 1 ;
1362 if(!GTK_SHEET_IS_FROZEN(sheet))
1365 for ( i = first ; i <= first + n_columns ; ++i )
1367 gtk_sheet_column_title_button_draw(sheet, i);
1368 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, i);
1372 gtk_sheet_column_title_button_draw(sheet, -1);
1377 gtk_sheet_construct (GtkSheet *sheet,
1382 g_return_if_fail(G_IS_SHEET_COLUMN(hgeo));
1383 g_return_if_fail(G_IS_SHEET_ROW(vgeo));
1385 sheet->column_geometry = hgeo;
1386 sheet->row_geometry = vgeo;
1389 sheet->columns_resizable = TRUE;
1390 sheet->rows_resizable = TRUE;
1392 sheet->row_titles_visible = TRUE;
1393 sheet->row_title_area.width = DEFAULT_COLUMN_WIDTH;
1395 sheet->column_titles_visible = TRUE;
1396 sheet->autoscroll = TRUE;
1397 sheet->justify_entry = TRUE;
1400 /* create sheet entry */
1401 sheet->entry_type = 0;
1402 create_sheet_entry (sheet);
1404 /* create global selection button */
1405 create_global_button(sheet);
1408 sheet->name = g_strdup(title);
1410 g_signal_connect(sheet->column_geometry, "columns_changed",
1411 G_CALLBACK(column_titles_changed), sheet);
1417 gtk_sheet_new_with_custom_entry (GSheetRow *rows, GSheetColumn *columns, const gchar *title,
1422 widget = gtk_type_new (gtk_sheet_get_type ());
1424 gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget),
1425 rows, columns, title, entry_type);
1431 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1437 gtk_sheet_construct(sheet, vgeo, hgeo, title);
1439 sheet->entry_type = entry_type;
1440 create_sheet_entry(sheet);
1446 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
1450 g_return_if_fail (sheet != NULL);
1451 g_return_if_fail (GTK_IS_SHEET (sheet));
1453 state = sheet->state;
1455 if(sheet->state == GTK_SHEET_NORMAL)
1456 gtk_sheet_hide_active_cell(sheet);
1458 sheet->entry_type = entry_type;
1460 create_sheet_entry(sheet);
1462 if(state == GTK_SHEET_NORMAL)
1464 gtk_sheet_show_active_cell(sheet);
1465 g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
1467 G_CALLBACK(gtk_sheet_entry_changed),
1473 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
1475 g_return_if_fail (sheet != NULL);
1476 g_return_if_fail (GTK_IS_SHEET (sheet));
1478 if(show == sheet->show_grid) return;
1480 sheet->show_grid = show;
1482 if(!GTK_SHEET_IS_FROZEN(sheet))
1483 gtk_sheet_range_draw(sheet, NULL);
1487 gtk_sheet_grid_visible(GtkSheet *sheet)
1489 g_return_val_if_fail (sheet != NULL, 0);
1490 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1492 return sheet->show_grid;
1496 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
1498 g_return_if_fail (sheet != NULL);
1499 g_return_if_fail (GTK_IS_SHEET (sheet));
1502 gdk_color_parse("white", &sheet->bg_color);
1503 gdk_color_alloc(gdk_colormap_get_system(), &sheet->bg_color);
1505 sheet->bg_color = *color;
1507 if(!GTK_SHEET_IS_FROZEN(sheet))
1508 gtk_sheet_range_draw(sheet, NULL);
1512 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
1514 g_return_if_fail (sheet != NULL);
1515 g_return_if_fail (GTK_IS_SHEET (sheet));
1518 gdk_color_parse("black", &sheet->grid_color);
1519 gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1521 sheet->grid_color = *color;
1523 if(!GTK_SHEET_IS_FROZEN(sheet))
1524 gtk_sheet_range_draw(sheet, NULL);
1528 gtk_sheet_get_columns_count(GtkSheet *sheet)
1530 g_return_val_if_fail (sheet != NULL, 0);
1531 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1533 return xxx_column_count(sheet);
1537 gtk_sheet_get_rows_count(GtkSheet *sheet)
1539 g_return_val_if_fail (sheet != NULL, 0);
1540 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1542 return yyy_row_count(sheet);
1546 gtk_sheet_get_state(GtkSheet *sheet)
1548 g_return_val_if_fail (sheet != NULL, 0);
1549 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1551 return (sheet->state);
1555 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
1557 g_return_if_fail (sheet != NULL);
1558 g_return_if_fail (GTK_IS_SHEET (sheet));
1560 if(GTK_WIDGET_REALIZED(sheet))
1561 gtk_sheet_real_unselect_range(sheet, NULL);
1563 sheet->selection_mode = mode;
1567 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1569 g_return_if_fail (sheet != NULL);
1570 g_return_if_fail (GTK_IS_SHEET (sheet));
1572 sheet->autoresize = autoresize;
1576 gtk_sheet_autoresize (GtkSheet *sheet)
1578 g_return_val_if_fail (sheet != NULL, FALSE);
1579 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1581 return sheet->autoresize;
1585 gtk_sheet_set_column_width (GtkSheet * sheet,
1591 gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
1593 gint text_width = 0;
1596 g_return_if_fail (sheet != NULL);
1597 g_return_if_fail (GTK_IS_SHEET (sheet));
1598 if (column >= xxx_column_count(sheet) || column < 0) return;
1600 for (row = 0; row < yyy_row_count(sheet); row++)
1602 gchar *text = gtk_sheet_cell_get_text(sheet, row, column);
1603 if (text && strlen(text) > 0){
1604 GtkSheetCellAttr attributes;
1606 gtk_sheet_get_attributes(sheet, row, column, &attributes);
1607 if(attributes.is_visible){
1608 gint width = STRING_WIDTH(GTK_WIDGET(sheet),
1609 attributes.font_desc,
1611 + 2*CELLOFFSET + attributes.border.width;
1612 text_width = MAX (text_width, width);
1615 dispose_string(sheet, text);
1618 if(text_width > xxx_column_width(sheet, column) )
1620 gtk_sheet_set_column_width(sheet, column, text_width);
1621 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
1627 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1629 g_return_if_fail (sheet != NULL);
1630 g_return_if_fail (GTK_IS_SHEET (sheet));
1632 sheet->autoscroll = autoscroll;
1636 gtk_sheet_autoscroll (GtkSheet *sheet)
1638 g_return_val_if_fail (sheet != NULL, FALSE);
1639 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1641 return sheet->autoscroll;
1645 gtk_sheet_set_clip_text (GtkSheet *sheet, gboolean clip_text)
1647 g_return_if_fail (sheet != NULL);
1648 g_return_if_fail (GTK_IS_SHEET (sheet));
1650 sheet->clip_text = clip_text;
1654 gtk_sheet_clip_text (GtkSheet *sheet)
1656 g_return_val_if_fail (sheet != NULL, FALSE);
1657 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1659 return sheet->clip_text;
1663 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1665 g_return_if_fail (sheet != NULL);
1666 g_return_if_fail (GTK_IS_SHEET (sheet));
1668 sheet->justify_entry = justify;
1672 gtk_sheet_justify_entry (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->justify_entry;
1681 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1683 g_return_if_fail (sheet != NULL);
1684 g_return_if_fail (GTK_IS_SHEET (sheet));
1688 GTK_SHEET_SET_FLAGS(sheet,GTK_SHEET_IS_LOCKED);
1689 gtk_widget_hide(sheet->sheet_entry);
1690 gtk_widget_unmap(sheet->sheet_entry);
1694 GTK_SHEET_UNSET_FLAGS(sheet,GTK_SHEET_IS_LOCKED);
1695 if (GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)))
1697 gtk_widget_show (sheet->sheet_entry);
1698 gtk_widget_map (sheet->sheet_entry);
1702 gtk_entry_set_editable(GTK_ENTRY(sheet->sheet_entry), locked);
1707 gtk_sheet_locked (const GtkSheet *sheet)
1709 g_return_val_if_fail (sheet != NULL, FALSE);
1710 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1712 return GTK_SHEET_IS_LOCKED(sheet);
1715 /* This routine has problems with gtk+-1.2 related with the
1716 * label/button drawing - I think it's a bug in gtk+-1.2 */
1719 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
1721 /* GtkWidget *old_widget;
1722 */ GtkWidget *label;
1724 g_return_if_fail (sheet != NULL);
1725 g_return_if_fail (title != NULL);
1726 g_return_if_fail (GTK_IS_SHEET (sheet));
1729 g_free (sheet->name);
1731 sheet->name = g_strdup (title);
1733 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
1735 if(GTK_BIN(sheet->button)->child)
1736 label = GTK_BIN(sheet->button)->child;
1738 gtk_label_set_text(GTK_LABEL(label), title);
1740 size_allocate_global_button(sheet);
1742 /* remove and destroy the old widget */
1744 old_widget = GTK_BIN (sheet->button)->child;
1747 gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
1750 label = gtk_label_new (title);
1751 gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
1753 gtk_container_add (GTK_CONTAINER (sheet->button), label);
1754 gtk_widget_show (label);
1756 size_allocate_global_button(sheet);
1758 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
1761 gtk_widget_destroy (old_widget);
1766 gtk_sheet_freeze (GtkSheet *sheet)
1768 g_return_if_fail (sheet != NULL);
1769 g_return_if_fail (GTK_IS_SHEET (sheet));
1771 sheet->freeze_count++;
1772 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1776 gtk_sheet_thaw(GtkSheet *sheet)
1778 g_return_if_fail (sheet != NULL);
1779 g_return_if_fail (GTK_IS_SHEET (sheet));
1781 if(sheet->freeze_count == 0) return;
1783 sheet->freeze_count--;
1784 if(sheet->freeze_count > 0) return;
1786 adjust_scrollbars(sheet);
1788 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1790 sheet->old_vadjustment = -1.;
1791 sheet->old_hadjustment = -1.;
1793 if(sheet->hadjustment)
1794 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1796 if(sheet->vadjustment)
1797 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1800 if(sheet->state == GTK_STATE_NORMAL)
1801 if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
1802 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
1804 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1806 (GtkSignalFunc)gtk_sheet_entry_changed,
1807 GTK_OBJECT(GTK_WIDGET(sheet)));
1808 gtk_sheet_show_active_cell(sheet);
1815 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
1817 if(width < COLUMN_MIN_WIDTH) return;
1819 sheet->row_title_area.width = width;
1820 sheet->view.col0 = COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
1821 sheet->view.coli = COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1824 adjust_scrollbars(sheet);
1826 sheet->old_hadjustment = -1.;
1827 if(sheet->hadjustment)
1828 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1830 size_allocate_global_button(sheet);
1834 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
1836 if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
1838 sheet->column_title_area.height = height;
1839 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
1840 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
1842 adjust_scrollbars(sheet);
1844 sheet->old_vadjustment = -1.;
1845 if(sheet->vadjustment)
1846 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1848 size_allocate_global_button(sheet);
1852 gtk_sheet_show_column_titles(GtkSheet *sheet)
1856 if(sheet->column_titles_visible) return;
1858 sheet->column_titles_visible = TRUE;
1861 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1862 gdk_window_show(sheet->column_title_window);
1863 gdk_window_move_resize (sheet->column_title_window,
1864 sheet->column_title_area.x,
1865 sheet->column_title_area.y,
1866 sheet->column_title_area.width,
1867 sheet->column_title_area.height);
1869 for(col = MIN_VISIBLE_COLUMN(sheet);
1870 col <= MAX_VISIBLE_COLUMN(sheet);
1873 GtkSheetButton *button = xxx_column_button(sheet, col);
1874 GtkSheetChild *child = button->child;
1876 gtk_sheet_child_show(child);
1877 gtk_sheet_button_free(button);
1879 adjust_scrollbars(sheet);
1882 sheet->old_vadjustment = -1.;
1883 if(sheet->vadjustment)
1884 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1886 size_allocate_global_button(sheet);
1891 gtk_sheet_show_row_titles(GtkSheet *sheet)
1895 if(sheet->row_titles_visible) return;
1897 sheet->row_titles_visible = TRUE;
1900 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1901 gdk_window_show(sheet->row_title_window);
1902 gdk_window_move_resize (sheet->row_title_window,
1903 sheet->row_title_area.x,
1904 sheet->row_title_area.y,
1905 sheet->row_title_area.width,
1906 sheet->row_title_area.height);
1908 for(row = MIN_VISIBLE_ROW(sheet);
1909 row <= MAX_VISIBLE_ROW(sheet);
1912 const GtkSheetButton *button = yyy_row_button(sheet, row);
1913 GtkSheetChild *child = button->child;
1916 gtk_sheet_child_show(child);
1919 adjust_scrollbars(sheet);
1922 sheet->old_hadjustment = -1.;
1923 if(sheet->hadjustment)
1924 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1926 size_allocate_global_button(sheet);
1930 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1934 if(!sheet->column_titles_visible) return;
1936 sheet->column_titles_visible = FALSE;
1938 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1939 if(sheet->column_title_window)
1940 gdk_window_hide(sheet->column_title_window);
1941 if(GTK_WIDGET_VISIBLE(sheet->button))
1942 gtk_widget_hide(sheet->button);
1944 for(col = MIN_VISIBLE_COLUMN(sheet);
1945 col <= MAX_VISIBLE_COLUMN(sheet);
1948 GtkSheetButton *button = xxx_column_button(sheet, col);
1949 GtkSheetChild *child = button->child;
1951 gtk_sheet_child_hide(child);
1952 gtk_sheet_button_free(button);
1954 adjust_scrollbars(sheet);
1957 sheet->old_vadjustment = -1.;
1958 if(sheet->vadjustment)
1959 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1964 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1968 if(!sheet->row_titles_visible) return;
1970 sheet->row_titles_visible = FALSE;
1973 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1974 if(sheet->row_title_window)
1975 gdk_window_hide(sheet->row_title_window);
1976 if(GTK_WIDGET_VISIBLE(sheet->button))
1977 gtk_widget_hide(sheet->button);
1978 for(row = MIN_VISIBLE_ROW(sheet);
1979 row <= MAX_VISIBLE_ROW(sheet);
1982 const GtkSheetButton *button = yyy_row_button(sheet, row);
1983 GtkSheetChild *child = button->child;
1986 gtk_sheet_child_hide(child);
1988 adjust_scrollbars(sheet);
1991 sheet->old_hadjustment = -1.;
1992 if(sheet->hadjustment)
1993 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1998 gtk_sheet_column_titles_visible(GtkSheet *sheet)
2000 g_return_val_if_fail (sheet != NULL, FALSE);
2001 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2002 return sheet->column_titles_visible;
2006 gtk_sheet_row_titles_visible(GtkSheet *sheet)
2008 g_return_val_if_fail (sheet != NULL, FALSE);
2009 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2010 return sheet->row_titles_visible;
2016 gtk_sheet_moveto (GtkSheet * sheet,
2023 guint width, height;
2025 gint min_row, min_col;
2027 g_return_if_fail (sheet != NULL);
2028 g_return_if_fail (GTK_IS_SHEET (sheet));
2029 g_return_if_fail (sheet->hadjustment != NULL);
2030 g_return_if_fail (sheet->vadjustment != NULL);
2032 if (row < 0 || row >= yyy_row_count(sheet))
2034 if (column < 0 || column >= xxx_column_count(sheet))
2037 height = sheet->sheet_window_height;
2038 width = sheet->sheet_window_width;
2040 /* adjust vertical scrollbar */
2042 if (row >= 0 && row_align >=0.)
2045 y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
2047 (1.-row_align)*yyy_row_height(sheet, row);
2049 y = ROW_TOP_YPIXEL (sheet, row) - sheet->voffset
2050 - (gint) ( row_align*height + (1. - row_align) * yyy_row_height(sheet, row));
2052 /* This forces the sheet to scroll when you don't see the entire cell */
2055 if(row_align == 1.){
2056 while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
2057 if(yyy_row_is_visible(sheet, min_row))
2058 adjust += yyy_row_height(sheet, min_row);
2059 if(adjust >= height){
2064 min_row = MAX(min_row, 0);
2065 y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
2066 yyy_row_height(sheet, min_row) - 1;
2070 sheet->vadjustment->value = 0.0;
2072 sheet->vadjustment->value = y;
2074 sheet->old_vadjustment = -1.;
2075 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
2080 /* adjust horizontal scrollbar */
2081 if (column >= 0 && col_align >= 0.)
2084 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
2086 (1.-col_align)*sheet->column[column].width;
2088 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset
2089 - (gint) ( col_align*width + (1.-col_align)*
2090 xxx_column_width(sheet, column));
2093 /* This forces the sheet to scroll when you don't see the entire cell */
2096 if(col_align == 1.){
2097 while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
2098 if(xxx_column_is_visible(sheet, min_col))
2099 adjust += xxx_column_width(sheet, min_col);
2101 if(adjust >= width){
2106 min_col = MAX(min_col, 0);
2107 x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
2108 xxx_column_width(sheet, min_col) - 1;
2112 sheet->hadjustment->value = 0.0;
2114 sheet->hadjustment->value = x;
2116 sheet->old_vadjustment = -1.;
2117 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
2125 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
2127 g_return_if_fail (sheet != NULL);
2128 g_return_if_fail (GTK_IS_SHEET (sheet));
2130 sheet->columns_resizable = resizable;
2134 gtk_sheet_columns_resizable (GtkSheet *sheet)
2136 g_return_val_if_fail (sheet != NULL, FALSE);
2137 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2139 return sheet->columns_resizable;
2144 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2146 g_return_if_fail (sheet != NULL);
2147 g_return_if_fail (GTK_IS_SHEET (sheet));
2149 sheet->rows_resizable = resizable;
2153 gtk_sheet_rows_resizable (GtkSheet *sheet)
2155 g_return_val_if_fail (sheet != NULL, FALSE);
2156 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2158 return sheet->rows_resizable;
2163 gtk_sheet_select_row (GtkSheet * sheet,
2166 g_return_if_fail (sheet != NULL);
2167 g_return_if_fail (GTK_IS_SHEET (sheet));
2169 if (row < 0 || row >= yyy_row_count(sheet))
2172 if(sheet->state != GTK_SHEET_NORMAL)
2173 gtk_sheet_real_unselect_range(sheet, NULL);
2176 gboolean veto = TRUE;
2177 veto = gtk_sheet_deactivate_cell(sheet);
2181 sheet->state=GTK_SHEET_ROW_SELECTED;
2182 sheet->range.row0 = row;
2183 sheet->range.col0 = 0;
2184 sheet->range.rowi = row;
2185 sheet->range.coli = xxx_column_count(sheet) - 1;
2186 sheet->active_cell.row = row;
2187 sheet->active_cell.col = 0;
2189 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
2190 gtk_sheet_real_select_range(sheet, NULL);
2195 gtk_sheet_select_column (GtkSheet * sheet, gint column)
2197 g_return_if_fail (sheet != NULL);
2198 g_return_if_fail (GTK_IS_SHEET (sheet));
2200 if (column < 0 || column >= xxx_column_count(sheet))
2203 if(sheet->state != GTK_SHEET_NORMAL)
2204 gtk_sheet_real_unselect_range(sheet, NULL);
2207 gboolean veto = TRUE;
2208 veto = gtk_sheet_deactivate_cell(sheet);
2212 sheet->state=GTK_SHEET_COLUMN_SELECTED;
2213 sheet->range.row0 = 0;
2214 sheet->range.col0 = column;
2215 sheet->range.rowi = yyy_row_count(sheet) - 1;
2216 sheet->range.coli = column;
2217 sheet->active_cell.row = 0;
2218 sheet->active_cell.col = column;
2220 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
2221 gtk_sheet_real_select_range(sheet, NULL);
2225 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2228 g_return_if_fail (sheet != NULL);
2229 g_return_if_fail (GTK_IS_SHEET (sheet));
2231 if(GTK_SHEET_IN_CLIP(sheet)) return;
2233 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2236 sheet->clip_range = sheet->range;
2238 sheet->clip_range=*range;
2241 sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet);
2243 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
2244 &sheet->clip_range);
2249 gtk_sheet_unclip_range(GtkSheet *sheet)
2252 g_return_if_fail (sheet != NULL);
2253 g_return_if_fail (GTK_IS_SHEET (sheet));
2255 if(!GTK_SHEET_IN_CLIP(sheet)) return;
2257 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2258 gtk_timeout_remove(sheet->clip_timer);
2259 gtk_sheet_range_draw(sheet, &sheet->clip_range);
2261 if(gtk_sheet_range_isvisible(sheet, sheet->range))
2262 gtk_sheet_range_draw(sheet, &sheet->range);
2266 gtk_sheet_in_clip (GtkSheet *sheet)
2268 g_return_val_if_fail (sheet != NULL, FALSE);
2269 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2271 return GTK_SHEET_IN_CLIP(sheet);
2275 gtk_sheet_flash(gpointer data)
2278 gint x,y,width,height;
2279 GdkRectangle clip_area;
2281 sheet=GTK_SHEET(data);
2283 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
2284 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
2285 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
2286 if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE;
2287 if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE;
2289 GDK_THREADS_ENTER();
2291 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2292 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2293 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2294 xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2295 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2296 yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2298 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2299 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2300 clip_area.width=sheet->sheet_window_width;
2301 clip_area.height=sheet->sheet_window_height;
2307 if(width>clip_area.width) width=clip_area.width+10;
2312 if(height>clip_area.height) height=clip_area.height+10;
2314 gdk_draw_pixmap(sheet->sheet_window,
2315 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2321 gdk_draw_pixmap(sheet->sheet_window,
2322 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2328 gdk_draw_pixmap(sheet->sheet_window,
2329 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2335 gdk_draw_pixmap(sheet->sheet_window,
2336 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2343 sheet->interval=sheet->interval+1;
2344 if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
2346 gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2347 gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
2348 gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2350 GDK_THREADS_LEAVE();
2357 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
2359 GdkRectangle clip_area;
2360 gint x,y,width,height;
2362 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
2364 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2365 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2366 clip_area.width=sheet->sheet_window_width;
2367 clip_area.height=sheet->sheet_window_height;
2369 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
2371 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2372 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2373 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2374 xxx_column_width(sheet, sheet->clip_range.coli) - 1;
2375 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2376 yyy_row_height(sheet, sheet->clip_range.rowi)-1;
2382 if(width>clip_area.width) width=clip_area.width+10;
2387 if(height>clip_area.height) height=clip_area.height+10;
2389 gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
2391 gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE,
2395 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2397 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
2402 gtk_sheet_range_isvisible (GtkSheet * sheet,
2403 GtkSheetRange range)
2405 g_return_val_if_fail (sheet != NULL, FALSE);
2407 if (range.row0 < 0 || range.row0 >= yyy_row_count(sheet))
2410 if (range.rowi < 0 || range.rowi >= yyy_row_count(sheet))
2413 if (range.col0 < 0 || range.col0 >= xxx_column_count(sheet))
2416 if (range.coli < 0 || range.coli >= xxx_column_count(sheet))
2419 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2422 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2425 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2428 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2435 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2436 gint row, gint column)
2438 GtkSheetRange range;
2441 range.col0 = column;
2443 range.coli = column;
2445 return gtk_sheet_range_isvisible(sheet, range);
2449 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2452 g_return_if_fail (sheet != NULL);
2453 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2454 g_return_if_fail (range != NULL);
2456 range->row0 = MIN_VISIBLE_ROW(sheet);
2457 range->col0 = MIN_VISIBLE_COLUMN(sheet);
2458 range->rowi = MAX_VISIBLE_ROW(sheet);
2459 range->coli = MAX_VISIBLE_COLUMN(sheet);
2464 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2466 g_return_val_if_fail (sheet != NULL, NULL);
2467 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2469 return sheet->vadjustment;
2473 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2475 g_return_val_if_fail (sheet != NULL, NULL);
2476 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2478 return sheet->hadjustment;
2482 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2483 GtkAdjustment *adjustment)
2485 GtkAdjustment *old_adjustment;
2487 g_return_if_fail (sheet != NULL);
2488 g_return_if_fail (GTK_IS_SHEET (sheet));
2490 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2492 if (sheet->vadjustment == adjustment)
2495 old_adjustment = sheet->vadjustment;
2497 if (sheet->vadjustment)
2499 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2500 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2503 sheet->vadjustment = adjustment;
2505 if (sheet->vadjustment)
2507 gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2508 gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2510 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2511 (GtkSignalFunc) vadjustment_changed,
2513 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2514 (GtkSignalFunc) vadjustment_value_changed,
2518 if (!sheet->vadjustment || !old_adjustment)
2520 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2524 sheet->old_vadjustment = sheet->vadjustment->value;
2528 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2529 GtkAdjustment *adjustment)
2531 GtkAdjustment *old_adjustment;
2533 g_return_if_fail (sheet != NULL);
2534 g_return_if_fail (GTK_IS_SHEET (sheet));
2536 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2538 if (sheet->hadjustment == adjustment)
2541 old_adjustment = sheet->hadjustment;
2543 if (sheet->hadjustment)
2545 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2546 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2549 sheet->hadjustment = adjustment;
2551 if (sheet->hadjustment)
2553 gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2554 gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2556 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2557 (GtkSignalFunc) hadjustment_changed,
2559 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2560 (GtkSignalFunc) hadjustment_value_changed,
2564 if (!sheet->hadjustment || !old_adjustment)
2566 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2570 sheet->old_hadjustment = sheet->hadjustment->value;
2574 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2575 GtkAdjustment *hadjustment,
2576 GtkAdjustment *vadjustment)
2578 if(sheet->hadjustment != hadjustment)
2579 gtk_sheet_set_hadjustment (sheet, hadjustment);
2581 if(sheet->vadjustment != vadjustment)
2582 gtk_sheet_set_vadjustment (sheet, vadjustment);
2586 gtk_sheet_finalize (GObject * object)
2590 g_return_if_fail (object != NULL);
2591 g_return_if_fail (GTK_IS_SHEET (object));
2593 sheet = GTK_SHEET (object);
2595 /* get rid of all the cells */
2596 gtk_sheet_range_clear (sheet, NULL);
2597 gtk_sheet_range_delete(sheet, NULL);
2600 g_free(sheet->name);
2604 if (G_OBJECT_CLASS (parent_class)->finalize)
2605 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2609 gtk_sheet_destroy (GtkObject * object)
2614 g_return_if_fail (object != NULL);
2615 g_return_if_fail (GTK_IS_SHEET (object));
2617 sheet = GTK_SHEET (object);
2619 /* destroy the entry */
2620 if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
2621 gtk_widget_destroy (sheet->sheet_entry);
2622 sheet->sheet_entry = NULL;
2625 /* destroy the global selection button */
2626 if(sheet->button && GTK_IS_WIDGET(sheet->button)){
2627 gtk_widget_destroy (sheet->button);
2628 sheet->button = NULL;
2632 gtk_timeout_remove(sheet->timer);
2636 if(sheet->clip_timer){
2637 gtk_timeout_remove(sheet->clip_timer);
2638 sheet->clip_timer = 0;
2641 /* unref adjustments */
2642 if (sheet->hadjustment)
2644 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2645 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2646 sheet->hadjustment = NULL;
2648 if (sheet->vadjustment)
2650 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2651 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2652 sheet->vadjustment = NULL;
2655 children = sheet->children;
2657 GtkSheetChild *child = (GtkSheetChild *)children->data;
2658 if(child && child->widget)
2659 gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
2660 children = sheet->children;
2662 sheet->children = NULL;
2664 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2665 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2669 gtk_sheet_style_set (GtkWidget *widget,
2670 GtkStyle *previous_style)
2674 g_return_if_fail (widget != NULL);
2675 g_return_if_fail (GTK_IS_SHEET (widget));
2677 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2678 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2680 sheet = GTK_SHEET (widget);
2682 if(GTK_WIDGET_REALIZED(widget))
2684 gtk_style_set_background (widget->style, widget->window, widget->state);
2690 gtk_sheet_realize (GtkWidget * widget)
2693 GdkWindowAttr attributes;
2694 gint attributes_mask;
2695 GdkGCValues values, auxvalues;
2696 GdkColormap *colormap;
2698 GtkSheetChild *child;
2701 g_return_if_fail (widget != NULL);
2702 g_return_if_fail (GTK_IS_SHEET (widget));
2704 sheet = GTK_SHEET (widget);
2706 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2708 attributes.window_type = GDK_WINDOW_CHILD;
2709 attributes.x = widget->allocation.x;
2710 attributes.y = widget->allocation.y;
2711 attributes.width = widget->allocation.width;
2712 attributes.height = widget->allocation.height;
2713 attributes.wclass = GDK_INPUT_OUTPUT;
2715 attributes.visual = gtk_widget_get_visual (widget);
2716 attributes.colormap = gtk_widget_get_colormap (widget);
2718 attributes.event_mask = gtk_widget_get_events (widget);
2719 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2720 GDK_BUTTON_PRESS_MASK |
2721 GDK_BUTTON_RELEASE_MASK |
2722 GDK_KEY_PRESS_MASK |
2723 GDK_POINTER_MOTION_MASK |
2724 GDK_POINTER_MOTION_HINT_MASK);
2725 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2728 attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2731 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2733 gdk_window_set_user_data (widget->window, sheet);
2735 widget->style = gtk_style_attach (widget->style, widget->window);
2737 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2740 if(sheet->row_titles_visible)
2741 attributes.x = sheet->row_title_area.width;
2743 attributes.width = sheet->column_title_area.width;
2744 attributes.height = sheet->column_title_area.height;
2746 /* column-title window */
2747 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2748 gdk_window_set_user_data (sheet->column_title_window, sheet);
2749 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2753 if(sheet->column_titles_visible)
2754 attributes.y = sheet->column_title_area.height;
2755 attributes.width = sheet->row_title_area.width;
2756 attributes.height = sheet->row_title_area.height;
2758 /* row-title window */
2759 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2760 gdk_window_set_user_data (sheet->row_title_window, sheet);
2761 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2764 attributes.cursor = gdk_cursor_new(GDK_PLUS);
2768 attributes.width = sheet->sheet_window_width,
2769 attributes.height = sheet->sheet_window_height;
2771 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2772 gdk_window_set_user_data (sheet->sheet_window, sheet);
2774 gdk_cursor_unref(attributes.cursor);
2776 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2777 gdk_window_show (sheet->sheet_window);
2779 /* backing_pixmap */
2780 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
2784 gdk_gc_unref(sheet->fg_gc);
2786 gdk_gc_unref(sheet->bg_gc);
2787 sheet->fg_gc = gdk_gc_new (widget->window);
2788 sheet->bg_gc = gdk_gc_new (widget->window);
2790 colormap = gtk_widget_get_colormap(widget);
2792 gdk_color_white(colormap, &widget->style->white);
2793 gdk_color_black(colormap, &widget->style->black);
2795 gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2797 values.foreground = widget->style->white;
2798 values.function = GDK_INVERT;
2799 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2801 gdk_gc_unref(sheet->xor_gc);
2802 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2808 if(sheet->sheet_entry->parent){
2809 gtk_widget_ref(sheet->sheet_entry);
2810 gtk_widget_unparent(sheet->sheet_entry);
2812 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2813 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2815 if(sheet->button && sheet->button->parent){
2816 gtk_widget_ref(sheet->button);
2817 gtk_widget_unparent(sheet->button);
2819 gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2820 gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2823 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2825 if(!sheet->cursor_drag)
2826 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2828 if(sheet->column_titles_visible)
2829 gdk_window_show(sheet->column_title_window);
2830 if(sheet->row_titles_visible)
2831 gdk_window_show(sheet->row_title_window);
2833 size_allocate_row_title_buttons(sheet);
2834 size_allocate_column_title_buttons(sheet);
2836 name = g_strdup(sheet->name);
2837 gtk_sheet_set_title(sheet, name);
2841 children = sheet->children;
2844 child = children->data;
2845 children = children->next;
2847 gtk_sheet_realize_child(sheet, child);
2852 create_global_button(GtkSheet *sheet)
2854 sheet->button = gtk_button_new_with_label(" ");
2856 gtk_signal_connect (GTK_OBJECT (sheet->button),
2858 (GtkSignalFunc) global_button_clicked,
2863 size_allocate_global_button(GtkSheet *sheet)
2865 GtkAllocation allocation;
2867 if(!sheet->column_titles_visible) return;
2868 if(!sheet->row_titles_visible) return;
2870 gtk_widget_size_request(sheet->button, NULL);
2874 allocation.width=sheet->row_title_area.width;
2875 allocation.height=sheet->column_title_area.height;
2877 gtk_widget_size_allocate(sheet->button, &allocation);
2878 gtk_widget_show(sheet->button);
2882 global_button_clicked(GtkWidget *widget, gpointer data)
2886 gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2887 gtk_widget_grab_focus(GTK_WIDGET(data));
2892 gtk_sheet_unrealize (GtkWidget * widget)
2896 g_return_if_fail (widget != NULL);
2897 g_return_if_fail (GTK_IS_SHEET (widget));
2899 sheet = GTK_SHEET (widget);
2901 gdk_cursor_destroy (sheet->cursor_drag);
2903 gdk_gc_destroy (sheet->xor_gc);
2904 gdk_gc_destroy (sheet->fg_gc);
2905 gdk_gc_destroy (sheet->bg_gc);
2907 gdk_window_destroy (sheet->sheet_window);
2908 gdk_window_destroy (sheet->column_title_window);
2909 gdk_window_destroy (sheet->row_title_window);
2912 g_object_unref(sheet->pixmap);
2913 sheet->pixmap = NULL;
2916 sheet->column_title_window=NULL;
2917 sheet->sheet_window = NULL;
2918 sheet->cursor_drag = NULL;
2919 sheet->xor_gc = NULL;
2920 sheet->fg_gc = NULL;
2921 sheet->bg_gc = NULL;
2923 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2924 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2928 gtk_sheet_map (GtkWidget * widget)
2931 GtkSheetChild *child;
2934 g_return_if_fail (widget != NULL);
2935 g_return_if_fail (GTK_IS_SHEET (widget));
2937 sheet = GTK_SHEET (widget);
2939 if (!GTK_WIDGET_MAPPED (widget))
2941 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2943 if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2945 gdk_window_show (widget->window);
2947 gdk_window_show (sheet->sheet_window);
2949 if(sheet->column_titles_visible){
2950 size_allocate_column_title_buttons(sheet);
2951 gdk_window_show (sheet->column_title_window);
2953 if(sheet->row_titles_visible){
2954 size_allocate_row_title_buttons(sheet);
2955 gdk_window_show (sheet->row_title_window);
2958 if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)
2959 && ! gtk_sheet_locked(sheet)
2960 && sheet->active_cell.row >=0
2961 && sheet->active_cell.col >=0 )
2963 gtk_widget_show (sheet->sheet_entry);
2964 gtk_widget_map (sheet->sheet_entry);
2967 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2968 !GTK_WIDGET_MAPPED (sheet->button)){
2969 gtk_widget_show(sheet->button);
2970 gtk_widget_map (sheet->button);
2973 if(GTK_BIN(sheet->button)->child)
2974 if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2975 !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2976 gtk_widget_map (GTK_BIN(sheet->button)->child);
2978 gtk_sheet_range_draw(sheet, NULL);
2979 gtk_sheet_activate_cell(sheet,
2980 sheet->active_cell.row,
2981 sheet->active_cell.col);
2983 children = sheet->children;
2986 child = children->data;
2987 children = children->next;
2989 if (GTK_WIDGET_VISIBLE (child->widget) &&
2990 !GTK_WIDGET_MAPPED (child->widget)){
2991 gtk_widget_map (child->widget);
2992 gtk_sheet_position_child(sheet, child);
3000 gtk_sheet_unmap (GtkWidget * widget)
3003 GtkSheetChild *child;
3006 g_return_if_fail (widget != NULL);
3007 g_return_if_fail (GTK_IS_SHEET (widget));
3009 sheet = GTK_SHEET (widget);
3011 if (GTK_WIDGET_MAPPED (widget))
3013 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3015 gdk_window_hide (sheet->sheet_window);
3016 if(sheet->column_titles_visible)
3017 gdk_window_hide (sheet->column_title_window);
3018 if(sheet->row_titles_visible)
3019 gdk_window_hide (sheet->row_title_window);
3020 gdk_window_hide (widget->window);
3022 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
3023 gtk_widget_unmap (sheet->sheet_entry);
3025 if (GTK_WIDGET_MAPPED (sheet->button))
3026 gtk_widget_unmap (sheet->button);
3028 children = sheet->children;
3031 child = children->data;
3032 children = children->next;
3034 if (GTK_WIDGET_VISIBLE (child->widget) &&
3035 GTK_WIDGET_MAPPED (child->widget))
3037 gtk_widget_unmap (child->widget);
3046 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
3049 GdkGC *fg_gc, *bg_gc;
3050 GtkSheetCellAttr attributes;
3053 g_return_if_fail (sheet != NULL);
3055 /* bail now if we arn't drawable yet */
3056 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3058 if (row < 0 || row >= yyy_row_count(sheet)) return;
3059 if (col < 0 || col >= xxx_column_count(sheet)) return;
3060 if (! xxx_column_is_visible(sheet, col)) return;
3061 if (! yyy_row_is_visible(sheet, row)) return;
3063 widget = GTK_WIDGET (sheet);
3065 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3067 /* select GC for background rectangle */
3068 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3069 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3071 fg_gc = sheet->fg_gc;
3072 bg_gc = sheet->bg_gc;
3074 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3075 area.y=ROW_TOP_YPIXEL(sheet,row);
3076 area.width= xxx_column_width(sheet, col);
3077 area.height=yyy_row_height(sheet, row);
3079 gdk_draw_rectangle (sheet->pixmap,
3087 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3089 if(sheet->show_grid){
3090 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3092 gdk_draw_rectangle (sheet->pixmap,
3096 area.width, area.height);
3101 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
3104 GdkGC *fg_gc, *bg_gc;
3105 GtkSheetCellAttr attributes;
3109 g_return_if_fail (sheet != NULL);
3111 /* bail now if we arn't drawable yet */
3112 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3114 if (row < 0 || row >= yyy_row_count(sheet)) return;
3115 if (col < 0 || col >= xxx_column_count(sheet)) return;
3116 if (!xxx_column_is_visible(sheet, col)) return;
3117 if (!yyy_row_is_visible(sheet, row)) return;
3119 widget = GTK_WIDGET (sheet);
3121 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3123 /* select GC for background rectangle */
3124 gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
3125 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3127 fg_gc = sheet->fg_gc;
3128 bg_gc = sheet->bg_gc;
3130 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3131 area.y=ROW_TOP_YPIXEL(sheet,row);
3132 area.width=xxx_column_width(sheet, col);
3133 area.height=yyy_row_height(sheet, row);
3135 width = attributes.border.width;
3136 gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
3137 attributes.border.line_style,
3138 attributes.border.cap_style,
3139 attributes.border.join_style);
3142 if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
3143 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3144 area.x, area.y-width/2,
3145 area.x, area.y+area.height+width/2+1);
3147 if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
3148 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3149 area.x+area.width, area.y-width/2,
3151 area.y+area.height+width/2+1);
3153 if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
3154 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3155 area.x-width/2,area.y,
3156 area.x+area.width+width/2+1,
3159 if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
3160 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3161 area.x-width/2, area.y+area.height,
3162 area.x+area.width+width/2+1,
3163 area.y+area.height);
3170 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3173 GdkRectangle area, clip_area;
3175 gint text_width, text_height, y;
3177 gint size, sizel, sizer;
3178 GdkGC *fg_gc, *bg_gc;
3179 GtkSheetCellAttr attributes;
3180 PangoLayout *layout;
3181 PangoRectangle rect;
3182 PangoRectangle logical_rect;
3183 PangoLayoutLine *line;
3184 PangoFontMetrics *metrics;
3185 PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet));
3186 gint ascent, descent, y_pos;
3190 g_return_if_fail (sheet != NULL);
3192 /* bail now if we aren't drawable yet */
3193 if (!GTK_WIDGET_DRAWABLE (sheet))
3196 label = gtk_sheet_cell_get_text(sheet, row, col);
3200 if (row < 0 || row >= yyy_row_count(sheet)) return;
3201 if (col < 0 || col >= xxx_column_count(sheet)) return;
3202 if (! xxx_column_is_visible(sheet, col)) return;
3203 if (!yyy_row_is_visible(sheet, row)) return;
3206 widget = GTK_WIDGET(sheet);
3208 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3210 /* select GC for background rectangle */
3211 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3212 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3214 fg_gc = sheet->fg_gc;
3215 bg_gc = sheet->bg_gc;
3217 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3218 area.y=ROW_TOP_YPIXEL(sheet,row);
3219 area.width = xxx_column_width(sheet, col);
3220 area.height = yyy_row_height(sheet, row);
3224 layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
3225 dispose_string(sheet, label);
3226 pango_layout_set_font_description (layout, attributes.font_desc);
3228 pango_layout_get_pixel_extents (layout, NULL, &rect);
3230 line = pango_layout_get_lines (layout)->data;
3231 pango_layout_line_get_extents (line, NULL, &logical_rect);
3233 metrics = pango_context_get_metrics(context,
3234 attributes.font_desc,
3235 pango_context_get_language(context));
3237 ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
3238 descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
3240 pango_font_metrics_unref(metrics);
3242 /* Align primarily for locale's ascent/descent */
3244 logical_rect.height /= PANGO_SCALE;
3245 logical_rect.y /= PANGO_SCALE;
3246 y_pos = area.height - logical_rect.height;
3248 if (logical_rect.height > area.height)
3249 y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
3252 else if (y_pos + logical_rect.height > area.height)
3253 y_pos = area.height - logical_rect.height;
3255 text_width = rect.width;
3256 text_height = rect.height;
3257 y = area.y + y_pos - CELLOFFSET;
3259 switch(attributes.justification){
3260 case GTK_JUSTIFY_RIGHT:
3263 if(!gtk_sheet_clip_text(sheet)){
3264 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3265 if( !gtk_sheet_cell_empty(sheet, row, i)) break;
3266 if(size>=text_width+CELLOFFSET) break;
3267 size+=xxx_column_width(sheet, i);
3268 xxx_column_set_right_column(sheet, i,
3270 xxx_column_right_column(sheet, i)));
3275 xoffset+=area.width-text_width - 2 * CELLOFFSET -
3276 attributes.border.width/2;
3278 case GTK_JUSTIFY_CENTER:
3281 area.x+=area.width/2;
3282 if(!gtk_sheet_clip_text(sheet)){
3283 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3284 if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3285 if(sizer>=text_width/2) break;
3286 sizer+= xxx_column_width(sheet, i);
3287 xxx_column_set_left_column(sheet, i,
3290 xxx_column_left_column(sheet, i)));
3292 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3293 if( ! gtk_sheet_cell_empty(sheet, row, i)) break;
3294 if(sizel>=text_width/2) break;
3295 sizel+=xxx_column_width(sheet, i);
3296 xxx_column_set_right_column(sheet, i,
3298 xxx_column_right_column(sheet, i)));
3300 size=MIN(sizel, sizer);
3303 xoffset+= sizel - text_width/2 - CELLOFFSET;
3304 area.width=sizel+sizer;
3306 case GTK_JUSTIFY_LEFT:
3309 if(!gtk_sheet_clip_text(sheet)){
3310 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3311 if(! gtk_sheet_cell_empty(sheet, row, i)) break;
3312 if(size>=text_width+CELLOFFSET) break;
3313 size+=xxx_column_width(sheet, i);
3314 xxx_column_set_left_column(sheet, i,
3317 xxx_column_left_column(sheet, i)));
3322 xoffset += attributes.border.width/2;
3326 if(!gtk_sheet_clip_text(sheet)) clip_area = area;
3327 gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
3330 gdk_draw_layout (sheet->pixmap, fg_gc,
3331 area.x + xoffset + CELLOFFSET,
3335 gdk_gc_set_clip_rectangle(fg_gc, NULL);
3336 g_object_unref(G_OBJECT(layout));
3338 gdk_draw_pixmap(sheet->sheet_window,
3339 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3353 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
3356 GtkSheetRange drawing_range;
3359 g_return_if_fail(sheet != NULL);
3360 g_return_if_fail(GTK_SHEET(sheet));
3362 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3363 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3364 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
3368 drawing_range.row0=MIN_VISIBLE_ROW(sheet);
3369 drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
3370 drawing_range.rowi=MIN(MAX_VISIBLE_ROW(sheet), yyy_row_count(sheet) - 1);
3371 drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
3374 gdk_draw_rectangle (sheet->pixmap,
3375 GTK_WIDGET(sheet)->style->white_gc,
3378 sheet->sheet_window_width,sheet->sheet_window_height);
3383 drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3384 drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3385 drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3386 drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3390 if(drawing_range.coli == xxx_column_count(sheet) - 1)
3392 area.x=COLUMN_LEFT_XPIXEL(sheet,
3393 xxx_column_count(sheet) - 1) +
3394 xxx_column_width(sheet, xxx_column_count(sheet) - 1) + 1;
3398 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3400 gdk_draw_rectangle (sheet->pixmap,
3404 sheet->sheet_window_width - area.x,
3405 sheet->sheet_window_height);
3407 gdk_draw_pixmap(sheet->sheet_window,
3408 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3414 sheet->sheet_window_width - area.x,
3415 sheet->sheet_window_height);
3418 if(drawing_range.rowi == yyy_row_count(sheet) - 1){
3420 area.y=ROW_TOP_YPIXEL(sheet,
3421 yyy_row_count(sheet) - 1) +
3422 yyy_row_height(sheet, yyy_row_count(sheet) - 1) + 1;
3424 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3426 gdk_draw_rectangle (sheet->pixmap,
3430 sheet->sheet_window_width,
3431 sheet->sheet_window_height - area.y);
3433 gdk_draw_pixmap(sheet->sheet_window,
3434 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3440 sheet->sheet_window_width,
3441 sheet->sheet_window_height - area.y);
3444 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3445 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3446 gtk_sheet_cell_draw_default(sheet, i, j);
3449 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3450 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3451 gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3452 gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3453 gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3454 gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3455 gtk_sheet_cell_draw_border(sheet, i, j, 15);
3458 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3459 for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3460 gtk_sheet_cell_draw_label (sheet, i, j);
3462 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3463 for(j= xxx_column_left_column(sheet, drawing_range.col0);
3464 j<drawing_range.col0; j++)
3465 gtk_sheet_cell_draw_label (sheet, i, j);
3467 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3468 for(j = drawing_range.coli+1;
3469 j <= xxx_column_right_column(sheet, drawing_range.coli);
3471 gtk_sheet_cell_draw_label (sheet, i, j);
3473 gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3475 if(sheet->state != GTK_SHEET_NORMAL &&
3476 gtk_sheet_range_isvisible(sheet, sheet->range))
3477 gtk_sheet_range_draw_selection(sheet, drawing_range);
3479 if(sheet->state == GTK_STATE_NORMAL &&
3480 sheet->active_cell.row >= drawing_range.row0 &&
3481 sheet->active_cell.row <= drawing_range.rowi &&
3482 sheet->active_cell.col >= drawing_range.col0 &&
3483 sheet->active_cell.col <= drawing_range.coli)
3484 gtk_sheet_show_active_cell(sheet);
3489 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3495 if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3496 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3499 if(!gtk_sheet_range_isvisible(sheet, range)) return;
3500 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3504 range.col0=MAX(sheet->range.col0, range.col0);
3505 range.coli=MIN(sheet->range.coli, range.coli);
3506 range.row0=MAX(sheet->range.row0, range.row0);
3507 range.rowi=MIN(sheet->range.rowi, range.rowi);
3509 range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3510 range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3511 range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3512 range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3514 for(i=range.row0; i<=range.rowi; i++){
3515 for(j=range.col0; j<=range.coli; j++){
3517 if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED &&
3518 xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
3521 row_button_set(sheet, i);
3522 column_button_set(sheet, j);
3525 area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3526 area.y=ROW_TOP_YPIXEL(sheet,i);
3527 area.width= xxx_column_width(sheet, j);
3528 area.height=yyy_row_height(sheet, i);
3530 if(i==sheet->range.row0)
3533 area.height=area.height-2;
3535 if(i==sheet->range.rowi) area.height=area.height-3;
3536 if(j==sheet->range.col0)
3539 area.width=area.width-2;
3541 if(j==sheet->range.coli) area.width=area.width-3;
3543 if(i!=sheet->active_cell.row || j!=sheet->active_cell.col)
3545 gdk_draw_rectangle (sheet->sheet_window,
3549 area.width,area.height);
3556 gtk_sheet_draw_border(sheet, sheet->range);
3560 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3562 gint x,y,width,height;
3564 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3566 x = COLUMN_LEFT_XPIXEL(sheet,range.col0);
3567 y = ROW_TOP_YPIXEL(sheet, range.row0);
3568 width = COLUMN_LEFT_XPIXEL(sheet, range.coli) - x +
3569 xxx_column_width(sheet, range.coli);
3571 height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+yyy_row_height(sheet, range.rowi);
3573 if(range.row0 == sheet->range.row0)
3578 if(range.rowi==sheet->range.rowi) height = height + 5;
3579 if(range.col0==sheet->range.col0)
3584 if(range.coli == sheet->range.coli) width = width + 5;
3586 width = MIN(width, sheet->sheet_window_width - x);
3587 height = MIN(height, sheet->sheet_window_height - y);
3594 x = (sheet->row_titles_visible)
3595 ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3596 y = (sheet->column_titles_visible)
3597 ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3599 if(range.coli == xxx_column_count(sheet) - 1)
3600 width = sheet->sheet_window_width - x;
3601 if(range.rowi == yyy_row_count(sheet) - 1)
3602 height=sheet->sheet_window_height - y;
3604 gdk_draw_pixmap(sheet->sheet_window,
3605 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3617 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3619 GtkSheetCellAttr attributes;
3621 g_return_if_fail (sheet != NULL);
3622 g_return_if_fail (GTK_IS_SHEET (sheet));
3623 if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3624 if (col < 0 || row < 0) return;
3626 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3627 gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3631 safe_strcmp(const gchar *s1, const gchar *s2)
3633 if ( !s1 && !s2) return 0;
3634 if ( !s1) return -1;
3635 if ( !s2) return +1;
3636 return strcmp(s1, s2);
3640 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col,
3641 GtkJustification justification,
3644 GSheetModel *model ;
3648 GtkSheetRange range;
3650 GtkSheetCellAttr attributes;
3652 g_return_if_fail (sheet != NULL);
3653 g_return_if_fail (GTK_IS_SHEET (sheet));
3654 if (col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3655 if (col < 0 || row < 0) return;
3657 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3659 attributes.justification = justification;
3661 model = gtk_sheet_get_model(sheet);
3663 old_text = g_sheet_model_get_string(model, row, col);
3667 if (0 != safe_strcmp(old_text, text))
3668 changed = g_sheet_model_set_string(model, text, row, col);
3670 if ( g_sheet_model_free_strings(model))
3674 if(changed && attributes.is_visible)
3676 gchar *s = gtk_sheet_cell_get_text(sheet, row, col);
3678 if(s && strlen(s) > 0) {
3679 text_width = STRING_WIDTH(GTK_WIDGET(sheet),
3680 attributes.font_desc, text);
3682 dispose_string(sheet, s);
3686 range.col0 = sheet->view.col0;
3687 range.coli = sheet->view.coli;
3689 if(gtk_sheet_autoresize(sheet) &&
3690 text_width > xxx_column_width(sheet, col) - 2*CELLOFFSET-attributes.border.width){
3691 gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3692 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3695 if(!GTK_SHEET_IS_FROZEN(sheet))
3696 gtk_sheet_range_draw(sheet, &range);
3700 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3706 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3708 GtkSheetRange range;
3710 g_return_if_fail (sheet != NULL);
3711 g_return_if_fail (GTK_IS_SHEET (sheet));
3712 if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3713 if (column < 0 || row < 0) return;
3717 range.col0 = sheet->view.col0;
3718 range.coli = sheet->view.coli;
3720 gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3722 if(!GTK_SHEET_IS_FROZEN(sheet)){
3723 gtk_sheet_range_draw(sheet, &range);
3728 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3730 GtkSheetRange range;
3732 g_return_if_fail (sheet != NULL);
3733 g_return_if_fail (GTK_IS_SHEET (sheet));
3734 if (column >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return;
3735 if (column < 0 || row < 0) return;
3739 range.col0 = sheet->view.col0;
3740 range.coli = sheet->view.coli;
3742 gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3744 if(!GTK_SHEET_IS_FROZEN(sheet)){
3745 gtk_sheet_range_draw(sheet, &range);
3750 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3752 GSheetModel *model = gtk_sheet_get_model(sheet);
3754 gchar *old_text = gtk_sheet_cell_get_text(sheet, row, column);
3756 if (old_text && strlen(old_text) > 0 )
3758 g_sheet_model_datum_clear(model, row, column);
3760 if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3761 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL],
3765 dispose_string (sheet, old_text);
3769 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3771 g_return_if_fail (sheet != NULL);
3772 g_return_if_fail (GTK_IS_SHEET (sheet));
3774 gtk_sheet_real_range_clear(sheet, range, FALSE);
3778 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3780 g_return_if_fail (sheet != NULL);
3781 g_return_if_fail (GTK_IS_SHEET (sheet));
3783 gtk_sheet_real_range_clear(sheet, range, TRUE);
3788 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range,
3792 GtkSheetRange clear;
3796 clear.rowi = yyy_row_count(sheet) - 1;
3798 clear.coli = xxx_column_count(sheet) - 1;
3802 clear.row0=MAX(clear.row0, 0);
3803 clear.col0=MAX(clear.col0, 0);
3804 clear.rowi=MIN(clear.rowi, yyy_row_count(sheet) - 1 );
3805 clear.coli=MIN(clear.coli, xxx_column_count(sheet) - 1 );
3807 for(i=clear.row0; i<=clear.rowi; i++)
3808 for(j=clear.col0; j<=clear.coli; j++){
3809 gtk_sheet_real_cell_clear(sheet, i, j, delete);
3812 gtk_sheet_range_draw(sheet, NULL);
3817 gtk_sheet_cell_empty (const GtkSheet *sheet, gint row, gint col)
3820 char *text = gtk_sheet_cell_get_text(sheet, row, col);
3821 empty = (text == NULL );
3823 dispose_string(sheet, text);
3830 gtk_sheet_cell_get_text (const GtkSheet *sheet, gint row, gint col)
3833 g_return_val_if_fail (sheet != NULL, NULL);
3834 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3836 if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet))
3838 if(col < 0 || row < 0) return NULL;
3840 model = gtk_sheet_get_model(sheet);
3845 return g_sheet_model_get_string(model, row, col);
3850 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3853 GtkSheetRange *range;
3855 g_return_val_if_fail (sheet != NULL, 0);
3856 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3857 if(col >= xxx_column_count(sheet) || row >= yyy_row_count(sheet)) return 0;
3858 if(col < 0 || row < 0) return 0;
3860 state = sheet->state;
3861 range = &sheet->range;
3865 case GTK_SHEET_NORMAL:
3866 return GTK_STATE_NORMAL;
3868 case GTK_SHEET_ROW_SELECTED:
3869 if(row>=range->row0 && row<=range->rowi)
3870 return GTK_STATE_SELECTED;
3872 case GTK_SHEET_COLUMN_SELECTED:
3873 if(col>=range->col0 && col<=range->coli)
3874 return GTK_STATE_SELECTED;
3876 case GTK_SHEET_RANGE_SELECTED:
3877 if(row >= range->row0 && row <= range->rowi && \
3878 col >= range->col0 && col <= range->coli)
3879 return GTK_STATE_SELECTED;
3882 return GTK_STATE_NORMAL;
3886 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3894 g_return_val_if_fail (sheet != NULL, 0);
3895 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3897 /* bounds checking, return false if the user clicked
3898 * on a blank area */
3899 trow = ROW_FROM_YPIXEL (sheet, y);
3900 if (trow >= yyy_row_count(sheet))
3905 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3906 if (tcol >= xxx_column_count(sheet))
3915 gtk_sheet_get_cell_area (GtkSheet * sheet,
3920 g_return_val_if_fail (sheet != NULL, 0);
3921 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3923 if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet))
3926 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3927 (sheet->row_titles_visible
3928 ? sheet->row_title_area.width
3930 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3931 (sheet->column_titles_visible
3932 ? sheet->column_title_area.height
3934 area->width= (column == -1) ? sheet->row_title_area.width
3935 : xxx_column_width(sheet, column);
3937 area->height= (row == -1) ? sheet->column_title_area.height
3938 : yyy_row_height(sheet, row);
3941 if(row < 0 || column < 0) return FALSE;
3943 area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3944 area->y = ROW_TOP_YPIXEL(sheet, row);
3945 if(sheet->row_titles_visible)
3946 area->x -= sheet->row_title_area.width;
3947 if(sheet->column_titles_visible)
3948 area->y -= sheet->column_title_area.height;
3950 area->width=sheet->column[column].width;
3951 area->height=yyy_row_height(sheet, row);
3957 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3959 g_return_val_if_fail (sheet != NULL, 0);
3960 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3962 if(row < -1 || column < -1) return FALSE;
3963 if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet))
3966 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3968 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3971 sheet->active_cell.row = row;
3972 sheet->active_cell.col = column;
3974 if ( row == -1 || column == -1)
3976 gtk_sheet_hide_active_cell(sheet);
3980 if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3982 if(gtk_sheet_autoscroll(sheet))
3983 gtk_sheet_move_query(sheet, row, column);
3989 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3991 g_return_if_fail (sheet != NULL);
3992 g_return_if_fail (GTK_IS_SHEET (sheet));
3994 *row = sheet->active_cell.row;
3995 *column = sheet->active_cell.col;
3999 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
4004 GtkJustification justification;
4005 GtkSheetCellAttr attributes;
4007 g_return_if_fail (data != NULL);
4008 g_return_if_fail (GTK_IS_SHEET (data));
4010 sheet=GTK_SHEET(data);
4012 if(!GTK_WIDGET_VISIBLE(widget)) return;
4013 if(sheet->state != GTK_STATE_NORMAL) return;
4015 row=sheet->active_cell.row;
4016 col=sheet->active_cell.col;
4018 if(row<0 || col<0) return;
4020 sheet->active_cell.row=-1;
4021 sheet->active_cell.col=-1;
4023 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4025 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4027 if(text && strlen(text) > 0)
4029 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4030 justification = attributes.justification;
4031 gtk_sheet_set_cell(sheet, row, col, justification, text);
4034 if(sheet->freeze_count == 0)
4035 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4037 sheet->active_cell.row=row;;
4038 sheet->active_cell.col=col;
4043 gtk_sheet_deactivate_cell(GtkSheet *sheet)
4045 gboolean veto = TRUE;
4047 g_return_val_if_fail (sheet != NULL, FALSE);
4048 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4050 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
4051 if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
4053 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE],
4054 sheet->active_cell.row,
4055 sheet->active_cell.col, &veto);
4057 if(!veto) return FALSE;
4059 if ( sheet->active_cell.row == -1 || sheet->active_cell.col == -1 )
4062 gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
4063 (GtkSignalFunc) gtk_sheet_entry_changed,
4064 GTK_OBJECT(GTK_WIDGET(sheet)));
4066 gtk_sheet_hide_active_cell(sheet);
4067 sheet->active_cell.row = -1;
4068 sheet->active_cell.col = -1;
4070 if(GTK_SHEET_REDRAW_PENDING(sheet)){
4071 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
4072 gtk_sheet_range_draw(sheet, NULL);
4079 gtk_sheet_hide_active_cell(GtkSheet *sheet)
4083 GtkJustification justification;
4084 GtkSheetCellAttr attributes;
4086 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4088 row=sheet->active_cell.row;
4089 col=sheet->active_cell.col;
4091 if(row < 0 || col < 0) return;
4093 if(sheet->freeze_count == 0)
4094 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4096 text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4098 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4099 justification=attributes.justification;
4101 if(text && strlen(text) != 0)
4103 gtk_sheet_set_cell(sheet, row, col, justification, text);
4104 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
4108 gtk_sheet_cell_clear(sheet, row, col);
4111 row=sheet->active_cell.row;
4112 col=sheet->active_cell.col;
4115 column_button_release(sheet, col);
4116 row_button_release(sheet, row);
4119 gtk_widget_hide(sheet->sheet_entry);
4120 gtk_widget_unmap(sheet->sheet_entry);
4122 if(row != -1 && col != -1)
4123 gdk_draw_pixmap(sheet->sheet_window,
4124 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4126 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4127 ROW_TOP_YPIXEL(sheet,row)-1,
4128 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4129 ROW_TOP_YPIXEL(sheet,row)-1,
4130 xxx_column_width(sheet, col) + 4,
4131 yyy_row_height(sheet, row)+4);
4133 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4135 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4140 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
4142 gboolean veto = TRUE;
4144 g_return_val_if_fail (sheet != NULL, FALSE);
4145 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4147 if(row < 0 || col < 0) return FALSE;
4148 if(row >= yyy_row_count(sheet) || col >= xxx_column_count(sheet))
4151 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4152 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
4155 if(!veto) return FALSE;
4156 if(sheet->state != GTK_SHEET_NORMAL){
4157 sheet->state=GTK_SHEET_NORMAL;
4158 gtk_sheet_real_unselect_range(sheet, NULL);
4161 sheet->range.row0 = row;
4162 sheet->range.col0 = col;
4163 sheet->range.rowi = row;
4164 sheet->range.coli = col;
4165 sheet->active_cell.row = row;
4166 sheet->active_cell.col = col;
4167 sheet->selection_cell.row = row;
4168 sheet->selection_cell.col = col;
4170 row_button_set(sheet, row);
4171 column_button_set(sheet, col);
4174 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4175 gtk_sheet_show_active_cell(sheet);
4177 g_signal_connect(G_OBJECT(gtk_sheet_get_entry(sheet)),
4179 G_CALLBACK(gtk_sheet_entry_changed),
4182 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4188 gtk_sheet_show_active_cell(GtkSheet *sheet)
4190 GtkEntry *sheet_entry;
4191 GtkSheetCellAttr attributes;
4193 const gchar *old_text;
4194 GtkJustification justification;
4197 g_return_if_fail (sheet != NULL);
4198 g_return_if_fail (GTK_IS_SHEET (sheet));
4200 row = sheet->active_cell.row;
4201 col = sheet->active_cell.col;
4203 /* Don't show the active cell, if there is no active cell: */
4204 if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4207 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4208 if(sheet->state != GTK_SHEET_NORMAL) return;
4209 if(GTK_SHEET_IN_SELECTION(sheet)) return;
4211 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4213 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4215 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4217 justification = GTK_JUSTIFY_LEFT;
4219 if(gtk_sheet_justify_entry(sheet))
4220 justification = attributes.justification;
4222 text = gtk_sheet_cell_get_text(sheet, row, col);
4224 text = g_strdup("");
4226 gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4228 if(gtk_sheet_locked(sheet) || !attributes.is_editable)
4229 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4231 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4233 /*** Added by John Gotts. Mar 25, 2005 *********/
4234 old_text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
4235 if (strcmp(old_text, text) != 0)
4237 if(!GTK_IS_ITEM_ENTRY(sheet_entry))
4238 gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4240 gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), text, justification);
4243 gtk_sheet_entry_set_max_size(sheet);
4244 gtk_sheet_size_allocate_entry(sheet);
4246 gtk_widget_map(sheet->sheet_entry);
4247 gtk_sheet_draw_active_cell(sheet);
4249 gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4251 dispose_string(sheet, text);
4255 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4259 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4260 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4262 row = sheet->active_cell.row;
4263 col = sheet->active_cell.col;
4265 if(row < 0 || col < 0) return;
4267 if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4269 row_button_set(sheet, row);
4270 column_button_set(sheet, col);
4272 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4273 gtk_sheet_draw_border(sheet, sheet->range);
4278 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4280 gint pixmap_width, pixmap_height;
4282 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4284 if(width == 0 && height == 0){
4285 width=sheet->sheet_window_width+80;
4286 height=sheet->sheet_window_height+80;
4292 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4295 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4299 /* reallocate if sizes don't match */
4300 gdk_window_get_size (sheet->pixmap,
4301 &pixmap_width, &pixmap_height);
4302 if ((pixmap_width != width) || (pixmap_height != height))
4304 g_object_unref(sheet->pixmap);
4305 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4308 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4314 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4316 gint i,j, mask1, mask2;
4317 gint state, selected;
4318 gint x,y,width,height;
4319 GtkSheetRange new_range, aux_range;
4321 g_return_if_fail (sheet != NULL);
4323 if(range==NULL) range=&sheet->range;
4327 range->row0=MIN(range->row0, sheet->range.row0);
4328 range->rowi=MAX(range->rowi, sheet->range.rowi);
4329 range->col0=MIN(range->col0, sheet->range.col0);
4330 range->coli=MAX(range->coli, sheet->range.coli);
4332 range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4333 range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4334 range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4335 range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4337 aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4338 aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4339 aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4340 aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4342 for(i=range->row0; i<=range->rowi; i++){
4343 for(j=range->col0; j<=range->coli; j++){
4345 state=gtk_sheet_cell_get_state(sheet, i, j);
4346 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4347 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4349 if(state==GTK_STATE_SELECTED && selected &&
4350 xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4351 (i==sheet->range.row0 || i==sheet->range.rowi ||
4352 j==sheet->range.col0 || j==sheet->range.coli ||
4353 i==new_range.row0 || i==new_range.rowi ||
4354 j==new_range.col0 || j==new_range.coli)){
4356 mask1 = i==sheet->range.row0 ? 1 : 0;
4357 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4358 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4359 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4361 mask2 = i==new_range.row0 ? 1 : 0;
4362 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4363 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4364 mask2 = j==new_range.coli ? mask2+8 : mask2;
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);
4371 height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4373 if(i==sheet->range.row0){
4377 if(i==sheet->range.rowi) height=height+3;
4378 if(j==sheet->range.col0){
4382 if(j==sheet->range.coli) width=width+3;
4384 gdk_draw_pixmap(sheet->sheet_window,
4385 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4394 if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4395 x=COLUMN_LEFT_XPIXEL(sheet,j);
4396 y=ROW_TOP_YPIXEL(sheet, i);
4397 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+
4398 xxx_column_width(sheet, j);
4400 height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4402 if(i==new_range.row0){
4406 if(i==new_range.rowi) height=height-3;
4407 if(j==new_range.col0){
4411 if(j==new_range.coli) width=width-3;
4413 gdk_draw_rectangle (sheet->sheet_window,
4424 for(i=range->row0; i<=range->rowi; i++){
4425 for(j=range->col0; j<=range->coli; j++){
4427 state=gtk_sheet_cell_get_state(sheet, i, j);
4428 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4429 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4431 if(state==GTK_STATE_SELECTED && !selected &&
4432 xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4434 x=COLUMN_LEFT_XPIXEL(sheet,j);
4435 y=ROW_TOP_YPIXEL(sheet, i);
4436 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4437 height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4439 if(i==sheet->range.row0){
4443 if(i==sheet->range.rowi) height=height+3;
4444 if(j==sheet->range.col0){
4448 if(j==sheet->range.coli) width=width+3;
4450 gdk_draw_pixmap(sheet->sheet_window,
4451 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4463 for(i=range->row0; i<=range->rowi; i++){
4464 for(j=range->col0; j<=range->coli; j++){
4466 state=gtk_sheet_cell_get_state(sheet, i, j);
4467 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4468 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4470 if(state!=GTK_STATE_SELECTED && selected &&
4471 xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i) &&
4472 (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4474 x=COLUMN_LEFT_XPIXEL(sheet,j);
4475 y=ROW_TOP_YPIXEL(sheet, i);
4476 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+ xxx_column_width(sheet, j);
4477 height=ROW_TOP_YPIXEL(sheet, i)-y+yyy_row_height(sheet, i);
4479 if(i==new_range.row0){
4483 if(i==new_range.rowi) height=height-3;
4484 if(j==new_range.col0){
4488 if(j==new_range.coli) width=width-3;
4490 gdk_draw_rectangle (sheet->sheet_window,
4501 for(i=aux_range.row0; i<=aux_range.rowi; i++){
4502 for(j=aux_range.col0; j<=aux_range.coli; j++){
4504 if(xxx_column_is_visible(sheet, j) && yyy_row_is_visible(sheet, i)){
4506 state=gtk_sheet_cell_get_state(sheet, i, j);
4508 mask1 = i==sheet->range.row0 ? 1 : 0;
4509 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4510 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4511 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4513 mask2 = i==new_range.row0 ? 1 : 0;
4514 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4515 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4516 mask2 = j==new_range.coli ? mask2+8 : mask2;
4517 if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4518 x=COLUMN_LEFT_XPIXEL(sheet,j);
4519 y=ROW_TOP_YPIXEL(sheet, i);
4520 width=xxx_column_width(sheet, j);
4521 height=yyy_row_height(sheet, i);
4523 gdk_draw_rectangle (sheet->sheet_window,
4531 gdk_draw_rectangle (sheet->sheet_window,
4538 gdk_draw_rectangle (sheet->sheet_window,
4546 gdk_draw_rectangle (sheet->sheet_window,
4563 gtk_sheet_draw_corners(sheet, new_range);
4568 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4573 gint x,y,width,height;
4575 widget = GTK_WIDGET(sheet);
4577 x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4578 y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4579 width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+
4580 xxx_column_width(sheet, new_range.coli);
4582 height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4583 yyy_row_height(sheet, new_range.rowi);
4585 area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4586 area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4587 area.width=sheet->sheet_window_width;
4588 area.height=sheet->sheet_window_height;
4594 if(width>area.width) width=area.width+10;
4599 if(height>area.height) height=area.height+10;
4601 gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4603 for(i=-1; i<=1; ++i)
4604 gdk_draw_rectangle (sheet->sheet_window,
4608 width-2*i,height-2*i);
4610 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4612 gtk_sheet_draw_corners(sheet, new_range);
4617 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4622 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4623 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4624 y=ROW_TOP_YPIXEL(sheet,range.row0);
4625 gdk_draw_pixmap(sheet->sheet_window,
4626 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4634 gdk_draw_rectangle (sheet->sheet_window,
4641 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4642 sheet->state == GTK_SHEET_COLUMN_SELECTED){
4643 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4644 xxx_column_width(sheet, range.coli);
4645 y=ROW_TOP_YPIXEL(sheet,range.row0);
4647 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4649 y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4652 gdk_draw_pixmap(sheet->sheet_window,
4653 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4661 gdk_draw_rectangle (sheet->sheet_window,
4664 x-width+width/2,y-width+width/2,
4668 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4669 sheet->state == GTK_SHEET_ROW_SELECTED){
4670 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4671 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4672 yyy_row_height(sheet, range.rowi);
4674 if(sheet->state == GTK_SHEET_ROW_SELECTED)
4676 x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4679 gdk_draw_pixmap(sheet->sheet_window,
4680 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4688 gdk_draw_rectangle (sheet->sheet_window,
4691 x-width+width/2,y-width+width/2,
4695 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4696 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4697 xxx_column_width(sheet, range.coli);
4698 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4699 yyy_row_height(sheet, range.rowi);
4701 if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4702 if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4703 gdk_draw_pixmap(sheet->sheet_window,
4704 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4712 gdk_draw_rectangle (sheet->sheet_window,
4715 x-width+width/2,y-width+width/2,
4724 gtk_sheet_real_select_range (GtkSheet * sheet,
4725 const GtkSheetRange * range)
4729 g_return_if_fail (sheet != NULL);
4731 if(range == NULL) range = &sheet->range;
4733 memcpy(&sheet->range, range, sizeof(*range));
4735 if(range->row0 < 0 || range->rowi < 0) return;
4736 if(range->col0 < 0 || range->coli < 0) return;
4738 state = sheet->state;
4740 if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4741 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4743 gtk_sheet_new_selection(sheet, &sheet->range);
4747 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4748 gtk_sheet_range_draw_selection(sheet, sheet->range);
4751 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], &sheet->range);
4755 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4757 g_return_if_fail (sheet != NULL);
4759 if(range==NULL) range=&sheet->range;
4761 if(range->row0 < 0 || range->rowi < 0) return;
4762 if(range->col0 < 0 || range->coli < 0) return;
4765 if ( gtk_sheet_locked(sheet)) return ;
4767 if(sheet->state != GTK_SHEET_NORMAL)
4768 gtk_sheet_real_unselect_range(sheet, NULL);
4771 gboolean veto = TRUE;
4772 veto = gtk_sheet_deactivate_cell(sheet);
4776 sheet->range.row0=range->row0;
4777 sheet->range.rowi=range->rowi;
4778 sheet->range.col0=range->col0;
4779 sheet->range.coli=range->coli;
4780 sheet->active_cell.row=range->row0;
4781 sheet->active_cell.col=range->col0;
4782 sheet->selection_cell.row=range->rowi;
4783 sheet->selection_cell.col=range->coli;
4785 sheet->state = GTK_SHEET_RANGE_SELECTED;
4786 gtk_sheet_real_select_range(sheet, NULL);
4791 gtk_sheet_unselect_range (GtkSheet * sheet)
4793 gtk_sheet_real_unselect_range(sheet, NULL);
4794 sheet->state = GTK_STATE_NORMAL;
4795 gtk_sheet_activate_cell(sheet,
4796 sheet->active_cell.row, sheet->active_cell.col);
4801 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4802 const GtkSheetRange *range)
4804 g_return_if_fail (sheet != NULL);
4805 g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4808 range = &sheet->range;
4810 if(range->row0 < 0 || range->rowi < 0) return;
4811 if(range->col0 < 0 || range->coli < 0) return;
4813 if (gtk_sheet_range_isvisible (sheet, *range))
4814 gtk_sheet_draw_backing_pixmap(sheet, *range);
4817 for(i=range->col0; i<=range->coli; i++){
4818 column_button_release(sheet, i);
4821 for(i=range->row0; i<=range->rowi; i++){
4822 row_button_release(sheet, i);
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);
4846 sheet = GTK_SHEET (widget);
4848 if (GTK_WIDGET_DRAWABLE (widget))
4850 range.row0 = ROW_FROM_YPIXEL(sheet, event->area.y);
4851 range.col0 = COLUMN_FROM_XPIXEL(sheet, event->area.x);
4852 range.rowi = ROW_FROM_YPIXEL(sheet, event->area.y + event->area.height);
4853 range.coli = COLUMN_FROM_XPIXEL(sheet, event->area.x + event->area.width);
4855 /* exposure events on the sheet */
4856 if(event->window == sheet->row_title_window &&
4857 sheet->row_titles_visible)
4860 for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
4861 gtk_sheet_row_title_button_draw(sheet, i);
4864 if(event->window == sheet->column_title_window &&
4865 sheet->column_titles_visible)
4868 for(i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
4869 gtk_sheet_column_title_button_draw(sheet, i);
4872 if (event->window == sheet->sheet_window)
4874 gtk_sheet_draw_backing_pixmap(sheet, range);
4876 if(sheet->state != GTK_SHEET_NORMAL)
4878 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4879 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4880 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4881 gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4883 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4884 gtk_sheet_range_draw_selection(sheet, sheet->range);
4885 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4886 draw_xor_rectangle(sheet, sheet->drag_range);
4889 if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet)))
4891 if(sheet->state == GTK_SHEET_NORMAL){
4892 gtk_sheet_draw_active_cell(sheet);
4893 if(!GTK_SHEET_IN_SELECTION(sheet))
4894 gtk_widget_queue_draw(sheet->sheet_entry);
4900 if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4901 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4903 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4910 gtk_sheet_button_press (GtkWidget * widget,
4911 GdkEventButton * event)
4914 GdkModifierType mods;
4915 gint x, y, row, column;
4918 g_return_val_if_fail (widget != NULL, FALSE);
4919 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4920 g_return_val_if_fail (event != NULL, FALSE);
4922 sheet = GTK_SHEET (widget);
4924 if ( event->type == GDK_2BUTTON_PRESS)
4926 gtk_widget_get_pointer (widget, &x, &y);
4927 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4929 if (event->window == sheet->column_title_window )
4931 gtk_signal_emit (GTK_OBJECT (sheet),
4932 sheet_signals[DOUBLE_CLICK_COLUMN], column);
4934 else if (event->window == sheet->row_title_window )
4936 gtk_signal_emit (GTK_OBJECT (sheet),
4937 sheet_signals[DOUBLE_CLICK_ROW], row);
4943 if(event->type != GDK_BUTTON_PRESS) return TRUE;
4945 gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4947 if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4950 /* press on resize windows */
4951 if (event->window == sheet->column_title_window &&
4952 gtk_sheet_columns_resizable(sheet))
4954 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4955 if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4957 if (event->type == GDK_2BUTTON_PRESS){
4958 gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
4959 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_XDRAG);
4962 gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4963 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4964 gdk_pointer_grab (sheet->column_title_window, FALSE,
4965 GDK_POINTER_MOTION_HINT_MASK |
4966 GDK_BUTTON1_MOTION_MASK |
4967 GDK_BUTTON_RELEASE_MASK,
4968 NULL, NULL, event->time);
4970 draw_xor_vline (sheet);
4975 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4977 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4979 if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4981 gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4982 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4983 gdk_pointer_grab (sheet->row_title_window, FALSE,
4984 GDK_POINTER_MOTION_HINT_MASK |
4985 GDK_BUTTON1_MOTION_MASK |
4986 GDK_BUTTON_RELEASE_MASK,
4987 NULL, NULL, event->time);
4989 draw_xor_hline (sheet);
4994 /* the sheet itself does not handle other than single click events */
4995 if(event->type != GDK_BUTTON_PRESS) return FALSE;
4997 /* selections on the sheet */
4998 if(event->window == sheet->sheet_window){
4999 gtk_widget_get_pointer (widget, &x, &y);
5000 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5001 gdk_pointer_grab (sheet->sheet_window, FALSE,
5002 GDK_POINTER_MOTION_HINT_MASK |
5003 GDK_BUTTON1_MOTION_MASK |
5004 GDK_BUTTON_RELEASE_MASK,
5005 NULL, NULL, event->time);
5006 gtk_grab_add(GTK_WIDGET(sheet));
5007 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5008 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5010 if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
5011 sheet->cursor_drag->type==GDK_SIZING &&
5012 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
5013 if(sheet->state==GTK_STATE_NORMAL) {
5014 row=sheet->active_cell.row;
5015 column=sheet->active_cell.col;
5016 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
5017 sheet->active_cell.row=row;
5018 sheet->active_cell.col=column;
5019 sheet->drag_range=sheet->range;
5020 sheet->state=GTK_SHEET_RANGE_SELECTED;
5021 gtk_sheet_select_range(sheet, &sheet->drag_range);
5025 if(row > sheet->range.rowi) row--;
5026 if(column > sheet->range.coli) column--;
5027 sheet->drag_cell.row = row;
5028 sheet->drag_cell.col = column;
5029 sheet->drag_range=sheet->range;
5030 draw_xor_rectangle(sheet, sheet->drag_range);
5031 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5033 else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
5034 !GTK_SHEET_IN_SELECTION(sheet)
5035 && ! GTK_SHEET_IN_DRAG(sheet)
5036 && ! gtk_sheet_locked(sheet)
5037 && sheet->active_cell.row >= 0
5038 && sheet->active_cell.col >= 0
5041 if(sheet->state==GTK_STATE_NORMAL) {
5042 row=sheet->active_cell.row;
5043 column=sheet->active_cell.col;
5044 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
5045 sheet->active_cell.row=row;
5046 sheet->active_cell.col=column;
5047 sheet->drag_range=sheet->range;
5048 sheet->state=GTK_SHEET_RANGE_SELECTED;
5049 gtk_sheet_select_range(sheet, &sheet->drag_range);
5053 if(row < sheet->range.row0) row++;
5054 if(row > sheet->range.rowi) row--;
5055 if(column < sheet->range.col0) column++;
5056 if(column > sheet->range.coli) column--;
5057 sheet->drag_cell.row=row;
5058 sheet->drag_cell.col=column;
5059 sheet->drag_range=sheet->range;
5060 draw_xor_rectangle(sheet, sheet->drag_range);
5061 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5065 gtk_sheet_click_cell(sheet, row, column, &veto);
5066 if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5070 if(event->window == sheet->column_title_window){
5071 gtk_widget_get_pointer (widget, &x, &y);
5072 column = COLUMN_FROM_XPIXEL(sheet, x);
5073 if(xxx_column_is_sensitive(sheet, column)){
5074 gtk_sheet_click_cell(sheet, -1, column, &veto);
5075 gtk_grab_add(GTK_WIDGET(sheet));
5076 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5077 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5078 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5082 if(event->window == sheet->row_title_window){
5083 gtk_widget_get_pointer (widget, &x, &y);
5084 row = ROW_FROM_YPIXEL(sheet, y);
5085 if(yyy_row_is_sensitive(sheet, row)){
5086 gtk_sheet_click_cell(sheet, row, -1, &veto);
5087 gtk_grab_add(GTK_WIDGET(sheet));
5088 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5089 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5090 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5098 gtk_sheet_scroll(gpointer data)
5101 gint x,y,row,column;
5104 sheet=GTK_SHEET(data);
5106 GDK_THREADS_ENTER();
5108 gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
5109 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5113 if(GTK_SHEET_IN_SELECTION(sheet))
5114 gtk_sheet_extend_selection(sheet, row, column);
5116 if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
5117 move=gtk_sheet_move_query(sheet, row, column);
5118 if(move) draw_xor_rectangle(sheet, sheet->drag_range);
5121 GDK_THREADS_LEAVE();
5128 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
5132 if(row >= yyy_row_count(sheet) || column >= xxx_column_count(sheet)){
5137 if(column >= 0 && row >= 0)
5138 if(! xxx_column_is_visible(sheet, column) || !yyy_row_is_visible(sheet, row))
5144 _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
5145 sheet->active_cell.row, sheet->active_cell.col,
5146 &row, &column, veto);
5149 if(sheet->state == GTK_STATE_NORMAL) return;
5151 row = sheet->active_cell.row;
5152 column = sheet->active_cell.col;
5154 gtk_sheet_activate_cell(sheet, row, column);
5158 if(row == -1 && column >= 0){
5159 if(gtk_sheet_autoscroll(sheet))
5160 gtk_sheet_move_query(sheet, row, column);
5161 gtk_sheet_select_column(sheet, column);
5164 if(column == -1 && row >= 0){
5165 if(gtk_sheet_autoscroll(sheet))
5166 gtk_sheet_move_query(sheet, row, column);
5167 gtk_sheet_select_row(sheet, row);
5171 if(row==-1 && column ==-1){
5172 sheet->range.row0=0;
5173 sheet->range.col0=0;
5174 sheet->range.rowi = yyy_row_count(sheet) - 1;
5175 sheet->range.coli = xxx_column_count(sheet) - 1;
5176 sheet->active_cell.row=0;
5177 sheet->active_cell.col=0;
5178 gtk_sheet_select_range(sheet, NULL);
5182 if(row!=-1 && column !=-1){
5183 if(sheet->state != GTK_SHEET_NORMAL){
5184 sheet->state = GTK_SHEET_NORMAL;
5185 gtk_sheet_real_unselect_range(sheet, NULL);
5189 if(!gtk_sheet_deactivate_cell(sheet)){
5195 if(gtk_sheet_autoscroll(sheet))
5196 gtk_sheet_move_query(sheet, row, column);
5197 sheet->active_cell.row=row;
5198 sheet->active_cell.col=column;
5199 sheet->selection_cell.row=row;
5200 sheet->selection_cell.col=column;
5201 sheet->range.row0=row;
5202 sheet->range.col0=column;
5203 sheet->range.rowi=row;
5204 sheet->range.coli=column;
5205 sheet->state=GTK_SHEET_NORMAL;
5206 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5207 gtk_sheet_draw_active_cell(sheet);
5211 g_assert_not_reached();
5212 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5213 sheet->active_cell.col);
5217 gtk_sheet_button_release (GtkWidget * widget,
5218 GdkEventButton * event)
5223 sheet=GTK_SHEET(widget);
5225 /* release on resize windows */
5226 if (GTK_SHEET_IN_XDRAG (sheet))
5228 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5229 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5230 gtk_widget_get_pointer (widget, &x, NULL);
5231 gdk_pointer_ungrab (event->time);
5232 draw_xor_vline (sheet);
5234 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col,
5235 new_column_width (sheet, sheet->drag_cell.col, &x));
5236 sheet->old_hadjustment = -1.;
5237 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5241 if (GTK_SHEET_IN_YDRAG (sheet)){
5242 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5243 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5244 gtk_widget_get_pointer (widget, NULL, &y);
5245 gdk_pointer_ungrab (event->time);
5246 draw_xor_hline (sheet);
5248 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5249 sheet->old_vadjustment = -1.;
5250 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5255 if (GTK_SHEET_IN_DRAG(sheet)){
5256 GtkSheetRange old_range;
5257 draw_xor_rectangle(sheet, sheet->drag_range);
5258 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5259 gdk_pointer_ungrab (event->time);
5261 gtk_sheet_real_unselect_range(sheet, NULL);
5263 sheet->active_cell.row = sheet->active_cell.row +
5264 (sheet->drag_range.row0 - sheet->range.row0);
5265 sheet->active_cell.col = sheet->active_cell.col +
5266 (sheet->drag_range.col0 - sheet->range.col0);
5267 sheet->selection_cell.row = sheet->selection_cell.row +
5268 (sheet->drag_range.row0 - sheet->range.row0);
5269 sheet->selection_cell.col = sheet->selection_cell.col +
5270 (sheet->drag_range.col0 - sheet->range.col0);
5271 old_range=sheet->range;
5272 sheet->range=sheet->drag_range;
5273 sheet->drag_range=old_range;
5274 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5275 &sheet->drag_range, &sheet->range);
5276 gtk_sheet_select_range(sheet, &sheet->range);
5279 if (GTK_SHEET_IN_RESIZE(sheet)){
5280 GtkSheetRange old_range;
5281 draw_xor_rectangle(sheet, sheet->drag_range);
5282 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5283 gdk_pointer_ungrab (event->time);
5285 gtk_sheet_real_unselect_range(sheet, NULL);
5287 sheet->active_cell.row = sheet->active_cell.row +
5288 (sheet->drag_range.row0 - sheet->range.row0);
5289 sheet->active_cell.col = sheet->active_cell.col +
5290 (sheet->drag_range.col0 - sheet->range.col0);
5291 if(sheet->drag_range.row0 < sheet->range.row0)
5292 sheet->selection_cell.row = sheet->drag_range.row0;
5293 if(sheet->drag_range.rowi >= sheet->range.rowi)
5294 sheet->selection_cell.row = sheet->drag_range.rowi;
5295 if(sheet->drag_range.col0 < sheet->range.col0)
5296 sheet->selection_cell.col = sheet->drag_range.col0;
5297 if(sheet->drag_range.coli >= sheet->range.coli)
5298 sheet->selection_cell.col = sheet->drag_range.coli;
5299 old_range = sheet->range;
5300 sheet->range = sheet->drag_range;
5301 sheet->drag_range = old_range;
5303 if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5304 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5305 &sheet->drag_range, &sheet->range);
5306 gtk_sheet_select_range(sheet, &sheet->range);
5309 if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5310 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5311 gdk_pointer_ungrab (event->time);
5312 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5313 sheet->active_cell.col);
5316 if(GTK_SHEET_IN_SELECTION)
5317 gdk_pointer_ungrab (event->time);
5319 gtk_timeout_remove(sheet->timer);
5320 gtk_grab_remove(GTK_WIDGET(sheet));
5322 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5328 gtk_sheet_motion (GtkWidget * widget,
5329 GdkEventMotion * event)
5332 GdkModifierType mods;
5333 GdkCursorType new_cursor;
5337 g_return_val_if_fail (widget != NULL, FALSE);
5338 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5339 g_return_val_if_fail (event != NULL, FALSE);
5341 sheet = GTK_SHEET (widget);
5343 /* selections on the sheet */
5347 if(event->window == sheet->column_title_window &&
5348 gtk_sheet_columns_resizable(sheet))
5350 gtk_widget_get_pointer(widget, &x, &y);
5351 if(!GTK_SHEET_IN_SELECTION(sheet) &&
5352 POSSIBLE_XDRAG(sheet, x, &column))
5354 new_cursor = GDK_SB_H_DOUBLE_ARROW;
5355 if(new_cursor != sheet->cursor_drag->type)
5357 gdk_cursor_destroy(sheet->cursor_drag);
5358 sheet->cursor_drag = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5359 gdk_window_set_cursor(sheet->column_title_window,
5360 sheet->cursor_drag);
5365 new_cursor = GDK_TOP_LEFT_ARROW;
5366 if(!GTK_SHEET_IN_XDRAG(sheet) &&
5367 new_cursor != sheet->cursor_drag->type)
5369 gdk_cursor_destroy(sheet->cursor_drag);
5370 sheet->cursor_drag = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5371 gdk_window_set_cursor(sheet->column_title_window,
5372 sheet->cursor_drag);
5377 if(event->window == sheet->row_title_window &&
5378 gtk_sheet_rows_resizable(sheet))
5380 gtk_widget_get_pointer(widget, &x, &y);
5381 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column))
5383 new_cursor = GDK_SB_V_DOUBLE_ARROW;
5384 if(new_cursor != sheet->cursor_drag->type){
5385 gdk_cursor_destroy(sheet->cursor_drag);
5386 sheet->cursor_drag = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5387 gdk_window_set_cursor(sheet->row_title_window, sheet->cursor_drag);
5392 new_cursor = GDK_TOP_LEFT_ARROW;
5393 if(!GTK_SHEET_IN_YDRAG(sheet) &&
5394 new_cursor != sheet->cursor_drag->type)
5396 gdk_cursor_destroy(sheet->cursor_drag);
5397 sheet->cursor_drag = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5398 gdk_window_set_cursor(sheet->row_title_window, sheet->cursor_drag);
5403 new_cursor = GDK_PLUS;
5404 if( event->window == sheet->sheet_window &&
5405 !POSSIBLE_DRAG(sheet, x, y, &row, &column) &&
5406 !GTK_SHEET_IN_DRAG(sheet) &&
5407 !POSSIBLE_RESIZE(sheet, x, y, &row, &column) &&
5408 !GTK_SHEET_IN_RESIZE(sheet) &&
5409 new_cursor != sheet->cursor_drag->type)
5411 gdk_cursor_destroy(sheet->cursor_drag);
5412 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
5413 gdk_window_set_cursor(sheet->sheet_window, sheet->cursor_drag);
5416 new_cursor = GDK_TOP_LEFT_ARROW;
5417 if( event->window == sheet->sheet_window &&
5418 !(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) && (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) &&
5420 new_cursor != sheet->cursor_drag->type)
5422 gdk_cursor_destroy(sheet->cursor_drag);
5423 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5424 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5427 new_cursor=GDK_SIZING;
5428 if( event->window == sheet->sheet_window &&
5429 !GTK_SHEET_IN_DRAG(sheet) &&
5430 (POSSIBLE_RESIZE(sheet, x, y, &row, &column) ||
5431 GTK_SHEET_IN_RESIZE(sheet)) &&
5432 new_cursor != sheet->cursor_drag->type)
5434 gdk_cursor_destroy(sheet->cursor_drag);
5435 sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5436 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5439 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5440 if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5442 if (GTK_SHEET_IN_XDRAG (sheet))
5444 if (event->is_hint || event->window != widget->window)
5445 gtk_widget_get_pointer (widget, &x, NULL);
5449 new_column_width (sheet, sheet->drag_cell.col, &x);
5450 if (x != sheet->x_drag)
5452 draw_xor_vline (sheet);
5454 draw_xor_vline (sheet);
5459 if (GTK_SHEET_IN_YDRAG (sheet))
5461 if (event->is_hint || event->window != widget->window)
5462 gtk_widget_get_pointer (widget, NULL, &y);
5466 new_row_height (sheet, sheet->drag_cell.row, &y);
5467 if (y != sheet->y_drag)
5469 draw_xor_hline (sheet);
5471 draw_xor_hline (sheet);
5476 if (GTK_SHEET_IN_DRAG(sheet))
5479 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5480 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5481 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5482 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5486 if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5487 aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet))
5489 aux=sheet->drag_range;
5490 sheet->drag_range.row0 = sheet->range.row0 + row;
5491 sheet->drag_range.col0 = sheet->range.col0 + column;
5492 sheet->drag_range.rowi = sheet->range.rowi + row;
5493 sheet->drag_range.coli = sheet->range.coli + column;
5494 if(aux.row0 != sheet->drag_range.row0 ||
5495 aux.col0 != sheet->drag_range.col0)
5497 draw_xor_rectangle (sheet, aux);
5498 draw_xor_rectangle (sheet, sheet->drag_range);
5504 if (GTK_SHEET_IN_RESIZE(sheet))
5507 gint v_h, current_col, current_row, col_threshold, row_threshold;
5510 if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5511 abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5513 current_col = COLUMN_FROM_XPIXEL(sheet,x);
5514 current_row = ROW_FROM_YPIXEL(sheet,y);
5515 column = current_col-sheet->drag_cell.col;
5516 row = current_row-sheet->drag_cell.row;
5518 /*use half of column width resp. row height as threshold to expand selection*/
5519 col_threshold = COLUMN_LEFT_XPIXEL(sheet,current_col)+xxx_column_width (sheet,current_col)/2;
5522 if (x < col_threshold)
5525 else if (column < 0)
5527 if (x > col_threshold)
5530 row_threshold = ROW_TOP_YPIXEL(sheet,current_row) +
5531 yyy_row_height (sheet, current_row)/2;
5534 if(y < row_threshold)
5539 if(y > row_threshold)
5543 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5544 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5554 if(aux.row0+row >= 0 && aux.rowi+row < yyy_row_count(sheet) &&
5555 aux.col0+column >= 0 && aux.coli+column < xxx_column_count(sheet)){
5557 aux=sheet->drag_range;
5558 sheet->drag_range=sheet->range;
5560 if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5561 if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5562 if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5563 if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5565 if(aux.row0 != sheet->drag_range.row0 ||
5566 aux.rowi != sheet->drag_range.rowi ||
5567 aux.col0 != sheet->drag_range.col0 ||
5568 aux.coli != sheet->drag_range.coli){
5569 draw_xor_rectangle (sheet, aux);
5570 draw_xor_rectangle (sheet, sheet->drag_range);
5578 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5580 if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5581 column==sheet->active_cell.col) return TRUE;
5583 if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5584 gtk_sheet_extend_selection(sheet, row, column);
5590 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5592 gint row_move, column_move;
5593 gfloat row_align, col_align;
5594 guint height, width;
5596 gint new_col = column;
5603 height = sheet->sheet_window_height;
5604 width = sheet->sheet_window_width;
5606 if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5608 new_row = MIN(yyy_row_count(sheet), row + 1);
5610 if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet) - 1 &&
5611 ROW_TOP_YPIXEL(sheet, yyy_row_count(sheet)-1) +
5612 yyy_row_height(sheet, yyy_row_count(sheet)-1) < height){
5617 if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5621 if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5623 new_col = MIN(xxx_column_count(sheet) - 1, column + 1);
5625 if(MAX_VISIBLE_COLUMN(sheet) == (xxx_column_count(sheet) - 1) &&
5626 COLUMN_LEFT_XPIXEL(sheet, xxx_column_count(sheet) - 1) +
5627 xxx_column_width(sheet, xxx_column_count(sheet) - 1) < width)
5629 column_move = FALSE;
5633 if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5638 if(row_move || column_move){
5639 gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5642 return(row_move || column_move);
5646 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5648 GtkSheetRange range;
5652 if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5655 if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5657 gtk_sheet_move_query(sheet, row, column);
5658 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5660 if(GTK_SHEET_IN_DRAG(sheet)) return;
5664 switch(sheet->state){
5665 case GTK_SHEET_ROW_SELECTED:
5666 column = xxx_column_count(sheet) - 1;
5668 case GTK_SHEET_COLUMN_SELECTED:
5669 row = yyy_row_count(sheet) - 1;
5671 case GTK_SHEET_NORMAL:
5672 sheet->state=GTK_SHEET_RANGE_SELECTED;
5673 r=sheet->active_cell.row;
5674 c=sheet->active_cell.col;
5675 sheet->range.col0=c;
5676 sheet->range.row0=r;
5677 sheet->range.coli=c;
5678 sheet->range.rowi=r;
5679 gdk_draw_pixmap(sheet->sheet_window,
5680 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5682 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5683 ROW_TOP_YPIXEL(sheet,r)-1,
5684 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5685 ROW_TOP_YPIXEL(sheet,r)-1,
5686 xxx_column_width(sheet, c)+4,
5687 yyy_row_height(sheet, r)+4);
5688 gtk_sheet_range_draw_selection(sheet, sheet->range);
5689 case GTK_SHEET_RANGE_SELECTED:
5690 sheet->state=GTK_SHEET_RANGE_SELECTED;
5693 sheet->selection_cell.row = row;
5694 sheet->selection_cell.col = column;
5696 range.col0=MIN(column,sheet->active_cell.col);
5697 range.coli=MAX(column,sheet->active_cell.col);
5698 range.row0=MIN(row,sheet->active_cell.row);
5699 range.rowi=MAX(row,sheet->active_cell.row);
5701 if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5702 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5703 state==GTK_SHEET_NORMAL)
5704 gtk_sheet_real_select_range(sheet, &range);
5709 gtk_sheet_entry_key_press(GtkWidget *widget,
5713 gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5718 gtk_sheet_key_press(GtkWidget *widget,
5724 gboolean extend_selection = FALSE;
5725 gboolean force_move = FALSE;
5726 gboolean in_selection = FALSE;
5727 gboolean veto = TRUE;
5730 sheet = GTK_SHEET(widget);
5732 if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5733 key->keyval==GDK_Control_R) return FALSE;
5737 if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5738 gtk_sheet_clip_range(sheet, sheet->range);
5739 if(key->keyval=='x' || key->keyval == 'X')
5740 gtk_sheet_unclip_range(sheet);
5745 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L
5746 || key->keyval==GDK_Shift_R;
5749 in_selection = GTK_SHEET_IN_SELECTION(sheet);
5750 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5752 switch(key->keyval){
5753 case GDK_Return: case GDK_KP_Enter:
5754 if(sheet->state == GTK_SHEET_NORMAL &&
5755 !GTK_SHEET_IN_SELECTION(sheet))
5756 gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
5758 row = sheet->active_cell.row;
5759 col = sheet->active_cell.col;
5760 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5761 row = MIN_VISIBLE_ROW(sheet)-1;
5762 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5763 col = MIN_VISIBLE_COLUMN(sheet);
5764 if(row < yyy_row_count(sheet) - 1){
5766 while(!yyy_row_is_visible(sheet, row) && row<yyy_row_count(sheet)-1)
5769 gtk_sheet_click_cell(sheet, row, col, &veto);
5770 extend_selection = FALSE;
5772 case GDK_ISO_Left_Tab:
5773 row = sheet->active_cell.row;
5774 col = sheet->active_cell.col;
5775 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5776 col = MIN_VISIBLE_COLUMN(sheet)-1;
5777 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5778 row = MIN_VISIBLE_ROW(sheet);
5781 while(! xxx_column_is_visible(sheet, col) && col>0) col--;
5784 gtk_sheet_click_cell(sheet, row, col, &veto);
5785 extend_selection = FALSE;
5788 row = sheet->active_cell.row;
5789 col = sheet->active_cell.col;
5790 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5791 col = MIN_VISIBLE_COLUMN(sheet)-1;
5792 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5793 row = MIN_VISIBLE_ROW(sheet);
5794 if(col < xxx_column_count(sheet) - 1)
5797 while(! xxx_column_is_visible(sheet, col) &&
5798 col < xxx_column_count(sheet) - 1)
5801 gtk_sheet_click_cell(sheet, row, col, &veto);
5802 extend_selection = FALSE;
5804 /* case GDK_BackSpace:
5805 if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5806 if(sheet->active_cell.col > 0){
5807 col = sheet->active_cell.col - scroll;
5808 row = sheet->active_cell.row;
5809 while(!sheet->column[col].is_visible && col > 0) col--;
5812 gtk_sheet_click_cell(sheet, row, col, &veto);
5813 extend_selection = FALSE;
5817 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5819 if(extend_selection){
5820 if(state==GTK_STATE_NORMAL){
5821 row=sheet->active_cell.row;
5822 col=sheet->active_cell.col;
5823 gtk_sheet_click_cell(sheet, row, col, &veto);
5826 if(sheet->selection_cell.row > 0){
5827 row = sheet->selection_cell.row - scroll;
5828 while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5830 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5834 col = sheet->active_cell.col;
5835 row = sheet->active_cell.row;
5836 if(state==GTK_SHEET_COLUMN_SELECTED)
5837 row = MIN_VISIBLE_ROW(sheet);
5838 if(state==GTK_SHEET_ROW_SELECTED)
5839 col = MIN_VISIBLE_COLUMN(sheet);
5841 while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5843 gtk_sheet_click_cell(sheet, row, col, &veto);
5844 extend_selection = FALSE;
5847 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5849 if(extend_selection){
5850 if(state==GTK_STATE_NORMAL){
5851 row=sheet->active_cell.row;
5852 col=sheet->active_cell.col;
5853 gtk_sheet_click_cell(sheet, row, col, &veto);
5856 if(sheet->selection_cell.row < yyy_row_count(sheet)-1){
5857 row = sheet->selection_cell.row + scroll;
5858 while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5859 row = MIN(yyy_row_count(sheet)-1, row);
5860 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5864 col = sheet->active_cell.col;
5865 row = sheet->active_cell.row;
5866 if(sheet->active_cell.row < yyy_row_count(sheet)-1){
5867 if(state==GTK_SHEET_COLUMN_SELECTED)
5868 row = MIN_VISIBLE_ROW(sheet)-1;
5869 if(state==GTK_SHEET_ROW_SELECTED)
5870 col = MIN_VISIBLE_COLUMN(sheet);
5872 while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5873 row = MIN(yyy_row_count(sheet)-1, row);
5875 gtk_sheet_click_cell(sheet, row, col, &veto);
5876 extend_selection = FALSE;
5879 if(extend_selection){
5880 if(state==GTK_STATE_NORMAL){
5881 row=sheet->active_cell.row;
5882 col=sheet->active_cell.col;
5883 gtk_sheet_click_cell(sheet, row, col, &veto);
5886 if(sheet->selection_cell.col < xxx_column_count(sheet) - 1)
5888 col = sheet->selection_cell.col + 1;
5889 while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1)
5891 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5895 col = sheet->active_cell.col;
5896 row = sheet->active_cell.row;
5897 if(sheet->active_cell.col < xxx_column_count(sheet) - 1){
5899 if(state==GTK_SHEET_ROW_SELECTED)
5900 col = MIN_VISIBLE_COLUMN(sheet)-1;
5901 if(state==GTK_SHEET_COLUMN_SELECTED)
5902 row = MIN_VISIBLE_ROW(sheet);
5903 while(! xxx_column_is_visible(sheet, col) && col < xxx_column_count(sheet) - 1) col++;
5904 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5906 gtk_sheet_click_cell(sheet, row, col, &veto);
5911 extend_selection = FALSE;
5914 if(extend_selection){
5915 if(state==GTK_STATE_NORMAL){
5916 row=sheet->active_cell.row;
5917 col=sheet->active_cell.col;
5918 gtk_sheet_click_cell(sheet, row, col, &veto);
5921 if(sheet->selection_cell.col > 0){
5922 col = sheet->selection_cell.col - 1;
5923 while(! xxx_column_is_visible(sheet, col) && col > 0) col--;
5924 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5928 col = sheet->active_cell.col - 1;
5929 row = sheet->active_cell.row;
5930 if(state==GTK_SHEET_ROW_SELECTED)
5931 col = MIN_VISIBLE_COLUMN(sheet)-1;
5932 if(state==GTK_SHEET_COLUMN_SELECTED)
5933 row = MIN_VISIBLE_ROW(sheet);
5934 while(! xxx_column_is_visible(sheet, col) && col > 0) col--;
5937 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5939 gtk_sheet_click_cell(sheet, row, col, &veto);
5943 extend_selection = FALSE;
5947 while(!yyy_row_is_visible(sheet, row) && row < yyy_row_count(sheet)-1) row++;
5948 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5949 extend_selection = FALSE;
5952 row=yyy_row_count(sheet)-1;
5953 while(!yyy_row_is_visible(sheet, row) && row > 0) row--;
5954 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5955 extend_selection = FALSE;
5959 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5960 if(extend_selection) return TRUE;
5962 if(state == GTK_SHEET_ROW_SELECTED)
5963 sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5964 if(state == GTK_SHEET_COLUMN_SELECTED)
5965 sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5969 if(extend_selection) return TRUE;
5971 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5972 sheet->active_cell.col);
5978 gtk_sheet_size_request (GtkWidget * widget,
5979 GtkRequisition * requisition)
5983 GtkSheetChild *child;
5984 GtkRequisition child_requisition;
5986 g_return_if_fail (widget != NULL);
5987 g_return_if_fail (GTK_IS_SHEET (widget));
5988 g_return_if_fail (requisition != NULL);
5990 sheet = GTK_SHEET (widget);
5992 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5993 requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5995 /* compute the size of the column title area */
5996 if(sheet->column_titles_visible)
5997 requisition->height += sheet->column_title_area.height;
5999 /* compute the size of the row title area */
6000 if(sheet->row_titles_visible)
6001 requisition->width += sheet->row_title_area.width;
6003 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6004 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6005 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6006 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6008 if(!sheet->column_titles_visible)
6009 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6011 if(!sheet->row_titles_visible)
6012 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6014 children = sheet->children;
6017 child = children->data;
6018 children = children->next;
6020 gtk_widget_size_request(child->widget, &child_requisition);
6026 gtk_sheet_size_allocate (GtkWidget * widget,
6027 GtkAllocation * allocation)
6030 GtkAllocation sheet_allocation;
6033 g_return_if_fail (widget != NULL);
6034 g_return_if_fail (GTK_IS_SHEET (widget));
6035 g_return_if_fail (allocation != NULL);
6037 sheet = GTK_SHEET (widget);
6038 widget->allocation = *allocation;
6039 border_width = GTK_CONTAINER(widget)->border_width;
6041 if (GTK_WIDGET_REALIZED (widget))
6042 gdk_window_move_resize (widget->window,
6043 allocation->x + border_width,
6044 allocation->y + border_width,
6045 allocation->width - 2*border_width,
6046 allocation->height - 2*border_width);
6048 /* use internal allocation structure for all the math
6049 * because it's easier than always subtracting the container
6051 sheet->internal_allocation.x = 0;
6052 sheet->internal_allocation.y = 0;
6053 sheet->internal_allocation.width = allocation->width - 2*border_width;
6054 sheet->internal_allocation.height = allocation->height - 2*border_width;
6056 sheet_allocation.x = 0;
6057 sheet_allocation.y = 0;
6058 sheet_allocation.width = allocation->width - 2*border_width;
6059 sheet_allocation.height = allocation->height - 2*border_width;
6061 sheet->sheet_window_width = sheet_allocation.width;
6062 sheet->sheet_window_height = sheet_allocation.height;
6064 if (GTK_WIDGET_REALIZED (widget))
6065 gdk_window_move_resize (sheet->sheet_window,
6068 sheet_allocation.width,
6069 sheet_allocation.height);
6071 /* position the window which holds the column title buttons */
6072 sheet->column_title_area.x = 0;
6073 sheet->column_title_area.y = 0;
6074 if(sheet->row_titles_visible)
6075 sheet->column_title_area.x = sheet->row_title_area.width;
6076 sheet->column_title_area.width = sheet_allocation.width -
6077 sheet->column_title_area.x;
6078 if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
6079 gdk_window_move_resize (sheet->column_title_window,
6080 sheet->column_title_area.x,
6081 sheet->column_title_area.y,
6082 sheet->column_title_area.width,
6083 sheet->column_title_area.height);
6085 sheet->sheet_window_width = sheet_allocation.width;
6086 sheet->sheet_window_height = sheet_allocation.height;
6088 /* column button allocation */
6089 size_allocate_column_title_buttons (sheet);
6091 /* position the window which holds the row title buttons */
6092 sheet->row_title_area.x = 0;
6093 sheet->row_title_area.y = 0;
6094 if(sheet->column_titles_visible)
6095 sheet->row_title_area.y = sheet->column_title_area.height;
6096 sheet->row_title_area.height = sheet_allocation.height -
6097 sheet->row_title_area.y;
6099 if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
6100 gdk_window_move_resize (sheet->row_title_window,
6101 sheet->row_title_area.x,
6102 sheet->row_title_area.y,
6103 sheet->row_title_area.width,
6104 sheet->row_title_area.height);
6107 /* row button allocation */
6108 size_allocate_row_title_buttons (sheet);
6110 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6111 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6112 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6113 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6115 if(!sheet->column_titles_visible)
6116 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6118 if(!sheet->row_titles_visible)
6119 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6121 size_allocate_column_title_buttons(sheet);
6122 size_allocate_row_title_buttons(sheet);
6124 /* re-scale backing pixmap */
6125 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
6126 gtk_sheet_position_children(sheet);
6128 /* set the scrollbars adjustments */
6129 adjust_scrollbars (sheet);
6133 size_allocate_column_title_buttons (GtkSheet * sheet)
6138 if (!sheet->column_titles_visible) return;
6139 if (!GTK_WIDGET_REALIZED (sheet))
6142 width = sheet->sheet_window_width;
6145 if(sheet->row_titles_visible)
6147 width -= sheet->row_title_area.width;
6148 x = sheet->row_title_area.width;
6151 if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6153 sheet->column_title_area.width = width;
6154 sheet->column_title_area.x = x;
6155 gdk_window_move_resize (sheet->column_title_window,
6156 sheet->column_title_area.x,
6157 sheet->column_title_area.y,
6158 sheet->column_title_area.width,
6159 sheet->column_title_area.height);
6163 if(MAX_VISIBLE_COLUMN(sheet) == xxx_column_count(sheet) - 1)
6164 gdk_window_clear_area (sheet->column_title_window,
6166 sheet->column_title_area.width,
6167 sheet->column_title_area.height);
6169 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6171 for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
6172 gtk_sheet_column_title_button_draw(sheet, i);
6176 size_allocate_row_title_buttons (GtkSheet * sheet)
6181 if (!sheet->row_titles_visible) return;
6182 if (!GTK_WIDGET_REALIZED (sheet))
6185 height = sheet->sheet_window_height;
6188 if(sheet->column_titles_visible)
6190 height -= sheet->column_title_area.height;
6191 y = sheet->column_title_area.height;
6194 if(sheet->row_title_area.height != height || sheet->row_title_area.y != y)
6196 sheet->row_title_area.y = y;
6197 sheet->row_title_area.height = height;
6198 gdk_window_move_resize (sheet->row_title_window,
6199 sheet->row_title_area.x,
6200 sheet->row_title_area.y,
6201 sheet->row_title_area.width,
6202 sheet->row_title_area.height);
6204 if(MAX_VISIBLE_ROW(sheet) == yyy_row_count(sheet)-1)
6205 gdk_window_clear_area (sheet->row_title_window,
6207 sheet->row_title_area.width,
6208 sheet->row_title_area.height);
6210 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6212 for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6214 if ( i >= yyy_row_count(sheet))
6216 gtk_sheet_row_title_button_draw(sheet, i);
6222 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6224 GtkAllocation shentry_allocation;
6225 GtkSheetCellAttr attributes = { 0 };
6226 GtkEntry *sheet_entry;
6227 GtkStyle *style = NULL, *previous_style = NULL;
6229 gint size, max_size, text_size, column_width;
6232 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6233 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6235 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6237 if ( ! gtk_sheet_get_attributes(sheet, sheet->active_cell.row,
6238 sheet->active_cell.col,
6242 if ( GTK_WIDGET_REALIZED(sheet->sheet_entry) )
6244 if(!GTK_WIDGET(sheet_entry)->style)
6245 gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6247 previous_style = GTK_WIDGET(sheet_entry)->style;
6249 style = gtk_style_copy(previous_style);
6250 style->bg[GTK_STATE_NORMAL] = attributes.background;
6251 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6252 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6253 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6254 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6255 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6257 pango_font_description_free(style->font_desc);
6258 g_assert(attributes.font_desc);
6259 style->font_desc = pango_font_description_copy(attributes.font_desc);
6261 GTK_WIDGET(sheet_entry)->style = style;
6262 gtk_widget_size_request(sheet->sheet_entry, NULL);
6263 GTK_WIDGET(sheet_entry)->style = previous_style;
6265 if(style != previous_style){
6266 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6267 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6268 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6269 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6270 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6272 gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6276 if(GTK_IS_ITEM_ENTRY(sheet_entry))
6277 max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
6282 text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6283 if(text && strlen(text) > 0)
6284 text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6286 column_width=xxx_column_width(sheet, sheet->active_cell.col);
6288 size=MIN(text_size, max_size);
6289 size=MAX(size,column_width-2*CELLOFFSET);
6291 row=sheet->active_cell.row;
6292 col=sheet->active_cell.col;
6294 shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6295 shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6296 shentry_allocation.width = column_width;
6297 shentry_allocation.height = yyy_row_height(sheet, sheet->active_cell.row);
6299 if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry))
6301 shentry_allocation.height -= 2*CELLOFFSET;
6302 shentry_allocation.y += CELLOFFSET;
6303 if(gtk_sheet_clip_text(sheet))
6304 shentry_allocation.width = column_width - 2*CELLOFFSET;
6306 shentry_allocation.width = size;
6308 switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
6309 case GTK_JUSTIFY_CENTER:
6310 shentry_allocation.x += (column_width)/2 - size/2;
6312 case GTK_JUSTIFY_RIGHT:
6313 shentry_allocation.x += column_width - size - CELLOFFSET;
6315 case GTK_JUSTIFY_LEFT:
6316 case GTK_JUSTIFY_FILL:
6317 shentry_allocation.x += CELLOFFSET;
6322 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry))
6324 shentry_allocation.x += 2;
6325 shentry_allocation.y += 2;
6326 shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6327 shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6330 gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6332 if(previous_style == style) gtk_style_unref(previous_style);
6336 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
6340 gint sizel=0, sizer=0;
6342 GtkJustification justification;
6345 row=sheet->active_cell.row;
6346 col=sheet->active_cell.col;
6348 if( ! GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || gtk_sheet_clip_text(sheet))
6351 justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6353 switch(justification){
6354 case GTK_JUSTIFY_FILL:
6355 case GTK_JUSTIFY_LEFT:
6356 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6357 if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6362 size+=xxx_column_width(sheet, i);
6364 size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6366 case GTK_JUSTIFY_RIGHT:
6367 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
6369 if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6374 size+=xxx_column_width(sheet, i);
6377 case GTK_JUSTIFY_CENTER:
6378 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6379 /* if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6385 sizer+=xxx_column_width(sheet, i);
6387 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
6389 if((s = gtk_sheet_cell_get_text(sheet, row, i)))
6394 sizel+=xxx_column_width(sheet, i);
6396 size=2*MIN(sizel, sizer);
6401 size += xxx_column_width(sheet, col);
6402 GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size = size;
6406 create_sheet_entry(GtkSheet *sheet)
6411 gint found_entry = FALSE;
6413 widget = GTK_WIDGET(sheet);
6415 if(sheet->sheet_entry)
6417 /* avoids warnings */
6418 gtk_widget_ref(sheet->sheet_entry);
6419 gtk_widget_unparent(sheet->sheet_entry);
6420 gtk_widget_destroy(sheet->sheet_entry);
6423 if(sheet->entry_type)
6425 if(!g_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY))
6427 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6429 sheet->sheet_entry = parent;
6431 entry = gtk_sheet_get_entry (sheet);
6432 if(GTK_IS_ENTRY(entry))
6437 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6444 g_warning ("Entry type must be GtkEntry subclass, using default");
6445 entry = gtk_item_entry_new();
6446 sheet->sheet_entry = entry;
6449 sheet->sheet_entry = parent;
6453 entry = gtk_item_entry_new();
6454 sheet->sheet_entry = entry;
6457 gtk_widget_size_request(sheet->sheet_entry, NULL);
6459 if(GTK_WIDGET_REALIZED(sheet))
6461 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6462 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6463 gtk_widget_realize(sheet->sheet_entry);
6466 gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6467 (GtkSignalFunc) gtk_sheet_entry_key_press,
6470 gtk_widget_show (sheet->sheet_entry);
6474 /* Finds the last child widget that happens to be of type GtkEntry */
6476 find_entry(GtkWidget *w, gpointer user_data)
6478 GtkWidget **entry = user_data;
6479 if ( GTK_IS_ENTRY(w))
6486 gtk_sheet_get_entry(GtkSheet *sheet)
6489 GtkWidget *entry = NULL;
6490 GtkTableChild *table_child;
6491 GtkBoxChild *box_child;
6492 GList *children = NULL;
6494 g_return_val_if_fail (sheet != NULL, NULL);
6495 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6496 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6498 if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6500 parent = GTK_WIDGET(sheet->sheet_entry);
6502 if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6503 if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6505 if(GTK_IS_CONTAINER(parent))
6507 gtk_container_forall(GTK_CONTAINER(parent), find_entry, &entry);
6509 if(GTK_IS_ENTRY(entry))
6513 if(!children) return NULL;
6516 if(GTK_IS_TABLE(parent)) {
6517 table_child = children->data;
6518 entry = table_child->widget;
6520 if(GTK_IS_BOX(parent)){
6521 box_child = children->data;
6522 entry = box_child->widget;
6525 if(GTK_IS_ENTRY(entry))
6527 children = children->next;
6531 if(!GTK_IS_ENTRY(entry)) return NULL;
6538 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6540 g_return_val_if_fail (sheet != NULL, NULL);
6541 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6542 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6544 return (sheet->sheet_entry);
6549 gtk_sheet_button_draw(GtkSheet *sheet, GdkWindow *window,
6550 GtkSheetButton *button, gboolean is_sensitive,
6551 GdkRectangle allocation)
6553 GtkShadowType shadow_type;
6554 gint text_width = 0, text_height = 0;
6555 GtkSheetChild *child = NULL;
6556 PangoAlignment align = PANGO_ALIGN_LEFT;
6564 g_return_if_fail(sheet != NULL);
6565 g_return_if_fail(button != NULL);
6567 rtl = gtk_widget_get_direction(GTK_WIDGET(sheet)) == GTK_TEXT_DIR_RTL;
6569 gdk_window_clear_area (window,
6570 allocation.x, allocation.y,
6571 allocation.width, allocation.height);
6573 gtk_paint_box (sheet->button->style, window,
6574 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6575 &allocation, GTK_WIDGET(sheet->button),
6577 allocation.x, allocation.y,
6578 allocation.width, allocation.height);
6580 state = button->state;
6581 if(!is_sensitive) state = GTK_STATE_INSENSITIVE;
6583 if (state == GTK_STATE_ACTIVE)
6584 shadow_type = GTK_SHADOW_IN;
6586 shadow_type = GTK_SHADOW_OUT;
6588 if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6589 gtk_paint_box (sheet->button->style, window,
6590 button->state, shadow_type,
6591 &allocation, GTK_WIDGET(sheet->button),
6593 allocation.x, allocation.y,
6594 allocation.width, allocation.height);
6596 if(button->label_visible)
6599 text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6601 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6603 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6605 allocation.y += 2*sheet->button->style->ythickness;
6608 if(button->label && strlen(button->label)>0){
6610 PangoLayout *layout = NULL;
6611 gint real_x = allocation.x, real_y = allocation.y;
6613 words=button->label;
6614 line = g_new(gchar, 1);
6617 while(words && *words != '\0'){
6620 line=g_realloc(line, len+2);
6624 if(*words == '\n' || *(words+1) == '\0'){
6625 text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6627 layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), line);
6628 switch(button->justification){
6629 case GTK_JUSTIFY_LEFT:
6630 real_x = allocation.x + CELLOFFSET;
6631 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6633 case GTK_JUSTIFY_RIGHT:
6634 real_x = allocation.x + allocation.width - text_width - CELLOFFSET;
6635 align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
6637 case GTK_JUSTIFY_CENTER:
6639 real_x = allocation.x + (allocation.width - text_width)/2;
6640 align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
6641 pango_layout_set_justify (layout, TRUE);
6643 pango_layout_set_alignment (layout, align);
6644 gtk_paint_layout (GTK_WIDGET(sheet)->style,
6653 g_object_unref(G_OBJECT(layout));
6655 real_y += text_height + 2;
6658 line = g_new(gchar, 1);
6666 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6668 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6672 if((child = button->child) && (child->widget))
6674 child->x = allocation.x;
6675 child->y = allocation.y;
6677 child->x += (allocation.width - child->widget->requisition.width) / 2;
6678 child->y += (allocation.height - child->widget->requisition.height) / 2;
6679 allocation.x = child->x;
6680 allocation.y = child->y;
6681 allocation.width = child->widget->requisition.width;
6682 allocation.height = child->widget->requisition.height;
6684 allocation.x = child->x;
6685 allocation.y = child->y;
6687 gtk_widget_set_state(child->widget, button->state);
6689 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6690 GTK_WIDGET_MAPPED(child->widget))
6692 gtk_widget_size_allocate(child->widget,
6694 gtk_widget_queue_draw(child->widget);
6698 gtk_sheet_button_free(button);
6702 /* COLUMN value of -1 indicates that the area to the right of the rightmost
6703 button should be redrawn */
6705 gtk_sheet_column_title_button_draw(GtkSheet *sheet, gint column)
6707 GdkWindow *window = NULL;
6708 GdkRectangle allocation;
6709 GtkSheetButton *button = NULL;
6710 gboolean is_sensitive = FALSE;
6712 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6714 if(column >= 0 && ! xxx_column_is_visible(sheet, column)) return;
6715 if(column >= 0 && !sheet->column_titles_visible) return;
6716 if(column>=0 && column < MIN_VISIBLE_COLUMN(sheet)) return;
6717 if(column>=0 && column > MAX_VISIBLE_COLUMN(sheet)) return;
6719 window = sheet->column_title_window;
6721 allocation.height = sheet->column_title_area.height;
6725 const gint cols = xxx_column_count(sheet) ;
6726 allocation.x = COLUMN_LEFT_XPIXEL(sheet, cols - 1)
6728 allocation.width = sheet->column_title_area.width
6729 + sheet->column_title_area.x
6732 gdk_window_clear_area (window,
6733 allocation.x, allocation.y,
6734 allocation.width, allocation.height);
6738 button = xxx_column_button(sheet, column);
6739 allocation.x = COLUMN_LEFT_XPIXEL(sheet, column) + CELL_SPACING;
6740 if(sheet->row_titles_visible)
6741 allocation.x -= sheet->row_title_area.width;
6743 allocation.width = xxx_column_width(sheet, column);
6745 is_sensitive = xxx_column_is_sensitive(sheet, column);
6746 gtk_sheet_button_draw(sheet, window, button,
6747 is_sensitive, allocation);
6752 gtk_sheet_row_title_button_draw(GtkSheet *sheet, gint row)
6754 GdkWindow *window = NULL;
6755 GdkRectangle allocation;
6756 GtkSheetButton *button = NULL;
6757 gboolean is_sensitive = FALSE;
6760 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6762 if(row >= 0 && !yyy_row_is_visible(sheet, row)) return;
6763 if(row >= 0 && !sheet->row_titles_visible) return;
6764 if(row>=0 && row < MIN_VISIBLE_ROW(sheet)) return;
6765 if(row>=0 && row > MAX_VISIBLE_ROW(sheet)) return;
6768 window=sheet->row_title_window;
6769 button = yyy_row_button(sheet, row);
6771 allocation.y = ROW_TOP_YPIXEL(sheet, row) + CELL_SPACING;
6772 if(sheet->column_titles_visible)
6773 allocation.y -= sheet->column_title_area.height;
6774 allocation.width = sheet->row_title_area.width;
6775 allocation.height = yyy_row_height(sheet, row);
6776 is_sensitive = yyy_row_is_sensitive(sheet, row);
6778 gtk_sheet_button_draw(sheet, window, button, is_sensitive, allocation);
6785 * vadjustment_changed
6786 * hadjustment_changed
6787 * vadjustment_value_changed
6788 * hadjustment_value_changed */
6791 adjust_scrollbars (GtkSheet * sheet)
6794 if(sheet->vadjustment){
6795 sheet->vadjustment->page_size = sheet->sheet_window_height;
6796 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6797 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6798 sheet->vadjustment->lower = 0;
6799 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6801 if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6803 sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) -
6804 sheet->sheet_window_height);
6805 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
6809 gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6813 if(sheet->hadjustment){
6814 sheet->hadjustment->page_size = sheet->sheet_window_width;
6815 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6816 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6817 sheet->hadjustment->lower = 0;
6818 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6820 if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6822 sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) -
6823 sheet->sheet_window_width);
6824 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment),
6828 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6832 if(GTK_WIDGET_REALIZED(sheet))
6834 if(sheet->row_titles_visible){
6835 size_allocate_row_title_buttons(sheet);
6836 gdk_window_show(sheet->row_title_window);
6839 if(sheet->column_titles_visible){
6840 size_allocate_column_title_buttons(sheet);
6841 gdk_window_show(sheet->column_title_window);
6844 gtk_sheet_range_draw(sheet, NULL);
6851 vadjustment_changed (GtkAdjustment * adjustment,
6856 g_return_if_fail (adjustment != NULL);
6857 g_return_if_fail (data != NULL);
6859 sheet = GTK_SHEET (data);
6864 hadjustment_changed (GtkAdjustment * adjustment,
6869 g_return_if_fail (adjustment != NULL);
6870 g_return_if_fail (data != NULL);
6872 sheet = GTK_SHEET (data);
6877 vadjustment_value_changed (GtkAdjustment * adjustment,
6881 gint diff, value, old_value;
6885 g_return_if_fail (adjustment != NULL);
6886 g_return_if_fail (data != NULL);
6887 g_return_if_fail (GTK_IS_SHEET (data));
6889 sheet = GTK_SHEET (data);
6891 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6893 row = ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6894 if(!sheet->column_titles_visible)
6895 row=ROW_FROM_YPIXEL(sheet, CELL_SPACING);
6897 old_value = -sheet->voffset;
6899 new_row = g_sheet_row_pixel_to_row(sheet->row_geometry,
6900 adjustment->value,sheet);
6902 y = g_sheet_row_start_pixel(sheet->row_geometry, new_row, sheet);
6904 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6905 yyy_row_height(sheet, row) > sheet->vadjustment->step_increment)
6907 /* This avoids embarrassing twitching */
6908 if(row == new_row && row != yyy_row_count(sheet) - 1 &&
6909 adjustment->value - sheet->old_vadjustment >=
6910 sheet->vadjustment->step_increment &&
6911 new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6913 y=y+yyy_row_height(sheet, row);
6917 /* Negative old_adjustment enforces the redraw, otherwise avoid
6919 if(sheet->old_vadjustment >= 0. && row == new_row)
6921 sheet->old_vadjustment = sheet->vadjustment->value;
6925 sheet->old_vadjustment = sheet->vadjustment->value;
6926 adjustment->value=y;
6931 sheet->vadjustment->step_increment = yyy_row_height(sheet, 0);
6935 sheet->vadjustment->step_increment =
6936 MIN(yyy_row_height(sheet, new_row), yyy_row_height(sheet, new_row-1));
6939 sheet->vadjustment->value = adjustment->value;
6941 value = adjustment->value;
6943 if (value >= -sheet->voffset)
6946 diff = value + sheet->voffset;
6951 diff = -sheet->voffset - value;
6954 sheet->voffset = -value;
6956 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height + 1);
6957 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height - 1);
6958 if(!sheet->column_titles_visible)
6959 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6961 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6962 sheet->state == GTK_SHEET_NORMAL &&
6963 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6964 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6965 sheet->active_cell.col))
6969 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6971 if(!text || strlen(text)==0)
6972 gtk_sheet_cell_clear(sheet,
6973 sheet->active_cell.row,
6974 sheet->active_cell.col);
6975 gtk_widget_unmap(sheet->sheet_entry);
6978 gtk_sheet_position_children(sheet);
6980 gtk_sheet_range_draw(sheet, NULL);
6981 size_allocate_row_title_buttons(sheet);
6982 size_allocate_global_button(sheet);
6986 hadjustment_value_changed (GtkAdjustment * adjustment,
6990 gint i, diff, value, old_value;
6991 gint column, new_column;
6994 g_return_if_fail (adjustment != NULL);
6995 g_return_if_fail (data != NULL);
6996 g_return_if_fail (GTK_IS_SHEET (data));
6998 sheet = GTK_SHEET (data);
7000 if(GTK_SHEET_IS_FROZEN(sheet)) return;
7002 column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
7003 if(!sheet->row_titles_visible)
7004 column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
7006 old_value = -sheet->hoffset;
7008 for(i=0; i < xxx_column_count(sheet); i++)
7010 if(xxx_column_is_visible(sheet, i)) x += xxx_column_width(sheet, i);
7011 if(x > adjustment->value) break;
7013 x-=xxx_column_width(sheet, i);
7016 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
7017 xxx_column_width(sheet, i) > sheet->hadjustment->step_increment){
7018 /* This avoids embarrassing twitching */
7019 if(column == new_column && column != xxx_column_count(sheet) - 1 &&
7020 adjustment->value - sheet->old_hadjustment >=
7021 sheet->hadjustment->step_increment &&
7022 new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
7024 x=x+xxx_column_width(sheet, column);
7028 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
7029 if(sheet->old_hadjustment >= 0. && new_column == column){
7030 sheet->old_hadjustment = sheet->hadjustment->value;
7034 sheet->old_hadjustment = sheet->hadjustment->value;
7035 adjustment->value=x;
7037 if(new_column == 0){
7038 sheet->hadjustment->step_increment=
7039 xxx_column_width(sheet, 0);
7041 sheet->hadjustment->step_increment=
7042 MIN(xxx_column_width(sheet, new_column), xxx_column_width(sheet, new_column-1));
7046 sheet->hadjustment->value=adjustment->value;
7048 value = adjustment->value;
7050 if (value >= -sheet->hoffset)
7053 diff = value + sheet->hoffset;
7058 diff = -sheet->hoffset - value;
7061 sheet->hoffset = -value;
7063 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
7064 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7065 if(!sheet->row_titles_visible)
7066 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
7068 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
7069 sheet->state == GTK_SHEET_NORMAL &&
7070 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
7071 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
7072 sheet->active_cell.col))
7076 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
7077 if(!text || strlen(text)==0)
7078 gtk_sheet_cell_clear(sheet,
7079 sheet->active_cell.row,
7080 sheet->active_cell.col);
7082 gtk_widget_unmap(sheet->sheet_entry);
7085 gtk_sheet_position_children(sheet);
7087 gtk_sheet_range_draw(sheet, NULL);
7088 size_allocate_column_title_buttons(sheet);
7092 /* COLUMN RESIZING */
7094 draw_xor_vline (GtkSheet * sheet)
7098 g_return_if_fail (sheet != NULL);
7100 widget = GTK_WIDGET (sheet);
7102 gdk_draw_line (widget->window, sheet->xor_gc,
7104 sheet->column_title_area.height,
7106 sheet->sheet_window_height + 1);
7111 draw_xor_hline (GtkSheet * sheet)
7115 g_return_if_fail (sheet != NULL);
7117 widget = GTK_WIDGET (sheet);
7119 gdk_draw_line (widget->window, sheet->xor_gc,
7120 sheet->row_title_area.width,
7123 sheet->sheet_window_width + 1,
7127 /* SELECTED RANGE */
7129 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
7132 GdkRectangle clip_area, area;
7135 area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
7136 area.y=ROW_TOP_YPIXEL(sheet, range.row0);
7137 area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
7138 xxx_column_width(sheet, range.coli);
7139 area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
7140 yyy_row_height(sheet, range.rowi);
7142 clip_area.x=sheet->row_title_area.width;
7143 clip_area.y=sheet->column_title_area.height;
7144 clip_area.width=sheet->sheet_window_width;
7145 clip_area.height=sheet->sheet_window_height;
7147 if(!sheet->row_titles_visible) clip_area.x = 0;
7148 if(!sheet->column_titles_visible) clip_area.y = 0;
7151 area.width=area.width+area.x;
7154 if(area.width>clip_area.width) area.width=clip_area.width+10;
7156 area.height=area.height+area.y;
7159 if(area.height>clip_area.height) area.height=clip_area.height+10;
7164 clip_area.height+=3;
7166 gdk_gc_get_values(sheet->xor_gc, &values);
7168 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
7171 gdk_draw_rectangle(sheet->sheet_window,
7175 area.width-2*i, area.height-2*i);
7178 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
7180 gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
7185 /* this function returns the new width of the column being resized given
7186 * the column and x position of the cursor; the x cursor position is passed
7187 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7189 new_column_width (GtkSheet * sheet,
7198 min_width = sheet->column_requisition;
7200 /* you can't shrink a column to less than its minimum width */
7201 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + min_width)
7203 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + min_width;
7206 /* don't grow past the end of the window */
7208 if (cx > sheet->sheet_window_width)
7210 *x = cx = sheet->sheet_window_width;
7213 /* calculate new column width making sure it doesn't end up
7214 * less than the minimum width */
7215 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7216 if (width < min_width)
7219 xxx_set_column_width(sheet, column, width);
7220 sheet->view.coli = COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7221 size_allocate_column_title_buttons (sheet);
7226 /* this function returns the new height of the row being resized given
7227 * the row and y position of the cursor; the y cursor position is passed
7228 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7230 new_row_height (GtkSheet * sheet,
7238 min_height = sheet->row_requisition;
7240 /* you can't shrink a row to less than its minimum height */
7241 if (cy < ROW_TOP_YPIXEL (sheet, row) + min_height)
7244 *y = cy = ROW_TOP_YPIXEL (sheet, row) + min_height;
7247 /* don't grow past the end of the window */
7249 if (cy > sheet->sheet_window_height)
7251 *y = cy = sheet->sheet_window_height;
7254 /* calculate new row height making sure it doesn't end up
7255 * less than the minimum height */
7256 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7257 if (height < min_height)
7258 height = min_height;
7260 yyy_set_row_height(sheet, row, height);
7261 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7262 size_allocate_row_title_buttons (sheet);
7268 gtk_sheet_set_column_width (GtkSheet * sheet,
7274 g_return_if_fail (sheet != NULL);
7275 g_return_if_fail (GTK_IS_SHEET (sheet));
7277 if (column < 0 || column >= xxx_column_count(sheet))
7280 gtk_sheet_column_size_request(sheet, column, &min_width);
7281 if(width < min_width) return;
7283 xxx_set_column_width(sheet, column, width);
7285 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet))
7287 size_allocate_column_title_buttons (sheet);
7288 adjust_scrollbars (sheet);
7289 gtk_sheet_size_allocate_entry(sheet);
7290 gtk_sheet_range_draw (sheet, NULL);
7293 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7294 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH],
7301 gtk_sheet_set_row_height (GtkSheet * sheet,
7307 g_return_if_fail (sheet != NULL);
7308 g_return_if_fail (GTK_IS_SHEET (sheet));
7310 if (row < 0 || row >= yyy_row_count(sheet))
7313 gtk_sheet_row_size_request(sheet, row, &min_height);
7314 if(height < min_height) return;
7316 yyy_set_row_height(sheet, row, height);
7318 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7319 size_allocate_row_title_buttons (sheet);
7320 adjust_scrollbars (sheet);
7321 gtk_sheet_size_allocate_entry(sheet);
7322 gtk_sheet_range_draw (sheet, NULL);
7325 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7326 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7332 gtk_sheet_get_attributes(const GtkSheet *sheet, gint row, gint col,
7333 GtkSheetCellAttr *attributes)
7335 const GdkColor *fg, *bg;
7336 const GtkJustification *j ;
7337 const PangoFontDescription *font_desc ;
7338 const GtkSheetCellBorder *border ;
7340 g_return_val_if_fail (sheet != NULL, FALSE);
7341 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7343 if(row < 0 || col < 0) return FALSE;
7345 init_attributes(sheet, col, attributes);
7350 attributes->is_editable = g_sheet_model_is_editable(sheet->model, row, col);
7351 attributes->is_visible = g_sheet_model_is_visible(sheet->model, row, col);
7353 fg = g_sheet_model_get_foreground(sheet->model, row, col);
7355 attributes->foreground = *fg;
7357 bg = g_sheet_model_get_background(sheet->model, row, col);
7359 attributes->background = *bg;
7361 j = g_sheet_model_get_justification(sheet->model, row, col);
7362 if (j) attributes->justification = *j;
7364 font_desc = g_sheet_model_get_font_desc(sheet->model, row, col);
7365 if ( font_desc ) attributes->font_desc = font_desc;
7367 border = g_sheet_model_get_cell_border(sheet->model, row, col);
7369 if ( border ) attributes->border = *border;
7375 init_attributes(const GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7377 /* DEFAULT VALUES */
7378 attributes->foreground = GTK_WIDGET(sheet)->style->black;
7379 attributes->background = sheet->bg_color;
7380 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7381 GdkColormap *colormap;
7382 colormap=gdk_colormap_get_system();
7383 gdk_color_black(colormap, &attributes->foreground);
7384 attributes->background = sheet->bg_color;
7386 attributes->justification = xxx_column_justification(sheet, col);
7387 attributes->border.width = 0;
7388 attributes->border.line_style = GDK_LINE_SOLID;
7389 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7390 attributes->border.join_style = GDK_JOIN_MITER;
7391 attributes->border.mask = 0;
7392 attributes->border.color = GTK_WIDGET(sheet)->style->black;
7393 attributes->is_editable = TRUE;
7394 attributes->is_visible = TRUE;
7395 attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7399 /********************************************************************
7400 * Container Functions:
7405 * gtk_sheet_move_child
7406 * gtk_sheet_position_child
7407 * gtk_sheet_position_children
7408 * gtk_sheet_realize_child
7409 * gtk_sheet_get_child_at
7410 ********************************************************************/
7413 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7415 GtkRequisition child_requisition;
7416 GtkSheetChild *child_info;
7418 g_return_val_if_fail(sheet != NULL, NULL);
7419 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7420 g_return_val_if_fail(child != NULL, NULL);
7421 g_return_val_if_fail(child->parent == NULL, NULL);
7423 child_info = g_new (GtkSheetChild, 1);
7424 child_info->widget = child;
7427 child_info->attached_to_cell = FALSE;
7428 child_info->floating = TRUE;
7429 child_info->xpadding = child_info->ypadding = 0;
7430 child_info->xexpand = child_info->yexpand = FALSE;
7431 child_info->xshrink = child_info->yshrink = FALSE;
7432 child_info->xfill = child_info->yfill = FALSE;
7434 sheet->children = g_list_append(sheet->children, child_info);
7436 gtk_widget_set_parent (child, GTK_WIDGET(sheet));
7438 gtk_widget_size_request(child, &child_requisition);
7440 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7442 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7443 (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
7444 gtk_sheet_realize_child(sheet, child_info);
7446 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7447 !GTK_WIDGET_MAPPED(child))
7448 gtk_widget_map(child);
7451 gtk_sheet_position_child(sheet, child_info);
7453 /* This will avoid drawing on the titles */
7455 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7457 if(sheet->row_titles_visible)
7458 gdk_window_show(sheet->row_title_window);
7459 if(sheet->column_titles_visible)
7460 gdk_window_show(sheet->column_title_window);
7463 return (child_info);
7467 gtk_sheet_attach_floating (GtkSheet *sheet,
7472 GtkSheetChild *child;
7474 if(row < 0 || col < 0){
7475 gtk_sheet_button_attach(sheet, widget, row, col);
7479 gtk_sheet_get_cell_area(sheet, row, col, &area);
7480 child = gtk_sheet_put(sheet, widget, area.x, area.y);
7481 child->attached_to_cell = TRUE;
7487 gtk_sheet_attach_default (GtkSheet *sheet,
7491 if(row < 0 || col < 0){
7492 gtk_sheet_button_attach(sheet, widget, row, col);
7496 gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
7500 gtk_sheet_attach (GtkSheet *sheet,
7509 GtkSheetChild *child = NULL;
7511 if(row < 0 || col < 0){
7512 gtk_sheet_button_attach(sheet, widget, row, col);
7516 child = g_new0(GtkSheetChild, 1);
7517 child->attached_to_cell = TRUE;
7518 child->floating = FALSE;
7519 child->widget = widget;
7522 child->xpadding = xpadding;
7523 child->ypadding = ypadding;
7524 child->xexpand = (xoptions & GTK_EXPAND) != 0;
7525 child->yexpand = (yoptions & GTK_EXPAND) != 0;
7526 child->xshrink = (xoptions & GTK_SHRINK) != 0;
7527 child->yshrink = (yoptions & GTK_SHRINK) != 0;
7528 child->xfill = (xoptions & GTK_FILL) != 0;
7529 child->yfill = (yoptions & GTK_FILL) != 0;
7531 sheet->children = g_list_append(sheet->children, child);
7533 gtk_sheet_get_cell_area(sheet, row, col, &area);
7535 child->x = area.x + child->xpadding;
7536 child->y = area.y + child->ypadding;
7538 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7540 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7541 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7542 gtk_sheet_realize_child(sheet, child);
7544 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7545 !GTK_WIDGET_MAPPED(widget))
7546 gtk_widget_map(widget);
7549 gtk_sheet_position_child(sheet, child);
7551 /* This will avoid drawing on the titles */
7553 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
7555 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
7556 gdk_window_show(sheet->row_title_window);
7557 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
7558 gdk_window_show(sheet->column_title_window);
7564 gtk_sheet_button_attach (GtkSheet *sheet,
7568 GtkSheetButton *button = 0;
7569 GtkSheetChild *child;
7570 GtkRequisition button_requisition;
7572 if(row >= 0 && col >= 0) return;
7573 if(row < 0 && col < 0) return;
7575 child = g_new (GtkSheetChild, 1);
7576 child->widget = widget;
7579 child->attached_to_cell = TRUE;
7580 child->floating = FALSE;
7583 child->xpadding = child->ypadding = 0;
7584 child->xshrink = child->yshrink = FALSE;
7585 child->xfill = child->yfill = FALSE;
7588 sheet->children = g_list_append(sheet->children, child);
7590 gtk_sheet_button_size_request(sheet, button, &button_requisition);
7593 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7595 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7596 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
7597 gtk_sheet_realize_child(sheet, child);
7599 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7600 !GTK_WIDGET_MAPPED(widget))
7601 gtk_widget_map(widget);
7604 if(row == -1) size_allocate_column_title_buttons(sheet);
7605 if(col == -1) size_allocate_row_title_buttons(sheet);
7610 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
7615 gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
7621 while(words && *words != '\0'){
7622 if(*words == '\n' || *(words+1) == '\0'){
7623 req->height += row_height;
7626 req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
7634 if(n > 0) req->height -= 2;
7638 gtk_sheet_button_size_request (GtkSheet *sheet,
7639 const GtkSheetButton *button,
7640 GtkRequisition *button_requisition)
7642 GtkRequisition requisition;
7643 GtkRequisition label_requisition;
7645 if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
7646 label_size_request(sheet, button->label, &label_requisition);
7647 label_requisition.width += 2*CELLOFFSET;
7648 label_requisition.height += 2*CELLOFFSET;
7650 label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7651 label_requisition.width = COLUMN_MIN_WIDTH;
7656 gtk_widget_size_request(button->child->widget, &requisition);
7657 requisition.width += 2*button->child->xpadding;
7658 requisition.height += 2*button->child->ypadding;
7659 requisition.width += 2*sheet->button->style->xthickness;
7660 requisition.height += 2*sheet->button->style->ythickness;
7664 requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
7665 requisition.width = COLUMN_MIN_WIDTH;
7668 *button_requisition = requisition;
7669 button_requisition->width = MAX(requisition.width, label_requisition.width);
7670 button_requisition->height = MAX(requisition.height, label_requisition.height);
7675 gtk_sheet_row_size_request (GtkSheet *sheet,
7679 GtkRequisition button_requisition;
7682 gtk_sheet_button_size_request(sheet,
7683 yyy_row_button(sheet, row),
7684 &button_requisition);
7686 *requisition = button_requisition.height;
7688 children = sheet->children;
7690 GtkSheetChild *child = (GtkSheetChild *)children->data;
7691 GtkRequisition child_requisition;
7693 if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
7694 gtk_widget_get_child_requisition(child->widget, &child_requisition);
7696 if(child_requisition.height + 2 * child->ypadding > *requisition)
7697 *requisition = child_requisition.height + 2 * child->ypadding;
7699 children = children->next;
7702 sheet->row_requisition = * requisition;
7706 gtk_sheet_column_size_request (GtkSheet *sheet,
7710 GtkRequisition button_requisition;
7713 gtk_sheet_button_size_request(sheet,
7714 xxx_column_button(sheet, col),
7715 &button_requisition);
7717 *requisition = button_requisition.width;
7719 children = sheet->children;
7721 GtkSheetChild *child = (GtkSheetChild *)children->data;
7722 GtkRequisition child_requisition;
7724 if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
7725 gtk_widget_get_child_requisition(child->widget, &child_requisition);
7727 if(child_requisition.width + 2 * child->xpadding > *requisition)
7728 *requisition = child_requisition.width + 2 * child->xpadding;
7730 children = children->next;
7733 sheet->column_requisition = *requisition;
7737 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
7739 GtkSheetChild *child;
7742 g_return_if_fail(sheet != NULL);
7743 g_return_if_fail(GTK_IS_SHEET(sheet));
7745 children = sheet->children;
7748 child = children->data;
7750 if(child->widget == widget){
7753 child->row = ROW_FROM_YPIXEL(sheet, y);
7754 child->col = COLUMN_FROM_XPIXEL(sheet, x);
7755 gtk_sheet_position_child(sheet, child);
7759 children = children->next;
7762 g_warning("Widget must be a GtkSheet child");
7767 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
7769 GtkRequisition child_requisition;
7770 GtkAllocation child_allocation;
7776 gtk_widget_get_child_requisition(child->widget, &child_requisition);
7778 if(sheet->column_titles_visible)
7779 yoffset = sheet->column_title_area.height;
7781 if(sheet->row_titles_visible)
7782 xoffset = sheet->row_title_area.width;
7784 if(child->attached_to_cell){
7786 child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
7787 child->y = ROW_TOP_YPIXEL(sheet, child->row);
7789 if(sheet->row_titles_visible)
7790 child->x-=sheet->row_title_area.width;
7791 if(sheet->column_titles_visible)
7792 child->y-=sheet->column_title_area.height;
7794 width = xxx_column_width(sheet, child->col);
7795 height = yyy_row_height(sheet, child->row);
7798 gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
7799 child->x = area.x + child->xpadding;
7800 child->y = area.y + child->ypadding;
7802 if(!child->floating){
7803 if(child_requisition.width + 2*child->xpadding <= xxx_column_width(sheet, child->col)){
7805 child_requisition.width = child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7808 child->x = area.x + xxx_column_width(sheet, child->col) / 2 -
7809 child_requisition.width / 2;
7811 child_allocation.width = child_requisition.width;
7814 if(!child->xshrink){
7815 gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
7817 child_allocation.width = xxx_column_width(sheet, child->col) - 2*child->xpadding;
7820 if(child_requisition.height + 2*child->ypadding <= yyy_row_height(sheet, child->row)){
7822 child_requisition.height = child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7825 child->y = area.y + yyy_row_height(sheet, child->row) / 2 -
7826 child_requisition.height / 2;
7828 child_allocation.height = child_requisition.height;
7831 if(!child->yshrink){
7832 gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
7834 child_allocation.height = yyy_row_height(sheet, child->row) - 2*child->ypadding;
7837 child_allocation.width = child_requisition.width;
7838 child_allocation.height = child_requisition.height;
7841 x = child_allocation.x = child->x + xoffset;
7842 y = child_allocation.y = child->y + yoffset;
7846 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
7847 x = child_allocation.x = child->x + xoffset;
7848 y = child_allocation.y = child->y + sheet->voffset + yoffset;
7849 y = child_allocation.y = child->y + yoffset;
7850 child_allocation.width = child_requisition.width;
7851 child_allocation.height = child_requisition.height;
7854 gtk_widget_size_allocate(child->widget, &child_allocation);
7855 gtk_widget_queue_draw(child->widget);
7859 gtk_sheet_forall (GtkContainer *container,
7860 gboolean include_internals,
7861 GtkCallback callback,
7862 gpointer callback_data)
7865 GtkSheetChild *child;
7868 g_return_if_fail (GTK_IS_SHEET (container));
7869 g_return_if_fail (callback != NULL);
7871 sheet = GTK_SHEET (container);
7872 children = sheet->children;
7875 child = children->data;
7876 children = children->next;
7878 (* callback) (child->widget, callback_data);
7881 (* callback) (sheet->button, callback_data);
7882 if(sheet->sheet_entry)
7883 (* callback) (sheet->sheet_entry, callback_data);
7888 gtk_sheet_position_children(GtkSheet *sheet)
7891 GtkSheetChild *child;
7893 children = sheet->children;
7897 child = (GtkSheetChild *)children->data;
7899 if(child->col !=-1 && child->row != -1)
7900 gtk_sheet_position_child(sheet, child);
7902 if(child->row == -1){
7903 if(child->col < MIN_VISIBLE_COLUMN(sheet) ||
7904 child->col > MAX_VISIBLE_COLUMN(sheet))
7905 gtk_sheet_child_hide(child);
7907 gtk_sheet_child_show(child);
7909 if(child->col == -1){
7910 if(child->row < MIN_VISIBLE_ROW(sheet) ||
7911 child->row > MAX_VISIBLE_ROW(sheet))
7912 gtk_sheet_child_hide(child);
7914 gtk_sheet_child_show(child);
7917 children = children->next;
7923 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
7927 GtkSheetChild *child = 0;
7929 g_return_if_fail(container != NULL);
7930 g_return_if_fail(GTK_IS_SHEET(container));
7932 sheet = GTK_SHEET(container);
7934 children = sheet->children;
7938 child = (GtkSheetChild *)children->data;
7940 if(child->widget == widget) break;
7942 children = children->next;
7947 gtk_widget_unparent (widget);
7948 child->widget = NULL;
7950 sheet->children = g_list_remove_link (sheet->children, children);
7951 g_list_free_1 (children);
7958 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
7962 widget = GTK_WIDGET(sheet);
7964 if(GTK_WIDGET_REALIZED(widget)){
7965 if(child->row == -1)
7966 gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
7967 else if(child->col == -1)
7968 gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
7970 gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
7973 gtk_widget_set_parent(child->widget, widget);
7979 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
7982 GtkSheetChild *child = 0;
7984 g_return_val_if_fail(sheet != NULL, NULL);
7985 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7987 children = sheet->children;
7991 child = (GtkSheetChild *)children->data;
7993 if(child->attached_to_cell)
7994 if(child->row == row && child->col == col) break;
7996 children = children->next;
7999 if(children) return child;
8005 gtk_sheet_child_hide(GtkSheetChild *child)
8007 g_return_if_fail(child != NULL);
8008 gtk_widget_hide(child->widget);
8012 gtk_sheet_child_show(GtkSheetChild *child)
8014 g_return_if_fail(child != NULL);
8016 gtk_widget_show(child->widget);
8020 gtk_sheet_get_model(const GtkSheet *sheet)
8022 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
8024 return sheet->model;
8029 gtk_sheet_button_new(void)
8031 GtkSheetButton *button = g_malloc(sizeof(GtkSheetButton));
8033 button->state = GTK_STATE_NORMAL;
8034 button->label = NULL;
8035 button->label_visible = TRUE;
8036 button->child = NULL;
8037 button->justification = GTK_JUSTIFY_FILL;
8044 gtk_sheet_button_free(GtkSheetButton *button)
8046 if (!button) return ;
8048 g_free(button->label);