Updated all po files by running make update-po (in prep for a release)
[geda-gaf/whiteaudio.git] / gattrib / src / gtksheet_2_2.c
blob6fcf77bff5b3d2cd1c28bf4d258fd58a219a0c19
1 /* GtkSheet widget for Gtk+.
2 * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
4 * Based on GtkClist widget by Jay Painter, but major changes.
5 * Memory allocation routines inspired on SC (Spreadsheet Calculator)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <glib.h>
31 #include <glib-object.h>
32 #include <gobject/gvaluecollector.h>
33 #include <gdk/gdk.h>
34 #include <gdk/gdkkeysyms.h>
35 #include <gtk/gtksignal.h>
36 #include <gtk/gtklabel.h>
37 #include <gtk/gtkbutton.h>
38 #include <gtk/gtkadjustment.h>
39 #include <gtk/gtktable.h>
40 #include <gtk/gtkbox.h>
41 #include <gtk/gtkmain.h>
42 #include <gtk/gtktypeutils.h>
43 #include <gtk/gtkentry.h>
44 #include <gtk/gtkcontainer.h>
45 #include <gtk/gtkpixmap.h>
46 #include <pango/pango.h>
47 #include "gtkitementry_2_2.h"
48 #include "gtksheet_2_2.h"
49 #include "gtkextra-marshal.h"
51 /*------------------------------------------------------------------
52 * Gattrib specific includes -- stuff dealing with gattrib data structs.
53 * Included here in order to grab sheet_head->CHANGED, which is set
54 * when the user puts a new value in a cell.
55 *------------------------------------------------------------------*/
56 #include <libgeda/libgeda.h> /* geda library fcns */
57 #include "../include/struct.h" /* typdef and struct declarations */
58 #include "../include/prototype.h" /* function prototypes */
59 #include "../include/globals.h"
61 #ifdef HAVE_LIBDMALLOC
62 #include <dmalloc.h>
63 #endif
66 /* sheet flags */
67 enum
69 GTK_SHEET_IS_LOCKED = 1 << 0,
70 GTK_SHEET_IS_FROZEN = 1 << 1,
71 GTK_SHEET_IN_XDRAG = 1 << 2,
72 GTK_SHEET_IN_YDRAG = 1 << 3,
73 GTK_SHEET_IN_DRAG = 1 << 4,
74 GTK_SHEET_IN_SELECTION = 1 << 5,
75 GTK_SHEET_IN_RESIZE = 1 << 6,
76 GTK_SHEET_IN_CLIP = 1 << 7,
77 GTK_SHEET_REDRAW_PENDING = 1 << 8,
80 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
81 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
82 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~(flag))
84 #define GTK_SHEET_IS_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
94 #define DRAG_WIDTH 6
95 #define TIMEOUT_SCROLL 20
96 #define TIMEOUT_FLASH 200
97 #define TIME_INTERVAL 8
98 #define COLUMN_MIN_WIDTH 10
99 #define MINROWS 1
100 #define MINCOLS 1
101 #define MAXLENGTH 30
102 #define CELLOFFSET 4
103 #define DEFAULT_COLUMN_WIDTH 80
105 static inline guint DEFAULT_ROW_HEIGHT(GtkWidget *widget)
107 if(!widget->style->font_desc) return 24;
108 else {
109 PangoContext *context = gtk_widget_get_pango_context(widget);
110 PangoFontMetrics *metrics = pango_context_get_metrics(context,
111 widget->style->font_desc,
112 pango_context_get_language(context));
113 guint val = pango_font_metrics_get_descent(metrics) +
114 pango_font_metrics_get_ascent(metrics);
115 pango_font_metrics_unref(metrics);
116 return PANGO_PIXELS(val)+2*CELLOFFSET;
119 static inline guint DEFAULT_FONT_ASCENT(GtkWidget *widget)
121 if(!widget->style->font_desc) return 12;
122 else {
123 PangoContext *context = gtk_widget_get_pango_context(widget);
124 PangoFontMetrics *metrics = pango_context_get_metrics(context,
125 widget->style->font_desc,
126 pango_context_get_language(context));
127 guint val = pango_font_metrics_get_ascent(metrics);
128 pango_font_metrics_unref(metrics);
129 return PANGO_PIXELS(val);
132 static inline guint STRING_WIDTH(GtkWidget *widget,
133 PangoFontDescription *font, const gchar *text)
135 PangoRectangle rect;
136 PangoLayout *layout;
138 layout = gtk_widget_create_pango_layout (widget, text);
139 pango_layout_set_font_description (layout, font);
141 pango_layout_get_extents (layout, NULL, &rect);
143 g_object_unref(G_OBJECT(layout));
144 return PANGO_PIXELS(rect.width);
147 static inline guint DEFAULT_FONT_DESCENT(GtkWidget *widget)
149 if(!widget->style->font_desc) return 12;
150 else {
151 PangoContext *context = gtk_widget_get_pango_context(widget);
152 PangoFontMetrics *metrics = pango_context_get_metrics(context,
153 widget->style->font_desc,
154 pango_context_get_language(context));
155 guint val = pango_font_metrics_get_descent(metrics);
156 pango_font_metrics_unref(metrics);
157 return PANGO_PIXELS(val);
161 /*! \brief gives the top pixel of the given row in context of
162 * the sheet's voffset
165 static inline gint
166 ROW_TOP_YPIXEL(GtkSheet *sheet, gint nrow)
168 return (sheet->voffset + sheet->row[nrow].top_ypixel);
172 /*! \brief returns the row index from a y pixel location in the
173 * context of the sheet's voffset
176 static inline gint
177 ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
179 gint i, cy;
181 cy = sheet->voffset;
182 if(sheet->column_titles_visible) cy += sheet->column_title_area.height;
183 if(y < cy) return 0;
184 for (i = 0; i <= sheet->maxrow; i++)
186 if (y >= cy && y <= (cy + sheet->row[i].height) && sheet->row[i].is_visible)
187 return i;
188 if(sheet->row[i].is_visible) cy += sheet->row[i].height;
192 /* no match */
193 return sheet->maxrow;
197 /*! \brief gives the left pixel of the given column in context of
198 * the sheet's hoffset
201 static inline gint
202 COLUMN_LEFT_XPIXEL(GtkSheet *sheet, gint ncol)
204 return (sheet->hoffset + sheet->column[ncol].left_xpixel);
207 /*! \brief returns the column index from a x pixel location in the
208 * context of the sheet's hoffset
211 static inline gint
212 COLUMN_FROM_XPIXEL (GtkSheet * sheet,
213 gint x)
215 gint i, cx;
217 cx = sheet->hoffset;
218 if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
219 if(x < cx) return 0;
220 for (i = 0; i <= sheet->maxcol; i++)
222 if (x >= cx && x <= (cx + sheet->column[i].width) && sheet->column[i].is_visible)
223 return i;
224 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
228 /* no match */
229 return sheet->maxcol;
232 /*! \brief returns the total height of the sheet
235 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
237 gint i,cx;
239 cx = 0;
240 if(sheet->column_titles_visible) cx += sheet->column_title_area.height;
241 for (i=0;i<=sheet->maxrow; i++)
242 if(sheet->row[i].is_visible) cx += sheet->row[i].height;
244 return cx;
248 /*! \brief returns the total width of the sheet
251 static inline gint SHEET_WIDTH(GtkSheet *sheet)
253 gint i,cx;
255 cx = 0;
256 if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
257 for (i=0;i<=sheet->maxcol; i++)
258 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
260 return cx;
263 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
264 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
265 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
266 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
269 static inline gint
270 POSSIBLE_XDRAG(GtkSheet *sheet, gint x, gint *drag_column)
272 gint column, xdrag;
274 column=COLUMN_FROM_XPIXEL(sheet, x);
275 *drag_column=column;
277 xdrag=COLUMN_LEFT_XPIXEL(sheet,column)+CELL_SPACING;
278 if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
279 while(!sheet->column[column-1].is_visible && column>0) column--;
280 *drag_column=column-1;
281 return sheet->column[column-1].is_sensitive;
284 xdrag+=sheet->column[column].width;
285 if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
286 return sheet->column[column].is_sensitive;
288 return FALSE;
291 static inline gint
292 POSSIBLE_YDRAG(GtkSheet *sheet, gint y, gint *drag_row)
294 gint row, ydrag;
296 row=ROW_FROM_YPIXEL(sheet, y);
297 *drag_row=row;
299 ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
300 if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
301 while(!sheet->row[row-1].is_visible && row>0) row--;
302 *drag_row=row-1;
303 return sheet->row[row-1].is_sensitive;
306 ydrag+=sheet->row[row].height;
308 if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
309 return sheet->row[row].is_sensitive;
312 return FALSE;
315 static inline gint POSSIBLE_DRAG(GtkSheet *sheet, gint x, gint y,
316 gint *drag_row, gint *drag_column)
318 gint ydrag, xdrag;
320 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
321 *drag_row=ROW_FROM_YPIXEL(sheet,y);
323 if(x>=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0)-DRAG_WIDTH/2 &&
324 x<=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
325 sheet->column[sheet->range.coli].width+DRAG_WIDTH/2){
326 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
327 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
328 *drag_row=sheet->range.row0;
329 return TRUE;
331 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
332 sheet->row[sheet->range.rowi].height;
333 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
334 *drag_row=sheet->range.rowi;
335 return TRUE;
339 if(y>=ROW_TOP_YPIXEL(sheet,sheet->range.row0)-DRAG_WIDTH/2 &&
340 y<=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
341 sheet->row[sheet->range.rowi].height+DRAG_WIDTH/2){
342 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0);
343 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
344 *drag_column=sheet->range.col0;
345 return TRUE;
347 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
348 sheet->column[sheet->range.coli].width;
349 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
350 *drag_column=sheet->range.coli;
351 return TRUE;
354 return FALSE;
357 static inline gint POSSIBLE_RESIZE(GtkSheet *sheet, gint x, gint y,
358 gint *drag_row, gint *drag_column)
360 gint xdrag, ydrag;
362 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
363 sheet->column[sheet->range.coli].width;
365 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
366 sheet->row[sheet->range.rowi].height;
368 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
369 ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
371 if(sheet->state == GTK_SHEET_ROW_SELECTED)
372 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
374 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
375 *drag_row=ROW_FROM_YPIXEL(sheet,y);
377 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
378 y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
380 return FALSE;
383 static void gtk_sheet_class_init (GtkSheetClass * klass);
384 static void gtk_sheet_init (GtkSheet * sheet);
385 static void gtk_sheet_destroy (GtkObject * object);
386 static void gtk_sheet_finalize (GObject * object);
387 static void gtk_sheet_style_set (GtkWidget *widget,
388 GtkStyle *previous_style);
389 static void gtk_sheet_realize (GtkWidget * widget);
390 static void gtk_sheet_unrealize (GtkWidget * widget);
391 static void gtk_sheet_map (GtkWidget * widget);
392 static void gtk_sheet_unmap (GtkWidget * widget);
393 static gint gtk_sheet_expose (GtkWidget * widget,
394 GdkEventExpose * event);
395 static void gtk_sheet_forall (GtkContainer *container,
396 gboolean include_internals,
397 GtkCallback callback,
398 gpointer callback_data);
400 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
401 GtkAdjustment *hadjustment,
402 GtkAdjustment *vadjustment);
404 static gint gtk_sheet_button_press (GtkWidget * widget,
405 GdkEventButton * event);
406 static gint gtk_sheet_button_release (GtkWidget * widget,
407 GdkEventButton * event);
408 static gint gtk_sheet_motion (GtkWidget * widget,
409 GdkEventMotion * event);
411 #if 0
412 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
413 GdkEventKey *key);
414 #endif
416 static gint gtk_sheet_key_press (GtkWidget *widget,
417 GdkEventKey *key);
419 static void gtk_sheet_size_request (GtkWidget * widget,
420 GtkRequisition * requisition);
421 static void gtk_sheet_size_allocate (GtkWidget * widget,
422 GtkAllocation * allocation);
424 /* Sheet queries */
426 static gint gtk_sheet_range_isvisible (GtkSheet * sheet,
427 GtkSheetRange range);
428 static gint gtk_sheet_cell_isvisible (GtkSheet * sheet,
429 gint row, gint column);
430 /* Clipped Range */
432 static gint gtk_sheet_scroll (gpointer data);
433 static gint gtk_sheet_flash (gpointer data);
435 /* Drawing Routines */
437 /* draw cell background and frame */
438 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
439 gint row, gint column);
441 /* draw cell border */
442 static void gtk_sheet_cell_draw_border (GtkSheet *sheet,
443 gint row, gint column,
444 gint mask);
446 /* draw cell contents */
447 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
448 gint row, gint column);
450 /* draw visible part of range. If range==NULL then draw the whole screen */
451 static void gtk_sheet_range_draw (GtkSheet *sheet,
452 const GtkSheetRange *range);
454 /* highlight the visible part of the selected range */
455 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
456 GtkSheetRange range);
458 /* Selection */
460 static gint gtk_sheet_move_query (GtkSheet *sheet,
461 gint row, gint column);
462 static void gtk_sheet_real_select_range (GtkSheet * sheet,
463 GtkSheetRange * range);
464 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
465 const GtkSheetRange * range);
466 static void gtk_sheet_extend_selection (GtkSheet *sheet,
467 gint row, gint column);
468 static void gtk_sheet_new_selection (GtkSheet *sheet,
469 GtkSheetRange *range);
470 static void gtk_sheet_draw_border (GtkSheet *sheet,
471 GtkSheetRange range);
472 static void gtk_sheet_draw_corners (GtkSheet *sheet,
473 GtkSheetRange range);
476 /* Active Cell handling */
478 static void gtk_sheet_entry_changed (GtkWidget *widget,
479 gpointer data);
480 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
481 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
482 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
483 gint row, gint col);
484 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
485 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
486 static void gtk_sheet_click_cell (GtkSheet *sheet,
487 gint row,
488 gint column,
489 gboolean *veto);
491 /* Backing Pixmap */
493 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
494 guint width, guint height);
495 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
496 GtkSheetRange range);
497 /* Scrollbars */
499 static void adjust_scrollbars (GtkSheet * sheet);
500 static void vadjustment_changed (GtkAdjustment * adjustment,
501 gpointer data);
502 static void hadjustment_changed (GtkAdjustment * adjustment,
503 gpointer data);
504 static void vadjustment_value_changed (GtkAdjustment * adjustment,
505 gpointer data);
506 static void hadjustment_value_changed (GtkAdjustment * adjustment,
507 gpointer data);
510 static void draw_xor_vline (GtkSheet * sheet);
511 static void draw_xor_hline (GtkSheet * sheet);
512 static void draw_xor_rectangle (GtkSheet *sheet,
513 GtkSheetRange range);
514 static void gtk_sheet_draw_flashing_range (GtkSheet *sheet,
515 GtkSheetRange range);
516 static guint new_column_width (GtkSheet * sheet,
517 gint column,
518 gint * x);
519 static guint new_row_height (GtkSheet * sheet,
520 gint row,
521 gint * y);
522 /* Sheet Button */
524 static void create_global_button (GtkSheet *sheet);
525 static void global_button_clicked (GtkWidget *widget,
526 gpointer data);
527 /* Sheet Entry */
529 static void create_sheet_entry (GtkSheet *sheet);
530 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
531 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
533 /* Sheet button gadgets */
535 static void size_allocate_column_title_buttons (GtkSheet * sheet);
536 static void size_allocate_row_title_buttons (GtkSheet * sheet);
537 static void gtk_sheet_recalc_top_ypixels (GtkSheet *sheet,
538 gint row);
539 static void gtk_sheet_recalc_left_xpixels (GtkSheet *sheet,
540 gint column);
541 static void row_button_set (GtkSheet *sheet,
542 gint row);
543 static void column_button_set (GtkSheet *sheet,
544 gint column);
545 static void row_button_release (GtkSheet *sheet,
546 gint row);
547 static void column_button_release (GtkSheet *sheet,
548 gint column);
549 static void gtk_sheet_button_draw (GtkSheet *sheet,
550 gint row, gint column);
551 static void size_allocate_global_button (GtkSheet *sheet);
552 static void gtk_sheet_button_size_request (GtkSheet *sheet,
553 GtkSheetButton *button,
554 GtkRequisition *requisition);
556 /* Attributes routines */
558 static void gtk_sheet_set_cell_attributes (GtkSheet *sheet,
559 gint row, gint col,
560 GtkSheetCellAttr attributes);
562 static void init_attributes (GtkSheet *sheet, gint col,
563 GtkSheetCellAttr *attributes);
564 /* Memory allocation routines */
565 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
566 const GtkSheetRange *range,
567 gboolean delete);
568 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
569 gint row,
570 gint column,
571 gboolean delete);
572 static GtkSheetCell * gtk_sheet_cell_new (void);
573 static gint AddRow (GtkSheet *sheet, gint nrows);
574 static gint AddColumn (GtkSheet *sheet, gint ncols);
575 static gint InsertRow (GtkSheet *sheet, gint row, gint nrows);
576 static gint InsertColumn (GtkSheet *sheet, gint col, gint ncols);
577 static gint DeleteRow (GtkSheet *sheet, gint row, gint nrows);
578 static gint DeleteColumn (GtkSheet *sheet, gint col, gint ncols);
579 static gint GrowSheet (GtkSheet *sheet,
580 gint newrows, gint newcols);
581 static gint CheckBounds (GtkSheet *sheet,
582 gint row, gint col);
584 /* Container Functions */
585 static void gtk_sheet_remove (GtkContainer *container,
586 GtkWidget *widget);
587 static void gtk_sheet_realize_child (GtkSheet *sheet,
588 GtkSheetChild *child);
589 static void gtk_sheet_position_child (GtkSheet *sheet,
590 GtkSheetChild *child);
591 static void gtk_sheet_position_children (GtkSheet *sheet);
592 static void gtk_sheet_child_show (GtkSheetChild *child);
593 static void gtk_sheet_child_hide (GtkSheetChild *child);
594 static void gtk_sheet_column_size_request (GtkSheet *sheet,
595 gint col,
596 guint *requisition);
597 static void gtk_sheet_row_size_request (GtkSheet *sheet,
598 gint row,
599 guint *requisition);
602 /* Signals */
604 /* \brief Imported from gtkextra.c by SDB 7.22.2004
607 void
608 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...)
610 gboolean *result;
611 GValue ret = { 0, };
612 GValue instance_and_params [10] = { {0, }, };
613 va_list var_args;
614 GSignalQuery query;
615 gchar *error;
616 int i;
618 va_start (var_args, signal_id);
620 g_value_init(instance_and_params + 0, GTK_OBJECT_TYPE(object));
621 g_value_set_instance (instance_and_params + 0, G_OBJECT(object));
623 g_signal_query(signal_id, &query);
625 for (i = 0; i < query.n_params; i++)
627 gboolean static_scope = query.param_types[i]&~G_SIGNAL_TYPE_STATIC_SCOPE;
628 g_value_init(instance_and_params + i + 1, query.param_types[i]);
631 G_VALUE_COLLECT (instance_and_params + i + 1,
632 var_args,
633 static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
634 &error);
636 if (error)
638 g_warning ("%s: %s", G_STRLOC, error);
639 g_free (error);
640 while (i-- > 0)
641 g_value_unset (instance_and_params + i);
643 va_end (var_args);
644 return;
650 g_value_init(&ret, query.return_type);
651 result = va_arg(var_args,gboolean *);
652 g_value_set_boolean(&ret, *result);
653 g_signal_emitv(instance_and_params, signal_id, 0, &ret);
654 *result = g_value_get_boolean(&ret);
655 g_value_unset (&ret);
657 for (i = 0; i < query.n_params; i++)
658 g_value_unset (instance_and_params + 1 + i);
659 g_value_unset (instance_and_params + 0);
661 va_end (var_args);
665 enum {
666 SELECT_ROW,
667 SELECT_COLUMN,
668 SELECT_RANGE,
669 CLIP_RANGE,
670 RESIZE_RANGE,
671 MOVE_RANGE,
672 TRAVERSE,
673 DEACTIVATE,
674 ACTIVATE,
675 SET_CELL,
676 CLEAR_CELL,
677 CHANGED,
678 NEW_COL_WIDTH,
679 NEW_ROW_HEIGHT,
680 LAST_SIGNAL
683 static GtkContainerClass *parent_class = NULL;
684 static guint sheet_signals[LAST_SIGNAL] = {0};
687 GType
688 gtk_sheet_get_type ()
690 static GType sheet_type = 0;
692 if (!sheet_type)
694 static const GTypeInfo sheet_info =
696 sizeof (GtkSheetClass),
697 NULL,
698 NULL,
699 (GClassInitFunc) gtk_sheet_class_init,
700 NULL,
701 NULL,
702 sizeof (GtkSheet),
704 (GInstanceInitFunc) gtk_sheet_init,
705 NULL,
707 sheet_type =
708 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
709 &sheet_info, 0);
711 return sheet_type;
714 static GtkSheetRange*
715 gtk_sheet_range_copy (const GtkSheetRange *range)
717 GtkSheetRange *new_range;
719 g_return_val_if_fail (range != NULL, NULL);
721 new_range = g_new (GtkSheetRange, 1);
723 *new_range = *range;
725 return new_range;
728 static void
729 gtk_sheet_range_free (GtkSheetRange *range)
731 g_return_if_fail (range != NULL);
733 g_free (range);
736 GType
737 gtk_sheet_range_get_type (void)
739 static GType sheet_range_type;
741 if(!sheet_range_type)
743 sheet_range_type = g_boxed_type_register_static("GtkSheetRange", (GBoxedCopyFunc)gtk_sheet_range_copy, (GBoxedFreeFunc)gtk_sheet_range_free);
745 return sheet_range_type;
749 static void
750 gtk_sheet_class_init (GtkSheetClass * klass)
752 GtkObjectClass *object_class;
753 GtkWidgetClass *widget_class;
754 GtkContainerClass *container_class;
755 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
757 object_class = (GtkObjectClass *) klass;
758 widget_class = (GtkWidgetClass *) klass;
759 container_class = (GtkContainerClass *) klass;
761 parent_class = g_type_class_peek_parent (klass);
763 sheet_signals[SELECT_ROW] =
764 gtk_signal_new ("select_row",
765 GTK_RUN_LAST,
766 GTK_CLASS_TYPE(object_class),
767 GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
768 gtkextra_VOID__INT,
769 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
771 sheet_signals[SELECT_COLUMN] =
772 gtk_signal_new ("select_column",
773 GTK_RUN_LAST,
774 GTK_CLASS_TYPE(object_class),
775 GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
776 gtkextra_VOID__INT,
777 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
779 sheet_signals[SELECT_RANGE] =
780 gtk_signal_new ("select_range",
781 GTK_RUN_LAST,
782 GTK_CLASS_TYPE(object_class),
783 GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
784 gtkextra_VOID__BOXED,
785 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
787 sheet_signals[CLIP_RANGE] =
788 gtk_signal_new ("clip_range",
789 GTK_RUN_LAST,
790 GTK_CLASS_TYPE(object_class),
791 GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
792 gtkextra_VOID__BOXED,
793 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
795 sheet_signals[RESIZE_RANGE] =
796 gtk_signal_new ("resize_range",
797 GTK_RUN_LAST,
798 GTK_CLASS_TYPE(object_class),
799 GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
800 gtkextra_VOID__BOXED_BOXED,
801 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
802 sheet_signals[MOVE_RANGE] =
803 gtk_signal_new ("move_range",
804 GTK_RUN_LAST,
805 GTK_CLASS_TYPE(object_class),
806 GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
807 gtkextra_VOID__BOXED_BOXED,
808 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
809 sheet_signals[TRAVERSE] =
810 gtk_signal_new ("traverse",
811 GTK_RUN_LAST,
812 GTK_CLASS_TYPE(object_class),
813 GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
814 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
815 GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
816 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
818 sheet_signals[DEACTIVATE] =
819 gtk_signal_new ("deactivate",
820 GTK_RUN_LAST,
821 GTK_CLASS_TYPE(object_class),
822 GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
823 gtkextra_BOOLEAN__INT_INT,
824 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
826 sheet_signals[ACTIVATE] =
827 gtk_signal_new ("activate",
828 GTK_RUN_LAST,
829 GTK_CLASS_TYPE(object_class),
830 GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
831 gtkextra_BOOLEAN__INT_INT,
832 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
834 sheet_signals[SET_CELL] =
835 gtk_signal_new ("set_cell",
836 GTK_RUN_LAST,
837 GTK_CLASS_TYPE(object_class),
838 GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
839 gtkextra_VOID__INT_INT,
840 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
842 sheet_signals[CLEAR_CELL] =
843 gtk_signal_new ("clear_cell",
844 GTK_RUN_LAST,
845 GTK_CLASS_TYPE(object_class),
846 GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
847 gtkextra_VOID__INT_INT,
848 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
850 sheet_signals[CHANGED] =
851 gtk_signal_new ("changed",
852 GTK_RUN_LAST,
853 GTK_CLASS_TYPE(object_class),
854 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
855 gtkextra_VOID__INT_INT,
856 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
858 sheet_signals[NEW_COL_WIDTH] =
859 gtk_signal_new ("new_column_width",
860 GTK_RUN_LAST,
861 GTK_CLASS_TYPE(object_class),
862 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
863 gtkextra_VOID__INT_INT,
864 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
866 sheet_signals[NEW_ROW_HEIGHT] =
867 gtk_signal_new ("new_row_height",
868 GTK_RUN_LAST,
869 GTK_CLASS_TYPE(object_class),
870 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
871 gtkextra_VOID__INT_INT,
872 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
876 widget_class->set_scroll_adjustments_signal =
877 gtk_signal_new ("set_scroll_adjustments",
878 GTK_RUN_LAST,
879 GTK_CLASS_TYPE(object_class),
880 GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
881 gtkextra_VOID__OBJECT_OBJECT,
882 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
885 container_class->add = NULL;
886 container_class->remove = gtk_sheet_remove;
887 container_class->forall = gtk_sheet_forall;
889 object_class->destroy = gtk_sheet_destroy;
890 gobject_class->finalize = gtk_sheet_finalize;
892 widget_class->realize = gtk_sheet_realize;
893 widget_class->unrealize = gtk_sheet_unrealize;
894 widget_class->map = gtk_sheet_map;
895 widget_class->unmap = gtk_sheet_unmap;
896 widget_class->style_set = gtk_sheet_style_set;
897 widget_class->button_press_event = gtk_sheet_button_press;
898 widget_class->button_release_event = gtk_sheet_button_release;
899 widget_class->motion_notify_event = gtk_sheet_motion;
900 widget_class->key_press_event = gtk_sheet_key_press;
901 widget_class->expose_event = gtk_sheet_expose;
902 widget_class->size_request = gtk_sheet_size_request;
903 widget_class->size_allocate = gtk_sheet_size_allocate;
904 widget_class->focus_in_event = NULL;
905 widget_class->focus_out_event = NULL;
907 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
908 klass->select_row = NULL;
909 klass->select_column = NULL;
910 klass->select_range = NULL;
911 klass->clip_range = NULL;
912 klass->resize_range = NULL;
913 klass->move_range = NULL;
914 klass->traverse = NULL;
915 klass->deactivate = NULL;
916 klass->activate = NULL;
917 klass->set_cell = NULL;
918 klass->clear_cell = NULL;
919 klass->changed = NULL;
921 gtk_widget_class_install_style_property (widget_class,
922 g_param_spec_boxed ("default-border",
923 NULL, /* P_("Default Spacing"),*/
924 NULL, /* P_("Extra space to add for CAN_DEFAULT buttons"), */
925 GTK_TYPE_BORDER,
926 G_PARAM_READABLE));
928 gtk_widget_class_install_style_property (widget_class,
929 g_param_spec_boxed ("default-outside-border",
930 NULL, /* P_("Default Outside Spacing"), */
931 NULL, /* P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"), */
932 GTK_TYPE_BORDER,
933 G_PARAM_READABLE));
936 static void
937 gtk_sheet_init (GtkSheet *sheet)
939 sheet->children = NULL;
941 sheet->flags = 0;
942 sheet->selection_mode = GTK_SELECTION_BROWSE;
943 sheet->freeze_count = 0;
944 sheet->state = GTK_SHEET_NORMAL;
946 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
947 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
949 sheet->maxrow = 0;
950 sheet->maxcol = 0;
952 sheet->view.row0 = 0;
953 sheet->view.col0 = 0;
954 sheet->view.rowi = 0;
955 sheet->view.coli = 0;
957 sheet->maxallocrow = 0;
958 sheet->maxalloccol = 0;
960 sheet->column_title_window=NULL;
961 sheet->column_title_area.x=0;
962 sheet->column_title_area.y=0;
963 sheet->column_title_area.width=0;
964 sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
966 sheet->row_title_window=NULL;
967 sheet->row_title_area.x=0;
968 sheet->row_title_area.y=0;
969 sheet->row_title_area.width=DEFAULT_COLUMN_WIDTH;
970 sheet->row_title_area.height=0;
972 sheet->active_cell.row=0;
973 sheet->active_cell.col=0;
974 sheet->selection_cell.row=0;
975 sheet->selection_cell.col=0;
977 sheet->sheet_entry=NULL;
978 sheet->pixmap=NULL;
980 sheet->range.row0=0;
981 sheet->range.rowi=0;
982 sheet->range.col0=0;
983 sheet->range.coli=0;
985 sheet->state=GTK_SHEET_NORMAL;
987 sheet->sheet_window = NULL;
988 sheet->sheet_window_width = 0;
989 sheet->sheet_window_height = 0;
990 sheet->sheet_entry = NULL;
991 sheet->button = NULL;
993 sheet->hoffset = 0;
994 sheet->voffset = 0;
996 sheet->hadjustment = NULL;
997 sheet->vadjustment = NULL;
999 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
1000 sheet->xor_gc = NULL;
1001 sheet->fg_gc = NULL;
1002 sheet->bg_gc = NULL;
1003 sheet->x_drag = 0;
1004 sheet->y_drag = 0;
1006 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
1007 gdk_color_parse("gray", &sheet->grid_color);
1008 gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1009 sheet->show_grid = TRUE;
1012 GtkWidget *
1013 gtk_sheet_new (guint rows, guint columns, const gchar *title)
1015 GtkWidget *widget;
1017 /* sanity check */
1018 g_return_val_if_fail (columns >= MINCOLS, NULL);
1019 g_return_val_if_fail (rows >= MINROWS, NULL);
1021 widget = gtk_type_new (gtk_sheet_get_type ());
1023 gtk_sheet_construct(GTK_SHEET(widget), rows, columns, title);
1025 return widget;
1028 void
1029 gtk_sheet_construct (GtkSheet *sheet, guint rows, guint columns, const gchar *title)
1031 sheet->row=(GtkSheetRow *)g_malloc(sizeof(GtkSheetRow));
1032 sheet->column=(GtkSheetColumn *)g_malloc(sizeof(GtkSheetColumn));
1033 sheet->data=(GtkSheetCell ***)g_malloc(sizeof(GtkSheetCell **));
1035 sheet->data[0] = (GtkSheetCell **)g_malloc(sizeof(GtkSheetCell *)+sizeof(gdouble));
1036 sheet->data[0][0] = NULL;
1038 sheet->columns_resizable = TRUE;
1039 sheet->rows_resizable = TRUE;
1040 sheet->row_titles_visible = TRUE;
1041 sheet->column_titles_visible = TRUE;
1042 sheet->autoscroll = TRUE;
1043 sheet->justify_entry = TRUE;
1044 sheet->locked = FALSE;
1046 /* set number of rows and columns */
1047 GrowSheet(sheet, MINROWS, MINCOLS);
1049 /* Init row an column zero */
1050 AddRow(sheet,-1);
1051 AddColumn(sheet,-1);
1053 /* Add rows and columns */
1054 AddRow(sheet,rows-1);
1055 AddColumn(sheet,columns-1);
1057 /* create sheet entry */
1058 sheet->entry_type = 0;
1059 create_sheet_entry (sheet);
1061 /* create global selection button */
1062 create_global_button(sheet);
1064 if(title)
1065 sheet->name = g_strdup(title);
1070 GtkWidget *
1071 gtk_sheet_new_browser(guint rows, guint columns, const gchar *title)
1073 GtkWidget *widget;
1075 widget = gtk_type_new (gtk_sheet_get_type ());
1077 gtk_sheet_construct_browser(GTK_SHEET(widget), rows, columns, title);
1079 return widget;
1082 void
1083 gtk_sheet_construct_browser(GtkSheet *sheet, guint rows, guint columns,
1084 const gchar *title)
1086 gtk_sheet_construct(sheet, rows, columns, title);
1088 gtk_sheet_set_locked(sheet, TRUE);
1089 sheet->autoresize = TRUE;
1092 GtkWidget *
1093 gtk_sheet_new_with_custom_entry (guint rows, guint columns, const gchar *title,
1094 GtkType entry_type)
1096 GtkWidget *widget;
1098 widget = gtk_type_new (gtk_sheet_get_type ());
1100 gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget),
1101 rows, columns, title, entry_type);
1103 return widget;
1106 void
1107 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1108 guint rows, guint columns,
1109 const gchar *title,
1110 GtkType entry_type)
1112 gtk_sheet_construct(sheet, rows, columns, title);
1114 sheet->entry_type = entry_type;
1115 create_sheet_entry(sheet);
1119 void
1120 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
1122 gint state;
1124 g_return_if_fail (sheet != NULL);
1125 g_return_if_fail (GTK_IS_SHEET (sheet));
1127 state = sheet->state;
1129 if(sheet->state == GTK_SHEET_NORMAL)
1130 gtk_sheet_hide_active_cell(sheet);
1132 sheet->entry_type = entry_type;
1134 create_sheet_entry(sheet);
1136 if(state == GTK_SHEET_NORMAL)
1138 gtk_sheet_show_active_cell(sheet);
1139 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1140 "changed",
1141 (GtkSignalFunc)gtk_sheet_entry_changed,
1142 GTK_OBJECT(GTK_WIDGET(sheet)));
1147 void
1148 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
1150 g_return_if_fail (sheet != NULL);
1151 g_return_if_fail (GTK_IS_SHEET (sheet));
1153 if(show == sheet->show_grid) return;
1155 sheet->show_grid = show;
1157 if(!GTK_SHEET_IS_FROZEN(sheet))
1158 gtk_sheet_range_draw(sheet, NULL);
1161 gboolean
1162 gtk_sheet_grid_visible(GtkSheet *sheet)
1164 g_return_val_if_fail (sheet != NULL, 0);
1165 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1167 return sheet->show_grid;
1170 void
1171 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
1173 g_return_if_fail (sheet != NULL);
1174 g_return_if_fail (GTK_IS_SHEET (sheet));
1176 if(!color)
1177 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
1178 else
1179 sheet->bg_color = *color;
1181 if(!GTK_SHEET_IS_FROZEN(sheet))
1182 gtk_sheet_range_draw(sheet, NULL);
1185 void
1186 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
1188 g_return_if_fail (sheet != NULL);
1189 g_return_if_fail (GTK_IS_SHEET (sheet));
1191 if(!color)
1192 gdk_color_black(gdk_colormap_get_system(), &sheet->grid_color);
1193 else
1194 sheet->grid_color = *color;
1196 if(!GTK_SHEET_IS_FROZEN(sheet))
1197 gtk_sheet_range_draw(sheet, NULL);
1200 guint
1201 gtk_sheet_get_columns_count(GtkSheet *sheet)
1203 g_return_val_if_fail (sheet != NULL, 0);
1204 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1206 return sheet->maxcol + 1;
1209 guint
1210 gtk_sheet_get_rows_count(GtkSheet *sheet)
1212 g_return_val_if_fail (sheet != NULL, 0);
1213 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1215 return sheet->maxrow + 1;
1218 gint
1219 gtk_sheet_get_state(GtkSheet *sheet)
1221 g_return_val_if_fail (sheet != NULL, 0);
1222 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1224 return (sheet->state);
1227 void
1228 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
1230 g_return_if_fail (sheet != NULL);
1231 g_return_if_fail (GTK_IS_SHEET (sheet));
1233 if(GTK_WIDGET_REALIZED(sheet))
1234 gtk_sheet_real_unselect_range(sheet, NULL);
1236 sheet->selection_mode = mode;
1239 void
1240 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1242 g_return_if_fail (sheet != NULL);
1243 g_return_if_fail (GTK_IS_SHEET (sheet));
1245 sheet->autoresize = autoresize;
1248 gboolean
1249 gtk_sheet_autoresize (GtkSheet *sheet)
1251 g_return_val_if_fail (sheet != NULL, FALSE);
1252 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1254 return sheet->autoresize;
1257 void
1258 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1260 g_return_if_fail (sheet != NULL);
1261 g_return_if_fail (GTK_IS_SHEET (sheet));
1263 sheet->autoscroll = autoscroll;
1266 gboolean
1267 gtk_sheet_autoscroll (GtkSheet *sheet)
1269 g_return_val_if_fail (sheet != NULL, FALSE);
1270 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1272 return sheet->autoscroll;
1275 void
1276 gtk_sheet_set_clip_text (GtkSheet *sheet, gboolean clip_text)
1278 g_return_if_fail (sheet != NULL);
1279 g_return_if_fail (GTK_IS_SHEET (sheet));
1281 sheet->clip_text = clip_text;
1284 gboolean
1285 gtk_sheet_clip_text (GtkSheet *sheet)
1287 g_return_val_if_fail (sheet != NULL, FALSE);
1288 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1290 return sheet->clip_text;
1293 void
1294 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1296 g_return_if_fail (sheet != NULL);
1297 g_return_if_fail (GTK_IS_SHEET (sheet));
1299 sheet->justify_entry = justify;
1302 gboolean
1303 gtk_sheet_justify_entry (GtkSheet *sheet)
1305 g_return_val_if_fail (sheet != NULL, FALSE);
1306 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1308 return sheet->justify_entry;
1311 void
1312 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1314 g_return_if_fail (sheet != NULL);
1315 g_return_if_fail (GTK_IS_SHEET (sheet));
1317 sheet->locked = locked;
1320 gboolean
1321 gtk_sheet_locked (GtkSheet *sheet)
1323 g_return_val_if_fail (sheet != NULL, FALSE);
1324 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1326 return sheet->locked;
1329 /* This routine has problems with gtk+-1.2 related with the
1330 * label/button drawing - I think it's a bug in gtk+-1.2 */
1332 void
1333 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
1335 /* GtkWidget *old_widget;
1336 */ GtkWidget *label;
1338 g_return_if_fail (sheet != NULL);
1339 g_return_if_fail (title != NULL);
1340 g_return_if_fail (GTK_IS_SHEET (sheet));
1342 if (sheet->name)
1343 g_free (sheet->name);
1345 sheet->name = g_strdup (title);
1347 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
1349 if(GTK_BIN(sheet->button)->child)
1350 label = GTK_BIN(sheet->button)->child;
1352 gtk_label_set_text(GTK_LABEL(label), title);
1354 size_allocate_global_button(sheet);
1356 /* remove and destroy the old widget */
1358 old_widget = GTK_BIN (sheet->button)->child;
1359 if (old_widget)
1361 gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
1364 label = gtk_label_new (title);
1365 gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
1367 gtk_container_add (GTK_CONTAINER (sheet->button), label);
1368 gtk_widget_show (label);
1370 size_allocate_global_button(sheet);
1372 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
1374 if(old_widget)
1375 gtk_widget_destroy (old_widget);
1379 void
1380 gtk_sheet_freeze (GtkSheet *sheet)
1382 g_return_if_fail (sheet != NULL);
1383 g_return_if_fail (GTK_IS_SHEET (sheet));
1385 sheet->freeze_count++;
1386 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1389 void
1390 gtk_sheet_thaw(GtkSheet *sheet)
1392 g_return_if_fail (sheet != NULL);
1393 g_return_if_fail (GTK_IS_SHEET (sheet));
1395 if(sheet->freeze_count == 0) return;
1397 sheet->freeze_count--;
1398 if(sheet->freeze_count > 0) return;
1400 adjust_scrollbars(sheet);
1402 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1404 sheet->old_vadjustment = -1.;
1405 sheet->old_hadjustment = -1.;
1407 if(sheet->hadjustment)
1408 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1409 "value_changed");
1410 if(sheet->vadjustment)
1411 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1412 "value_changed");
1414 if(sheet->state == GTK_STATE_NORMAL)
1415 if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
1416 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
1418 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1419 "changed",
1420 (GtkSignalFunc)gtk_sheet_entry_changed,
1421 GTK_OBJECT(GTK_WIDGET(sheet)));
1422 gtk_sheet_show_active_cell(sheet);
1428 void
1429 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
1431 if(width < COLUMN_MIN_WIDTH) return;
1433 sheet->row_title_area.width = width;
1434 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
1435 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1436 gtk_sheet_recalc_top_ypixels(sheet, 0);
1437 gtk_sheet_recalc_left_xpixels(sheet, 0);
1438 adjust_scrollbars(sheet);
1440 sheet->old_hadjustment = -1.;
1441 if(sheet->hadjustment)
1442 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1443 "value_changed");
1444 size_allocate_global_button(sheet);
1447 void
1448 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
1450 if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
1452 sheet->column_title_area.height = height;
1453 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
1454 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
1455 gtk_sheet_recalc_top_ypixels(sheet, 0);
1456 gtk_sheet_recalc_left_xpixels(sheet, 0);
1457 adjust_scrollbars(sheet);
1459 sheet->old_vadjustment = -1.;
1460 if(sheet->vadjustment)
1461 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1462 "value_changed");
1463 size_allocate_global_button(sheet);
1466 void
1467 gtk_sheet_show_column_titles(GtkSheet *sheet)
1469 gint col;
1471 if(sheet->column_titles_visible) return;
1473 sheet->column_titles_visible = TRUE;
1474 gtk_sheet_recalc_top_ypixels(sheet, 0);
1475 gtk_sheet_recalc_left_xpixels(sheet, 0);
1476 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1477 gdk_window_show(sheet->column_title_window);
1478 gdk_window_move_resize (sheet->column_title_window,
1479 sheet->column_title_area.x,
1480 sheet->column_title_area.y,
1481 sheet->column_title_area.width,
1482 sheet->column_title_area.height);
1484 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1485 GtkSheetChild *child;
1486 child = sheet->column[col].button.child;
1487 if(child){
1488 gtk_sheet_child_show(child);
1491 adjust_scrollbars(sheet);
1494 sheet->old_vadjustment = -1.;
1495 if(sheet->vadjustment)
1496 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1497 "value_changed");
1498 size_allocate_global_button(sheet);
1501 void
1502 gtk_sheet_show_row_titles(GtkSheet *sheet)
1504 gint row;
1506 if(sheet->row_titles_visible) return;
1508 sheet->row_titles_visible = TRUE;
1509 gtk_sheet_recalc_top_ypixels(sheet, 0);
1510 gtk_sheet_recalc_left_xpixels(sheet, 0);
1511 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1512 gdk_window_show(sheet->row_title_window);
1513 gdk_window_move_resize (sheet->row_title_window,
1514 sheet->row_title_area.x,
1515 sheet->row_title_area.y,
1516 sheet->row_title_area.width,
1517 sheet->row_title_area.height);
1519 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1520 GtkSheetChild *child;
1521 child = sheet->row[row].button.child;
1522 if(child){
1523 gtk_sheet_child_show(child);
1526 adjust_scrollbars(sheet);
1529 sheet->old_hadjustment = -1.;
1530 if(sheet->hadjustment)
1531 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1532 "value_changed");
1533 size_allocate_global_button(sheet);
1536 void
1537 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1539 gint col;
1541 if(!sheet->column_titles_visible) return;
1543 sheet->column_titles_visible = FALSE;
1544 gtk_sheet_recalc_top_ypixels(sheet, 0);
1545 gtk_sheet_recalc_left_xpixels(sheet, 0);
1546 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1547 if(sheet->column_title_window)
1548 gdk_window_hide(sheet->column_title_window);
1549 if(GTK_WIDGET_VISIBLE(sheet->button))
1550 gtk_widget_hide(sheet->button);
1552 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1553 GtkSheetChild *child;
1554 child = sheet->column[col].button.child;
1555 if(child){
1556 gtk_sheet_child_hide(child);
1559 adjust_scrollbars(sheet);
1562 sheet->old_vadjustment = -1.;
1563 if(sheet->vadjustment)
1564 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1565 "value_changed");
1568 void
1569 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1571 gint row;
1573 if(!sheet->row_titles_visible) return;
1575 sheet->row_titles_visible = FALSE;
1576 gtk_sheet_recalc_top_ypixels(sheet, 0);
1577 gtk_sheet_recalc_left_xpixels(sheet, 0);
1578 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1579 if(sheet->row_title_window)
1580 gdk_window_hide(sheet->row_title_window);
1581 if(GTK_WIDGET_VISIBLE(sheet->button))
1582 gtk_widget_hide(sheet->button);
1583 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1584 GtkSheetChild *child;
1585 child = sheet->row[row].button.child;
1586 if(child){
1587 gtk_sheet_child_hide(child);
1590 adjust_scrollbars(sheet);
1593 sheet->old_hadjustment = -1.;
1594 if(sheet->hadjustment)
1595 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1596 "value_changed");
1599 gboolean
1600 gtk_sheet_column_titles_visible(GtkSheet *sheet)
1602 g_return_val_if_fail (sheet != NULL, FALSE);
1603 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1604 return sheet->column_titles_visible;
1607 gboolean
1608 gtk_sheet_row_titles_visible(GtkSheet *sheet)
1610 g_return_val_if_fail (sheet != NULL, FALSE);
1611 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1612 return sheet->row_titles_visible;
1615 void
1616 gtk_sheet_set_column_title (GtkSheet * sheet,
1617 gint column,
1618 const gchar * title)
1620 g_return_if_fail (sheet != NULL);
1621 g_return_if_fail (GTK_IS_SHEET (sheet));
1623 if (sheet->column[column].name)
1624 g_free (sheet->column[column].name);
1626 sheet->column[column].name = g_strdup(title);
1629 void
1630 gtk_sheet_set_row_title (GtkSheet * sheet,
1631 gint row,
1632 const gchar * title)
1634 g_return_if_fail (sheet != NULL);
1635 g_return_if_fail (GTK_IS_SHEET (sheet));
1637 if (sheet->row[row].name)
1638 g_free (sheet->row[row].name);
1640 sheet->row[row].name = g_strdup (title);
1643 const gchar *
1644 gtk_sheet_get_row_title (GtkSheet * sheet,
1645 gint row)
1647 g_return_val_if_fail (sheet != NULL, NULL);
1648 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1650 return(sheet->row[row].name);
1653 const gchar *
1654 gtk_sheet_get_column_title (GtkSheet * sheet,
1655 gint column)
1657 g_return_val_if_fail (sheet != NULL, NULL);
1658 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1660 return(sheet->column[column].name);
1663 void
1664 gtk_sheet_row_button_add_label(GtkSheet *sheet, gint row, const gchar *label)
1666 GtkSheetButton *button;
1667 GtkRequisition req;
1668 gboolean aux;
1670 g_return_if_fail (sheet != NULL);
1671 g_return_if_fail (GTK_IS_SHEET (sheet));
1673 if(row < 0 || row > sheet->maxrow) return;
1675 button = &sheet->row[row].button;
1676 if (button->label) g_free (button->label);
1677 button->label = g_strdup (label);
1679 aux = gtk_sheet_autoresize(sheet);
1680 gtk_sheet_set_autoresize(sheet, TRUE);
1681 gtk_sheet_button_size_request(sheet, button, &req);
1682 gtk_sheet_set_autoresize(sheet, aux);
1684 if(req.height > sheet->row[row].height)
1685 gtk_sheet_set_row_height(sheet, row, req.height);
1687 if(req.width > sheet->row_title_area.width){
1688 gtk_sheet_set_row_titles_width(sheet, req.width);
1691 if(!GTK_SHEET_IS_FROZEN(sheet)){
1692 gtk_sheet_button_draw(sheet, row, -1);
1693 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1697 const gchar *
1698 gtk_sheet_row_button_get_label(GtkSheet *sheet, gint row)
1700 g_return_val_if_fail (sheet != NULL, NULL);
1701 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1703 if(row < 0 || row > sheet->maxrow) return NULL;
1705 return (sheet->row[row].button.label);
1708 void
1709 gtk_sheet_row_label_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
1711 g_return_if_fail (sheet != NULL);
1712 g_return_if_fail (GTK_IS_SHEET (sheet));
1714 if(row < 0 || row > sheet->maxrow) return;
1716 sheet->row[row].button.label_visible = visible;
1718 if(!GTK_SHEET_IS_FROZEN(sheet)){
1719 gtk_sheet_button_draw(sheet, row, -1);
1720 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1724 void
1725 gtk_sheet_rows_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1727 gint i;
1729 g_return_if_fail (sheet != NULL);
1730 g_return_if_fail (GTK_IS_SHEET (sheet));
1732 for(i = 0; i <= sheet->maxrow; i++)
1733 gtk_sheet_row_label_set_visibility(sheet, i, visible);
1737 void
1738 gtk_sheet_column_button_add_label(GtkSheet *sheet, gint column, const gchar *label)
1740 GtkSheetButton *button;
1741 GtkRequisition req;
1742 gboolean aux;
1744 g_return_if_fail (sheet != NULL);
1745 g_return_if_fail (GTK_IS_SHEET (sheet));
1747 if(column < 0 || column >sheet->maxcol) return;
1749 button = &sheet->column[column].button;
1750 if (button->label) g_free (button->label);
1751 button->label = g_strdup (label);
1753 aux = gtk_sheet_autoresize(sheet);
1754 gtk_sheet_set_autoresize(sheet, TRUE);
1755 gtk_sheet_button_size_request(sheet, button, &req);
1756 gtk_sheet_set_autoresize(sheet, aux);
1758 if(req.width > sheet->column[column].width)
1759 gtk_sheet_set_column_width(sheet, column, req.width);
1761 if(req.height > sheet->column_title_area.height)
1762 gtk_sheet_set_column_titles_height(sheet, req.height);
1764 if(!GTK_SHEET_IS_FROZEN(sheet)){
1765 gtk_sheet_button_draw(sheet, -1, column);
1766 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1770 const gchar *
1771 gtk_sheet_column_button_get_label(GtkSheet *sheet, gint column)
1773 g_return_val_if_fail (sheet != NULL, NULL);
1774 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1776 if(column < 0 || column >sheet->maxcol) return NULL;
1778 return(sheet->column[column].button.label);
1781 void
1782 gtk_sheet_column_label_set_visibility(GtkSheet *sheet, gint col, gboolean visible)
1784 g_return_if_fail (sheet != NULL);
1785 g_return_if_fail (GTK_IS_SHEET (sheet));
1787 if(col < 0 || col > sheet->maxcol) return;
1789 sheet->column[col].button.label_visible = visible;
1791 if(!GTK_SHEET_IS_FROZEN(sheet)){
1792 gtk_sheet_button_draw(sheet, -1, col);
1793 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, col);
1797 void
1798 gtk_sheet_columns_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1800 gint i;
1802 g_return_if_fail (sheet != NULL);
1803 g_return_if_fail (GTK_IS_SHEET (sheet));
1805 for(i = 0; i <= sheet->maxcol; i++)
1806 gtk_sheet_column_label_set_visibility(sheet, i, visible);
1809 void
1810 gtk_sheet_row_button_justify(GtkSheet *sheet, gint row,
1811 GtkJustification justification)
1813 GtkSheetButton *button;
1815 g_return_if_fail (sheet != NULL);
1816 g_return_if_fail (GTK_IS_SHEET (sheet));
1818 if(row < 0 || row > sheet->maxrow) return;
1820 button = &sheet->row[row].button;
1821 button->justification = justification;
1823 if(!GTK_SHEET_IS_FROZEN(sheet)){
1824 gtk_sheet_button_draw(sheet, row, -1);
1825 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1829 void
1830 gtk_sheet_column_button_justify(GtkSheet *sheet, gint column,
1831 GtkJustification justification)
1833 GtkSheetButton *button;
1835 g_return_if_fail (sheet != NULL);
1836 g_return_if_fail (GTK_IS_SHEET (sheet));
1838 if(column < 0 || column > sheet->maxcol) return;
1840 button = &sheet->column[column].button;
1841 button->justification = justification;
1843 if(!GTK_SHEET_IS_FROZEN(sheet)){
1844 gtk_sheet_button_draw(sheet, -1, column);
1845 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1850 void
1851 gtk_sheet_moveto (GtkSheet * sheet,
1852 gint row,
1853 gint column,
1854 gfloat row_align,
1855 gfloat col_align)
1857 gint x, y;
1858 guint width, height;
1859 gint adjust;
1860 gint min_row, min_col;
1862 g_return_if_fail (sheet != NULL);
1863 g_return_if_fail (GTK_IS_SHEET (sheet));
1864 g_return_if_fail (sheet->hadjustment != NULL);
1865 g_return_if_fail (sheet->vadjustment != NULL);
1867 if (row < 0 || row > sheet->maxrow)
1868 return;
1869 if (column < 0 || column > sheet->maxcol)
1870 return;
1872 height = sheet->sheet_window_height;
1873 width = sheet->sheet_window_width;
1875 /* adjust vertical scrollbar */
1877 if (row >= 0 && row_align >=0.)
1879 y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
1880 row_align*height-
1881 (1.-row_align)*sheet->row[row].height;
1883 /* This forces the sheet to scroll when you don't see the entire cell */
1884 min_row = row;
1885 adjust = 0;
1886 if(row_align == 1.){
1887 while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
1888 if(sheet->row[min_row].is_visible)
1889 adjust += sheet->row[min_row].height;
1890 if(adjust >= height){
1891 break;
1893 min_row--;
1895 min_row = MAX(min_row, 0);
1896 y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
1897 sheet->row[min_row].height - 1;
1900 if (y < 0)
1901 sheet->vadjustment->value = 0.0;
1902 else
1903 sheet->vadjustment->value = y;
1905 sheet->old_vadjustment = -1.;
1906 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1907 "value_changed");
1911 /* adjust horizontal scrollbar */
1912 if (column >= 0 && col_align >= 0.)
1914 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
1915 col_align*width -
1916 (1.-col_align)*sheet->column[column].width;
1918 /* This forces the sheet to scroll when you don't see the entire cell */
1919 min_col = column;
1920 adjust = 0;
1921 if(col_align == 1.){
1922 while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
1923 if(sheet->column[min_col].is_visible)
1924 adjust += sheet->column[min_col].width;
1925 if(adjust >= width){
1926 break;
1928 min_col--;
1930 min_col = MAX(min_col, 0);
1931 x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
1932 sheet->column[min_col].width - 1;
1935 if (x < 0)
1936 sheet->hadjustment->value = 0.0;
1937 else
1938 sheet->hadjustment->value = x;
1940 sheet->old_vadjustment = -1.;
1941 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1942 "value_changed");
1947 void
1948 gtk_sheet_column_set_sensitivity(GtkSheet *sheet, gint column, gboolean sensitive)
1950 g_return_if_fail (sheet != NULL);
1951 g_return_if_fail (GTK_IS_SHEET (sheet));
1953 if(column < 0 || column > sheet->maxcol) return;
1955 sheet->column[column].is_sensitive=sensitive;
1956 if(!sensitive)
1957 sheet->column[column].button.state=GTK_STATE_INSENSITIVE;
1958 else
1959 sheet->column[column].button.state=GTK_STATE_NORMAL;
1961 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
1962 gtk_sheet_button_draw(sheet, -1, column);
1966 void
1967 gtk_sheet_columns_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
1969 gint i;
1971 g_return_if_fail (sheet != NULL);
1972 g_return_if_fail (GTK_IS_SHEET (sheet));
1974 for(i=0; i<=sheet->maxcol; i++)
1975 gtk_sheet_column_set_sensitivity(sheet, i, sensitive);
1978 void
1979 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
1981 g_return_if_fail (sheet != NULL);
1982 g_return_if_fail (GTK_IS_SHEET (sheet));
1984 sheet->columns_resizable = resizable;
1987 gboolean
1988 gtk_sheet_columns_resizable (GtkSheet *sheet)
1990 g_return_val_if_fail (sheet != NULL, FALSE);
1991 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1993 return sheet->columns_resizable;
1996 void
1997 gtk_sheet_row_set_sensitivity(GtkSheet *sheet, gint row, gboolean sensitive)
2000 g_return_if_fail (sheet != NULL);
2001 g_return_if_fail (GTK_IS_SHEET (sheet));
2003 if(row < 0 || row > sheet->maxrow) return;
2005 sheet->row[row].is_sensitive=sensitive;
2006 if(!sensitive)
2007 sheet->row[row].button.state=GTK_STATE_INSENSITIVE;
2008 else
2009 sheet->row[row].button.state=GTK_STATE_NORMAL;
2011 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
2012 gtk_sheet_button_draw(sheet, row, -1);
2015 void
2016 gtk_sheet_rows_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
2018 gint i;
2020 g_return_if_fail (sheet != NULL);
2021 g_return_if_fail (GTK_IS_SHEET (sheet));
2023 for(i=0; i<=sheet->maxrow; i++)
2024 gtk_sheet_row_set_sensitivity(sheet, i, sensitive);
2028 void
2029 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2031 g_return_if_fail (sheet != NULL);
2032 g_return_if_fail (GTK_IS_SHEET (sheet));
2034 sheet->rows_resizable = resizable;
2037 gboolean
2038 gtk_sheet_rows_resizable (GtkSheet *sheet)
2040 g_return_val_if_fail (sheet != NULL, FALSE);
2041 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2043 return sheet->rows_resizable;
2046 void
2047 gtk_sheet_column_set_visibility(GtkSheet *sheet, gint column, gboolean visible)
2049 g_return_if_fail (sheet != NULL);
2050 g_return_if_fail (GTK_IS_SHEET (sheet));
2052 if(column < 0 || column > sheet->maxcol) return;
2053 if(sheet->column[column].is_visible == visible) return;
2055 sheet->column[column].is_visible = visible;
2057 gtk_sheet_recalc_left_xpixels(sheet, column);
2059 if(!GTK_SHEET_IS_FROZEN(sheet) &&
2060 gtk_sheet_cell_isvisible(sheet, MIN_VISIBLE_ROW(sheet), column)){
2061 gtk_sheet_range_draw(sheet, NULL);
2062 size_allocate_column_title_buttons(sheet);
2066 void
2067 gtk_sheet_row_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
2069 g_return_if_fail (sheet != NULL);
2070 g_return_if_fail (GTK_IS_SHEET (sheet));
2072 if(row < 0 || row > sheet->maxrow) return;
2073 if(sheet->row[row].is_visible == visible) return;
2075 sheet->row[row].is_visible = visible;
2077 gtk_sheet_recalc_top_ypixels(sheet, row);
2079 if(!GTK_SHEET_IS_FROZEN(sheet) &&
2080 gtk_sheet_cell_isvisible(sheet, row, MIN_VISIBLE_COLUMN(sheet))){
2081 gtk_sheet_range_draw(sheet, NULL);
2082 size_allocate_row_title_buttons(sheet);
2086 void
2087 gtk_sheet_select_row (GtkSheet * sheet,
2088 gint row)
2090 g_return_if_fail (sheet != NULL);
2091 g_return_if_fail (GTK_IS_SHEET (sheet));
2093 if (row < 0 || row > sheet->maxrow)
2094 return;
2096 if(sheet->state != GTK_SHEET_NORMAL)
2097 gtk_sheet_real_unselect_range(sheet, NULL);
2098 else
2100 gboolean veto = TRUE;
2101 veto = gtk_sheet_deactivate_cell(sheet);
2102 if(!veto) return;
2105 sheet->state=GTK_SHEET_ROW_SELECTED;
2106 sheet->range.row0=row;
2107 sheet->range.col0=0;
2108 sheet->range.rowi=row;
2109 sheet->range.coli=sheet->maxcol;
2110 sheet->active_cell.row=row;
2111 sheet->active_cell.col=0;
2113 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
2114 gtk_sheet_real_select_range(sheet, NULL);
2119 void
2120 gtk_sheet_select_column (GtkSheet * sheet,
2121 gint column)
2124 g_return_if_fail (sheet != NULL);
2125 g_return_if_fail (GTK_IS_SHEET (sheet));
2127 if (column < 0 || column > sheet->maxcol)
2128 return;
2130 if(sheet->state != GTK_SHEET_NORMAL)
2131 gtk_sheet_real_unselect_range(sheet, NULL);
2132 else
2134 gboolean veto = TRUE;
2135 veto = gtk_sheet_deactivate_cell(sheet);
2136 if(!veto) return;
2139 sheet->state=GTK_SHEET_COLUMN_SELECTED;
2140 sheet->range.row0=0;
2141 sheet->range.col0=column;
2142 sheet->range.rowi=sheet->maxrow;
2143 sheet->range.coli=column;
2144 sheet->active_cell.row=0;
2145 sheet->active_cell.col=column;
2147 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
2148 gtk_sheet_real_select_range(sheet, NULL);
2152 void
2153 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2156 g_return_if_fail (sheet != NULL);
2157 g_return_if_fail (GTK_IS_SHEET (sheet));
2159 if(GTK_SHEET_IN_CLIP(sheet)) return;
2161 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2163 if(range == NULL)
2164 sheet->clip_range = sheet->range;
2165 else
2166 sheet->clip_range=*range;
2168 sheet->interval=0;
2169 sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet);
2171 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
2172 &sheet->clip_range);
2176 void
2177 gtk_sheet_unclip_range(GtkSheet *sheet)
2180 g_return_if_fail (sheet != NULL);
2181 g_return_if_fail (GTK_IS_SHEET (sheet));
2183 if(!GTK_SHEET_IN_CLIP(sheet)) return;
2185 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2186 gtk_timeout_remove(sheet->clip_timer);
2187 gtk_sheet_range_draw(sheet, &sheet->clip_range);
2189 if(gtk_sheet_range_isvisible(sheet, sheet->range))
2190 gtk_sheet_range_draw(sheet, &sheet->range);
2193 gboolean
2194 gtk_sheet_in_clip (GtkSheet *sheet)
2196 g_return_val_if_fail (sheet != NULL, FALSE);
2197 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2199 return GTK_SHEET_IN_CLIP(sheet);
2202 static gint
2203 gtk_sheet_flash(gpointer data)
2205 GtkSheet *sheet;
2206 gint x,y,width,height;
2207 GdkRectangle clip_area;
2209 sheet=GTK_SHEET(data);
2211 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
2212 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
2213 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
2214 if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE;
2215 if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE;
2217 GDK_THREADS_ENTER();
2219 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2220 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2221 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2222 sheet->column[sheet->clip_range.coli].width-1;
2223 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2224 sheet->row[sheet->clip_range.rowi].height-1;
2226 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2227 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2228 clip_area.width=sheet->sheet_window_width;
2229 clip_area.height=sheet->sheet_window_height;
2231 if(x<0) {
2232 width=width+x+1;
2233 x=-1;
2235 if(width>clip_area.width) width=clip_area.width+10;
2236 if(y<0) {
2237 height=height+y+1;
2238 y=-1;
2240 if(height>clip_area.height) height=clip_area.height+10;
2242 gdk_draw_pixmap(sheet->sheet_window,
2243 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2244 sheet->pixmap,
2245 x, y,
2246 x, y,
2247 1, height);
2249 gdk_draw_pixmap(sheet->sheet_window,
2250 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2251 sheet->pixmap,
2252 x, y,
2253 x, y,
2254 width, 1);
2256 gdk_draw_pixmap(sheet->sheet_window,
2257 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2258 sheet->pixmap,
2259 x, y+height,
2260 x, y+height,
2261 width, 1);
2263 gdk_draw_pixmap(sheet->sheet_window,
2264 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2265 sheet->pixmap,
2266 x+width, y,
2267 x+width, y,
2268 1, height);
2271 sheet->interval=sheet->interval+1;
2272 if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
2274 gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2275 gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
2276 gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2278 GDK_THREADS_LEAVE();
2280 return TRUE;
2284 static void
2285 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
2287 GdkRectangle clip_area;
2288 gint x,y,width,height;
2290 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
2292 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2293 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2294 clip_area.width=sheet->sheet_window_width;
2295 clip_area.height=sheet->sheet_window_height;
2297 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
2299 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2300 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2301 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2302 sheet->column[sheet->clip_range.coli].width-1;
2303 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2304 sheet->row[sheet->clip_range.rowi].height-1;
2306 if(x<0) {
2307 width=width+x+1;
2308 x=-1;
2310 if(width>clip_area.width) width=clip_area.width+10;
2311 if(y<0) {
2312 height=height+y+1;
2313 y=-1;
2315 if(height>clip_area.height) height=clip_area.height+10;
2317 gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
2319 gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE,
2320 x, y,
2321 width, height);
2323 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2325 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
2329 static gint
2330 gtk_sheet_range_isvisible (GtkSheet * sheet,
2331 GtkSheetRange range)
2333 g_return_val_if_fail (sheet != NULL, FALSE);
2335 if (range.row0 < 0 || range.row0 > sheet->maxrow)
2336 return FALSE;
2338 if (range.rowi < 0 || range.rowi > sheet->maxrow)
2339 return FALSE;
2341 if (range.col0 < 0 || range.col0 > sheet->maxcol)
2342 return FALSE;
2344 if (range.coli < 0 || range.coli > sheet->maxcol)
2345 return FALSE;
2347 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2348 return FALSE;
2350 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2351 return FALSE;
2353 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2354 return FALSE;
2356 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2357 return FALSE;
2359 return TRUE;
2362 static gint
2363 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2364 gint row, gint column)
2366 GtkSheetRange range;
2368 range.row0 = row;
2369 range.col0 = column;
2370 range.rowi = row;
2371 range.coli = column;
2373 return gtk_sheet_range_isvisible(sheet, range);
2376 void
2377 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2380 g_return_if_fail (sheet != NULL);
2381 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2382 g_return_if_fail (range != NULL);
2384 range->row0 = MIN_VISIBLE_ROW(sheet);
2385 range->col0 = MIN_VISIBLE_COLUMN(sheet);
2386 range->rowi = MAX_VISIBLE_ROW(sheet);
2387 range->coli = MAX_VISIBLE_COLUMN(sheet);
2391 GtkAdjustment *
2392 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2394 g_return_val_if_fail (sheet != NULL, NULL);
2395 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2397 return sheet->vadjustment;
2400 GtkAdjustment *
2401 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2403 g_return_val_if_fail (sheet != NULL, NULL);
2404 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2406 return sheet->hadjustment;
2409 void
2410 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2411 GtkAdjustment *adjustment)
2413 GtkAdjustment *old_adjustment;
2415 g_return_if_fail (sheet != NULL);
2416 g_return_if_fail (GTK_IS_SHEET (sheet));
2417 if (adjustment)
2418 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2420 if (sheet->vadjustment == adjustment)
2421 return;
2423 old_adjustment = sheet->vadjustment;
2425 if (sheet->vadjustment)
2427 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2428 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2431 sheet->vadjustment = adjustment;
2433 if (sheet->vadjustment)
2435 gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2436 gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2438 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2439 (GtkSignalFunc) vadjustment_changed,
2440 (gpointer) sheet);
2441 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2442 (GtkSignalFunc) vadjustment_value_changed,
2443 (gpointer) sheet);
2446 if (!sheet->vadjustment || !old_adjustment)
2448 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2449 return;
2452 sheet->old_vadjustment = sheet->vadjustment->value;
2455 void
2456 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2457 GtkAdjustment *adjustment)
2459 GtkAdjustment *old_adjustment;
2461 g_return_if_fail (sheet != NULL);
2462 g_return_if_fail (GTK_IS_SHEET (sheet));
2463 if (adjustment)
2464 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2466 if (sheet->hadjustment == adjustment)
2467 return;
2469 old_adjustment = sheet->hadjustment;
2471 if (sheet->hadjustment)
2473 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2474 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2477 sheet->hadjustment = adjustment;
2479 if (sheet->hadjustment)
2481 gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2482 gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2484 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2485 (GtkSignalFunc) hadjustment_changed,
2486 (gpointer) sheet);
2487 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2488 (GtkSignalFunc) hadjustment_value_changed,
2489 (gpointer) sheet);
2492 if (!sheet->hadjustment || !old_adjustment)
2494 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2495 return;
2498 sheet->old_hadjustment = sheet->hadjustment->value;
2501 static void
2502 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2503 GtkAdjustment *hadjustment,
2504 GtkAdjustment *vadjustment)
2506 if(sheet->hadjustment != hadjustment)
2507 gtk_sheet_set_hadjustment (sheet, hadjustment);
2508 if(sheet->vadjustment != vadjustment)
2509 gtk_sheet_set_vadjustment (sheet, vadjustment);
2512 static void
2513 gtk_sheet_finalize (GObject * object)
2515 GtkSheet *sheet;
2517 g_return_if_fail (object != NULL);
2518 g_return_if_fail (GTK_IS_SHEET (object));
2520 sheet = GTK_SHEET (object);
2522 /* get rid of all the cells */
2523 gtk_sheet_range_clear (sheet, NULL);
2524 gtk_sheet_range_delete(sheet, NULL);
2526 gtk_sheet_delete_rows (sheet, 0, sheet->maxrow + 1);
2527 gtk_sheet_delete_columns (sheet, 0, sheet->maxcol + 1);
2529 DeleteRow (sheet, 0, sheet->maxrow + 1);
2530 DeleteColumn (sheet, 0, sheet->maxcol + 1);
2532 g_free(sheet->row);
2533 sheet->row = NULL;
2534 g_free(sheet->column);
2535 sheet->column = NULL;
2536 g_free(sheet->data);
2537 sheet->data = NULL;
2539 if(sheet->name){
2540 g_free(sheet->name);
2541 sheet->name = NULL;
2544 if (G_OBJECT_CLASS (parent_class)->finalize)
2545 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2548 static void
2549 gtk_sheet_destroy (GtkObject * object)
2551 GtkSheet *sheet;
2552 GList *children;
2554 g_return_if_fail (object != NULL);
2555 g_return_if_fail (GTK_IS_SHEET (object));
2557 sheet = GTK_SHEET (object);
2559 /* destroy the entry */
2560 if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
2561 gtk_widget_destroy (sheet->sheet_entry);
2562 sheet->sheet_entry = NULL;
2565 /* destroy the global selection button */
2566 if(sheet->button && GTK_IS_WIDGET(sheet->button)){
2567 gtk_widget_destroy (sheet->button);
2568 sheet->button = NULL;
2571 if(sheet->timer){
2572 gtk_timeout_remove(sheet->timer);
2573 sheet->timer = 0;
2576 if(sheet->clip_timer){
2577 gtk_timeout_remove(sheet->clip_timer);
2578 sheet->clip_timer = 0;
2581 /* unref adjustments */
2582 if (sheet->hadjustment)
2584 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2585 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2586 sheet->hadjustment = NULL;
2588 if (sheet->vadjustment)
2590 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2591 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2592 sheet->vadjustment = NULL;
2595 children = sheet->children;
2596 while(children){
2597 GtkSheetChild *child = (GtkSheetChild *)children->data;
2598 if(child && child->widget)
2599 gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
2600 children = sheet->children;
2602 sheet->children = NULL;
2604 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2605 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2608 static void
2609 gtk_sheet_style_set (GtkWidget *widget,
2610 GtkStyle *previous_style)
2612 GtkSheet *sheet;
2614 g_return_if_fail (widget != NULL);
2615 g_return_if_fail (GTK_IS_SHEET (widget));
2617 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2618 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2620 sheet = GTK_SHEET (widget);
2622 if(GTK_WIDGET_REALIZED(widget))
2624 gtk_style_set_background (widget->style, widget->window, widget->state);
2629 static void
2630 gtk_sheet_realize (GtkWidget * widget)
2632 GtkSheet *sheet;
2633 GdkWindowAttr attributes;
2634 gint attributes_mask;
2635 GdkGCValues values, auxvalues;
2636 GdkColormap *colormap;
2637 gchar *name;
2638 GtkSheetChild *child;
2639 GList *children;
2641 g_return_if_fail (widget != NULL);
2642 g_return_if_fail (GTK_IS_SHEET (widget));
2644 sheet = GTK_SHEET (widget);
2646 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2648 attributes.window_type = GDK_WINDOW_CHILD;
2649 attributes.x = widget->allocation.x;
2650 attributes.y = widget->allocation.y;
2651 attributes.width = widget->allocation.width;
2652 attributes.height = widget->allocation.height;
2653 attributes.wclass = GDK_INPUT_OUTPUT;
2655 attributes.visual = gtk_widget_get_visual (widget);
2656 attributes.colormap = gtk_widget_get_colormap (widget);
2658 attributes.event_mask = gtk_widget_get_events (widget);
2659 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2660 GDK_BUTTON_PRESS_MASK |
2661 GDK_BUTTON_RELEASE_MASK |
2662 GDK_KEY_PRESS_MASK |
2663 GDK_POINTER_MOTION_MASK |
2664 GDK_POINTER_MOTION_HINT_MASK);
2665 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2666 GDK_WA_CURSOR;
2668 attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2670 /* main window */
2671 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2673 gdk_window_set_user_data (widget->window, sheet);
2675 widget->style = gtk_style_attach (widget->style, widget->window);
2677 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2679 attributes.x = 0;
2680 if(sheet->row_titles_visible)
2681 attributes.x = sheet->row_title_area.width;
2682 attributes.y = 0;
2683 attributes.width = sheet->column_title_area.width;
2684 attributes.height = sheet->column_title_area.height;
2686 /* column-title window */
2687 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2688 gdk_window_set_user_data (sheet->column_title_window, sheet);
2689 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2691 attributes.x = 0;
2692 attributes.y = 0;
2693 if(sheet->column_titles_visible)
2694 attributes.y = sheet->column_title_area.height;
2695 attributes.width = sheet->row_title_area.width;
2696 attributes.height = sheet->row_title_area.height;
2698 /* row-title window */
2699 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2700 gdk_window_set_user_data (sheet->row_title_window, sheet);
2701 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2703 /* sheet-window */
2704 attributes.cursor = gdk_cursor_new(GDK_PLUS);
2706 attributes.x = 0;
2707 attributes.y = 0;
2708 attributes.width = sheet->sheet_window_width,
2709 attributes.height = sheet->sheet_window_height;
2711 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2712 gdk_window_set_user_data (sheet->sheet_window, sheet);
2714 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2715 gdk_window_show (sheet->sheet_window);
2717 /* backing_pixmap */
2718 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
2720 /* GCs */
2721 if(sheet->fg_gc)
2722 gdk_gc_unref(sheet->fg_gc);
2723 if(sheet->bg_gc)
2724 gdk_gc_unref(sheet->bg_gc);
2725 sheet->fg_gc = gdk_gc_new (widget->window);
2726 sheet->bg_gc = gdk_gc_new (widget->window);
2728 colormap = gtk_widget_get_colormap(widget);
2730 gdk_color_white(colormap, &widget->style->white);
2731 gdk_color_black(colormap, &widget->style->black);
2733 gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2735 values.foreground = widget->style->white;
2736 values.function = GDK_INVERT;
2737 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2738 if(sheet->xor_gc)
2739 gdk_gc_unref(sheet->xor_gc);
2740 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2741 &values,
2742 GDK_GC_FOREGROUND |
2743 GDK_GC_FUNCTION |
2744 GDK_GC_SUBWINDOW);
2746 if(sheet->sheet_entry->parent){
2747 gtk_widget_ref(sheet->sheet_entry);
2748 gtk_widget_unparent(sheet->sheet_entry);
2750 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2751 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2753 if(sheet->button && sheet->button->parent){
2754 gtk_widget_ref(sheet->button);
2755 gtk_widget_unparent(sheet->button);
2757 gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2758 gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2761 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2763 if(!sheet->cursor_drag)
2764 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2766 if(sheet->column_titles_visible)
2767 gdk_window_show(sheet->column_title_window);
2768 if(sheet->row_titles_visible)
2769 gdk_window_show(sheet->row_title_window);
2771 size_allocate_row_title_buttons(sheet);
2772 size_allocate_column_title_buttons(sheet);
2774 name = g_strdup(sheet->name);
2775 gtk_sheet_set_title(sheet, name);
2777 g_free(name);
2779 children = sheet->children;
2780 while(children)
2782 child = children->data;
2783 children = g_list_next(children);
2785 gtk_sheet_realize_child(sheet, child);
2789 static void
2790 create_global_button(GtkSheet *sheet)
2792 sheet->button = gtk_button_new_with_label(" ");
2794 gtk_signal_connect (GTK_OBJECT (sheet->button),
2795 "pressed",
2796 (GtkSignalFunc) global_button_clicked,
2797 (gpointer) sheet);
2800 static void
2801 size_allocate_global_button(GtkSheet *sheet)
2803 GtkAllocation allocation;
2805 if(!sheet->column_titles_visible) return;
2806 if(!sheet->row_titles_visible) return;
2808 gtk_widget_size_request(sheet->button, NULL);
2810 allocation.x=0;
2811 allocation.y=0;
2812 allocation.width=sheet->row_title_area.width;
2813 allocation.height=sheet->column_title_area.height;
2815 gtk_widget_size_allocate(sheet->button, &allocation);
2816 gtk_widget_show(sheet->button);
2819 static void
2820 global_button_clicked(GtkWidget *widget, gpointer data)
2822 gboolean veto;
2824 gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2825 gtk_widget_grab_focus(GTK_WIDGET(data));
2829 static void
2830 gtk_sheet_unrealize (GtkWidget * widget)
2832 GtkSheet *sheet;
2834 g_return_if_fail (widget != NULL);
2835 g_return_if_fail (GTK_IS_SHEET (widget));
2837 sheet = GTK_SHEET (widget);
2839 gdk_cursor_destroy (sheet->cursor_drag);
2841 gdk_gc_destroy (sheet->xor_gc);
2842 gdk_gc_destroy (sheet->fg_gc);
2843 gdk_gc_destroy (sheet->bg_gc);
2845 gdk_window_destroy (sheet->sheet_window);
2846 gdk_window_destroy (sheet->column_title_window);
2847 gdk_window_destroy (sheet->row_title_window);
2849 if (sheet->pixmap){
2850 g_object_unref (sheet->pixmap);
2851 sheet->pixmap = NULL;
2854 sheet->column_title_window=NULL;
2855 sheet->sheet_window = NULL;
2856 sheet->cursor_drag = NULL;
2857 sheet->xor_gc = NULL;
2858 sheet->fg_gc = NULL;
2859 sheet->bg_gc = NULL;
2861 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2862 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2865 static void
2866 gtk_sheet_map (GtkWidget * widget)
2868 GtkSheet *sheet;
2869 GtkSheetChild *child;
2870 GList *children;
2872 g_return_if_fail (widget != NULL);
2873 g_return_if_fail (GTK_IS_SHEET (widget));
2875 sheet = GTK_SHEET (widget);
2877 if (!GTK_WIDGET_MAPPED (widget))
2879 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2881 if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2883 gdk_window_show (widget->window);
2885 gdk_window_show (sheet->sheet_window);
2887 if(sheet->column_titles_visible){
2888 gdk_window_show (sheet->column_title_window);
2890 if(sheet->row_titles_visible){
2891 gdk_window_show (sheet->row_title_window);
2894 if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)){
2895 gtk_widget_show (sheet->sheet_entry);
2896 gtk_widget_map (sheet->sheet_entry);
2899 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2900 !GTK_WIDGET_MAPPED (sheet->button)){
2901 gtk_widget_show(sheet->button);
2902 gtk_widget_map (sheet->button);
2905 if(GTK_BIN(sheet->button)->child)
2906 if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2907 !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2908 gtk_widget_map (GTK_BIN(sheet->button)->child);
2910 gtk_sheet_range_draw(sheet, NULL);
2911 gtk_sheet_activate_cell(sheet,
2912 sheet->active_cell.row,
2913 sheet->active_cell.col);
2915 children = sheet->children;
2916 while (children)
2918 child = children->data;
2919 children = g_list_next(children);
2921 if (GTK_WIDGET_VISIBLE (child->widget) &&
2922 !GTK_WIDGET_MAPPED (child->widget)){
2923 gtk_widget_map (child->widget);
2924 gtk_sheet_position_child(sheet, child);
2931 static void
2932 gtk_sheet_unmap (GtkWidget * widget)
2934 GtkSheet *sheet;
2935 GtkSheetChild *child;
2936 GList *children;
2938 g_return_if_fail (widget != NULL);
2939 g_return_if_fail (GTK_IS_SHEET (widget));
2941 sheet = GTK_SHEET (widget);
2943 if (GTK_WIDGET_MAPPED (widget))
2945 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2947 gdk_window_hide (sheet->sheet_window);
2948 if(sheet->column_titles_visible)
2949 gdk_window_hide (sheet->column_title_window);
2950 if(sheet->row_titles_visible)
2951 gdk_window_hide (sheet->row_title_window);
2952 gdk_window_hide (widget->window);
2954 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2955 gtk_widget_unmap (sheet->sheet_entry);
2957 if (GTK_WIDGET_MAPPED (sheet->button))
2958 gtk_widget_unmap (sheet->button);
2960 children = sheet->children;
2961 while (children)
2963 child = children->data;
2964 children = g_list_next(children);
2966 if (GTK_WIDGET_VISIBLE (child->widget) &&
2967 GTK_WIDGET_MAPPED (child->widget))
2969 gtk_widget_unmap (child->widget);
2977 static void
2978 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2980 GtkWidget *widget;
2981 GdkGC *fg_gc, *bg_gc;
2982 GtkSheetCellAttr attributes;
2983 GdkRectangle area;
2985 g_return_if_fail (sheet != NULL);
2987 /* bail now if we arn't drawable yet */
2988 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2990 if (row < 0 || row > sheet->maxrow) return;
2991 if (col < 0 || col > sheet->maxcol) return;
2992 if (!sheet->column[col].is_visible) return;
2993 if (!sheet->row[row].is_visible) return;
2995 widget = GTK_WIDGET (sheet);
2997 gtk_sheet_get_attributes(sheet, row, col, &attributes);
2999 /* select GC for background rectangle */
3000 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3001 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3003 fg_gc = sheet->fg_gc;
3004 bg_gc = sheet->bg_gc;
3006 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3007 area.y=ROW_TOP_YPIXEL(sheet,row);
3008 area.width=sheet->column[col].width;
3009 area.height=sheet->row[row].height;
3011 gdk_draw_rectangle (sheet->pixmap,
3012 bg_gc,
3013 TRUE,
3014 area.x,
3015 area.y,
3016 area.width,
3017 area.height);
3019 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3021 if(sheet->show_grid){
3022 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3024 gdk_draw_rectangle (sheet->pixmap,
3025 sheet->bg_gc,
3026 FALSE,
3027 area.x, area.y,
3028 area.width, area.height);
3032 static void
3033 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
3035 GtkWidget *widget;
3036 GdkGC *fg_gc, *bg_gc;
3037 GtkSheetCellAttr attributes;
3038 GdkRectangle area;
3039 guint width;
3041 g_return_if_fail (sheet != NULL);
3043 /* bail now if we arn't drawable yet */
3044 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3046 if (row < 0 || row > sheet->maxrow) return;
3047 if (col < 0 || col > sheet->maxcol) return;
3048 if (!sheet->column[col].is_visible) return;
3049 if (!sheet->row[row].is_visible) return;
3051 widget = GTK_WIDGET (sheet);
3053 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3055 /* select GC for background rectangle */
3056 gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
3057 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3059 fg_gc = sheet->fg_gc;
3060 bg_gc = sheet->bg_gc;
3062 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3063 area.y=ROW_TOP_YPIXEL(sheet,row);
3064 area.width=sheet->column[col].width;
3065 area.height=sheet->row[row].height;
3067 width = attributes.border.width;
3068 gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
3069 attributes.border.line_style,
3070 attributes.border.cap_style,
3071 attributes.border.join_style);
3072 if(width>0){
3074 if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
3075 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3076 area.x, area.y-width/2,
3077 area.x, area.y+area.height+width/2+1);
3079 if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
3080 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3081 area.x+area.width, area.y-width/2,
3082 area.x+area.width,
3083 area.y+area.height+width/2+1);
3085 if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
3086 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3087 area.x-width/2,area.y,
3088 area.x+area.width+width/2+1,
3089 area.y);
3091 if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
3092 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3093 area.x-width/2, area.y+area.height,
3094 area.x+area.width+width/2+1,
3095 area.y+area.height);
3101 static void
3102 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3104 GtkWidget *widget;
3105 GdkRectangle area, clip_area;
3106 gint i;
3107 gint text_width, text_height, y;
3108 gint xoffset=0;
3109 gint size, sizel, sizer;
3110 GdkGC *fg_gc, *bg_gc;
3111 GtkSheetCellAttr attributes;
3112 PangoLayout *layout;
3113 PangoRectangle rect;
3114 PangoRectangle logical_rect;
3115 PangoLayoutLine *line;
3116 PangoFontMetrics *metrics;
3117 PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet));
3118 gint ascent, descent, y_pos;
3120 char *label;
3122 g_return_if_fail (sheet != NULL);
3124 /* bail now if we aren't drawable yet */
3125 if (!GTK_WIDGET_DRAWABLE (sheet))
3126 return;
3128 if (row > sheet->maxallocrow) return;
3129 if (col > sheet->maxalloccol) return;
3130 if (!sheet->data[row]) return;
3131 if (!sheet->data[row][col]) return;
3132 if (!sheet->data[row][col]->text || strlen(sheet->data[row][col]->text)==0)
3133 return;
3135 if (row < 0 || row > sheet->maxrow) return;
3136 if (col < 0 || col > sheet->maxcol) return;
3137 if (!sheet->column[col].is_visible) return;
3138 if (!sheet->row[row].is_visible) return;
3141 widget = GTK_WIDGET(sheet);
3143 label = sheet->data[row][col]->text;
3145 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3147 /* select GC for background rectangle */
3148 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3149 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3151 fg_gc = sheet->fg_gc;
3152 bg_gc = sheet->bg_gc;
3154 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3155 area.y=ROW_TOP_YPIXEL(sheet,row);
3156 area.width=sheet->column[col].width;
3157 area.height=sheet->row[row].height;
3159 clip_area = area;
3161 layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
3162 pango_layout_set_font_description (layout, attributes.font_desc);
3164 pango_layout_get_pixel_extents (layout, NULL, &rect);
3166 line = pango_layout_get_lines (layout)->data;
3167 pango_layout_line_get_extents (line, NULL, &logical_rect);
3169 metrics = pango_context_get_metrics(context,
3170 attributes.font_desc,
3171 pango_context_get_language(context));
3173 ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
3174 descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
3176 pango_font_metrics_unref(metrics);
3178 /* Align primarily for locale's ascent/descent */
3180 logical_rect.height /= PANGO_SCALE;
3181 logical_rect.y /= PANGO_SCALE;
3182 y_pos = area.height - logical_rect.height;
3184 if (logical_rect.height > area.height)
3185 y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
3186 else if (y_pos < 0)
3187 y_pos = 0;
3188 else if (y_pos + logical_rect.height > area.height)
3189 y_pos = area.height - logical_rect.height;
3191 text_width = rect.width;
3192 text_height = rect.height;
3193 y = area.y + y_pos - CELLOFFSET;
3195 switch(attributes.justification){
3196 case GTK_JUSTIFY_RIGHT:
3197 size=area.width;
3198 area.x+=area.width;
3199 if(!gtk_sheet_clip_text(sheet)){
3200 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3201 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3202 if(size>=text_width+CELLOFFSET) break;
3203 size+=sheet->column[i].width;
3204 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
3206 area.width=size;
3208 area.x-=size;
3209 xoffset+=area.width-text_width - 2 * CELLOFFSET -
3210 attributes.border.width/2;
3211 break;
3212 case GTK_JUSTIFY_CENTER:
3213 sizel=area.width/2;
3214 sizer=area.width/2;
3215 area.x+=area.width/2;
3216 if(!gtk_sheet_clip_text(sheet)){
3217 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3218 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3219 if(sizer>=text_width/2) break;
3220 sizer+=sheet->column[i].width;
3221 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
3223 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3224 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3225 if(sizel>=text_width/2) break;
3226 sizel+=sheet->column[i].width;
3227 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
3229 size=MIN(sizel, sizer);
3231 area.x-=sizel;
3232 xoffset+= sizel - text_width/2 - CELLOFFSET;
3233 area.width=sizel+sizer;
3234 break;
3235 case GTK_JUSTIFY_LEFT:
3236 default:
3237 size=area.width;
3238 if(!gtk_sheet_clip_text(sheet)){
3239 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3240 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3241 if(size>=text_width+CELLOFFSET) break;
3242 size+=sheet->column[i].width;
3243 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
3245 area.width=size;
3247 xoffset += attributes.border.width/2;
3248 break;
3251 if(!gtk_sheet_clip_text(sheet)) clip_area = area;
3252 gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
3255 gdk_draw_layout (sheet->pixmap, fg_gc,
3256 area.x + xoffset + CELLOFFSET,
3258 layout);
3260 gdk_gc_set_clip_rectangle(fg_gc, NULL);
3261 g_object_unref(G_OBJECT(layout));
3263 gdk_draw_pixmap(sheet->sheet_window,
3264 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3265 sheet->pixmap,
3266 area.x,
3267 area.y,
3268 area.x,
3269 area.y,
3270 area.width,
3271 area.height);
3277 static void
3278 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
3280 gint i,j;
3281 GtkSheetRange drawing_range;
3282 GdkRectangle area;
3284 g_return_if_fail(sheet != NULL);
3285 g_return_if_fail(GTK_SHEET(sheet));
3287 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3288 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3289 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
3291 if(range == NULL)
3293 drawing_range.row0=MIN_VISIBLE_ROW(sheet);
3294 drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
3295 drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
3296 drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
3298 gdk_draw_rectangle (sheet->pixmap,
3299 GTK_WIDGET(sheet)->style->white_gc,
3300 TRUE,
3301 0,0,
3302 sheet->sheet_window_width,sheet->sheet_window_height);
3305 else
3307 drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3308 drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3309 drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3310 drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3313 if(drawing_range.coli == sheet->maxcol){
3314 area.x=COLUMN_LEFT_XPIXEL(sheet,sheet->maxcol)+
3315 sheet->column[sheet->maxcol].width+1;
3316 area.y=0;
3318 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3320 gdk_draw_rectangle (sheet->pixmap,
3321 sheet->fg_gc,
3322 TRUE,
3323 area.x,area.y,
3324 sheet->sheet_window_width - area.x,
3325 sheet->sheet_window_height);
3327 gdk_draw_pixmap(sheet->sheet_window,
3328 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3329 sheet->pixmap,
3330 area.x,
3331 area.y,
3332 area.x,
3333 area.y,
3334 sheet->sheet_window_width - area.x,
3335 sheet->sheet_window_height);
3337 if(drawing_range.rowi == sheet->maxrow){
3338 area.x=0;
3339 area.y=ROW_TOP_YPIXEL(sheet,sheet->maxrow)+sheet->row[sheet->maxrow].height+1;
3341 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3343 gdk_draw_rectangle (sheet->pixmap,
3344 sheet->fg_gc,
3345 TRUE,
3346 area.x,area.y,
3347 sheet->sheet_window_width,
3348 sheet->sheet_window_height - area.y);
3350 gdk_draw_pixmap(sheet->sheet_window,
3351 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3352 sheet->pixmap,
3353 area.x,
3354 area.y,
3355 area.x,
3356 area.y,
3357 sheet->sheet_window_width,
3358 sheet->sheet_window_height - area.y);
3361 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3362 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3363 gtk_sheet_cell_draw_default(sheet, i, j);
3366 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3367 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3368 gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3369 gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3370 gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3371 gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3372 gtk_sheet_cell_draw_border(sheet, i, j, 15);
3375 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3376 for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3377 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3378 sheet->data[i] && sheet->data[i][j])
3379 gtk_sheet_cell_draw_label (sheet, i, j);
3381 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3382 for(j=sheet->column[drawing_range.col0].left_text_column; j<drawing_range.col0; j++)
3383 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3384 sheet->data[i] && sheet->data[i][j])
3385 gtk_sheet_cell_draw_label (sheet, i, j);
3387 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3388 for(j=drawing_range.coli+1; j<=sheet->column[drawing_range.coli].right_text_column; j++)
3389 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3390 sheet->data[i] && sheet->data[i][j])
3391 gtk_sheet_cell_draw_label (sheet, i, j);
3393 gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3395 if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
3396 gtk_sheet_range_draw_selection(sheet, drawing_range);
3398 if(sheet->state == GTK_STATE_NORMAL &&
3399 sheet->active_cell.row >= drawing_range.row0 &&
3400 sheet->active_cell.row <= drawing_range.rowi &&
3401 sheet->active_cell.col >= drawing_range.col0 &&
3402 sheet->active_cell.col <= drawing_range.coli)
3403 gtk_sheet_show_active_cell(sheet);
3407 static void
3408 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3410 GdkRectangle area;
3411 gint i,j;
3412 GtkSheetRange aux;
3414 if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3415 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3416 return;
3418 if(!gtk_sheet_range_isvisible(sheet, range)) return;
3419 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3421 aux=range;
3423 range.col0=MAX(sheet->range.col0, range.col0);
3424 range.coli=MIN(sheet->range.coli, range.coli);
3425 range.row0=MAX(sheet->range.row0, range.row0);
3426 range.rowi=MIN(sheet->range.rowi, range.rowi);
3428 range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3429 range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3430 range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3431 range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3433 for(i=range.row0; i<=range.rowi; i++){
3434 for(j=range.col0; j<=range.coli; j++){
3436 if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED &&
3437 sheet->column[j].is_visible && sheet->row[i].is_visible){
3439 row_button_set(sheet, i);
3440 column_button_set(sheet, j);
3442 area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3443 area.y=ROW_TOP_YPIXEL(sheet,i);
3444 area.width=sheet->column[j].width;
3445 area.height=sheet->row[i].height;
3447 if(i==sheet->range.row0){
3448 area.y=area.y+2;
3449 area.height=area.height-2;
3451 if(i==sheet->range.rowi) area.height=area.height-3;
3452 if(j==sheet->range.col0){
3453 area.x=area.x+2;
3454 area.width=area.width-2;
3456 if(j==sheet->range.coli) area.width=area.width-3;
3458 if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
3459 gdk_draw_rectangle (sheet->sheet_window,
3460 sheet->xor_gc,
3461 TRUE,
3462 area.x+1,area.y+1,
3463 area.width,area.height);
3470 gtk_sheet_draw_border(sheet, sheet->range);
3474 static void
3475 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3477 gint x,y,width,height;
3479 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3481 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
3482 y=ROW_TOP_YPIXEL(sheet, range.row0);
3483 width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-x+sheet->column[range.coli].width;
3484 height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+sheet->row[range.rowi].height;
3486 if(range.row0==sheet->range.row0){
3487 y=y-5;
3488 height=height+5;
3490 if(range.rowi==sheet->range.rowi) height=height+5;
3491 if(range.col0==sheet->range.col0){
3492 x=x-5;
3493 width=width+5;
3495 if(range.coli==sheet->range.coli) width=width+5;
3498 width=MIN(width, sheet->sheet_window_width-x);
3499 height=MIN(height, sheet->sheet_window_height-y);
3501 x--;
3502 y--;
3503 width+=2;
3504 height+=2;
3506 x = (sheet->row_titles_visible)
3507 ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3508 y = (sheet->column_titles_visible)
3509 ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3511 if(range.coli==sheet->maxcol) width=sheet->sheet_window_width-x;
3512 if(range.rowi==sheet->maxrow) height=sheet->sheet_window_height-y;
3514 gdk_draw_pixmap(sheet->sheet_window,
3515 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3516 sheet->pixmap,
3521 width+1,
3522 height+1);
3525 static GtkSheetCell *
3526 gtk_sheet_cell_new()
3528 GtkSheetCell *cell;
3529 cell = g_new(GtkSheetCell, 1);
3530 cell->text = NULL;
3531 cell->link = NULL;
3532 cell->attributes = NULL;
3533 return cell;
3536 void
3537 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3539 GtkSheetCellAttr attributes;
3541 g_return_if_fail (sheet != NULL);
3542 g_return_if_fail (GTK_IS_SHEET (sheet));
3543 if (col > sheet->maxcol || row > sheet->maxrow) return;
3544 if (col < 0 || row < 0) return;
3546 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3547 gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3550 void
3551 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col,
3552 GtkJustification justification,
3553 const gchar *text)
3555 GtkSheetCell **cell;
3556 GtkSheetRange range;
3557 gint text_width;
3558 GtkSheetCellAttr attributes;
3560 g_return_if_fail (sheet != NULL);
3561 g_return_if_fail (GTK_IS_SHEET (sheet));
3562 if (col > sheet->maxcol || row > sheet->maxrow) return;
3563 if (col < 0 || row < 0) return;
3565 CheckBounds(sheet, row, col);
3567 cell=&sheet->data[row][col];
3569 if(*cell==NULL)
3570 (*cell) = gtk_sheet_cell_new();
3572 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3574 (*cell)->row = row;
3575 (*cell)->col = col;
3577 attributes.justification = justification;
3578 gtk_sheet_set_cell_attributes(sheet, row, col, attributes);
3580 if((*cell)->text){
3581 g_free((*cell)->text);
3582 (*cell)->text = NULL;
3585 if(text)
3586 (*cell)->text=g_strdup(text);
3588 if(attributes.is_visible){
3590 text_width = 0;
3591 if((*cell)->text && strlen((*cell)->text) > 0) {
3592 text_width = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, (*cell)->text);
3595 range.row0 = row;
3596 range.rowi = row;
3597 range.col0 = sheet->view.col0;
3598 range.coli = sheet->view.coli;
3600 if(gtk_sheet_autoresize(sheet) &&
3601 text_width > sheet->column[col].width-2*CELLOFFSET-attributes.border.width){
3602 gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3603 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3605 else
3606 if(!GTK_SHEET_IS_FROZEN(sheet))
3607 gtk_sheet_range_draw(sheet, &range);
3609 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3614 void
3615 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3617 GtkSheetRange range;
3619 g_return_if_fail (sheet != NULL);
3620 g_return_if_fail (GTK_IS_SHEET (sheet));
3621 if (column > sheet->maxcol || row > sheet->maxrow) return;
3622 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3623 if (column < 0 || row < 0) return;
3625 range.row0 = row;
3626 range.rowi = row;
3627 range.col0 = sheet->view.col0;
3628 range.coli = sheet->view.coli;
3630 gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3632 if(!GTK_SHEET_IS_FROZEN(sheet)){
3633 gtk_sheet_range_draw(sheet, &range);
3637 void
3638 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3640 GtkSheetRange range;
3642 g_return_if_fail (sheet != NULL);
3643 g_return_if_fail (GTK_IS_SHEET (sheet));
3644 if (column > sheet->maxcol || row > sheet->maxrow) return;
3645 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3646 if (column < 0 || row < 0) return;
3648 range.row0 = row;
3649 range.rowi = row;
3650 range.col0 = sheet->view.col0;
3651 range.coli = sheet->view.coli;
3653 gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3655 if(!GTK_SHEET_IS_FROZEN(sheet)){
3656 gtk_sheet_range_draw(sheet, &range);
3660 static void
3661 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3663 gchar *text;
3664 gpointer link;
3666 if(row > sheet->maxallocrow || column > sheet->maxalloccol) return;
3667 if(!sheet->data[row]) return;
3668 if(!sheet->data[row][column]) return;
3670 text = gtk_sheet_cell_get_text(sheet, row, column);
3671 link = gtk_sheet_get_link(sheet, row, column);
3673 if(text){
3674 g_free(sheet->data[row][column]->text);
3675 sheet->data[row][column]->text = NULL;
3677 if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3678 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], row, column);
3681 if(delete){
3682 if(sheet->data[row][column]->attributes){
3683 g_free(sheet->data[row][column]->attributes);
3684 sheet->data[row][column]->attributes = NULL;
3686 sheet->data[row][column]->link = NULL;
3688 if(sheet->data[row][column]) g_free(sheet->data[row][column]);
3690 sheet->data[row][column] = NULL;
3695 void
3696 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3698 g_return_if_fail (sheet != NULL);
3699 g_return_if_fail (GTK_IS_SHEET (sheet));
3701 gtk_sheet_real_range_clear(sheet, range, FALSE);
3704 void
3705 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3707 g_return_if_fail (sheet != NULL);
3708 g_return_if_fail (GTK_IS_SHEET (sheet));
3710 gtk_sheet_real_range_clear(sheet, range, TRUE);
3713 static void
3714 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range,
3715 gboolean delete)
3717 gint i, j;
3718 GtkSheetRange clear;
3720 if(!range){
3721 clear.row0=0;
3722 clear.rowi=sheet->maxallocrow;
3723 clear.col0=0;
3724 clear.coli=sheet->maxalloccol;
3725 }else
3726 clear=*range;
3728 clear.row0=MAX(clear.row0, 0);
3729 clear.col0=MAX(clear.col0, 0);
3730 clear.rowi=MIN(clear.rowi, sheet->maxallocrow);
3731 clear.coli=MIN(clear.coli, sheet->maxalloccol);
3733 for(i=clear.row0; i<=clear.rowi; i++)
3734 for(j=clear.col0; j<=clear.coli; j++){
3735 gtk_sheet_real_cell_clear(sheet, i, j, delete);
3738 gtk_sheet_range_draw(sheet, NULL);
3742 gchar *
3743 gtk_sheet_cell_get_text (GtkSheet *sheet, gint row, gint col)
3745 g_return_val_if_fail (sheet != NULL, NULL);
3746 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3748 if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
3749 if(col < 0 || row < 0) return NULL;
3750 if(row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL;
3751 if(!sheet->data[row]) return NULL;
3752 if(!sheet->data[row][col]) return NULL;
3753 if(!sheet->data[row][col]->text) return NULL;
3754 if(strlen(sheet->data[row][col]->text) == 0) return NULL;
3756 return (sheet->data[row][col]->text);
3759 void
3760 gtk_sheet_link_cell(GtkSheet *sheet, gint row, gint col, gpointer link)
3762 g_return_if_fail (sheet != NULL);
3763 g_return_if_fail (GTK_IS_SHEET (sheet));
3764 if(col > sheet->maxcol || row > sheet->maxrow) return;
3765 if(col < 0 || row < 0) return;
3767 if(row > sheet->maxallocrow || col > sheet->maxalloccol ||
3768 !sheet->data[row] || !sheet->data[row][col])
3769 gtk_sheet_set_cell_text(sheet, row, col, "");
3771 sheet->data[row][col]->link = link;
3774 gpointer
3775 gtk_sheet_get_link(GtkSheet *sheet, gint row, gint col)
3777 g_return_val_if_fail (sheet != NULL, NULL);
3778 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3779 if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
3780 if(col < 0 || row < 0) return NULL;
3782 if (row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL;
3783 if (!sheet->data[row]) return NULL; /* Added by Chris Howell */
3784 if (!sheet->data[row][col]) return NULL; /* Added by Bob Lissner */
3786 return(sheet->data[row][col]->link);
3789 void
3790 gtk_sheet_remove_link(GtkSheet *sheet, gint row, gint col)
3792 g_return_if_fail (sheet != NULL);
3793 g_return_if_fail (GTK_IS_SHEET (sheet));
3794 if(col > sheet->maxcol || row > sheet->maxrow) return;
3795 if(col < 0 || row < 0) return;
3797 /* Fixed by Andreas Voegele */
3798 if(row < sheet->maxallocrow && col < sheet->maxalloccol &&
3799 sheet->data[row] && sheet->data[row][col] &&
3800 sheet->data[row][col]->link)
3801 sheet->data[row][col]->link = NULL;
3805 GtkStateType
3806 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3808 gint state;
3809 GtkSheetRange *range;
3811 g_return_val_if_fail (sheet != NULL, 0);
3812 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3813 if(col > sheet->maxcol || row > sheet->maxrow) return 0;
3814 if(col < 0 || row < 0) return 0;
3816 state = sheet->state;
3817 range = &sheet->range;
3819 switch (state){
3820 case GTK_SHEET_NORMAL:
3821 return GTK_STATE_NORMAL;
3822 break;
3823 case GTK_SHEET_ROW_SELECTED:
3824 if(row>=range->row0 && row<=range->rowi)
3825 return GTK_STATE_SELECTED;
3826 break;
3827 case GTK_SHEET_COLUMN_SELECTED:
3828 if(col>=range->col0 && col<=range->coli)
3829 return GTK_STATE_SELECTED;
3830 break;
3831 case GTK_SHEET_RANGE_SELECTED:
3832 if(row >= range->row0 && row <= range->rowi && \
3833 col >= range->col0 && col <= range->coli)
3834 return GTK_STATE_SELECTED;
3835 break;
3837 return GTK_STATE_NORMAL;
3840 gboolean
3841 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3842 gint x,
3843 gint y,
3844 gint * row,
3845 gint * column)
3847 gint trow, tcol;
3849 g_return_val_if_fail (sheet != NULL, 0);
3850 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3852 /* bounds checking, return false if the user clicked
3853 * on a blank area */
3854 trow = ROW_FROM_YPIXEL (sheet, y);
3855 if (trow > sheet->maxrow)
3856 return FALSE;
3858 *row = trow;
3860 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3861 if (tcol > sheet->maxcol)
3862 return FALSE;
3864 *column = tcol;
3866 return TRUE;
3869 gboolean
3870 gtk_sheet_get_cell_area (GtkSheet * sheet,
3871 gint row,
3872 gint column,
3873 GdkRectangle *area)
3875 g_return_val_if_fail (sheet != NULL, 0);
3876 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3878 if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
3880 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3881 (sheet->row_titles_visible
3882 ? sheet->row_title_area.width
3883 : 0));
3884 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3885 (sheet->column_titles_visible
3886 ? sheet->column_title_area.height
3887 : 0));
3888 area->width= (column == -1) ? sheet->row_title_area.width
3889 : sheet->column[column].width;
3890 area->height= (row == -1) ? sheet->column_title_area.height
3891 : sheet->row[row].height;
3894 if(row < 0 || column < 0) return FALSE;
3896 area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3897 area->y = ROW_TOP_YPIXEL(sheet, row);
3898 if(sheet->row_titles_visible)
3899 area->x -= sheet->row_title_area.width;
3900 if(sheet->column_titles_visible)
3901 area->y -= sheet->column_title_area.height;
3903 area->width=sheet->column[column].width;
3904 area->height=sheet->row[row].height;
3906 return TRUE;
3909 gboolean
3910 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3912 g_return_val_if_fail (sheet != NULL, 0);
3913 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3915 if(row < 0 || column < 0) return FALSE;
3916 if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
3918 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3920 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3923 sheet->active_cell.row=row;
3924 sheet->active_cell.col=column;
3926 if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3928 return TRUE;
3931 void
3932 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3934 g_return_if_fail (sheet != NULL);
3935 g_return_if_fail (GTK_IS_SHEET (sheet));
3937 *row = sheet->active_cell.row;
3938 *column = sheet->active_cell.col;
3941 static void
3942 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
3944 GtkSheet *sheet;
3945 gint row,col;
3946 const char *text;
3947 GtkJustification justification;
3948 GtkSheetCellAttr attributes;
3950 g_return_if_fail (data != NULL);
3951 g_return_if_fail (GTK_IS_SHEET (data));
3953 sheet=GTK_SHEET(data);
3955 if(!GTK_WIDGET_VISIBLE(widget)) return;
3956 if(sheet->state != GTK_STATE_NORMAL) return;
3958 row=sheet->active_cell.row;
3959 col=sheet->active_cell.col;
3961 if(row<0 || col<0) return;
3963 sheet->active_cell.row=-1;
3964 sheet->active_cell.col=-1;
3966 text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3968 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3970 if(text && strlen(text)!=0){
3971 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3972 justification=attributes.justification;
3973 gtk_sheet_set_cell(sheet, row, col, justification, text);
3975 else
3977 /* Added by Matias Mutchinick */
3978 gtk_sheet_cell_clear(sheet, row, col);
3981 if(sheet->freeze_count == 0)
3982 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3984 sheet->active_cell.row=row;;
3985 sheet->active_cell.col=col;
3990 static gboolean
3991 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3993 gboolean veto = TRUE;
3995 g_return_val_if_fail (sheet != NULL, FALSE);
3996 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3998 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
3999 if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
4001 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE],
4002 sheet->active_cell.row,
4003 sheet->active_cell.col, &veto);
4005 if(!veto) return FALSE;
4007 gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
4008 (GtkSignalFunc) gtk_sheet_entry_changed,
4009 GTK_OBJECT(GTK_WIDGET(sheet)));
4011 gtk_sheet_hide_active_cell(sheet);
4012 sheet->active_cell.row=-1;
4013 sheet->active_cell.col=-1;
4015 if(GTK_SHEET_REDRAW_PENDING(sheet)){
4016 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
4017 gtk_sheet_range_draw(sheet, NULL);
4020 return TRUE;
4023 static void
4024 gtk_sheet_hide_active_cell(GtkSheet *sheet)
4026 const char *text;
4027 gint row,col;
4028 GtkJustification justification;
4029 GtkSheetCellAttr attributes;
4031 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4033 row=sheet->active_cell.row;
4034 col=sheet->active_cell.col;
4036 if(row < 0 || col < 0) return;
4038 if(sheet->freeze_count == 0)
4039 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4041 text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4043 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4044 justification=attributes.justification;
4046 if(text && strlen(text)!=0){
4047 gtk_sheet_set_cell(sheet, row, col, justification, text);
4048 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
4050 else
4052 gtk_sheet_cell_clear(sheet, row, col);
4055 row=sheet->active_cell.row;
4056 col=sheet->active_cell.col;
4058 column_button_release(sheet, col);
4059 row_button_release(sheet, row);
4061 gtk_widget_unmap(sheet->sheet_entry);
4063 if(row != -1 && col != -1)
4064 gdk_draw_pixmap(sheet->sheet_window,
4065 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4066 sheet->pixmap,
4067 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4068 ROW_TOP_YPIXEL(sheet,row)-1,
4069 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4070 ROW_TOP_YPIXEL(sheet,row)-1,
4071 sheet->column[col].width+4,
4072 sheet->row[row].height+4);
4074 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4075 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
4076 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4078 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4082 static gboolean
4083 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
4085 gboolean veto = TRUE;
4087 g_return_val_if_fail (sheet != NULL, FALSE);
4088 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4090 if(row < 0 || col < 0) return FALSE;
4091 if(row > sheet->maxrow || col > sheet->maxcol) return FALSE;
4093 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4094 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
4097 if(!veto) return FALSE;
4098 if(sheet->state != GTK_SHEET_NORMAL){
4099 sheet->state=GTK_SHEET_NORMAL;
4100 gtk_sheet_real_unselect_range(sheet, NULL);
4103 sheet->range.row0=row;
4104 sheet->range.col0=col;
4105 sheet->range.rowi=row;
4106 sheet->range.coli=col;
4107 sheet->active_cell.row=row;
4108 sheet->active_cell.col=col;
4109 sheet->selection_cell.row=row;
4110 sheet->selection_cell.col=col;
4111 row_button_set(sheet, row);
4112 column_button_set(sheet, col);
4114 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4115 gtk_sheet_show_active_cell(sheet);
4117 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
4118 "changed",
4119 (GtkSignalFunc)gtk_sheet_entry_changed,
4120 GTK_OBJECT(GTK_WIDGET(sheet)));
4122 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4124 return TRUE;
4127 static void
4128 gtk_sheet_show_active_cell(GtkSheet *sheet)
4130 GtkSheetCell *cell;
4131 GtkEntry *sheet_entry;
4132 GtkSheetCellAttr attributes;
4133 gchar *text = NULL;
4134 GtkJustification justification;
4135 gint row, col;
4137 g_return_if_fail (sheet != NULL);
4138 g_return_if_fail (GTK_IS_SHEET (sheet));
4140 row = sheet->active_cell.row;
4141 col = sheet->active_cell.col;
4143 /* Don't show the active cell, if there is no active cell: */
4144 if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4145 return;
4147 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4148 if(sheet->state != GTK_SHEET_NORMAL) return;
4149 if(GTK_SHEET_IN_SELECTION(sheet)) return;
4151 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4153 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4155 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4157 justification = GTK_JUSTIFY_LEFT;
4159 if(gtk_sheet_justify_entry(sheet))
4160 justification = attributes.justification;
4162 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol) {
4163 if(sheet->data[row]) {
4164 if(sheet->data[row][col]) {
4165 cell = sheet->data[row][col];
4166 if(cell->text)
4167 text = g_strdup(cell->text);
4172 if(!text) text = g_strdup("");
4174 gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4176 if(gtk_sheet_locked(sheet) || !attributes.is_editable){
4177 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4178 }else{
4179 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4183 if(!GTK_IS_ITEM_ENTRY(sheet_entry))
4184 gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4185 else
4186 gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), text, justification);
4189 gtk_sheet_entry_set_max_size(sheet);
4190 gtk_sheet_size_allocate_entry(sheet);
4192 gtk_widget_map(sheet->sheet_entry);
4193 gtk_sheet_draw_active_cell(sheet);
4195 gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4196 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet_entry), GTK_HAS_FOCUS);
4197 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
4199 g_free(text);
4202 static void
4203 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4205 gint row, col;
4207 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4208 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4210 row = sheet->active_cell.row;
4211 col = sheet->active_cell.col;
4213 if(row<0 || col<0) return;
4215 if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4217 row_button_set(sheet, row);
4218 column_button_set(sheet, col);
4220 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4221 gtk_sheet_draw_border(sheet, sheet->range);
4226 static void
4227 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4229 gint pixmap_width, pixmap_height;
4231 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4233 if(width == 0 && height == 0){
4234 width=sheet->sheet_window_width+80;
4235 height=sheet->sheet_window_height+80;
4238 if (!sheet->pixmap)
4240 /* allocate */
4241 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4242 width, height,
4243 -1);
4244 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4246 else
4248 /* reallocate if sizes don't match */
4249 gdk_window_get_size (sheet->pixmap,
4250 &pixmap_width, &pixmap_height);
4251 if ((pixmap_width != width) || (pixmap_height != height))
4253 gdk_pixmap_unref(sheet->pixmap); /* replaced by SDB on 7.31.2006 */
4254 /* g_free(sheet->pixmap); */
4255 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4256 width, height,
4257 -1);
4258 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4263 static void
4264 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4266 gint i,j, mask1, mask2;
4267 gint state, selected;
4268 gint x,y,width,height;
4269 GtkSheetRange new_range, aux_range;
4271 g_return_if_fail (sheet != NULL);
4273 if(range==NULL) range=&sheet->range;
4275 new_range=*range;
4277 range->row0=MIN(range->row0, sheet->range.row0);
4278 range->rowi=MAX(range->rowi, sheet->range.rowi);
4279 range->col0=MIN(range->col0, sheet->range.col0);
4280 range->coli=MAX(range->coli, sheet->range.coli);
4282 range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4283 range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4284 range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4285 range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4287 aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4288 aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4289 aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4290 aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4292 for(i=range->row0; i<=range->rowi; i++){
4293 for(j=range->col0; j<=range->coli; j++){
4295 state=gtk_sheet_cell_get_state(sheet, i, j);
4296 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4297 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4299 if(state==GTK_STATE_SELECTED && selected &&
4300 sheet->column[j].is_visible && sheet->row[i].is_visible &&
4301 (i==sheet->range.row0 || i==sheet->range.rowi ||
4302 j==sheet->range.col0 || j==sheet->range.coli ||
4303 i==new_range.row0 || i==new_range.rowi ||
4304 j==new_range.col0 || j==new_range.coli)){
4306 mask1 = i==sheet->range.row0 ? 1 : 0;
4307 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4308 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4309 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4311 mask2 = i==new_range.row0 ? 1 : 0;
4312 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4313 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4314 mask2 = j==new_range.coli ? mask2+8 : mask2;
4316 if(mask1 != mask2){
4317 x=COLUMN_LEFT_XPIXEL(sheet,j);
4318 y=ROW_TOP_YPIXEL(sheet, i);
4319 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4320 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4322 if(i==sheet->range.row0){
4323 y=y-3;
4324 height=height+3;
4326 if(i==sheet->range.rowi) height=height+3;
4327 if(j==sheet->range.col0){
4328 x=x-3;
4329 width=width+3;
4331 if(j==sheet->range.coli) width=width+3;
4333 gdk_draw_pixmap(sheet->sheet_window,
4334 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4335 sheet->pixmap,
4336 x+1,
4337 y+1,
4338 x+1,
4339 y+1,
4340 width,
4341 height);
4343 if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4344 x=COLUMN_LEFT_XPIXEL(sheet,j);
4345 y=ROW_TOP_YPIXEL(sheet, i);
4346 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4347 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4349 if(i==new_range.row0){
4350 y=y+2;
4351 height=height-2;
4353 if(i==new_range.rowi) height=height-3;
4354 if(j==new_range.col0){
4355 x=x+2;
4356 width=width-2;
4358 if(j==new_range.coli) width=width-3;
4360 gdk_draw_rectangle (sheet->sheet_window,
4361 sheet->xor_gc,
4362 TRUE,
4363 x+1,y+1,
4364 width,height);
4371 for(i=range->row0; i<=range->rowi; i++){
4372 for(j=range->col0; j<=range->coli; j++){
4374 state=gtk_sheet_cell_get_state(sheet, i, j);
4375 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4376 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4378 if(state==GTK_STATE_SELECTED && !selected &&
4379 sheet->column[j].is_visible && sheet->row[i].is_visible){
4381 x=COLUMN_LEFT_XPIXEL(sheet,j);
4382 y=ROW_TOP_YPIXEL(sheet, i);
4383 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4384 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4386 if(i==sheet->range.row0){
4387 y=y-3;
4388 height=height+3;
4390 if(i==sheet->range.rowi) height=height+3;
4391 if(j==sheet->range.col0){
4392 x=x-3;
4393 width=width+3;
4395 if(j==sheet->range.coli) width=width+3;
4397 gdk_draw_pixmap(sheet->sheet_window,
4398 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4399 sheet->pixmap,
4400 x+1,
4401 y+1,
4402 x+1,
4403 y+1,
4404 width,
4405 height);
4410 for(i=range->row0; i<=range->rowi; i++){
4411 for(j=range->col0; j<=range->coli; j++){
4413 state=gtk_sheet_cell_get_state(sheet, i, j);
4414 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4415 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4417 if(state!=GTK_STATE_SELECTED && selected &&
4418 sheet->column[j].is_visible && sheet->row[i].is_visible &&
4419 (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4421 x=COLUMN_LEFT_XPIXEL(sheet,j);
4422 y=ROW_TOP_YPIXEL(sheet, i);
4423 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4424 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4426 if(i==new_range.row0){
4427 y=y+2;
4428 height=height-2;
4430 if(i==new_range.rowi) height=height-3;
4431 if(j==new_range.col0){
4432 x=x+2;
4433 width=width-2;
4435 if(j==new_range.coli) width=width-3;
4437 gdk_draw_rectangle (sheet->sheet_window,
4438 sheet->xor_gc,
4439 TRUE,
4440 x+1,y+1,
4441 width,height);
4448 for(i=aux_range.row0; i<=aux_range.rowi; i++){
4449 for(j=aux_range.col0; j<=aux_range.coli; j++){
4451 if(sheet->column[j].is_visible && sheet->row[i].is_visible){
4453 state=gtk_sheet_cell_get_state(sheet, i, j);
4455 mask1 = i==sheet->range.row0 ? 1 : 0;
4456 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4457 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4458 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4460 mask2 = i==new_range.row0 ? 1 : 0;
4461 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4462 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4463 mask2 = j==new_range.coli ? mask2+8 : mask2;
4464 if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4465 x=COLUMN_LEFT_XPIXEL(sheet,j);
4466 y=ROW_TOP_YPIXEL(sheet, i);
4467 width=sheet->column[j].width;
4468 height=sheet->row[i].height;
4469 if(mask2 & 1)
4470 gdk_draw_rectangle (sheet->sheet_window,
4471 sheet->xor_gc,
4472 TRUE,
4473 x+1,y-1,
4474 width,3);
4477 if(mask2 & 2)
4478 gdk_draw_rectangle (sheet->sheet_window,
4479 sheet->xor_gc,
4480 TRUE,
4481 x+1,y+height-1,
4482 width,3);
4484 if(mask2 & 4)
4485 gdk_draw_rectangle (sheet->sheet_window,
4486 sheet->xor_gc,
4487 TRUE,
4488 x-1,y+1,
4489 3,height);
4492 if(mask2 & 8)
4493 gdk_draw_rectangle (sheet->sheet_window,
4494 sheet->xor_gc,
4495 TRUE,
4496 x+width-1,y+1,
4497 3,height);
4509 *range=new_range;
4510 gtk_sheet_draw_corners(sheet, new_range);
4514 static void
4515 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4517 GtkWidget *widget;
4518 GdkRectangle area;
4519 gint i;
4520 gint x,y,width,height;
4522 widget = GTK_WIDGET(sheet);
4524 x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4525 y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4526 width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+
4527 sheet->column[new_range.coli].width;
4528 height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4529 sheet->row[new_range.rowi].height;
4531 area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4532 area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4533 area.width=sheet->sheet_window_width;
4534 area.height=sheet->sheet_window_height;
4536 if(x<0) {
4537 width=width+x;
4538 x=0;
4540 if(width>area.width) width=area.width+10;
4541 if(y<0) {
4542 height=height+y;
4543 y=0;
4545 if(height>area.height) height=area.height+10;
4547 gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4549 for(i=-1; i<=1; ++i)
4550 gdk_draw_rectangle (sheet->sheet_window,
4551 sheet->xor_gc,
4552 FALSE,
4553 x+i,y+i,
4554 width-2*i,height-2*i);
4556 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4558 gtk_sheet_draw_corners(sheet, new_range);
4562 static void
4563 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4565 gint x,y;
4566 guint width = 1;
4568 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4569 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4570 y=ROW_TOP_YPIXEL(sheet,range.row0);
4571 gdk_draw_pixmap(sheet->sheet_window,
4572 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4573 sheet->pixmap,
4574 x-1,
4575 y-1,
4576 x-1,
4577 y-1,
4579 3);
4580 gdk_draw_rectangle (sheet->sheet_window,
4581 sheet->xor_gc,
4582 TRUE,
4583 x-1,y-1,
4584 3,3);
4587 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4588 sheet->state == GTK_SHEET_COLUMN_SELECTED){
4589 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4590 sheet->column[range.coli].width;
4591 y=ROW_TOP_YPIXEL(sheet,range.row0);
4592 width = 1;
4593 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4595 y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4596 width = 3;
4598 gdk_draw_pixmap(sheet->sheet_window,
4599 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4600 sheet->pixmap,
4601 x-width,
4602 y-width,
4603 x-width,
4604 y-width,
4605 2*width+1,
4606 2*width+1);
4607 gdk_draw_rectangle (sheet->sheet_window,
4608 sheet->xor_gc,
4609 TRUE,
4610 x-width+width/2,y-width+width/2,
4611 2+width,2+width);
4614 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4615 sheet->state == GTK_SHEET_ROW_SELECTED){
4616 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4617 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4618 sheet->row[range.rowi].height;
4619 width = 1;
4620 if(sheet->state == GTK_SHEET_ROW_SELECTED)
4622 x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4623 width = 3;
4625 gdk_draw_pixmap(sheet->sheet_window,
4626 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4627 sheet->pixmap,
4628 x-width,
4629 y-width,
4630 x-width,
4631 y-width,
4632 2*width+1,
4633 2*width+1);
4634 gdk_draw_rectangle (sheet->sheet_window,
4635 sheet->xor_gc,
4636 TRUE,
4637 x-width+width/2,y-width+width/2,
4638 2+width,2+width);
4641 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4642 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4643 sheet->column[range.coli].width;
4644 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4645 sheet->row[range.rowi].height;
4646 width = 1;
4647 if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4648 if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4649 gdk_draw_pixmap(sheet->sheet_window,
4650 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4651 sheet->pixmap,
4652 x-width,
4653 y-width,
4654 x-width,
4655 y-width,
4656 2*width+1,
4657 2*width+1);
4658 gdk_draw_rectangle (sheet->sheet_window,
4659 sheet->xor_gc,
4660 TRUE,
4661 x-width+width/2,y-width+width/2,
4662 2+width,2+width);
4669 static void
4670 gtk_sheet_real_select_range (GtkSheet * sheet,
4671 GtkSheetRange * range)
4673 gint i;
4674 gint state;
4676 g_return_if_fail (sheet != NULL);
4678 if(range==NULL) range=&sheet->range;
4680 if(range->row0 < 0 || range->rowi < 0) return;
4681 if(range->col0 < 0 || range->coli < 0) return;
4683 state=sheet->state;
4685 if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4686 for(i=sheet->range.col0; i< range->col0; i++)
4687 column_button_release(sheet, i);
4688 for(i=range->coli+1; i<= sheet->range.coli; i++)
4689 column_button_release(sheet, i);
4690 for(i=range->col0; i<=range->coli; i++){
4691 column_button_set(sheet, i);
4695 if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4696 for(i=sheet->range.row0; i< range->row0; i++)
4697 row_button_release(sheet, i);
4698 for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4699 row_button_release(sheet, i);
4700 for(i=range->row0; i<=range->rowi; i++){
4701 row_button_set(sheet, i);
4705 if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4706 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4709 gtk_sheet_new_selection(sheet, range);
4711 sheet->range.col0=range->col0;
4712 sheet->range.coli=range->coli;
4713 sheet->range.row0=range->row0;
4714 sheet->range.rowi=range->rowi;
4717 else
4719 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4720 gtk_sheet_range_draw_selection(sheet, sheet->range);
4723 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4726 void
4727 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4729 g_return_if_fail (sheet != NULL);
4731 if(range==NULL) range=&sheet->range;
4733 if(range->row0 < 0 || range->rowi < 0) return;
4734 if(range->col0 < 0 || range->coli < 0) return;
4736 if(sheet->state != GTK_SHEET_NORMAL)
4737 gtk_sheet_real_unselect_range(sheet, NULL);
4738 else
4740 gboolean veto = TRUE;
4741 veto = gtk_sheet_deactivate_cell(sheet);
4742 if(!veto) return;
4745 sheet->range.row0=range->row0;
4746 sheet->range.rowi=range->rowi;
4747 sheet->range.col0=range->col0;
4748 sheet->range.coli=range->coli;
4749 sheet->active_cell.row=range->row0;
4750 sheet->active_cell.col=range->col0;
4751 sheet->selection_cell.row=range->rowi;
4752 sheet->selection_cell.col=range->coli;
4754 sheet->state = GTK_SHEET_RANGE_SELECTED;
4755 gtk_sheet_real_select_range(sheet, NULL);
4759 void
4760 gtk_sheet_unselect_range (GtkSheet * sheet)
4762 gtk_sheet_real_unselect_range(sheet, NULL);
4763 sheet->state = GTK_STATE_NORMAL;
4764 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4768 static void
4769 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4770 const GtkSheetRange *range)
4772 gint i;
4774 g_return_if_fail (sheet != NULL);
4775 g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4777 if(range==NULL){
4778 range=&sheet->range;
4781 if(range->row0 < 0 || range->rowi < 0) return;
4782 if(range->col0 < 0 || range->coli < 0) return;
4784 if (gtk_sheet_range_isvisible (sheet, *range)){
4785 gtk_sheet_draw_backing_pixmap(sheet, *range);
4788 for(i=range->col0; i<=range->coli; i++){
4789 column_button_release(sheet, i);
4792 for(i=range->row0; i<=range->rowi; i++){
4793 row_button_release(sheet, i);
4799 static gint
4800 gtk_sheet_expose (GtkWidget * widget,
4801 GdkEventExpose * event)
4803 GtkSheet *sheet;
4804 GtkSheetRange range;
4806 #ifdef DEBUG
4807 printf("---> Entered gtk_sheet_expose ... must have received expose_event\n");
4808 #endif
4810 g_return_val_if_fail (widget != NULL, FALSE);
4811 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4812 g_return_val_if_fail (event != NULL, FALSE);
4814 sheet = GTK_SHEET (widget);
4816 if (GTK_WIDGET_DRAWABLE (widget))
4818 range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4819 range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4820 range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4821 range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4823 /* exposure events on the sheet */
4825 if( (event->window == sheet->row_title_window) && sheet->row_titles_visible){
4826 size_allocate_row_title_buttons(sheet);
4829 if( (event->window == sheet->column_title_window) && sheet->column_titles_visible){
4830 size_allocate_column_title_buttons(sheet);
4833 if (event->window == sheet->sheet_window){
4834 gtk_sheet_draw_backing_pixmap(sheet, range);
4836 if(sheet->state != GTK_SHEET_NORMAL){
4837 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4838 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4839 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4840 gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4842 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4843 gtk_sheet_range_draw_selection(sheet, sheet->range);
4844 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4845 draw_xor_rectangle(sheet, sheet->drag_range);
4848 if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4849 if(sheet->state == GTK_SHEET_NORMAL){
4850 gtk_sheet_draw_active_cell(sheet);
4851 if(!GTK_SHEET_IN_SELECTION(sheet))
4852 gtk_widget_queue_draw(sheet->sheet_entry);
4861 if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4862 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4864 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4866 #ifdef DEBUG
4867 printf("<--- Leaving gtk_sheet_expose\n");
4868 #endif
4870 return FALSE;
4874 static gint
4875 gtk_sheet_button_press (GtkWidget * widget,
4876 GdkEventButton * event)
4878 GtkSheet *sheet;
4879 GdkModifierType mods;
4880 gint x, y, row, column;
4881 gboolean veto;
4883 g_return_val_if_fail (widget != NULL, FALSE);
4884 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4885 g_return_val_if_fail (event != NULL, FALSE);
4887 if(event->type != GDK_BUTTON_PRESS) return TRUE;
4888 gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4889 if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4891 sheet = GTK_SHEET (widget);
4893 /* press on resize windows */
4894 if (event->window == sheet->column_title_window &&
4895 gtk_sheet_columns_resizable(sheet))
4897 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4898 if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4899 guint req;
4900 gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4901 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4902 gdk_pointer_grab (sheet->column_title_window, FALSE,
4903 GDK_POINTER_MOTION_HINT_MASK |
4904 GDK_BUTTON1_MOTION_MASK |
4905 GDK_BUTTON_RELEASE_MASK,
4906 NULL, NULL, event->time);
4908 draw_xor_vline (sheet);
4909 return TRUE;
4913 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4915 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4917 if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4918 guint req;
4919 gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4920 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4921 gdk_pointer_grab (sheet->row_title_window, FALSE,
4922 GDK_POINTER_MOTION_HINT_MASK |
4923 GDK_BUTTON1_MOTION_MASK |
4924 GDK_BUTTON_RELEASE_MASK,
4925 NULL, NULL, event->time);
4927 draw_xor_hline (sheet);
4928 return TRUE;
4932 /* selections on the sheet */
4933 if(event->window == sheet->sheet_window){
4934 gtk_widget_get_pointer (widget, &x, &y);
4935 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4936 gdk_pointer_grab (sheet->sheet_window, FALSE,
4937 GDK_POINTER_MOTION_HINT_MASK |
4938 GDK_BUTTON1_MOTION_MASK |
4939 GDK_BUTTON_RELEASE_MASK,
4940 NULL, NULL, event->time);
4941 gtk_grab_add(GTK_WIDGET(sheet));
4942 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
4943 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4944 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
4945 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4947 if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4948 sheet->cursor_drag->type==GDK_SIZING &&
4949 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4950 if(sheet->state==GTK_STATE_NORMAL) {
4951 row=sheet->active_cell.row;
4952 column=sheet->active_cell.col;
4953 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4954 sheet->active_cell.row=row;
4955 sheet->active_cell.col=column;
4956 sheet->drag_range=sheet->range;
4957 sheet->state=GTK_SHEET_RANGE_SELECTED;
4958 gtk_sheet_select_range(sheet, &sheet->drag_range);
4960 sheet->x_drag=x;
4961 sheet->y_drag=y;
4962 if(row > sheet->range.rowi) row--;
4963 if(column > sheet->range.coli) column--;
4964 sheet->drag_cell.row = row;
4965 sheet->drag_cell.col = column;
4966 sheet->drag_range=sheet->range;
4967 draw_xor_rectangle(sheet, sheet->drag_range);
4968 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4970 else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4971 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_DRAG(sheet)) {
4972 if(sheet->state==GTK_STATE_NORMAL) {
4973 row=sheet->active_cell.row;
4974 column=sheet->active_cell.col;
4975 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4976 sheet->active_cell.row=row;
4977 sheet->active_cell.col=column;
4978 sheet->drag_range=sheet->range;
4979 sheet->state=GTK_SHEET_RANGE_SELECTED;
4980 gtk_sheet_select_range(sheet, &sheet->drag_range);
4982 sheet->x_drag=x;
4983 sheet->y_drag=y;
4984 if(row < sheet->range.row0) row++;
4985 if(row > sheet->range.rowi) row--;
4986 if(column < sheet->range.col0) column++;
4987 if(column > sheet->range.coli) column--;
4988 sheet->drag_cell.row=row;
4989 sheet->drag_cell.col=column;
4990 sheet->drag_range=sheet->range;
4991 draw_xor_rectangle(sheet, sheet->drag_range);
4992 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
4994 else
4996 gtk_sheet_click_cell(sheet, row, column, &veto);
4997 if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5002 if(event->window == sheet->column_title_window){
5003 gtk_widget_get_pointer (widget, &x, &y);
5004 column = COLUMN_FROM_XPIXEL(sheet, x);
5005 if(sheet->column[column].is_sensitive){;
5006 gtk_sheet_click_cell(sheet, -1, column, &veto);
5007 gtk_grab_add(GTK_WIDGET(sheet));
5008 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5009 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
5010 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
5011 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5012 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5016 if(event->window == sheet->row_title_window){
5017 gtk_widget_get_pointer (widget, &x, &y);
5018 row = ROW_FROM_YPIXEL(sheet, y);
5019 if(sheet->row[row].is_sensitive){
5020 gtk_sheet_click_cell(sheet, row, -1, &veto);
5021 gtk_grab_add(GTK_WIDGET(sheet));
5022 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5023 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
5024 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
5025 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5026 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5030 return TRUE;
5033 static gint
5034 gtk_sheet_scroll(gpointer data)
5036 GtkSheet *sheet;
5037 gint x,y,row,column;
5038 gint move;
5040 sheet=GTK_SHEET(data);
5042 GDK_THREADS_ENTER();
5044 gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
5045 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5047 move=TRUE;
5049 if(GTK_SHEET_IN_SELECTION(sheet))
5050 gtk_sheet_extend_selection(sheet, row, column);
5052 if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
5053 move=gtk_sheet_move_query(sheet, row, column);
5054 if(move) draw_xor_rectangle(sheet, sheet->drag_range);
5057 GDK_THREADS_LEAVE();
5059 return TRUE;
5063 static void
5064 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
5066 *veto = TRUE;
5068 if(row > sheet->maxrow || column > sheet->maxcol){
5069 *veto = FALSE;
5070 return;
5073 if(column >= 0 && row >= 0)
5074 if(!sheet->column[column].is_visible || !sheet->row[row].is_visible)
5076 *veto = FALSE;
5077 return;
5080 _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
5081 sheet->active_cell.row, sheet->active_cell.col,
5082 &row, &column, veto);
5084 if(!*veto){
5085 if(sheet->state == GTK_STATE_NORMAL) return;
5087 row = sheet->active_cell.row;
5088 column = sheet->active_cell.col;
5089 gtk_sheet_activate_cell(sheet, row, column);
5090 return;
5093 if(row == -1 && column >= 0){
5094 if(gtk_sheet_autoscroll(sheet))
5095 gtk_sheet_move_query(sheet, row, column);
5096 gtk_sheet_select_column(sheet, column);
5097 return;
5099 if(column == -1 && row >= 0){
5100 if(gtk_sheet_autoscroll(sheet))
5101 gtk_sheet_move_query(sheet, row, column);
5102 gtk_sheet_select_row(sheet, row);
5103 return;
5106 if(row==-1 && column ==-1){
5107 sheet->range.row0=0;
5108 sheet->range.col0=0;
5109 sheet->range.rowi=sheet->maxrow;
5110 sheet->range.coli=sheet->maxcol;
5111 sheet->active_cell.row=0;
5112 sheet->active_cell.col=0;
5113 gtk_sheet_select_range(sheet, NULL);
5114 return;
5117 if(row!=-1 && column !=-1){
5118 if(sheet->state != GTK_SHEET_NORMAL){
5119 sheet->state = GTK_SHEET_NORMAL;
5120 gtk_sheet_real_unselect_range(sheet, NULL);
5122 else
5124 if(!gtk_sheet_deactivate_cell(sheet)){
5125 *veto = FALSE;
5126 return;
5130 if(gtk_sheet_autoscroll(sheet))
5131 gtk_sheet_move_query(sheet, row, column);
5132 sheet->active_cell.row=row;
5133 sheet->active_cell.col=column;
5134 sheet->selection_cell.row=row;
5135 sheet->selection_cell.col=column;
5136 sheet->range.row0=row;
5137 sheet->range.col0=column;
5138 sheet->range.rowi=row;
5139 sheet->range.coli=column;
5140 sheet->state=GTK_SHEET_NORMAL;
5141 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5142 gtk_sheet_draw_active_cell(sheet);
5143 return;
5146 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5147 sheet->active_cell.col);
5150 static gint
5151 gtk_sheet_button_release (GtkWidget * widget,
5152 GdkEventButton * event)
5154 GtkSheet *sheet;
5155 gint x,y;
5157 sheet=GTK_SHEET(widget);
5159 /* release on resize windows */
5160 if (GTK_SHEET_IN_XDRAG (sheet)){
5161 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5162 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5163 gtk_widget_get_pointer (widget, &x, NULL);
5164 gdk_pointer_ungrab (event->time);
5165 draw_xor_vline (sheet);
5167 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
5168 sheet->old_hadjustment = -1.;
5169 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5170 return TRUE;
5173 if (GTK_SHEET_IN_YDRAG (sheet)){
5174 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5175 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5176 gtk_widget_get_pointer (widget, NULL, &y);
5177 gdk_pointer_ungrab (event->time);
5178 draw_xor_hline (sheet);
5180 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5181 sheet->old_vadjustment = -1.;
5182 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5183 return TRUE;
5187 if (GTK_SHEET_IN_DRAG(sheet)){
5188 GtkSheetRange old_range;
5189 draw_xor_rectangle(sheet, sheet->drag_range);
5190 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5191 gdk_pointer_ungrab (event->time);
5193 gtk_sheet_real_unselect_range(sheet, NULL);
5195 sheet->active_cell.row = sheet->active_cell.row +
5196 (sheet->drag_range.row0 - sheet->range.row0);
5197 sheet->active_cell.col = sheet->active_cell.col +
5198 (sheet->drag_range.col0 - sheet->range.col0);
5199 sheet->selection_cell.row = sheet->selection_cell.row +
5200 (sheet->drag_range.row0 - sheet->range.row0);
5201 sheet->selection_cell.col = sheet->selection_cell.col +
5202 (sheet->drag_range.col0 - sheet->range.col0);
5203 old_range=sheet->range;
5204 sheet->range=sheet->drag_range;
5205 sheet->drag_range=old_range;
5206 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5207 &sheet->drag_range, &sheet->range);
5208 gtk_sheet_select_range(sheet, &sheet->range);
5211 if (GTK_SHEET_IN_RESIZE(sheet)){
5212 GtkSheetRange old_range;
5213 draw_xor_rectangle(sheet, sheet->drag_range);
5214 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5215 gdk_pointer_ungrab (event->time);
5217 gtk_sheet_real_unselect_range(sheet, NULL);
5219 sheet->active_cell.row = sheet->active_cell.row +
5220 (sheet->drag_range.row0 - sheet->range.row0);
5221 sheet->active_cell.col = sheet->active_cell.col +
5222 (sheet->drag_range.col0 - sheet->range.col0);
5223 if(sheet->drag_range.row0 < sheet->range.row0)
5224 sheet->selection_cell.row = sheet->drag_range.row0;
5225 if(sheet->drag_range.rowi >= sheet->range.rowi)
5226 sheet->selection_cell.row = sheet->drag_range.rowi;
5227 if(sheet->drag_range.col0 < sheet->range.col0)
5228 sheet->selection_cell.col = sheet->drag_range.col0;
5229 if(sheet->drag_range.coli >= sheet->range.coli)
5230 sheet->selection_cell.col = sheet->drag_range.coli;
5231 old_range = sheet->range;
5232 sheet->range = sheet->drag_range;
5233 sheet->drag_range = old_range;
5235 if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5236 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5237 &sheet->drag_range, &sheet->range);
5238 gtk_sheet_select_range(sheet, &sheet->range);
5241 if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5242 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5243 gdk_pointer_ungrab (event->time);
5244 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5245 sheet->active_cell.col);
5248 if(GTK_SHEET_IN_SELECTION)
5249 gdk_pointer_ungrab (event->time);
5250 if(sheet->timer)
5251 gtk_timeout_remove(sheet->timer);
5252 gtk_grab_remove(GTK_WIDGET(sheet));
5254 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5256 return TRUE;
5259 static gint
5260 gtk_sheet_motion (GtkWidget * widget,
5261 GdkEventMotion * event)
5263 GtkSheet *sheet;
5264 GdkModifierType mods;
5265 GdkCursorType new_cursor;
5266 gint x, y, row, column;
5268 g_return_val_if_fail (widget != NULL, FALSE);
5269 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5270 g_return_val_if_fail (event != NULL, FALSE);
5273 sheet = GTK_SHEET (widget);
5276 /* selections on the sheet */
5277 x = event->x;
5278 y = event->y;
5280 if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
5281 gtk_widget_get_pointer(widget, &x, &y);
5282 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5283 new_cursor=GDK_SB_H_DOUBLE_ARROW;
5284 if(new_cursor != sheet->cursor_drag->type){
5285 gdk_cursor_destroy(sheet->cursor_drag);
5286 sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5287 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5289 }else{
5290 new_cursor=GDK_TOP_LEFT_ARROW;
5291 if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5292 gdk_cursor_destroy(sheet->cursor_drag);
5293 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5294 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5299 if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
5300 gtk_widget_get_pointer(widget, &x, &y);
5301 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5302 new_cursor=GDK_SB_V_DOUBLE_ARROW;
5303 if(new_cursor != sheet->cursor_drag->type){
5304 gdk_cursor_destroy(sheet->cursor_drag);
5305 sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5306 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5308 }else{
5309 new_cursor=GDK_TOP_LEFT_ARROW;
5310 if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5311 gdk_cursor_destroy(sheet->cursor_drag);
5312 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5313 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5318 new_cursor=GDK_PLUS;
5319 if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5320 !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5321 event->window == sheet->sheet_window &&
5322 new_cursor != sheet->cursor_drag->type){
5323 gdk_cursor_destroy(sheet->cursor_drag);
5324 sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5325 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5328 new_cursor=GDK_TOP_LEFT_ARROW;
5329 if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5330 (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) &&
5331 event->window == sheet->sheet_window &&
5332 new_cursor != sheet->cursor_drag->type){
5333 gdk_cursor_destroy(sheet->cursor_drag);
5334 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5335 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5338 new_cursor=GDK_SIZING;
5339 if(!GTK_SHEET_IN_DRAG(sheet) &&
5340 (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5341 event->window == sheet->sheet_window &&
5342 new_cursor != sheet->cursor_drag->type){
5343 gdk_cursor_destroy(sheet->cursor_drag);
5344 sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5345 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5348 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5349 if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5351 if (GTK_SHEET_IN_XDRAG (sheet)){
5352 if (event->is_hint || event->window != widget->window)
5353 gtk_widget_get_pointer (widget, &x, NULL);
5354 else
5355 x = event->x;
5357 new_column_width (sheet, sheet->drag_cell.col, &x);
5358 if (x != sheet->x_drag)
5360 draw_xor_vline (sheet);
5361 sheet->x_drag = x;
5362 draw_xor_vline (sheet);
5364 return TRUE;
5367 if (GTK_SHEET_IN_YDRAG (sheet)){
5368 if (event->is_hint || event->window != widget->window)
5369 gtk_widget_get_pointer (widget, NULL, &y);
5370 else
5371 y = event->y;
5373 new_row_height (sheet, sheet->drag_cell.row, &y);
5374 if (y != sheet->y_drag)
5376 draw_xor_hline (sheet);
5377 sheet->y_drag = y;
5378 draw_xor_hline (sheet);
5380 return TRUE;
5383 if (GTK_SHEET_IN_DRAG(sheet)){
5384 GtkSheetRange aux;
5385 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5386 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5387 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5388 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5389 sheet->x_drag=x;
5390 sheet->y_drag=y;
5391 aux=sheet->range;
5392 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5393 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5394 aux=sheet->drag_range;
5395 sheet->drag_range.row0=sheet->range.row0+row;
5396 sheet->drag_range.col0=sheet->range.col0+column;
5397 sheet->drag_range.rowi=sheet->range.rowi+row;
5398 sheet->drag_range.coli=sheet->range.coli+column;
5399 if(aux.row0 != sheet->drag_range.row0 ||
5400 aux.col0 != sheet->drag_range.col0){
5401 draw_xor_rectangle (sheet, aux);
5402 draw_xor_rectangle (sheet, sheet->drag_range);
5405 return TRUE;
5408 if (GTK_SHEET_IN_RESIZE(sheet)){
5409 GtkSheetRange aux;
5410 gint v_h;
5411 v_h=1;
5412 if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5413 abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5415 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5416 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5417 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5418 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5419 sheet->x_drag=x;
5420 sheet->y_drag=y;
5421 aux=sheet->range;
5423 if(row < sheet->range.row0 - sheet->range.rowi - 1)
5424 row=row+(sheet->range.rowi-sheet->range.row0 + 1);
5425 else if(row<0) row=0;
5427 if(column < sheet->range.col0 - sheet->range.coli - 1)
5428 column=column+(sheet->range.coli-sheet->range.col0 + 1);
5429 else if(column<0) column=0;
5431 if(v_h==1)
5432 column=0;
5433 else
5434 row=0;
5436 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5437 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5439 aux=sheet->drag_range;
5440 sheet->drag_range=sheet->range;
5442 if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5443 if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5444 if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5445 if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5447 if(aux.row0 != sheet->drag_range.row0 ||
5448 aux.rowi != sheet->drag_range.rowi ||
5449 aux.col0 != sheet->drag_range.col0 ||
5450 aux.coli != sheet->drag_range.coli){
5451 draw_xor_rectangle (sheet, aux);
5452 draw_xor_rectangle (sheet, sheet->drag_range);
5455 return TRUE;
5460 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5462 if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5463 column==sheet->active_cell.col) return TRUE;
5465 if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5466 gtk_sheet_extend_selection(sheet, row, column);
5468 return TRUE;
5471 static gint
5472 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5474 gint row_move, column_move;
5475 gfloat row_align, col_align;
5476 guint height, width;
5477 gint new_row = row;
5478 gint new_col = column;
5480 row_move=FALSE;
5481 column_move=FALSE;
5482 row_align=-1.;
5483 col_align=-1.;
5485 height = sheet->sheet_window_height;
5486 width = sheet->sheet_window_width;
5488 if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5489 row_align = 1.;
5490 new_row = MIN(sheet->maxrow, row + 1);
5491 row_move = TRUE;
5492 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow &&
5493 ROW_TOP_YPIXEL(sheet, sheet->maxrow) +
5494 sheet->row[sheet->maxrow].height < height){
5495 row_move = FALSE;
5496 row_align = -1.;
5499 if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5500 row_align= 0.;
5501 row_move = TRUE;
5503 if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5504 col_align = 1.;
5505 new_col = MIN(sheet->maxcol, column + 1);
5506 column_move = TRUE;
5507 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol &&
5508 COLUMN_LEFT_XPIXEL(sheet, sheet->maxcol) +
5509 sheet->column[sheet->maxcol].width < width){
5510 column_move = FALSE;
5511 col_align = -1.;
5514 if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5515 col_align = 0.;
5516 column_move = TRUE;
5519 if(row_move || column_move){
5520 gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5523 return(row_move || column_move);
5526 static void
5527 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5529 GtkSheetRange range;
5530 gint state;
5531 gint r,c;
5533 if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5534 return;
5536 if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5538 gtk_sheet_move_query(sheet, row, column);
5539 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5541 if(GTK_SHEET_IN_DRAG(sheet)) return;
5543 state=sheet->state;
5545 switch(sheet->state){
5546 case GTK_SHEET_ROW_SELECTED:
5547 column = sheet->maxcol;
5548 break;
5549 case GTK_SHEET_COLUMN_SELECTED:
5550 row = sheet->maxrow;
5551 break;
5552 case GTK_SHEET_NORMAL:
5553 sheet->state=GTK_SHEET_RANGE_SELECTED;
5554 r=sheet->active_cell.row;
5555 c=sheet->active_cell.col;
5556 sheet->range.col0=c;
5557 sheet->range.row0=r;
5558 sheet->range.coli=c;
5559 sheet->range.rowi=r;
5560 gdk_draw_pixmap(sheet->sheet_window,
5561 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5562 sheet->pixmap,
5563 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5564 ROW_TOP_YPIXEL(sheet,r)-1,
5565 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5566 ROW_TOP_YPIXEL(sheet,r)-1,
5567 sheet->column[c].width+4,
5568 sheet->row[r].height+4);
5569 gtk_sheet_range_draw_selection(sheet, sheet->range);
5570 case GTK_SHEET_RANGE_SELECTED:
5571 sheet->state=GTK_SHEET_RANGE_SELECTED;
5574 sheet->selection_cell.row = row;
5575 sheet->selection_cell.col = column;
5577 range.col0=MIN(column,sheet->active_cell.col);
5578 range.coli=MAX(column,sheet->active_cell.col);
5579 range.row0=MIN(row,sheet->active_cell.row);
5580 range.rowi=MAX(row,sheet->active_cell.row);
5582 if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5583 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5584 state==GTK_SHEET_NORMAL)
5585 gtk_sheet_real_select_range(sheet, &range);
5589 /* Removed by SDB while cleaning up key press behavior */
5590 #if 0
5591 static gint
5592 gtk_sheet_entry_key_press(GtkWidget *widget,
5593 GdkEventKey *key)
5595 gboolean focus;
5596 #ifdef DEBUG
5597 printf("Entered gtk_sheet_entry_key_press. . . . . \n");
5598 #endif
5600 gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5601 return focus;
5603 #endif
5605 static gint
5606 gtk_sheet_key_press(GtkWidget *widget,
5607 GdkEventKey *key)
5609 GtkSheet *sheet;
5610 gint row, col;
5611 gint state;
5612 gboolean extend_selection = FALSE;
5613 #if 0
5614 gboolean force_move = FALSE;
5615 #endif
5616 gboolean in_selection = FALSE;
5617 gboolean veto = TRUE;
5618 gint scroll = 1;
5620 sheet = GTK_SHEET(widget);
5622 #ifdef DEBUG
5623 printf("\n\nJust entered gtk_sheet_key_press. . . . \n");
5624 #endif
5627 if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5628 key->keyval==GDK_Control_R) return FALSE;
5632 if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5633 gtk_sheet_clip_range(sheet, sheet->range);
5634 if(key->keyval=='x' || key->keyval == 'X')
5635 gtk_sheet_unclip_range(sheet);
5636 return FALSE;
5640 /* extend_selection is set when shift, ctrl, etc is pressed & held down */
5641 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L
5642 || key->keyval==GDK_Shift_R;
5644 #ifdef DEBUG
5645 printf(". . . . extend_selection = %d\n", extend_selection);
5646 #endif
5648 state=sheet->state;
5649 in_selection = GTK_SHEET_IN_SELECTION(sheet);
5650 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5652 #ifdef DEBUG
5653 printf("We are about to enter the switch statement. . .\n");
5654 #endif
5656 switch(key->keyval){
5657 case GDK_Return: case GDK_KP_Enter:
5658 if(sheet->state == GTK_SHEET_NORMAL &&
5659 !GTK_SHEET_IN_SELECTION(sheet))
5660 gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
5661 "key_press_event");
5662 row = sheet->active_cell.row;
5663 col = sheet->active_cell.col;
5664 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5665 row = MIN_VISIBLE_ROW(sheet)-1;
5666 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5667 col = MIN_VISIBLE_COLUMN(sheet);
5668 if(row < sheet->maxrow){
5669 row = row + scroll;
5670 while(!sheet->row[row].is_visible && row<sheet->maxrow) row++;
5672 gtk_sheet_click_cell(sheet, row, col, &veto);
5673 extend_selection = FALSE;
5674 break;
5676 case GDK_ISO_Left_Tab:
5677 case GDK_Left: /* Left arrow */
5678 #ifdef DEBUG
5679 printf("In gtk_sheet_key_press, received GDK_Left.\n");
5680 #endif
5681 row = sheet->active_cell.row;
5682 col = sheet->active_cell.col;
5683 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5684 col = MIN_VISIBLE_COLUMN(sheet)-1;
5685 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5686 row = MIN_VISIBLE_ROW(sheet);
5687 if(col > 0){
5688 col = col - scroll;
5689 while(!sheet->column[col].is_visible && col>0) col--;
5690 col=MAX(0, col);
5692 gtk_sheet_click_cell(sheet, row, col, &veto);
5693 extend_selection = FALSE;
5694 break;
5696 case GDK_Tab:
5697 case GDK_Right: /* Right arrow */
5698 #ifdef DEBUG
5699 printf("In gtk_sheet_key_press, received GDK_Right.\n");
5700 #endif
5701 row = sheet->active_cell.row;
5702 col = sheet->active_cell.col;
5703 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5704 col = MIN_VISIBLE_COLUMN(sheet)-1;
5705 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5706 row = MIN_VISIBLE_ROW(sheet);
5707 if(col < sheet->maxcol){
5708 col = col + scroll;
5709 while(!sheet->column[col].is_visible && col<sheet->maxcol) col++;
5711 gtk_sheet_click_cell(sheet, row, col, &veto);
5712 extend_selection = FALSE;
5713 break;
5715 /* case GDK_BackSpace:
5716 if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5717 if(sheet->active_cell.col > 0){
5718 col = sheet->active_cell.col - scroll;
5719 row = sheet->active_cell.row;
5720 while(!sheet->column[col].is_visible && col > 0) col--;
5723 gtk_sheet_click_cell(sheet, row, col, &veto);
5724 extend_selection = FALSE;
5725 break;
5728 case GDK_Page_Up:
5729 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5730 case GDK_Up: /* arrow key up */
5731 if(extend_selection){
5732 if(state==GTK_STATE_NORMAL){
5733 row=sheet->active_cell.row;
5734 col=sheet->active_cell.col;
5735 gtk_sheet_click_cell(sheet, row, col, &veto);
5736 if(!veto) break;
5738 if(sheet->selection_cell.row > 0){
5739 row = sheet->selection_cell.row - scroll;
5740 while(!sheet->row[row].is_visible && row > 0) row--;
5741 row = MAX(0, row);
5742 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5744 return TRUE;
5746 col = sheet->active_cell.col;
5747 row = sheet->active_cell.row;
5748 if(state==GTK_SHEET_COLUMN_SELECTED)
5749 row = MIN_VISIBLE_ROW(sheet);
5750 if(state==GTK_SHEET_ROW_SELECTED)
5751 col = MIN_VISIBLE_COLUMN(sheet);
5752 row = row - scroll;
5753 while(!sheet->row[row].is_visible && row > 0) row--;
5754 row = MAX(0,row);
5755 gtk_sheet_click_cell(sheet, row, col, &veto);
5756 extend_selection = FALSE;
5757 break;
5759 case GDK_Page_Down:
5760 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5761 case GDK_Down: /* arrow key down */
5762 if(extend_selection){
5763 if(state==GTK_STATE_NORMAL){
5764 row=sheet->active_cell.row;
5765 col=sheet->active_cell.col;
5766 gtk_sheet_click_cell(sheet, row, col, &veto);
5767 if(!veto) break;
5769 if(sheet->selection_cell.row < sheet->maxrow){
5770 row = sheet->selection_cell.row + scroll;
5771 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5772 row = MIN(sheet->maxrow, row);
5773 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5775 return TRUE;
5777 col = sheet->active_cell.col;
5778 row = sheet->active_cell.row;
5779 if(sheet->active_cell.row < sheet->maxrow){
5780 if(state==GTK_SHEET_COLUMN_SELECTED)
5781 row = MIN_VISIBLE_ROW(sheet)-1;
5782 if(state==GTK_SHEET_ROW_SELECTED)
5783 col = MIN_VISIBLE_COLUMN(sheet);
5784 row = row + scroll;
5785 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5786 row = MIN(sheet->maxrow, row);
5788 gtk_sheet_click_cell(sheet, row, col, &veto);
5789 extend_selection = FALSE;
5790 break;
5792 #if 0
5793 case GDK_Right:
5794 if(extend_selection){
5795 if(state==GTK_STATE_NORMAL){
5796 row=sheet->active_cell.row;
5797 col=sheet->active_cell.col;
5798 gtk_sheet_click_cell(sheet, row, col, &veto);
5799 if(!veto) break;
5801 if(sheet->selection_cell.col < sheet->maxcol){
5802 col = sheet->selection_cell.col + 1;
5803 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5804 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5806 return TRUE;
5808 col = sheet->active_cell.col;
5809 row = sheet->active_cell.row;
5810 if(sheet->active_cell.col < sheet->maxcol){
5811 col ++;
5812 if(state==GTK_SHEET_ROW_SELECTED)
5813 col = MIN_VISIBLE_COLUMN(sheet)-1;
5814 if(state==GTK_SHEET_COLUMN_SELECTED)
5815 row = MIN_VISIBLE_ROW(sheet);
5816 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5817 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5818 || force_move) {
5819 gtk_sheet_click_cell(sheet, row, col, &veto);
5821 else
5822 return FALSE;
5824 extend_selection = FALSE;
5825 break;
5828 case GDK_Left:
5829 if(extend_selection){
5830 if(state==GTK_STATE_NORMAL){
5831 row=sheet->active_cell.row;
5832 col=sheet->active_cell.col;
5833 gtk_sheet_click_cell(sheet, row, col, &veto);
5834 if(!veto) break;
5836 if(sheet->selection_cell.col > 0){
5837 col = sheet->selection_cell.col - 1;
5838 while(!sheet->column[col].is_visible && col > 0) col--;
5839 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5841 return TRUE;
5843 col = sheet->active_cell.col - 1;
5844 row = sheet->active_cell.row;
5845 if(state==GTK_SHEET_ROW_SELECTED)
5846 col = MIN_VISIBLE_COLUMN(sheet)-1;
5847 if(state==GTK_SHEET_COLUMN_SELECTED)
5848 row = MIN_VISIBLE_ROW(sheet);
5849 while(!sheet->column[col].is_visible && col > 0) col--;
5850 col = MAX(0, col);
5852 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5853 || force_move){
5854 gtk_sheet_click_cell(sheet, row, col, &veto);
5856 else
5857 return FALSE;
5858 extend_selection = FALSE;
5859 break;
5860 #endif
5863 case GDK_Home:
5864 row=0;
5865 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5866 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5867 extend_selection = FALSE;
5868 break;
5870 case GDK_End:
5871 row=sheet->maxrow;
5872 while(!sheet->row[row].is_visible && row > 0) row--;
5873 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5874 extend_selection = FALSE;
5875 break;
5877 default:
5878 #ifdef DEBUG
5879 printf("In gtk_sheet_key_press, after switch, found default case.\n");
5880 printf(" User probably typed letter key or DEL.\n");
5881 #endif
5882 sheet_head->CHANGED = 1; /* cell has been updated. */
5883 if(in_selection) {
5884 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5885 if(extend_selection) return TRUE;
5887 if(state == GTK_SHEET_ROW_SELECTED)
5888 sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5889 if(state == GTK_SHEET_COLUMN_SELECTED)
5890 sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5891 return FALSE;
5892 } /* switch */
5894 if(extend_selection) return TRUE;
5896 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5897 sheet->active_cell.col);
5899 return TRUE;
5902 static void
5903 gtk_sheet_size_request (GtkWidget * widget,
5904 GtkRequisition * requisition)
5906 GtkSheet *sheet;
5907 GList *children;
5908 GtkSheetChild *child;
5909 GtkRequisition child_requisition;
5911 g_return_if_fail (widget != NULL);
5912 g_return_if_fail (GTK_IS_SHEET (widget));
5913 g_return_if_fail (requisition != NULL);
5915 sheet = GTK_SHEET (widget);
5917 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5918 requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5920 /* compute the size of the column title area */
5921 if(sheet->column_titles_visible)
5922 requisition->height += sheet->column_title_area.height;
5924 /* compute the size of the row title area */
5925 if(sheet->row_titles_visible)
5926 requisition->width += sheet->row_title_area.width;
5928 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5929 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5930 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5931 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5933 if(!sheet->column_titles_visible)
5934 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5936 if(!sheet->row_titles_visible)
5937 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5939 children = sheet->children;
5940 while (children)
5942 child = children->data;
5943 children = g_list_next(children);
5945 gtk_widget_size_request(child->widget, &child_requisition);
5950 static void
5951 gtk_sheet_size_allocate (GtkWidget * widget,
5952 GtkAllocation * allocation)
5954 GtkSheet *sheet;
5955 GtkAllocation sheet_allocation;
5956 gint border_width;
5958 g_return_if_fail (widget != NULL);
5959 g_return_if_fail (GTK_IS_SHEET (widget));
5960 g_return_if_fail (allocation != NULL);
5962 sheet = GTK_SHEET (widget);
5963 widget->allocation = *allocation;
5964 border_width = GTK_CONTAINER(widget)->border_width;
5966 if (GTK_WIDGET_REALIZED (widget))
5967 gdk_window_move_resize (widget->window,
5968 allocation->x + border_width,
5969 allocation->y + border_width,
5970 allocation->width - 2*border_width,
5971 allocation->height - 2*border_width);
5973 /* use internal allocation structure for all the math
5974 * because it's easier than always subtracting the container
5975 * border width */
5976 sheet->internal_allocation.x = 0;
5977 sheet->internal_allocation.y = 0;
5978 sheet->internal_allocation.width = allocation->width - 2*border_width;
5979 sheet->internal_allocation.height = allocation->height - 2*border_width;
5981 sheet_allocation.x = 0;
5982 sheet_allocation.y = 0;
5983 sheet_allocation.width = allocation->width - 2*border_width;
5984 sheet_allocation.height = allocation->height - 2*border_width;
5986 sheet->sheet_window_width = sheet_allocation.width;
5987 sheet->sheet_window_height = sheet_allocation.height;
5989 if (GTK_WIDGET_REALIZED (widget))
5990 gdk_window_move_resize (sheet->sheet_window,
5991 sheet_allocation.x,
5992 sheet_allocation.y,
5993 sheet_allocation.width,
5994 sheet_allocation.height);
5996 /* position the window which holds the column title buttons */
5997 sheet->column_title_area.x = 0;
5998 sheet->column_title_area.y = 0;
5999 if(sheet->row_titles_visible)
6000 sheet->column_title_area.x = sheet->row_title_area.width;
6001 sheet->column_title_area.width = sheet_allocation.width -
6002 sheet->column_title_area.x;
6003 if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
6004 gdk_window_move_resize (sheet->column_title_window,
6005 sheet->column_title_area.x,
6006 sheet->column_title_area.y,
6007 sheet->column_title_area.width,
6008 sheet->column_title_area.height);
6010 sheet->sheet_window_width = sheet_allocation.width;
6011 sheet->sheet_window_height = sheet_allocation.height;
6013 /* column button allocation */
6014 size_allocate_column_title_buttons (sheet);
6016 /* position the window which holds the row title buttons */
6017 sheet->row_title_area.x = 0;
6018 sheet->row_title_area.y = 0;
6019 if(sheet->column_titles_visible)
6020 sheet->row_title_area.y = sheet->column_title_area.height;
6021 sheet->row_title_area.height = sheet_allocation.height -
6022 sheet->row_title_area.y;
6024 if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
6025 gdk_window_move_resize (sheet->row_title_window,
6026 sheet->row_title_area.x,
6027 sheet->row_title_area.y,
6028 sheet->row_title_area.width,
6029 sheet->row_title_area.height);
6032 /* row button allocation */
6033 size_allocate_row_title_buttons (sheet);
6035 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6036 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6037 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6038 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6040 if(!sheet->column_titles_visible)
6041 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6043 if(!sheet->row_titles_visible)
6044 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6046 size_allocate_column_title_buttons(sheet);
6047 size_allocate_row_title_buttons(sheet);
6049 /* re-scale backing pixmap */
6050 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
6051 gtk_sheet_position_children(sheet);
6053 /* set the scrollbars adjustments */
6054 adjust_scrollbars (sheet);
6057 static void
6058 size_allocate_column_title_buttons (GtkSheet * sheet)
6060 gint i;
6061 gint x,width;
6063 if (!sheet->column_titles_visible) return;
6064 if (!GTK_WIDGET_REALIZED (sheet))
6065 return;
6067 width = sheet->sheet_window_width;
6068 x = 0;
6070 if(sheet->row_titles_visible)
6072 width -= sheet->row_title_area.width;
6073 x = sheet->row_title_area.width;
6076 if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6078 sheet->column_title_area.width = width;
6079 sheet->column_title_area.x = x;
6080 gdk_window_move_resize (sheet->column_title_window,
6081 sheet->column_title_area.x,
6082 sheet->column_title_area.y,
6083 sheet->column_title_area.width,
6084 sheet->column_title_area.height);
6088 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol)
6089 gdk_window_clear_area (sheet->column_title_window,
6090 0,0,
6091 sheet->column_title_area.width,
6092 sheet->column_title_area.height);
6094 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6096 for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
6097 gtk_sheet_button_draw(sheet,-1,i);
6100 static void
6101 size_allocate_row_title_buttons (GtkSheet * sheet)
6103 gint i;
6104 gint y, height;
6106 if (!sheet->row_titles_visible) return;
6107 if (!GTK_WIDGET_REALIZED (sheet))
6108 return;
6110 height = sheet->sheet_window_height;
6111 y = 0;
6113 if(sheet->column_titles_visible)
6115 height -= sheet->column_title_area.height;
6116 y = sheet->column_title_area.height;
6119 if(sheet->row_title_area.height != height || sheet->row_title_area.y != y){
6120 sheet->row_title_area.y = y;
6121 sheet->row_title_area.height = height;
6122 gdk_window_move_resize (sheet->row_title_window,
6123 sheet->row_title_area.x,
6124 sheet->row_title_area.y,
6125 sheet->row_title_area.width,
6126 sheet->row_title_area.height);
6128 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow)
6129 gdk_window_clear_area (sheet->row_title_window,
6130 0,0,
6131 sheet->row_title_area.width,
6132 sheet->row_title_area.height);
6134 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6136 for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6137 gtk_sheet_button_draw(sheet,i,-1);
6140 static void
6141 gtk_sheet_recalc_top_ypixels(GtkSheet *sheet, gint row)
6143 gint i, cy;
6145 cy = sheet->column_title_area.height;
6146 if(!sheet->column_titles_visible) cy = 0;
6147 for(i=0; i<=sheet->maxrow; i++){
6148 sheet->row[i].top_ypixel=cy;
6149 if(sheet->row[i].is_visible) cy+=sheet->row[i].height;
6153 static void
6154 gtk_sheet_recalc_left_xpixels(GtkSheet *sheet, gint column)
6156 gint i, cx;
6158 cx = sheet->row_title_area.width;
6159 if(!sheet->row_titles_visible) cx = 0;
6160 for(i=0; i<=sheet->maxcol; i++){
6161 sheet->column[i].left_xpixel=cx;
6162 if(sheet->column[i].is_visible) cx+=sheet->column[i].width;
6169 static void
6170 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6172 GtkAllocation shentry_allocation;
6173 GtkSheetCellAttr attributes;
6174 GtkEntry *sheet_entry;
6175 GtkStyle *style = NULL, *previous_style = NULL;
6176 gint row, col;
6177 gint size, max_size, text_size, column_width;
6178 const gchar *text;
6180 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6181 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6183 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6185 gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes);
6187 if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
6189 if(!GTK_WIDGET(sheet_entry)->style)
6190 gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6192 previous_style = GTK_WIDGET(sheet_entry)->style;
6194 style = gtk_style_copy(previous_style);
6195 style->bg[GTK_STATE_NORMAL] = attributes.background;
6196 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6197 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6198 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6199 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6200 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6202 pango_font_description_free(style->font_desc);
6203 style->font_desc = pango_font_description_copy(attributes.font_desc);
6205 GTK_WIDGET(sheet_entry)->style = style;
6206 gtk_widget_size_request(sheet->sheet_entry, NULL);
6207 GTK_WIDGET(sheet_entry)->style = previous_style;
6209 if(style != previous_style){
6210 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6211 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6212 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6213 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6214 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6216 gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6220 if(GTK_IS_ITEM_ENTRY(sheet_entry))
6221 max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
6222 else
6223 max_size = 0;
6225 text_size = 0;
6226 text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6227 if(text && strlen(text) > 0){
6228 text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6231 column_width=sheet->column[sheet->active_cell.col].width;
6233 size=MIN(text_size, max_size);
6234 size=MAX(size,column_width-2*CELLOFFSET);
6236 row=sheet->active_cell.row;
6237 col=sheet->active_cell.col;
6239 shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6240 shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6241 shentry_allocation.width = column_width;
6242 shentry_allocation.height = sheet->row[sheet->active_cell.row].height;
6244 if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6246 shentry_allocation.height -= 2*CELLOFFSET;
6247 shentry_allocation.y += CELLOFFSET;
6248 if(gtk_sheet_clip_text(sheet))
6249 shentry_allocation.width = column_width - 2*CELLOFFSET;
6250 else
6251 shentry_allocation.width = size;
6253 switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
6254 case GTK_JUSTIFY_CENTER:
6255 shentry_allocation.x += (column_width)/2 - size/2;
6256 break;
6257 case GTK_JUSTIFY_RIGHT:
6258 shentry_allocation.x += column_width - size - CELLOFFSET;
6259 break;
6260 case GTK_JUSTIFY_LEFT:
6261 case GTK_JUSTIFY_FILL:
6262 shentry_allocation.x += CELLOFFSET;
6263 break;
6268 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
6269 shentry_allocation.x += 2;
6270 shentry_allocation.y += 2;
6271 shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6272 shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6275 gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6277 if(previous_style == style) gtk_style_unref(previous_style);
6280 static void
6281 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
6283 gint i;
6284 gint size=0;
6285 gint sizel=0, sizer=0;
6286 gint row,col;
6287 GtkJustification justification;
6289 row=sheet->active_cell.row;
6290 col=sheet->active_cell.col;
6292 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || gtk_sheet_clip_text(sheet)) return;
6295 justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6297 switch(justification){
6298 case GTK_JUSTIFY_FILL:
6299 case GTK_JUSTIFY_LEFT:
6300 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6301 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6302 size+=sheet->column[i].width;
6304 size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6305 break;
6306 case GTK_JUSTIFY_RIGHT:
6307 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6308 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6309 size+=sheet->column[i].width;
6311 break;
6312 case GTK_JUSTIFY_CENTER:
6313 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6314 /* if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6316 sizer+=sheet->column[i].width;
6318 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6319 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6320 sizel+=sheet->column[i].width;
6322 size=2*MIN(sizel, sizer);
6323 break;
6326 if(size!=0) size+=sheet->column[col].width;
6327 GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size=size;
6331 static void
6332 create_sheet_entry(GtkSheet *sheet)
6334 GtkWidget *widget;
6335 GtkWidget *parent;
6336 GtkWidget *entry;
6337 GtkStyle *style;
6338 gint found_entry = FALSE;
6340 widget = GTK_WIDGET(sheet);
6342 style = gtk_style_copy(GTK_WIDGET(sheet)->style);
6344 if(sheet->sheet_entry){
6345 /* avoids warnings */
6346 gtk_widget_ref(sheet->sheet_entry);
6347 gtk_widget_unparent(sheet->sheet_entry);
6348 gtk_widget_destroy(sheet->sheet_entry);
6351 if(sheet->entry_type){
6353 if(!gtk_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6355 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6357 sheet->sheet_entry = parent;
6359 entry = gtk_sheet_get_entry (sheet);
6360 if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6362 } else {
6364 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6365 entry = parent;
6366 found_entry = TRUE;
6370 if(!found_entry){
6372 g_warning ("Entry type must be GtkEntry subclass, using default");
6373 entry = gtk_item_entry_new();
6374 sheet->sheet_entry = entry;
6376 } else {
6378 sheet->sheet_entry = parent;
6383 } else {
6385 entry = gtk_item_entry_new();
6386 sheet->sheet_entry = entry;
6390 gtk_widget_size_request(sheet->sheet_entry, NULL);
6392 if(GTK_WIDGET_REALIZED(sheet))
6394 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6395 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6396 gtk_widget_realize(sheet->sheet_entry);
6399 /* #if 0 */
6400 /* SDB says: I need to work out the event passing system */
6401 gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6402 (GtkSignalFunc) gtk_sheet_key_press,
6403 GTK_OBJECT(sheet));
6404 /* gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6405 (GtkSignalFunc) gtk_sheet_entry_key_press,
6406 GTK_OBJECT(sheet));
6408 /* #endif */
6410 gtk_widget_show (sheet->sheet_entry);
6414 GtkWidget *
6415 gtk_sheet_get_entry(GtkSheet *sheet)
6417 GtkWidget *parent;
6418 GtkWidget *entry = NULL;
6419 GtkTableChild *table_child;
6420 GtkBoxChild *box_child;
6421 GList *children = NULL;
6423 g_return_val_if_fail (sheet != NULL, NULL);
6424 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6425 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6427 if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6429 parent = GTK_WIDGET(sheet->sheet_entry);
6431 if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6432 if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6434 if(!children) return NULL;
6436 while(children){
6437 if(GTK_IS_TABLE(parent)) {
6438 table_child = children->data;
6439 entry = table_child->widget;
6441 if(GTK_IS_BOX(parent)){
6442 box_child = children->data;
6443 entry = box_child->widget;
6446 if(GTK_IS_ENTRY(entry))
6447 break;
6448 children = g_list_next(children);
6452 if(!GTK_IS_ENTRY(entry)) return NULL;
6454 return (entry);
6458 GtkWidget *
6459 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6461 g_return_val_if_fail (sheet != NULL, NULL);
6462 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6463 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6465 return (sheet->sheet_entry);
6468 /* BUTTONS */
6469 static void
6470 row_button_set (GtkSheet *sheet, gint row)
6472 if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6474 sheet->row[row].button.state = GTK_STATE_ACTIVE;
6475 gtk_sheet_button_draw(sheet, row, -1);
6479 static void
6480 column_button_set (GtkSheet *sheet, gint column)
6482 if(sheet->column[column].button.state == GTK_STATE_ACTIVE) return;
6484 sheet->column[column].button.state = GTK_STATE_ACTIVE;
6485 gtk_sheet_button_draw(sheet, -1, column);
6489 static void
6490 row_button_release (GtkSheet *sheet, gint row)
6492 if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6494 sheet->row[row].button.state = GTK_STATE_NORMAL;
6495 gtk_sheet_button_draw(sheet, row, -1);
6498 static void
6499 column_button_release (GtkSheet *sheet, gint column)
6501 if(sheet->column[column].button.state == GTK_STATE_NORMAL) return;
6503 sheet->column[column].button.state = GTK_STATE_NORMAL;
6504 gtk_sheet_button_draw(sheet, -1, column);
6507 static void
6508 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6510 GdkWindow *window = NULL;
6511 GtkShadowType shadow_type;
6512 guint width = 0, height = 0;
6513 gint x = 0, y = 0;
6514 gint index = 0;
6515 gint text_width = 0, text_height = 0;
6516 GtkSheetButton *button = NULL;
6517 GtkSheetChild *child = NULL;
6518 GdkRectangle allocation;
6519 gboolean is_sensitive = FALSE;
6520 gint state = 0;
6521 gint len = 0;
6522 gchar *line = 0;
6523 gchar *words = 0;
6524 gchar label[10];
6526 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6528 if(row >= 0 && !sheet->row[row].is_visible) return;
6529 if(column >= 0 && !sheet->column[column].is_visible) return;
6530 if(row >= 0 && !sheet->row_titles_visible) return;
6531 if(column >= 0 && !sheet->column_titles_visible) return;
6532 if(column>=0 && column <MIN_VISIBLE_COLUMN(sheet)) return;
6533 if(column>=0 && column >MAX_VISIBLE_COLUMN(sheet)) return;
6534 if(row>=0 && row <MIN_VISIBLE_ROW(sheet)) return;
6535 if(row>=0 && row >MAX_VISIBLE_ROW(sheet)) return;
6536 if( (row == -1) && (column == -1) ) return;
6538 if(row==-1){
6539 window=sheet->column_title_window;
6540 button=&sheet->column[column].button;
6541 index=column;
6542 x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6543 if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
6544 y = 0;
6545 width = sheet->column[column].width;
6546 height = sheet->column_title_area.height;
6547 is_sensitive=sheet->column[column].is_sensitive;
6549 else if(column==-1){
6550 window=sheet->row_title_window;
6551 button=&sheet->row[row].button;
6552 index=row;
6553 x = 0;
6554 y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6555 if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
6556 width = sheet->row_title_area.width;
6557 height = sheet->row[row].height;
6558 is_sensitive=sheet->row[row].is_sensitive;
6561 allocation.x = x;
6562 allocation.y = y;
6563 allocation.width = width;
6564 allocation.height = height;
6566 gdk_window_clear_area (window,
6567 x, y,
6568 width, height);
6570 gtk_paint_box (sheet->button->style, window,
6571 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6572 &allocation, GTK_WIDGET(sheet),
6573 "buttondefault", x, y, width, height);
6575 state = button->state;
6576 if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6578 if (state == GTK_STATE_ACTIVE)
6579 shadow_type = GTK_SHADOW_IN;
6580 else
6581 shadow_type = GTK_SHADOW_OUT;
6583 if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6584 gtk_paint_box (sheet->button->style, window,
6585 button->state, shadow_type,
6586 &allocation, GTK_WIDGET(sheet),
6587 "button", x, y, width, height);
6589 if(button->label_visible){
6591 text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6593 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6594 &allocation);
6595 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6597 y += DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))/2 + sheet->button->style->ythickness + DEFAULT_FONT_DESCENT(GTK_WIDGET(sheet));
6599 if(button->label && strlen(button->label)>0){
6601 words=button->label;
6602 line = g_new(gchar, 1);
6603 line[0]='\0';
6605 while(words && *words != '\0'){
6606 if(*words != '\n'){
6607 len=strlen(line);
6608 line=g_realloc(line, len+2);
6609 line[len]=*words;
6610 line[len+1]='\0';
6612 if(*words == '\n' || *(words+1) == '\0'){
6613 text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6615 switch(button->justification){
6616 case GTK_JUSTIFY_LEFT:
6617 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6618 &allocation, GTK_WIDGET(sheet), "label",
6619 x + CELLOFFSET, y,
6620 line);
6621 break;
6622 case GTK_JUSTIFY_RIGHT:
6623 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6624 &allocation, GTK_WIDGET(sheet), "label",
6625 x + width - text_width - CELLOFFSET, y,
6626 line);
6627 break;
6628 case GTK_JUSTIFY_CENTER:
6629 default:
6630 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6631 &allocation, GTK_WIDGET(sheet), "label",
6632 x + (width - text_width) /2, y,
6633 line);
6636 y += text_height + 2;
6638 g_free(line);
6639 line = g_new(gchar, 1);
6640 line[0]='\0';
6642 words++;
6644 g_free(line);
6645 }else{
6646 sprintf(label,"%d",index);
6647 text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, label);
6649 switch(button->justification){
6650 case GTK_JUSTIFY_LEFT:
6651 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6652 &allocation, GTK_WIDGET(sheet), "label",
6653 x + CELLOFFSET, y,
6654 label);
6655 break;
6656 case GTK_JUSTIFY_RIGHT:
6657 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6658 &allocation, GTK_WIDGET(sheet), "label",
6659 x + width - text_width - CELLOFFSET, y,
6660 label);
6661 break;
6662 case GTK_JUSTIFY_CENTER:
6663 default:
6664 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6665 &allocation, GTK_WIDGET(sheet), "label",
6666 x + (width - text_width) /2, y,
6667 label);
6672 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6673 NULL);
6674 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6678 if((child = button->child) && (child->widget)){
6679 child->x = allocation.x;
6680 child->y = allocation.y;
6682 child->x += (width - child->widget->requisition.width) / 2;
6683 child->y += (height - child->widget->requisition.height) / 2;
6684 allocation.x = child->x;
6685 allocation.y = child->y;
6686 allocation.width = child->widget->requisition.width;
6687 allocation.height = child->widget->requisition.height;
6689 x = child->x;
6690 y = child->y;
6692 gtk_widget_set_state(child->widget, button->state);
6694 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6695 GTK_WIDGET_MAPPED(child->widget))
6697 gtk_widget_size_allocate(child->widget,
6698 &allocation);
6699 gtk_widget_queue_draw(child->widget);
6706 /* SCROLLBARS
6708 * functions:
6709 * adjust_scrollbars
6710 * vadjustment_changed
6711 * hadjustment_changed
6712 * vadjustment_value_changed
6713 * hadjustment_value_changed */
6715 static void
6716 adjust_scrollbars (GtkSheet * sheet)
6719 if(sheet->vadjustment){
6720 sheet->vadjustment->page_size = sheet->sheet_window_height;
6721 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6722 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6723 sheet->vadjustment->lower = 0;
6724 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6726 if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6728 sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) -
6729 sheet->sheet_window_height);
6730 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
6731 "value_changed");
6734 gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6738 if(sheet->hadjustment){
6739 sheet->hadjustment->page_size = sheet->sheet_window_width;
6740 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6741 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6742 sheet->hadjustment->lower = 0;
6743 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6745 if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6747 sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) -
6748 sheet->sheet_window_width);
6749 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment),
6750 "value_changed");
6753 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6757 if(GTK_WIDGET_REALIZED(sheet))
6759 if(sheet->row_titles_visible){
6760 size_allocate_row_title_buttons(sheet);
6761 gdk_window_show(sheet->row_title_window);
6764 if(sheet->column_titles_visible){
6765 size_allocate_column_title_buttons(sheet);
6766 gdk_window_show(sheet->column_title_window);
6769 gtk_sheet_range_draw(sheet, NULL);
6775 static void
6776 vadjustment_changed (GtkAdjustment * adjustment,
6777 gpointer data)
6779 GtkSheet *sheet;
6781 g_return_if_fail (adjustment != NULL);
6782 g_return_if_fail (data != NULL);
6784 sheet = GTK_SHEET (data);
6788 static void
6789 hadjustment_changed (GtkAdjustment * adjustment,
6790 gpointer data)
6792 GtkSheet *sheet;
6794 g_return_if_fail (adjustment != NULL);
6795 g_return_if_fail (data != NULL);
6797 sheet = GTK_SHEET (data);
6802 static void
6803 vadjustment_value_changed (GtkAdjustment * adjustment,
6804 gpointer data)
6806 GtkSheet *sheet;
6807 gint diff, value, old_value;
6808 gint i;
6809 gint row, new_row;
6810 gint y=0;
6812 g_return_if_fail (adjustment != NULL);
6813 g_return_if_fail (data != NULL);
6814 g_return_if_fail (GTK_IS_SHEET (data));
6816 sheet = GTK_SHEET (data);
6818 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6820 row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6821 if(!sheet->column_titles_visible)
6822 row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6824 old_value = -sheet->voffset;
6826 for(i=0; i<= sheet->maxrow; i++){
6827 if(sheet->row[i].is_visible) y+=sheet->row[i].height;
6828 if(y > adjustment->value) break;
6830 y-=sheet->row[i].height;
6831 new_row=i;
6833 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6834 sheet->row[i].height > sheet->vadjustment->step_increment){
6835 /* This avoids embarrassing twitching */
6836 if(row == new_row && row != sheet->maxrow &&
6837 adjustment->value - sheet->old_vadjustment >=
6838 sheet->vadjustment->step_increment &&
6839 new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6840 new_row+=1;
6841 y=y+sheet->row[row].height;
6845 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6846 if(sheet->old_vadjustment >= 0. && row == new_row){
6847 sheet->old_vadjustment = sheet->vadjustment->value;
6848 return;
6851 sheet->old_vadjustment = sheet->vadjustment->value;
6852 adjustment->value=y;
6855 if(new_row == 0){
6856 sheet->vadjustment->step_increment=
6857 sheet->row[0].height;
6858 }else{
6859 sheet->vadjustment->step_increment=
6860 MIN(sheet->row[new_row].height, sheet->row[new_row-1].height);
6863 sheet->vadjustment->value=adjustment->value;
6865 value = adjustment->value;
6867 if (value >= -sheet->voffset)
6869 /* scroll down */
6870 diff = value + sheet->voffset;
6872 else
6874 /* scroll up */
6875 diff = -sheet->voffset - value;
6878 sheet->voffset = -value;
6880 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6881 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6882 if(!sheet->column_titles_visible)
6883 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6885 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6886 sheet->state == GTK_SHEET_NORMAL &&
6887 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6888 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6889 sheet->active_cell.col))
6891 const gchar *text;
6893 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6895 if(!text || strlen(text)==0)
6896 gtk_sheet_cell_clear(sheet,
6897 sheet->active_cell.row,
6898 sheet->active_cell.col);
6899 gtk_widget_unmap(sheet->sheet_entry);
6902 gtk_sheet_position_children(sheet);
6904 gtk_sheet_range_draw(sheet, NULL);
6905 size_allocate_row_title_buttons(sheet);
6906 size_allocate_global_button(sheet);
6909 static void
6910 hadjustment_value_changed (GtkAdjustment * adjustment,
6911 gpointer data)
6913 GtkSheet *sheet;
6914 gint i, diff, value, old_value;
6915 gint column, new_column;
6916 gint x=0;
6918 g_return_if_fail (adjustment != NULL);
6919 g_return_if_fail (data != NULL);
6920 g_return_if_fail (GTK_IS_SHEET (data));
6922 sheet = GTK_SHEET (data);
6924 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6926 column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6927 if(!sheet->row_titles_visible)
6928 column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6930 old_value = -sheet->hoffset;
6932 for(i=0; i<= sheet->maxcol; i++){
6933 if(sheet->column[i].is_visible) x+=sheet->column[i].width;
6934 if(x > adjustment->value) break;
6936 x-=sheet->column[i].width;
6937 new_column=i;
6939 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6940 sheet->column[i].width > sheet->hadjustment->step_increment){
6941 /* This avoids embarrassing twitching */
6942 if(column == new_column && column != sheet->maxcol &&
6943 adjustment->value - sheet->old_hadjustment >=
6944 sheet->hadjustment->step_increment &&
6945 new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6946 new_column+=1;
6947 x=x+sheet->column[column].width;
6951 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6952 if(sheet->old_hadjustment >= 0. && new_column == column){
6953 sheet->old_hadjustment = sheet->hadjustment->value;
6954 return;
6957 sheet->old_hadjustment = sheet->hadjustment->value;
6958 adjustment->value=x;
6960 if(new_column == 0){
6961 sheet->hadjustment->step_increment=
6962 sheet->column[0].width;
6963 }else{
6964 sheet->hadjustment->step_increment=
6965 MIN(sheet->column[new_column].width, sheet->column[new_column-1].width);
6969 sheet->hadjustment->value=adjustment->value;
6971 value = adjustment->value;
6973 if (value >= -sheet->hoffset)
6975 /* scroll right */
6976 diff = value + sheet->hoffset;
6978 else
6980 /* scroll left */
6981 diff = -sheet->hoffset - value;
6984 sheet->hoffset = -value;
6986 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6987 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6988 if(!sheet->row_titles_visible)
6989 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6991 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6992 sheet->state == GTK_SHEET_NORMAL &&
6993 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6994 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6995 sheet->active_cell.col))
6997 const gchar *text;
6999 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
7000 if(!text || strlen(text)==0)
7001 gtk_sheet_cell_clear(sheet,
7002 sheet->active_cell.row,
7003 sheet->active_cell.col);
7005 gtk_widget_unmap(sheet->sheet_entry);
7008 gtk_sheet_position_children(sheet);
7010 gtk_sheet_range_draw(sheet, NULL);
7011 size_allocate_column_title_buttons(sheet);
7015 /* COLUMN RESIZING */
7016 static void
7017 draw_xor_vline (GtkSheet * sheet)
7019 GtkWidget *widget;
7021 g_return_if_fail (sheet != NULL);
7023 widget = GTK_WIDGET (sheet);
7025 gdk_draw_line (widget->window, sheet->xor_gc,
7026 sheet->x_drag,
7027 sheet->column_title_area.height,
7028 sheet->x_drag,
7029 sheet->sheet_window_height + 1);
7032 /* ROW RESIZING */
7033 static void
7034 draw_xor_hline (GtkSheet * sheet)
7036 GtkWidget *widget;
7038 g_return_if_fail (sheet != NULL);
7040 widget = GTK_WIDGET (sheet);
7042 gdk_draw_line (widget->window, sheet->xor_gc,
7043 sheet->row_title_area.width,
7044 sheet->y_drag,
7046 sheet->sheet_window_width + 1,
7047 sheet->y_drag);
7050 /* SELECTED RANGE */
7051 static void
7052 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
7054 gint i;
7055 GdkRectangle clip_area, area;
7056 GdkGCValues values;
7058 area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
7059 area.y=ROW_TOP_YPIXEL(sheet, range.row0);
7060 area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
7061 sheet->column[range.coli].width;
7062 area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
7063 sheet->row[range.rowi].height;
7065 clip_area.x=sheet->row_title_area.width;
7066 clip_area.y=sheet->column_title_area.height;
7067 clip_area.width=sheet->sheet_window_width;
7068 clip_area.height=sheet->sheet_window_height;
7070 if(!sheet->row_titles_visible) clip_area.x = 0;
7071 if(!sheet->column_titles_visible) clip_area.y = 0;
7073 if(area.x<0) {
7074 area.width=area.width+area.x;
7075 area.x=0;
7077 if(area.width>clip_area.width) area.width=clip_area.width+10;
7078 if(area.y<0) {
7079 area.height=area.height+area.y;
7080 area.y=0;
7082 if(area.height>clip_area.height) area.height=clip_area.height+10;
7084 clip_area.x--;
7085 clip_area.y--;
7086 clip_area.width+=3;
7087 clip_area.height+=3;
7089 gdk_gc_get_values(sheet->xor_gc, &values);
7091 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
7093 for(i=-1;i<=1;i++)
7094 gdk_draw_rectangle(sheet->sheet_window,
7095 sheet->xor_gc,
7096 FALSE,
7097 area.x+i, area.y+i,
7098 area.width-2*i, area.height-2*i);
7101 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
7103 gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
7108 /* this function returns the new width of the column being resized given
7109 * the column and x position of the cursor; the x cursor position is passed
7110 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7111 static guint
7112 new_column_width (GtkSheet * sheet,
7113 gint column,
7114 gint * x)
7116 gint cx, width;
7117 GtkRequisition requisition;
7119 cx = *x;
7121 requisition.width = sheet->column[column].requisition;
7123 /* you can't shrink a column to less than its minimum width */
7124 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width)
7126 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width;
7129 /* don't grow past the end of the window */
7131 if (cx > sheet->sheet_window_width)
7133 *x = cx = sheet->sheet_window_width;
7136 /* calculate new column width making sure it doesn't end up
7137 * less than the minimum width */
7138 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7139 if (width < requisition.width)
7140 width = requisition.width;
7142 sheet->column[column].width = width;
7143 gtk_sheet_recalc_left_xpixels(sheet, column+1);
7144 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7145 size_allocate_column_title_buttons (sheet);
7147 return width;
7150 /* this function returns the new height of the row being resized given
7151 * the row and y position of the cursor; the y cursor position is passed
7152 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7153 static guint
7154 new_row_height (GtkSheet * sheet,
7155 gint row,
7156 gint * y)
7158 GtkRequisition requisition;
7159 gint cy, height;
7161 cy = *y;
7163 requisition.height = sheet->row[row].requisition;
7165 /* you can't shrink a row to less than its minimum height */
7166 if (cy < ROW_TOP_YPIXEL (sheet, row) + requisition.height)
7169 *y = cy = ROW_TOP_YPIXEL (sheet, row) + requisition.height;
7172 /* don't grow past the end of the window */
7174 if (cy > sheet->sheet_window_height)
7176 *y = cy = sheet->sheet_window_height;
7179 /* calculate new row height making sure it doesn't end up
7180 * less than the minimum height */
7181 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7182 if (height < requisition.height)
7183 height = requisition.height;
7185 sheet->row[row].height = height;
7186 gtk_sheet_recalc_top_ypixels(sheet, row);
7187 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7188 size_allocate_row_title_buttons (sheet);
7190 return height;
7193 void
7194 gtk_sheet_set_column_width (GtkSheet * sheet,
7195 gint column,
7196 guint width)
7198 guint min_width;
7200 g_return_if_fail (sheet != NULL);
7201 g_return_if_fail (GTK_IS_SHEET (sheet));
7203 if (column < 0 || column > sheet->maxcol)
7204 return;
7206 gtk_sheet_column_size_request(sheet, column, &min_width);
7207 if(width < min_width) return;
7209 sheet->column[column].width = width;
7211 gtk_sheet_recalc_left_xpixels(sheet, column+1);
7213 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7214 size_allocate_column_title_buttons (sheet);
7215 adjust_scrollbars (sheet);
7216 gtk_sheet_size_allocate_entry(sheet);
7217 gtk_sheet_range_draw (sheet, NULL);
7218 } else
7220 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7221 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
7225 void
7226 gtk_sheet_set_row_height (GtkSheet * sheet,
7227 gint row,
7228 guint height)
7230 guint min_height;
7232 g_return_if_fail (sheet != NULL);
7233 g_return_if_fail (GTK_IS_SHEET (sheet));
7235 if (row < 0 || row > sheet->maxrow)
7236 return;
7238 gtk_sheet_row_size_request(sheet, row, &min_height);
7239 if(height < min_height) return;
7241 sheet->row[row].height = height;
7243 gtk_sheet_recalc_top_ypixels(sheet, row+1);
7245 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7246 size_allocate_row_title_buttons (sheet);
7247 adjust_scrollbars (sheet);
7248 gtk_sheet_size_allocate_entry(sheet);
7249 gtk_sheet_range_draw (sheet, NULL);
7252 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7253 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7258 void
7259 gtk_sheet_add_column(GtkSheet *sheet, guint ncols)
7262 g_return_if_fail (sheet != NULL);
7263 g_return_if_fail (GTK_IS_SHEET (sheet));
7265 AddColumn(sheet, ncols);
7267 if(!GTK_WIDGET_REALIZED(sheet)) return;
7269 adjust_scrollbars(sheet);
7271 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7273 sheet->old_hadjustment = -1.;
7274 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7275 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7276 "value_changed");
7279 void
7280 gtk_sheet_add_row(GtkSheet *sheet, guint nrows)
7283 g_return_if_fail (sheet != NULL);
7284 g_return_if_fail (GTK_IS_SHEET (sheet));
7286 AddRow(sheet, nrows);
7288 if(!GTK_WIDGET_REALIZED(sheet)) return;
7290 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7292 adjust_scrollbars(sheet);
7294 sheet->old_vadjustment = -1.;
7295 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7296 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7297 "value_changed");
7300 void
7301 gtk_sheet_insert_rows(GtkSheet *sheet, guint row, guint nrows)
7303 GList *children;
7304 GtkSheetChild *child;
7306 g_return_if_fail (sheet != NULL);
7307 g_return_if_fail (GTK_IS_SHEET (sheet));
7309 if(GTK_WIDGET_REALIZED(sheet))
7310 gtk_sheet_real_unselect_range(sheet, NULL);
7312 InsertRow(sheet, row, nrows);
7314 children = sheet->children;
7315 while(children)
7317 child = (GtkSheetChild *)children->data;
7319 if(child->attached_to_cell)
7320 if(child->row >= row) child->row += nrows;
7322 children = g_list_next(children);
7325 if(!GTK_WIDGET_REALIZED(sheet)) return;
7327 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7328 adjust_scrollbars(sheet);
7330 sheet->old_vadjustment = -1.;
7331 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7332 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7333 "value_changed");
7337 void
7338 gtk_sheet_insert_columns(GtkSheet *sheet, guint col, guint ncols)
7340 GList *children;
7341 GtkSheetChild *child;
7343 g_return_if_fail (sheet != NULL);
7344 g_return_if_fail (GTK_IS_SHEET (sheet));
7346 if(GTK_WIDGET_REALIZED(sheet))
7347 gtk_sheet_real_unselect_range(sheet, NULL);
7349 InsertColumn(sheet, col, ncols);
7351 children = sheet->children;
7352 while(children)
7354 child = (GtkSheetChild *)children->data;
7356 if(child->attached_to_cell)
7357 if(child->col >= col) child->col += ncols;
7359 children = g_list_next(children);
7362 if(!GTK_WIDGET_REALIZED(sheet)) return;
7364 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7365 adjust_scrollbars(sheet);
7367 sheet->old_hadjustment = -1.;
7368 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7369 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7370 "value_changed");
7374 void
7375 gtk_sheet_delete_rows(GtkSheet *sheet, guint row, guint nrows)
7377 GList *children;
7378 GtkSheetChild *child;
7379 gint irow, icol;
7380 gboolean veto;
7382 g_return_if_fail (sheet != NULL);
7383 g_return_if_fail (GTK_IS_SHEET (sheet));
7385 nrows = MIN(nrows, sheet->maxrow-row+1);
7387 if(GTK_WIDGET_REALIZED(sheet))
7388 gtk_sheet_real_unselect_range(sheet, NULL);
7390 DeleteRow(sheet, row, nrows);
7392 children = sheet->children;
7393 while(children)
7395 child = (GtkSheetChild *)children->data;
7397 if(child->attached_to_cell &&
7398 child->row >= row && child->row < row+nrows){
7399 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7400 children = sheet->children;
7401 } else
7402 children = g_list_next(children);
7405 children = sheet->children;
7406 while(children)
7408 child = (GtkSheetChild *)children->data;
7410 if(child->attached_to_cell && child->row > row) child->row -= nrows;
7411 children = g_list_next(children);
7414 if(!GTK_WIDGET_REALIZED(sheet)) return;
7416 irow = sheet->active_cell.row;
7417 icol = sheet->active_cell.col;
7419 sheet->active_cell.row = -1;
7420 sheet->active_cell.col = -1;
7422 /* if(sheet->state == GTK_SHEET_ROW_SELECTED)
7425 irow = MIN(irow, sheet->maxrow);
7426 irow = MAX(irow, 0);
7427 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7429 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7430 sheet->active_cell.col);
7432 adjust_scrollbars(sheet);
7434 sheet->old_vadjustment = -1.;
7435 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7436 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7437 "value_changed");
7441 void
7442 gtk_sheet_delete_columns(GtkSheet *sheet, guint col, guint ncols)
7444 GList *children;
7445 GtkSheetChild *child;
7446 gint irow, icol;
7447 gboolean veto;
7449 g_return_if_fail (sheet != NULL);
7450 g_return_if_fail (GTK_IS_SHEET (sheet));
7452 ncols = MIN(ncols, sheet->maxcol-col+1);
7454 if(GTK_WIDGET_REALIZED(sheet))
7455 gtk_sheet_real_unselect_range(sheet, NULL);
7457 DeleteColumn(sheet, col, ncols);
7459 children = sheet->children;
7460 while(children)
7462 child = (GtkSheetChild *)children->data;
7464 if(child->attached_to_cell &&
7465 child->col >= col && child->col < col+ncols){
7466 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7467 children = sheet->children;
7468 } else
7469 children = g_list_next(children);
7472 children = sheet->children;
7473 while(children)
7475 child = (GtkSheetChild *)children->data;
7477 if(child->attached_to_cell && child->col > col) child->col -= ncols;
7478 children = g_list_next(children);
7481 if(!GTK_WIDGET_REALIZED(sheet)) return;
7483 irow = sheet->active_cell.row;
7484 icol = sheet->active_cell.col;
7486 sheet->active_cell.row = -1;
7487 sheet->active_cell.col = -1;
7489 /* if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
7492 icol = MIN(icol, sheet->maxcol);
7493 icol = MAX(icol, 0);
7494 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7496 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7497 sheet->active_cell.col);
7499 adjust_scrollbars(sheet);
7501 sheet->old_hadjustment = -1.;
7502 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7503 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7504 "value_changed");
7508 void
7509 gtk_sheet_range_set_background(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7511 gint i, j;
7512 GtkSheetCellAttr attributes;
7513 GtkSheetRange range;
7515 g_return_if_fail (sheet != NULL);
7516 g_return_if_fail (GTK_IS_SHEET (sheet));
7518 if(!urange)
7519 range = sheet->range;
7520 else
7521 range = *urange;
7523 for (i=range.row0; i<=range.rowi; i++)
7524 for (j=range.col0; j<=range.coli; j++){
7525 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7526 if(color != NULL)
7527 attributes.background = *color;
7528 else
7529 attributes.background = sheet->bg_color;
7531 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7534 range.row0--;
7535 range.col0--;
7536 range.rowi++;
7537 range.coli++;
7539 if(!GTK_SHEET_IS_FROZEN(sheet))
7540 gtk_sheet_range_draw(sheet, &range);
7544 void
7545 gtk_sheet_range_set_foreground(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7547 gint i, j;
7548 GtkSheetCellAttr attributes;
7549 GtkSheetRange range;
7551 g_return_if_fail (sheet != NULL);
7552 g_return_if_fail (GTK_IS_SHEET (sheet));
7554 if(!urange)
7555 range = sheet->range;
7556 else
7557 range = *urange;
7559 for (i=range.row0; i<=range.rowi; i++)
7560 for (j=range.col0; j<=range.coli; j++){
7561 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7563 if(color != NULL)
7564 attributes.foreground = *color;
7565 else
7566 gdk_color_black(gdk_colormap_get_system(), &attributes.foreground);
7568 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7571 if(!GTK_SHEET_IS_FROZEN(sheet))
7572 gtk_sheet_range_draw(sheet, &range);
7576 void
7577 gtk_sheet_range_set_justification(GtkSheet *sheet, const GtkSheetRange *urange,
7578 GtkJustification just)
7580 gint i, j;
7581 GtkSheetCellAttr attributes;
7582 GtkSheetRange range;
7584 g_return_if_fail (sheet != NULL);
7585 g_return_if_fail (GTK_IS_SHEET (sheet));
7587 if(!urange)
7588 range = sheet->range;
7589 else
7590 range = *urange;
7592 for (i=range.row0; i<=range.rowi; i++)
7593 for (j=range.col0; j<=range.coli; j++){
7594 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7595 attributes.justification = just;
7596 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7599 range.col0 = sheet->view.col0;
7600 range.coli = sheet->view.coli;
7602 if(!GTK_SHEET_IS_FROZEN(sheet))
7603 gtk_sheet_range_draw(sheet, &range);
7607 void
7608 gtk_sheet_column_set_justification(GtkSheet *sheet, gint col,
7609 GtkJustification justification)
7611 g_return_if_fail (sheet != NULL);
7612 g_return_if_fail (GTK_IS_SHEET (sheet));
7614 if(col > sheet->maxcol) return;
7616 sheet->column[col].justification = justification;
7618 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet) &&
7619 col >= MIN_VISIBLE_COLUMN(sheet) && col <= MAX_VISIBLE_COLUMN(sheet))
7620 gtk_sheet_range_draw(sheet, NULL);
7624 void
7625 gtk_sheet_range_set_editable(GtkSheet *sheet, const GtkSheetRange *urange, gboolean editable)
7627 gint i, j;
7628 GtkSheetCellAttr attributes;
7629 GtkSheetRange range;
7631 g_return_if_fail (sheet != NULL);
7632 g_return_if_fail (GTK_IS_SHEET (sheet));
7634 if(!urange)
7635 range = sheet->range;
7636 else
7637 range = *urange;
7639 for (i=range.row0; i<=range.rowi; i++)
7640 for (j=range.col0; j<=range.coli; j++){
7641 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7642 attributes.is_editable = editable;
7643 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7646 if(!GTK_SHEET_IS_FROZEN(sheet))
7647 gtk_sheet_range_draw(sheet, &range);
7651 void
7652 gtk_sheet_range_set_visible(GtkSheet *sheet, const GtkSheetRange *urange, gboolean visible)
7654 gint i, j;
7655 GtkSheetCellAttr attributes;
7656 GtkSheetRange range;
7658 g_return_if_fail (sheet != NULL);
7659 g_return_if_fail (GTK_IS_SHEET (sheet));
7661 if(!urange)
7662 range = sheet->range;
7663 else
7664 range = *urange;
7666 for (i=range.row0; i<=range.rowi; i++)
7667 for (j=range.col0; j<=range.coli; j++){
7668 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7669 attributes.is_visible=visible;
7670 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7673 if(!GTK_SHEET_IS_FROZEN(sheet))
7674 gtk_sheet_range_draw(sheet, &range);
7678 void
7679 gtk_sheet_range_set_border(GtkSheet *sheet, const GtkSheetRange *urange, gint mask,
7680 guint width, gint line_style)
7682 gint i, j;
7683 GtkSheetCellAttr attributes;
7684 GtkSheetRange range;
7686 g_return_if_fail (sheet != NULL);
7687 g_return_if_fail (GTK_IS_SHEET (sheet));
7689 if(!urange)
7690 range = sheet->range;
7691 else
7692 range = *urange;
7694 for (i=range.row0; i<=range.rowi; i++)
7695 for (j=range.col0; j<=range.coli; j++){
7696 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7697 attributes.border.mask = mask;
7698 attributes.border.width = width;
7699 attributes.border.line_style=line_style;
7700 attributes.border.cap_style=GDK_CAP_NOT_LAST;
7701 attributes.border.join_style=GDK_JOIN_MITER;
7702 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7705 range.row0--;
7706 range.col0--;
7707 range.rowi++;
7708 range.coli++;
7710 if(!GTK_SHEET_IS_FROZEN(sheet))
7711 gtk_sheet_range_draw(sheet, &range);
7715 void
7716 gtk_sheet_range_set_border_color(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7718 gint i, j;
7719 GtkSheetCellAttr attributes;
7720 GtkSheetRange range;
7722 g_return_if_fail (sheet != NULL);
7723 g_return_if_fail (GTK_IS_SHEET (sheet));
7725 if(!urange)
7726 range = sheet->range;
7727 else
7728 range = *urange;
7730 for (i=range.row0; i<=range.rowi; i++)
7731 for (j=range.col0; j<=range.coli; j++){
7732 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7733 attributes.border.color = *color;
7734 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7737 if(!GTK_SHEET_IS_FROZEN(sheet))
7738 gtk_sheet_range_draw(sheet, &range);
7742 void
7743 gtk_sheet_range_set_font(GtkSheet *sheet, const GtkSheetRange *urange, PangoFontDescription *font)
7745 gint i, j;
7746 gint font_height;
7747 GtkSheetCellAttr attributes;
7748 GtkSheetRange range;
7749 PangoContext *context;
7750 PangoFontMetrics *metrics;
7752 g_return_if_fail (sheet != NULL);
7753 g_return_if_fail (GTK_IS_SHEET (sheet));
7755 if(!urange)
7756 range = sheet->range;
7757 else
7758 range = *urange;
7760 gtk_sheet_freeze(sheet);
7762 context = gtk_widget_get_pango_context(GTK_WIDGET(sheet));
7763 metrics = pango_context_get_metrics(context,
7764 font,
7765 pango_context_get_language(context));
7766 font_height = pango_font_metrics_get_descent(metrics) +
7767 pango_font_metrics_get_ascent(metrics);
7768 font_height = PANGO_PIXELS(font_height) + 2*CELLOFFSET;
7770 for (i=range.row0; i<=range.rowi; i++)
7771 for (j=range.col0; j<=range.coli; j++){
7772 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7773 attributes.font_desc = font;
7774 if(font_height > sheet->row[i].height){
7775 sheet->row[i].height = font_height;
7776 gtk_sheet_recalc_top_ypixels(sheet, i);
7779 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7782 gtk_sheet_thaw(sheet);
7783 pango_font_metrics_unref(metrics);
7786 static void
7787 gtk_sheet_set_cell_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr attributes)
7789 GtkSheetCell **cell;
7791 if(row > sheet->maxrow || col >sheet->maxcol) return;
7793 CheckBounds(sheet, row, col);
7795 cell = &sheet->data[row][col];
7797 if(*cell==NULL){
7798 (*cell) = gtk_sheet_cell_new();
7799 (*cell)->row = row;
7800 (*cell)->col = col;
7803 if((*cell)->attributes == NULL)
7804 (*cell)->attributes = g_new(GtkSheetCellAttr, 1);
7806 *((*cell)->attributes) = attributes;
7809 gboolean
7810 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7812 GtkSheetCell **cell = NULL;
7814 g_return_val_if_fail (sheet != NULL, FALSE);
7815 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7817 if(row < 0 || col < 0) return FALSE;
7819 if(row > sheet->maxallocrow || col > sheet->maxalloccol){
7820 init_attributes(sheet, col, attributes);
7821 return FALSE;
7824 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol){
7825 if(sheet->data[row] && sheet->data[row][col])
7826 cell = &sheet->data[row][col];
7827 if(cell == NULL || *cell == NULL){
7828 init_attributes(sheet, col, attributes);
7829 return FALSE;
7830 } else
7831 if((*cell)->attributes == NULL){
7832 init_attributes(sheet, col, attributes);
7833 return FALSE;
7834 }else{
7835 *attributes = *(sheet->data[row][col]->attributes);
7836 if(sheet->column[col].justification != GTK_JUSTIFY_FILL)
7837 attributes->justification = sheet->column[col].justification;
7841 return TRUE;
7844 static void
7845 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7847 /* DEFAULT VALUES */
7848 attributes->foreground = GTK_WIDGET(sheet)->style->black;
7849 attributes->background = sheet->bg_color;
7850 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7851 GdkColormap *colormap;
7852 colormap=gdk_colormap_get_system();
7853 gdk_color_black(colormap, &attributes->foreground);
7854 attributes->background = sheet->bg_color;
7856 attributes->justification = sheet->column[col].justification;
7857 attributes->border.width = 0;
7858 attributes->border.line_style = GDK_LINE_SOLID;
7859 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7860 attributes->border.join_style = GDK_JOIN_MITER;
7861 attributes->border.mask = 0;
7862 attributes->border.color = GTK_WIDGET(sheet)->style->black;
7863 attributes->is_editable = TRUE;
7864 attributes->is_visible = TRUE;
7865 attributes->font = GTK_WIDGET(sheet)->style->private_font;
7866 attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7870 /**********************************************************************
7871 * Memory allocation routines:
7872 * AddRow & AddColumn allocate memory for GtkSheetColumn & GtkSheetRow structs.
7873 * InsertRow
7874 * InsertColumn
7875 * DeleteRow
7876 * DeleteColumn
7877 * GrowSheet allocates memory for the sheet cells contents using an array of
7878 * pointers. Alternative to this could be a linked list or a hash table.
7879 * CheckBounds checks whether the given cell is currently allocated or not.
7880 * If not, it calls to GrowSheet.
7881 **********************************************************************/
7883 static gint
7884 AddColumn(GtkSheet *tbl, gint ncols)
7886 gint i;
7888 if(ncols == -1 && tbl->maxcol == 0)
7890 ncols = 1;
7892 else
7894 tbl->maxcol += ncols;
7895 tbl->column = (GtkSheetColumn *)g_realloc(tbl->column,(tbl->maxcol+1)*
7896 sizeof(GtkSheetColumn));
7899 for(i=tbl->maxcol-ncols+1; i<= tbl->maxcol; i++){
7900 tbl->column[i].width=DEFAULT_COLUMN_WIDTH;
7901 tbl->column[i].button.label=NULL;
7902 tbl->column[i].button.child=NULL;
7903 tbl->column[i].button.state=GTK_STATE_NORMAL;
7904 tbl->column[i].button.justification=GTK_JUSTIFY_CENTER;
7905 tbl->column[i].button.label_visible = TRUE;
7906 tbl->column[i].name=NULL;
7907 tbl->column[i].is_visible=TRUE;
7908 tbl->column[i].is_sensitive=TRUE;
7909 tbl->column[i].left_text_column=i;
7910 tbl->column[i].right_text_column=i;
7911 tbl->column[i].justification=GTK_JUSTIFY_FILL;
7912 tbl->column[i].requisition=DEFAULT_COLUMN_WIDTH;
7913 if(i>0)
7915 tbl->column[i].left_text_column=tbl->column[i-1].left_text_column;
7916 tbl->column[i].left_xpixel=tbl->column[i-1].left_xpixel +
7917 tbl->column[i-1].width;
7919 else
7921 tbl->column[i].left_xpixel=tbl->row_title_area.width;
7922 if(!tbl->row_titles_visible)
7923 tbl->column[i].left_xpixel=0;
7926 return TRUE;
7929 static gint
7930 AddRow(GtkSheet *tbl, gint nrows)
7932 gint i;
7934 if(nrows == -1 && tbl->maxrow == 0)
7936 nrows = 1;
7938 else
7940 tbl->maxrow += nrows;
7941 tbl->row = (GtkSheetRow *)g_realloc(tbl->row,(tbl->maxrow+1)*
7942 sizeof(GtkSheetRow));
7945 for(i=tbl->maxrow-nrows+1; i<= tbl->maxrow; i++){
7946 tbl->row[i].requisition=tbl->row[i].height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7947 tbl->row[i].button.label=NULL;
7948 tbl->row[i].button.child=NULL;
7949 tbl->row[i].button.state=GTK_STATE_NORMAL;
7950 tbl->row[i].button.justification=GTK_JUSTIFY_CENTER;
7951 tbl->row[i].button.label_visible = TRUE;
7952 tbl->row[i].name=NULL;
7953 tbl->row[i].is_visible=TRUE;
7954 tbl->row[i].is_sensitive=TRUE;
7955 if(i>0)
7956 tbl->row[i].top_ypixel=tbl->row[i-1].top_ypixel+tbl->row[i-1].height;
7957 else
7959 tbl->row[i].top_ypixel=tbl->column_title_area.height;
7960 if(!tbl->column_titles_visible)
7961 tbl->row[i].top_ypixel=0;
7964 return TRUE;
7967 static gint
7968 InsertRow(GtkSheet *tbl, gint row, gint nrows)
7970 GtkSheetCell **pp;
7971 gint i,j;
7972 GtkSheetCell **auxdata;
7973 GtkSheetRow auxrow;
7975 AddRow(tbl,nrows);
7977 for(i=tbl->maxrow; i>=row+nrows; i--){
7978 auxrow = tbl->row[i];
7979 tbl->row[i]=tbl->row[i-nrows];
7980 tbl->row[i].is_visible=tbl->row[i-nrows].is_visible;
7981 tbl->row[i].is_sensitive=tbl->row[i-nrows].is_sensitive;
7982 if(auxrow.is_visible)
7983 tbl->row[i].top_ypixel+=nrows*DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7984 tbl->row[i-nrows]=auxrow;
7987 if(row <= tbl->maxallocrow){
7989 GrowSheet(tbl,nrows,0);
7991 for(i=tbl->maxallocrow; i>=row+nrows; i--){
7992 auxdata = tbl->data[i];
7993 tbl->data[i]=tbl->data[i-nrows];
7995 pp= tbl->data[i];
7996 for(j=0; j<=tbl->maxalloccol; j++,pp++){
7997 if(*pp!=(GtkSheetCell *)NULL)
7998 (*pp)->row=i;
8001 tbl->data[i-nrows]=auxdata;
8004 gtk_sheet_recalc_top_ypixels(tbl, 0);
8005 return TRUE;
8008 static gint
8009 InsertColumn(GtkSheet *tbl, gint col, gint ncols)
8011 gint i,j;
8012 GtkSheetColumn auxcol;
8014 AddColumn(tbl,ncols);
8016 for(i=tbl->maxcol; i>=col+ncols; i--){
8017 auxcol = tbl->column[i];
8018 tbl->column[i]=tbl->column[i-ncols];
8019 tbl->column[i].is_visible=tbl->column[i-ncols].is_visible;
8020 tbl->column[i].is_sensitive=tbl->column[i-ncols].is_sensitive;
8021 tbl->column[i].left_text_column=tbl->column[i-ncols].left_text_column;
8022 tbl->column[i].right_text_column=tbl->column[i-ncols].right_text_column;
8023 tbl->column[i].justification=tbl->column[i-ncols].justification;
8024 if(auxcol.is_visible) tbl->column[i].left_xpixel+=ncols*DEFAULT_COLUMN_WIDTH;
8025 tbl->column[i-ncols]=auxcol;
8028 if(col <= tbl->maxalloccol){
8030 GrowSheet(tbl,0,ncols);
8032 for(i=0; i<=tbl->maxallocrow; i++){
8033 for(j=tbl->maxalloccol; j>=col+ncols; j--){
8034 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
8035 tbl->data[i][j]=tbl->data[i][j-ncols];
8036 if(tbl->data[i][j]) tbl->data[i][j]->col=j;
8037 tbl->data[i][j-ncols]=NULL;
8041 gtk_sheet_recalc_left_xpixels(tbl, 0);
8042 return TRUE;
8045 static gint
8046 DeleteRow(GtkSheet *tbl, gint row, gint nrows)
8048 GtkSheetCell **auxdata = NULL;
8049 gint i,j;
8051 if(nrows <= 0 || row > tbl->maxrow) return TRUE;
8053 nrows=MIN(nrows,tbl->maxrow-row+1);
8055 for(i=row; i<row+nrows; i++){
8056 if(tbl->row[i].name){
8057 g_free(tbl->row[i].name);
8058 tbl->row[i].name = NULL;
8060 if(tbl->row[i].button.label){
8061 g_free(tbl->row[i].button.label);
8062 tbl->row[i].button.label = NULL;
8066 for(i=row; i<=tbl->maxrow-nrows; i++){
8067 if(i+nrows <= tbl->maxrow){
8068 tbl->row[i]=tbl->row[i+nrows];
8072 if(row <= tbl->maxallocrow){
8074 for(i=row; i<=tbl->maxrow-nrows; i++){
8075 if(i<=tbl->maxallocrow){
8076 auxdata=tbl->data[i];
8077 for(j=0; j<=tbl->maxalloccol; j++){
8078 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
8081 if(i+nrows<=tbl->maxallocrow){
8082 tbl->data[i]=tbl->data[i+nrows];
8083 tbl->data[i+nrows]=auxdata;
8084 for(j=0; j<=tbl->maxalloccol; j++){
8085 if(tbl->data[i][j]) tbl->data[i][j]->row=i;
8090 for(i=tbl->maxrow-nrows+1; i<=tbl->maxallocrow; i++){
8091 if(i > 0 && tbl->data[i]){
8092 g_free(tbl->data[i]);
8093 tbl->data[i] = NULL;
8097 tbl->maxallocrow-=MIN(nrows,tbl->maxallocrow-row+1);
8098 tbl->maxallocrow = MIN(tbl->maxallocrow, tbl->maxrow);
8102 tbl->maxrow-=nrows;
8103 gtk_sheet_recalc_top_ypixels(tbl, 0);
8104 return TRUE;
8107 static gint
8108 DeleteColumn(GtkSheet *tbl, gint column, gint ncols)
8110 gint i,j;
8111 GtkSheetColumn auxcol;
8113 ncols = MIN(ncols,tbl->maxcol-column+1);
8115 if(ncols <= 0 || column > tbl->maxcol) return TRUE;
8117 for(i=column; i<column+ncols; i++){
8118 auxcol=tbl->column[i];
8119 if(tbl->column[i].name){
8120 g_free(tbl->column[i].name);
8121 tbl->column[i].name = NULL;
8123 if(tbl->column[i].button.label){
8124 g_free(tbl->column[i].button.label);
8125 tbl->column[i].button.label = NULL;
8129 for(i=column; i<=tbl->maxcol-ncols; i++){
8130 if(i+ncols <= tbl->maxcol){
8131 tbl->column[i]=tbl->column[i+ncols];
8135 if(column <= tbl->maxalloccol){
8137 for(i=column; i<=tbl->maxcol-ncols; i++){
8138 if(i<=tbl->maxalloccol){
8139 for(j=0; j<=tbl->maxallocrow; j++){
8140 gtk_sheet_real_cell_clear(tbl, j, i, TRUE);
8141 if(i+ncols <= tbl->maxalloccol){
8142 tbl->data[j][i] = tbl->data[j][i+ncols];
8143 tbl->data[j][i+ncols] = NULL;
8144 if(tbl->data[j][i]) tbl->data[j][i]->col=i;
8151 tbl->maxalloccol-=MIN(ncols,tbl->maxalloccol-column+1);
8152 tbl->maxalloccol = MIN(tbl->maxalloccol, tbl->maxcol);
8154 tbl->maxcol-=ncols;
8155 gtk_sheet_recalc_left_xpixels(tbl, 0);
8156 return TRUE;
8159 static gint
8160 GrowSheet(GtkSheet *tbl, gint newrows, gint newcols)
8162 gint i,j;
8163 gint inirow, inicol;
8165 inirow = tbl->maxallocrow + 1;
8166 inicol = tbl->maxalloccol + 1;
8168 tbl->maxalloccol = tbl->maxalloccol + newcols;
8169 tbl->maxallocrow = tbl->maxallocrow + newrows;
8171 if(newrows>0){
8172 tbl->data = (GtkSheetCell***)
8173 g_realloc(tbl->data,(tbl->maxallocrow+1)*sizeof(GtkSheetCell **)+sizeof(double));
8175 for(i=inirow; i <= tbl->maxallocrow; i++){
8176 tbl->data[i] = (GtkSheetCell **) \
8177 g_malloc((tbl->maxcol+1)*sizeof(GtkSheetCell *)+sizeof(double));
8178 for(j=0; j<inicol; j++) {
8179 tbl->data[i][j] = NULL;
8185 if(newcols>0){
8186 for(i=0; i <= tbl->maxallocrow; i++) {
8187 tbl->data[i] = (GtkSheetCell **) \
8188 g_realloc(tbl->data[i],(tbl->maxalloccol+1)*sizeof(GtkSheetCell *)+sizeof(double));
8189 for(j=inicol; j <= tbl->maxalloccol; j++) {
8190 tbl->data[i][j] = NULL;
8195 return(0);
8198 static gint
8199 CheckBounds(GtkSheet *tbl, gint row, gint col)
8201 gint newrows=0,newcols=0;
8203 if(col>tbl->maxalloccol) newcols=col-tbl->maxalloccol;
8204 if(row>tbl->maxallocrow) newrows=row-tbl->maxallocrow;
8205 if(newrows>0 || newcols>0) GrowSheet(tbl, newrows, newcols);
8206 return(0);
8209 /********************************************************************
8210 * Container Functions:
8211 * gtk_sheet_add
8212 * gtk_sheet_put
8213 * gtk_sheet_attach
8214 * gtk_sheet_remove
8215 * gtk_sheet_move_child
8216 * gtk_sheet_position_child
8217 * gtk_sheet_position_children
8218 * gtk_sheet_realize_child
8219 * gtk_sheet_get_child_at
8220 ********************************************************************/
8222 GtkSheetChild *
8223 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
8225 GtkRequisition child_requisition;
8226 GtkSheetChild *child_info;
8228 g_return_val_if_fail(sheet != NULL, NULL);
8229 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
8230 g_return_val_if_fail(child != NULL, NULL);
8231 g_return_val_if_fail(child->parent == NULL, NULL);
8233 child_info = g_new (GtkSheetChild, 1);
8234 child_info->widget = child;
8235 child_info->x = x;
8236 child_info->y = y;
8237 child_info->attached_to_cell = FALSE;
8238 child_info->floating = TRUE;
8239 child_info->xpadding = child_info->ypadding = 0;
8240 child_info->xexpand = child_info->yexpand = FALSE;
8241 child_info->xshrink = child_info->yshrink = FALSE;
8242 child_info->xfill = child_info->yfill = FALSE;
8244 sheet->children = g_list_append(sheet->children, child_info);
8246 gtk_widget_set_parent (child, GTK_WIDGET(sheet));
8248 gtk_widget_size_request(child, &child_requisition);
8250 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8252 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8253 (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
8254 gtk_sheet_realize_child(sheet, child_info);
8256 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8257 !GTK_WIDGET_MAPPED(child))
8258 gtk_widget_map(child);
8261 gtk_sheet_position_child(sheet, child_info);
8263 /* This will avoid drawing on the titles */
8265 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
8267 if(sheet->row_titles_visible)
8268 gdk_window_show(sheet->row_title_window);
8269 if(sheet->column_titles_visible)
8270 gdk_window_show(sheet->column_title_window);
8273 return (child_info);
8276 void
8277 gtk_sheet_attach_floating (GtkSheet *sheet,
8278 GtkWidget *widget,
8279 gint row, gint col)
8281 GdkRectangle area;
8282 GtkSheetChild *child;
8284 if(row < 0 || col < 0){
8285 gtk_sheet_button_attach(sheet, widget, row, col);
8286 return;
8289 gtk_sheet_get_cell_area(sheet, row, col, &area);
8290 child = gtk_sheet_put(sheet, widget, area.x, area.y);
8291 child->attached_to_cell = TRUE;
8292 child->row = row;
8293 child->col = col;
8296 void
8297 gtk_sheet_attach_default (GtkSheet *sheet,
8298 GtkWidget *widget,
8299 gint row, gint col)
8301 if(row < 0 || col < 0){
8302 gtk_sheet_button_attach(sheet, widget, row, col);
8303 return;
8306 gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
8309 void
8310 gtk_sheet_attach (GtkSheet *sheet,
8311 GtkWidget *widget,
8312 gint row, gint col,
8313 gint xoptions,
8314 gint yoptions,
8315 gint xpadding,
8316 gint ypadding)
8318 GdkRectangle area;
8319 GtkSheetChild *child = NULL;
8321 if(row < 0 || col < 0){
8322 gtk_sheet_button_attach(sheet, widget, row, col);
8323 return;
8326 child = g_new0(GtkSheetChild, 1);
8327 child->attached_to_cell = TRUE;
8328 child->floating = FALSE;
8329 child->widget = widget;
8330 child->row = row;
8331 child->col = col;
8332 child->xpadding = xpadding;
8333 child->ypadding = ypadding;
8334 child->xexpand = (xoptions & GTK_EXPAND) != 0;
8335 child->yexpand = (yoptions & GTK_EXPAND) != 0;
8336 child->xshrink = (xoptions & GTK_SHRINK) != 0;
8337 child->yshrink = (yoptions & GTK_SHRINK) != 0;
8338 child->xfill = (xoptions & GTK_FILL) != 0;
8339 child->yfill = (yoptions & GTK_FILL) != 0;
8341 sheet->children = g_list_append(sheet->children, child);
8343 gtk_sheet_get_cell_area(sheet, row, col, &area);
8345 child->x = area.x + child->xpadding;
8346 child->y = area.y + child->ypadding;
8348 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8350 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8351 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
8352 gtk_sheet_realize_child(sheet, child);
8354 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8355 !GTK_WIDGET_MAPPED(widget))
8356 gtk_widget_map(widget);
8359 gtk_sheet_position_child(sheet, child);
8361 /* This will avoid drawing on the titles */
8363 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
8365 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
8366 gdk_window_show(sheet->row_title_window);
8367 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
8368 gdk_window_show(sheet->column_title_window);
8373 void
8374 gtk_sheet_button_attach (GtkSheet *sheet,
8375 GtkWidget *widget,
8376 gint row, gint col)
8378 GtkSheetButton *button;
8379 GtkSheetChild *child;
8380 GtkRequisition button_requisition;
8382 if(row >= 0 && col >= 0) return;
8383 if(row < 0 && col < 0) return;
8385 child = g_new (GtkSheetChild, 1);
8386 child->widget = widget;
8387 child->x = 0;
8388 child->y = 0;
8389 child->attached_to_cell = TRUE;
8390 child->floating = FALSE;
8391 child->row = row;
8392 child->col = col;
8393 child->xpadding = child->ypadding = 0;
8394 child->xshrink = child->yshrink = FALSE;
8395 child->xfill = child->yfill = FALSE;
8397 if(row == -1){
8398 button = &sheet->column[col].button;
8399 button->child = child;
8401 else
8403 button = &sheet->row[row].button;
8404 button->child = child;
8407 sheet->children = g_list_append(sheet->children, child);
8409 gtk_sheet_button_size_request(sheet, button, &button_requisition);
8411 if(row == -1){
8412 if(button_requisition.height > sheet->column_title_area.height)
8413 sheet->column_title_area.height = button_requisition.height;
8414 if(button_requisition.width > sheet->column[col].width)
8415 sheet->column[col].width = button_requisition.width;
8418 if(col == -1){
8419 if(button_requisition.width > sheet->row_title_area.width)
8420 sheet->row_title_area.width = button_requisition.width;
8421 if(button_requisition.height > sheet->row[row].height)
8422 sheet->row[row].height = button_requisition.height;
8425 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8427 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8428 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
8429 gtk_sheet_realize_child(sheet, child);
8431 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8432 !GTK_WIDGET_MAPPED(widget))
8433 gtk_widget_map(widget);
8436 if(row == -1) size_allocate_column_title_buttons(sheet);
8437 if(col == -1) size_allocate_row_title_buttons(sheet);
8441 static void
8442 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
8444 gchar *words;
8445 gchar word[1000];
8446 gint n = 0;
8447 gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
8449 req->height = 0;
8450 req->width = 0;
8451 words=label;
8453 while(words && *words != '\0'){
8454 if(*words == '\n' || *(words+1) == '\0'){
8455 req->height += row_height;
8457 word[n] = '\0';
8458 req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
8459 n = 0;
8460 } else {
8461 word[n++] = *words;
8463 words++;
8466 if(n > 0) req->height -= 2;
8469 static void
8470 gtk_sheet_button_size_request (GtkSheet *sheet,
8471 GtkSheetButton *button,
8472 GtkRequisition *button_requisition)
8474 GtkRequisition requisition;
8475 GtkRequisition label_requisition;
8477 if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
8478 label_size_request(sheet, button->label, &label_requisition);
8479 label_requisition.width += 2*CELLOFFSET;
8480 label_requisition.height += 2*CELLOFFSET;
8481 } else {
8482 label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8483 label_requisition.width = COLUMN_MIN_WIDTH;
8486 if(button->child)
8488 gtk_widget_size_request(button->child->widget, &requisition);
8489 requisition.width += 2*button->child->xpadding;
8490 requisition.height += 2*button->child->ypadding;
8491 requisition.width += 2*sheet->button->style->xthickness;
8492 requisition.height += 2*sheet->button->style->ythickness;
8494 else
8496 requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8497 requisition.width = COLUMN_MIN_WIDTH;
8500 *button_requisition = requisition;
8501 button_requisition->width = MAX(requisition.width, label_requisition.width);
8502 button_requisition->height = MAX(requisition.height, label_requisition.height);
8506 static void
8507 gtk_sheet_row_size_request (GtkSheet *sheet,
8508 gint row,
8509 guint *requisition)
8511 GtkRequisition button_requisition;
8512 GList *children;
8514 gtk_sheet_button_size_request(sheet, &sheet->row[row].button, &button_requisition);
8516 *requisition = button_requisition.height;
8518 children = sheet->children;
8519 while(children){
8520 GtkSheetChild *child = (GtkSheetChild *)children->data;
8521 GtkRequisition child_requisition;
8523 if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
8524 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8526 if(child_requisition.height + 2 * child->ypadding > *requisition)
8527 *requisition = child_requisition.height + 2 * child->ypadding;
8529 children = g_list_next(children);
8532 sheet->row[row].requisition = *requisition;
8535 static void
8536 gtk_sheet_column_size_request (GtkSheet *sheet,
8537 gint col,
8538 guint *requisition)
8540 GtkRequisition button_requisition;
8541 GList *children;
8543 gtk_sheet_button_size_request(sheet, &sheet->column[col].button, &button_requisition);
8545 *requisition = button_requisition.width;
8547 children = sheet->children;
8548 while(children){
8549 GtkSheetChild *child = (GtkSheetChild *)children->data;
8550 GtkRequisition child_requisition;
8552 if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
8553 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8555 if(child_requisition.width + 2 * child->xpadding > *requisition)
8556 *requisition = child_requisition.width + 2 * child->xpadding;
8558 children = g_list_next(children);
8561 sheet->column[col].requisition = *requisition;
8564 void
8565 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
8567 GtkSheetChild *child;
8568 GList *children;
8570 g_return_if_fail(sheet != NULL);
8571 g_return_if_fail(GTK_IS_SHEET(sheet));
8573 children = sheet->children;
8574 while(children)
8576 child = children->data;
8578 if(child->widget == widget){
8579 child->x = x;
8580 child->y = y;
8581 child->row = ROW_FROM_YPIXEL(sheet, y);
8582 child->col = COLUMN_FROM_XPIXEL(sheet, x);
8583 gtk_sheet_position_child(sheet, child);
8584 return;
8587 children = g_list_next(children);
8590 g_warning("Widget must be a GtkSheet child");
8594 static void
8595 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
8597 GtkRequisition child_requisition;
8598 GtkAllocation child_allocation;
8599 gint xoffset = 0;
8600 gint yoffset = 0;
8601 gint x = 0, y = 0;
8602 GdkRectangle area;
8604 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8606 if(sheet->column_titles_visible)
8607 yoffset = sheet->column_title_area.height;
8609 if(sheet->row_titles_visible)
8610 xoffset = sheet->row_title_area.width;
8612 if(child->attached_to_cell){
8614 child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
8615 child->y = ROW_TOP_YPIXEL(sheet, child->row);
8617 if(sheet->row_titles_visible)
8618 child->x-=sheet->row_title_area.width;
8619 if(sheet->column_titles_visible)
8620 child->y-=sheet->column_title_area.height;
8622 width = sheet->column[child->col].width;
8623 height = sheet->row[child->row].height;
8626 gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
8627 child->x = area.x + child->xpadding;
8628 child->y = area.y + child->ypadding;
8630 if(!child->floating){
8631 if(child_requisition.width + 2*child->xpadding <= sheet->column[child->col].width){
8632 if(child->xfill){
8633 child_requisition.width = child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
8634 } else {
8635 if(child->xexpand){
8636 child->x = area.x + sheet->column[child->col].width / 2 -
8637 child_requisition.width / 2;
8639 child_allocation.width = child_requisition.width;
8641 } else {
8642 if(!child->xshrink){
8643 gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
8645 child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
8648 if(child_requisition.height + 2*child->ypadding <= sheet->row[child->row].height){
8649 if(child->yfill){
8650 child_requisition.height = child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
8651 } else {
8652 if(child->yexpand){
8653 child->y = area.y + sheet->row[child->row].height / 2 -
8654 child_requisition.height / 2;
8656 child_allocation.height = child_requisition.height;
8658 } else {
8659 if(!child->yshrink){
8660 gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
8662 child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
8664 } else {
8665 child_allocation.width = child_requisition.width;
8666 child_allocation.height = child_requisition.height;
8669 x = child_allocation.x = child->x + xoffset;
8670 y = child_allocation.y = child->y + yoffset;
8672 else
8674 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
8675 x = child_allocation.x = child->x + xoffset;
8676 y = child_allocation.y = child->y + sheet->voffset + yoffset;
8677 y = child_allocation.y = child->y + yoffset;
8678 child_allocation.width = child_requisition.width;
8679 child_allocation.height = child_requisition.height;
8682 gtk_widget_size_allocate(child->widget, &child_allocation);
8683 gtk_widget_queue_draw(child->widget);
8686 static void
8687 gtk_sheet_forall (GtkContainer *container,
8688 gboolean include_internals,
8689 GtkCallback callback,
8690 gpointer callback_data)
8692 GtkSheet *sheet;
8693 GtkSheetChild *child;
8694 GList *children;
8696 g_return_if_fail (GTK_IS_SHEET (container));
8697 g_return_if_fail (callback != NULL);
8699 sheet = GTK_SHEET (container);
8701 children = sheet->children;
8702 while (children)
8704 child = children->data;
8705 children = g_list_next(children);
8707 (* callback) (child->widget, callback_data);
8709 if(sheet->button)
8710 (* callback) (sheet->button, callback_data);
8711 if(sheet->sheet_entry)
8712 (* callback) (sheet->sheet_entry, callback_data);
8716 static void
8717 gtk_sheet_position_children(GtkSheet *sheet)
8719 GList *children;
8720 GtkSheetChild *child;
8722 children = sheet->children;
8724 while(children)
8726 child = (GtkSheetChild *)children->data;
8728 if(child->col !=-1 && child->row != -1)
8729 gtk_sheet_position_child(sheet, child);
8731 if(child->row == -1){
8732 if(child->col < MIN_VISIBLE_COLUMN(sheet) ||
8733 child->col > MAX_VISIBLE_COLUMN(sheet))
8734 gtk_sheet_child_hide(child);
8735 else
8736 gtk_sheet_child_show(child);
8738 if(child->col == -1){
8739 if(child->row < MIN_VISIBLE_ROW(sheet) ||
8740 child->row > MAX_VISIBLE_ROW(sheet))
8741 gtk_sheet_child_hide(child);
8742 else
8743 gtk_sheet_child_show(child);
8746 children = g_list_next(children);
8751 static void
8752 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
8754 GtkSheet *sheet;
8755 GList *children;
8756 GtkSheetChild *child = 0;
8758 g_return_if_fail(container != NULL);
8759 g_return_if_fail(GTK_IS_SHEET(container));
8761 sheet = GTK_SHEET(container);
8763 children = sheet->children;
8765 while(children)
8767 child = (GtkSheetChild *)children->data;
8769 if(child->widget == widget) break;
8771 children = g_list_next(children);
8774 if (children)
8776 if(child->row == -1)
8777 sheet->row[child->col].button.child = NULL;
8779 if(child->col == -1)
8780 sheet->column[child->row].button.child = NULL;
8782 gtk_widget_unparent (widget);
8783 child->widget = NULL;
8785 sheet->children = g_list_remove_link (sheet->children, children);
8786 g_list_free_1 (children);
8787 g_free(child);
8792 static void
8793 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
8795 GtkWidget *widget;
8797 widget = GTK_WIDGET(sheet);
8799 if(GTK_WIDGET_REALIZED(widget)){
8800 if(child->row == -1)
8801 gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
8802 else if(child->col == -1)
8803 gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
8804 else
8805 gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
8808 gtk_widget_set_parent(child->widget, widget);
8813 GtkSheetChild *
8814 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
8816 GList *children;
8817 GtkSheetChild *child = 0;
8819 g_return_val_if_fail(sheet != NULL, NULL);
8820 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
8822 children = sheet->children;
8824 while(children)
8826 child = (GtkSheetChild *)children->data;
8828 if(child->attached_to_cell)
8829 if(child->row == row && child->col == col) break;
8831 children = g_list_next(children);
8834 if(children) return child;
8836 return NULL;
8839 static void
8840 gtk_sheet_child_hide(GtkSheetChild *child)
8842 g_return_if_fail(child != NULL);
8843 gtk_widget_hide(child->widget);
8846 static void
8847 gtk_sheet_child_show(GtkSheetChild *child)
8849 g_return_if_fail(child != NULL);
8851 gtk_widget_show(child->widget);