libgeda: Enable use from C++ programs.
[geda-gaf/whiteaudio.git] / gattrib / src / gtksheet_2_2.c
blob05710adeec76cba83b73d4b55d46a47166b297c2
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., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 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 "gtksheet_2_2.h"
48 #include "gtkextra-marshal.h"
50 /*------------------------------------------------------------------
51 * Gattrib specific includes -- stuff dealing with gattrib data structs.
52 * Included here in order to grab sheet_head->CHANGED, which is set
53 * when the user puts a new value in a cell.
54 *------------------------------------------------------------------*/
55 #include <libgeda/libgeda.h> /* geda library fcns */
56 #include "../include/struct.h" /* typdef and struct declarations */
57 #include "../include/prototype.h" /* function prototypes */
58 #include "../include/globals.h"
60 #ifdef HAVE_LIBDMALLOC
61 #include <dmalloc.h>
62 #endif
65 /* sheet flags */
66 enum
68 GTK_SHEET_IS_LOCKED = 1 << 0,
69 GTK_SHEET_IS_FROZEN = 1 << 1,
70 GTK_SHEET_IN_XDRAG = 1 << 2,
71 GTK_SHEET_IN_YDRAG = 1 << 3,
72 GTK_SHEET_IN_DRAG = 1 << 4,
73 GTK_SHEET_IN_SELECTION = 1 << 5,
74 GTK_SHEET_IN_RESIZE = 1 << 6,
75 GTK_SHEET_IN_CLIP = 1 << 7,
76 GTK_SHEET_REDRAW_PENDING = 1 << 8,
79 #define GTK_SHEET_FLAGS(sheet) (GTK_SHEET (sheet)->flags)
80 #define GTK_SHEET_SET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) |= (flag))
81 #define GTK_SHEET_UNSET_FLAGS(sheet,flag) (GTK_SHEET_FLAGS (sheet) &= ~(flag))
83 #define GTK_SHEET_IS_FROZEN(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IS_FROZEN)
84 #define GTK_SHEET_IN_XDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_XDRAG)
85 #define GTK_SHEET_IN_YDRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_YDRAG)
86 #define GTK_SHEET_IN_DRAG(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_DRAG)
87 #define GTK_SHEET_IN_SELECTION(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_SELECTION)
88 #define GTK_SHEET_IN_RESIZE(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_RESIZE)
89 #define GTK_SHEET_IN_CLIP(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_IN_CLIP)
90 #define GTK_SHEET_REDRAW_PENDING(sheet) (GTK_SHEET_FLAGS (sheet) & GTK_SHEET_REDRAW_PENDING)
92 #define CELL_SPACING 1
93 #define DRAG_WIDTH 6
94 #define TIMEOUT_SCROLL 20
95 #define TIMEOUT_FLASH 200
96 #define TIME_INTERVAL 8
97 #define COLUMN_MIN_WIDTH 10
98 #define MINROWS 1
99 #define MINCOLS 1
100 #define MAXLENGTH 30
101 #define CELLOFFSET 4
102 #define DEFAULT_COLUMN_WIDTH 80
104 static inline guint DEFAULT_ROW_HEIGHT(GtkWidget *widget)
106 if(!widget->style->font_desc) return 24;
107 else {
108 PangoContext *context = gtk_widget_get_pango_context(widget);
109 PangoFontMetrics *metrics = pango_context_get_metrics(context,
110 widget->style->font_desc,
111 pango_context_get_language(context));
112 guint val = pango_font_metrics_get_descent(metrics) +
113 pango_font_metrics_get_ascent(metrics);
114 pango_font_metrics_unref(metrics);
115 return PANGO_PIXELS(val)+2*CELLOFFSET;
118 static inline guint DEFAULT_FONT_ASCENT(GtkWidget *widget)
120 if(!widget->style->font_desc) return 12;
121 else {
122 PangoContext *context = gtk_widget_get_pango_context(widget);
123 PangoFontMetrics *metrics = pango_context_get_metrics(context,
124 widget->style->font_desc,
125 pango_context_get_language(context));
126 guint val = pango_font_metrics_get_ascent(metrics);
127 pango_font_metrics_unref(metrics);
128 return PANGO_PIXELS(val);
131 static inline guint STRING_WIDTH(GtkWidget *widget,
132 PangoFontDescription *font, const gchar *text)
134 PangoRectangle rect;
135 PangoLayout *layout;
137 layout = gtk_widget_create_pango_layout (widget, text);
138 pango_layout_set_font_description (layout, font);
140 pango_layout_get_extents (layout, NULL, &rect);
142 g_object_unref(G_OBJECT(layout));
143 return PANGO_PIXELS(rect.width);
146 static inline guint DEFAULT_FONT_DESCENT(GtkWidget *widget)
148 if(!widget->style->font_desc) return 12;
149 else {
150 PangoContext *context = gtk_widget_get_pango_context(widget);
151 PangoFontMetrics *metrics = pango_context_get_metrics(context,
152 widget->style->font_desc,
153 pango_context_get_language(context));
154 guint val = pango_font_metrics_get_descent(metrics);
155 pango_font_metrics_unref(metrics);
156 return PANGO_PIXELS(val);
160 /*! \brief gives the top pixel of the given row in context of
161 * the sheet's voffset
164 static inline gint
165 ROW_TOP_YPIXEL(GtkSheet *sheet, gint nrow)
167 return (sheet->voffset + sheet->row[nrow].top_ypixel);
171 /*! \brief returns the row index from a y pixel location in the
172 * context of the sheet's voffset
175 static inline gint
176 ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
178 gint i, cy;
180 cy = sheet->voffset;
181 if(sheet->column_titles_visible) cy += sheet->column_title_area.height;
182 if(y < cy) return 0;
183 for (i = 0; i <= sheet->maxrow; i++)
185 if (y >= cy && y <= (cy + sheet->row[i].height) && sheet->row[i].is_visible)
186 return i;
187 if(sheet->row[i].is_visible) cy += sheet->row[i].height;
191 /* no match */
192 return sheet->maxrow;
196 /*! \brief gives the left pixel of the given column in context of
197 * the sheet's hoffset
200 static inline gint
201 COLUMN_LEFT_XPIXEL(GtkSheet *sheet, gint ncol)
203 return (sheet->hoffset + sheet->column[ncol].left_xpixel);
206 /*! \brief returns the column index from a x pixel location in the
207 * context of the sheet's hoffset
210 static inline gint
211 COLUMN_FROM_XPIXEL (GtkSheet * sheet,
212 gint x)
214 gint i, cx;
216 cx = sheet->hoffset;
217 if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
218 if(x < cx) return 0;
219 for (i = 0; i <= sheet->maxcol; i++)
221 if (x >= cx && x <= (cx + sheet->column[i].width) && sheet->column[i].is_visible)
222 return i;
223 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
227 /* no match */
228 return sheet->maxcol;
231 /*! \brief returns the total height of the sheet
234 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
236 gint i,cx;
238 cx = 0;
239 if(sheet->column_titles_visible) cx += sheet->column_title_area.height;
240 for (i=0;i<=sheet->maxrow; i++)
241 if(sheet->row[i].is_visible) cx += sheet->row[i].height;
243 return cx;
247 /*! \brief returns the total width of the sheet
250 static inline gint SHEET_WIDTH(GtkSheet *sheet)
252 gint i,cx;
254 cx = 0;
255 if(sheet->row_titles_visible) cx += sheet->row_title_area.width;
256 for (i=0;i<=sheet->maxcol; i++)
257 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
259 return cx;
262 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
263 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
264 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
265 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
268 static inline gint
269 POSSIBLE_XDRAG(GtkSheet *sheet, gint x, gint *drag_column)
271 gint column, xdrag;
273 column=COLUMN_FROM_XPIXEL(sheet, x);
274 *drag_column=column;
276 xdrag=COLUMN_LEFT_XPIXEL(sheet,column)+CELL_SPACING;
277 if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
278 while(!sheet->column[column-1].is_visible && column>0) column--;
279 *drag_column=column-1;
280 return sheet->column[column-1].is_sensitive;
283 xdrag+=sheet->column[column].width;
284 if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
285 return sheet->column[column].is_sensitive;
287 return FALSE;
290 static inline gint
291 POSSIBLE_YDRAG(GtkSheet *sheet, gint y, gint *drag_row)
293 gint row, ydrag;
295 row=ROW_FROM_YPIXEL(sheet, y);
296 *drag_row=row;
298 ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
299 if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
300 while(!sheet->row[row-1].is_visible && row>0) row--;
301 *drag_row=row-1;
302 return sheet->row[row-1].is_sensitive;
305 ydrag+=sheet->row[row].height;
307 if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
308 return sheet->row[row].is_sensitive;
311 return FALSE;
314 static inline gint POSSIBLE_DRAG(GtkSheet *sheet, gint x, gint y,
315 gint *drag_row, gint *drag_column)
317 gint ydrag, xdrag;
319 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
320 *drag_row=ROW_FROM_YPIXEL(sheet,y);
322 if(x>=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0)-DRAG_WIDTH/2 &&
323 x<=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
324 sheet->column[sheet->range.coli].width+DRAG_WIDTH/2){
325 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
326 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
327 *drag_row=sheet->range.row0;
328 return TRUE;
330 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
331 sheet->row[sheet->range.rowi].height;
332 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
333 *drag_row=sheet->range.rowi;
334 return TRUE;
338 if(y>=ROW_TOP_YPIXEL(sheet,sheet->range.row0)-DRAG_WIDTH/2 &&
339 y<=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
340 sheet->row[sheet->range.rowi].height+DRAG_WIDTH/2){
341 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0);
342 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
343 *drag_column=sheet->range.col0;
344 return TRUE;
346 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
347 sheet->column[sheet->range.coli].width;
348 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
349 *drag_column=sheet->range.coli;
350 return TRUE;
353 return FALSE;
356 static inline gint POSSIBLE_RESIZE(GtkSheet *sheet, gint x, gint y,
357 gint *drag_row, gint *drag_column)
359 gint xdrag, ydrag;
361 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
362 sheet->column[sheet->range.coli].width;
364 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
365 sheet->row[sheet->range.rowi].height;
367 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
368 ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
370 if(sheet->state == GTK_SHEET_ROW_SELECTED)
371 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
373 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
374 *drag_row=ROW_FROM_YPIXEL(sheet,y);
376 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
377 y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
379 return FALSE;
382 static void gtk_sheet_class_init (GtkSheetClass * klass);
383 static void gtk_sheet_init (GtkSheet * sheet);
384 static void gtk_sheet_destroy (GtkObject * object);
385 static void gtk_sheet_finalize (GObject * object);
386 static void gtk_sheet_style_set (GtkWidget *widget,
387 GtkStyle *previous_style);
388 static void gtk_sheet_realize (GtkWidget * widget);
389 static void gtk_sheet_unrealize (GtkWidget * widget);
390 static void gtk_sheet_map (GtkWidget * widget);
391 static void gtk_sheet_unmap (GtkWidget * widget);
392 static gint gtk_sheet_expose (GtkWidget * widget,
393 GdkEventExpose * event);
394 static void gtk_sheet_forall (GtkContainer *container,
395 gboolean include_internals,
396 GtkCallback callback,
397 gpointer callback_data);
399 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
400 GtkAdjustment *hadjustment,
401 GtkAdjustment *vadjustment);
403 static gint gtk_sheet_button_press (GtkWidget * widget,
404 GdkEventButton * event);
405 static gint gtk_sheet_button_release (GtkWidget * widget,
406 GdkEventButton * event);
407 static gint gtk_sheet_motion (GtkWidget * widget,
408 GdkEventMotion * event);
410 #if 0
411 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
412 GdkEventKey *key);
413 #endif
415 static gint gtk_sheet_key_press (GtkWidget *widget,
416 GdkEventKey *key);
418 static void gtk_sheet_size_request (GtkWidget * widget,
419 GtkRequisition * requisition);
420 static void gtk_sheet_size_allocate (GtkWidget * widget,
421 GtkAllocation * allocation);
423 /* Sheet queries */
425 static gint gtk_sheet_range_isvisible (GtkSheet * sheet,
426 GtkSheetRange range);
427 static gint gtk_sheet_cell_isvisible (GtkSheet * sheet,
428 gint row, gint column);
429 /* Clipped Range */
431 static gint gtk_sheet_scroll (gpointer data);
432 static gint gtk_sheet_flash (gpointer data);
434 /* Drawing Routines */
436 /* draw cell background and frame */
437 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
438 gint row, gint column);
440 /* draw cell border */
441 static void gtk_sheet_cell_draw_border (GtkSheet *sheet,
442 gint row, gint column,
443 gint mask);
445 /* draw cell contents */
446 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
447 gint row, gint column);
449 /* draw visible part of range. If range==NULL then draw the whole screen */
450 static void gtk_sheet_range_draw (GtkSheet *sheet,
451 const GtkSheetRange *range);
453 /* highlight the visible part of the selected range */
454 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
455 GtkSheetRange range);
457 /* Selection */
459 static gint gtk_sheet_move_query (GtkSheet *sheet,
460 gint row, gint column);
461 static void gtk_sheet_real_select_range (GtkSheet * sheet,
462 GtkSheetRange * range);
463 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
464 const GtkSheetRange * range);
465 static void gtk_sheet_extend_selection (GtkSheet *sheet,
466 gint row, gint column);
467 static void gtk_sheet_new_selection (GtkSheet *sheet,
468 GtkSheetRange *range);
469 static void gtk_sheet_draw_border (GtkSheet *sheet,
470 GtkSheetRange range);
471 static void gtk_sheet_draw_corners (GtkSheet *sheet,
472 GtkSheetRange range);
475 /* Active Cell handling */
477 static void gtk_sheet_entry_changed (GtkWidget *widget,
478 gpointer data);
479 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
480 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
481 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
482 gint row, gint col);
483 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
484 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
485 static void gtk_sheet_click_cell (GtkSheet *sheet,
486 gint row,
487 gint column,
488 gboolean *veto);
490 /* Backing Pixmap */
492 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
493 guint width, guint height);
494 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
495 GtkSheetRange range);
496 /* Scrollbars */
498 static void adjust_scrollbars (GtkSheet * sheet);
499 static void vadjustment_changed (GtkAdjustment * adjustment,
500 gpointer data);
501 static void hadjustment_changed (GtkAdjustment * adjustment,
502 gpointer data);
503 static void vadjustment_value_changed (GtkAdjustment * adjustment,
504 gpointer data);
505 static void hadjustment_value_changed (GtkAdjustment * adjustment,
506 gpointer data);
509 static void draw_xor_vline (GtkSheet * sheet);
510 static void draw_xor_hline (GtkSheet * sheet);
511 static void draw_xor_rectangle (GtkSheet *sheet,
512 GtkSheetRange range);
513 static void gtk_sheet_draw_flashing_range (GtkSheet *sheet,
514 GtkSheetRange range);
515 static guint new_column_width (GtkSheet * sheet,
516 gint column,
517 gint * x);
518 static guint new_row_height (GtkSheet * sheet,
519 gint row,
520 gint * y);
521 /* Sheet Button */
523 static void create_global_button (GtkSheet *sheet);
524 static void global_button_clicked (GtkWidget *widget,
525 gpointer data);
526 /* Sheet Entry */
528 static void create_sheet_entry (GtkSheet *sheet);
529 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
531 /* Sheet button gadgets */
533 static void size_allocate_column_title_buttons (GtkSheet * sheet);
534 static void size_allocate_row_title_buttons (GtkSheet * sheet);
535 static void gtk_sheet_recalc_top_ypixels (GtkSheet *sheet,
536 gint row);
537 static void gtk_sheet_recalc_left_xpixels (GtkSheet *sheet,
538 gint column);
539 static void row_button_set (GtkSheet *sheet,
540 gint row);
541 static void column_button_set (GtkSheet *sheet,
542 gint column);
543 static void row_button_release (GtkSheet *sheet,
544 gint row);
545 static void column_button_release (GtkSheet *sheet,
546 gint column);
547 static void gtk_sheet_button_draw (GtkSheet *sheet,
548 gint row, gint column);
549 static void size_allocate_global_button (GtkSheet *sheet);
550 static void gtk_sheet_button_size_request (GtkSheet *sheet,
551 GtkSheetButton *button,
552 GtkRequisition *requisition);
554 /* Attributes routines */
556 static void gtk_sheet_set_cell_attributes (GtkSheet *sheet,
557 gint row, gint col,
558 GtkSheetCellAttr attributes);
560 static void init_attributes (GtkSheet *sheet, gint col,
561 GtkSheetCellAttr *attributes);
562 /* Memory allocation routines */
563 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
564 const GtkSheetRange *range,
565 gboolean delete);
566 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
567 gint row,
568 gint column,
569 gboolean delete);
570 static GtkSheetCell * gtk_sheet_cell_new (void);
571 static gint AddRow (GtkSheet *sheet, gint nrows);
572 static gint AddColumn (GtkSheet *sheet, gint ncols);
573 static gint InsertRow (GtkSheet *sheet, gint row, gint nrows);
574 static gint InsertColumn (GtkSheet *sheet, gint col, gint ncols);
575 static gint DeleteRow (GtkSheet *sheet, gint row, gint nrows);
576 static gint DeleteColumn (GtkSheet *sheet, gint col, gint ncols);
577 static gint GrowSheet (GtkSheet *sheet,
578 gint newrows, gint newcols);
579 static gint CheckBounds (GtkSheet *sheet,
580 gint row, gint col);
582 /* Container Functions */
583 static void gtk_sheet_remove (GtkContainer *container,
584 GtkWidget *widget);
585 static void gtk_sheet_realize_child (GtkSheet *sheet,
586 GtkSheetChild *child);
587 static void gtk_sheet_position_child (GtkSheet *sheet,
588 GtkSheetChild *child);
589 static void gtk_sheet_position_children (GtkSheet *sheet);
590 static void gtk_sheet_child_show (GtkSheetChild *child);
591 static void gtk_sheet_child_hide (GtkSheetChild *child);
592 static void gtk_sheet_column_size_request (GtkSheet *sheet,
593 gint col,
594 guint *requisition);
595 static void gtk_sheet_row_size_request (GtkSheet *sheet,
596 gint row,
597 guint *requisition);
600 /* Signals */
602 /* \brief Imported from gtkextra.c by SDB 7.22.2004
605 void
606 _gtkextra_signal_emit(GtkObject *object, guint signal_id, ...)
608 gboolean *result;
609 GValue ret = { 0, };
610 GValue instance_and_params [10] = { {0, }, };
611 va_list var_args;
612 GSignalQuery query;
613 gchar *error;
614 int i;
616 va_start (var_args, signal_id);
618 g_value_init(instance_and_params + 0, GTK_OBJECT_TYPE(object));
619 g_value_set_instance (instance_and_params + 0, G_OBJECT(object));
621 g_signal_query(signal_id, &query);
623 for (i = 0; i < query.n_params; i++)
625 gboolean static_scope = query.param_types[i]&~G_SIGNAL_TYPE_STATIC_SCOPE;
626 g_value_init(instance_and_params + i + 1, query.param_types[i]);
629 G_VALUE_COLLECT (instance_and_params + i + 1,
630 var_args,
631 static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
632 &error);
634 if (error)
636 g_warning ("%s: %s", G_STRLOC, error);
637 g_free (error);
638 while (i-- > 0)
639 g_value_unset (instance_and_params + i);
641 va_end (var_args);
642 return;
648 g_value_init(&ret, query.return_type);
649 result = va_arg(var_args,gboolean *);
650 g_value_set_boolean(&ret, *result);
651 g_signal_emitv(instance_and_params, signal_id, 0, &ret);
652 *result = g_value_get_boolean(&ret);
653 g_value_unset (&ret);
655 for (i = 0; i < query.n_params; i++)
656 g_value_unset (instance_and_params + 1 + i);
657 g_value_unset (instance_and_params + 0);
659 va_end (var_args);
663 enum {
664 SELECT_ROW,
665 SELECT_COLUMN,
666 SELECT_RANGE,
667 CLIP_RANGE,
668 RESIZE_RANGE,
669 MOVE_RANGE,
670 TRAVERSE,
671 DEACTIVATE,
672 ACTIVATE,
673 SET_CELL,
674 CLEAR_CELL,
675 CHANGED,
676 NEW_COL_WIDTH,
677 NEW_ROW_HEIGHT,
678 LAST_SIGNAL
681 static GtkContainerClass *parent_class = NULL;
682 static guint sheet_signals[LAST_SIGNAL] = {0};
685 GType
686 gtk_sheet_get_type ()
688 static GType sheet_type = 0;
690 if (!sheet_type)
692 static const GTypeInfo sheet_info =
694 sizeof (GtkSheetClass),
695 NULL,
696 NULL,
697 (GClassInitFunc) gtk_sheet_class_init,
698 NULL,
699 NULL,
700 sizeof (GtkSheet),
702 (GInstanceInitFunc) gtk_sheet_init,
703 NULL,
705 sheet_type =
706 g_type_register_static (GTK_TYPE_CONTAINER, "GtkSheet",
707 &sheet_info, 0);
709 return sheet_type;
712 static GtkSheetRange*
713 gtk_sheet_range_copy (const GtkSheetRange *range)
715 GtkSheetRange *new_range;
717 g_return_val_if_fail (range != NULL, NULL);
719 new_range = g_new (GtkSheetRange, 1);
721 *new_range = *range;
723 return new_range;
726 static void
727 gtk_sheet_range_free (GtkSheetRange *range)
729 g_return_if_fail (range != NULL);
731 g_free (range);
734 GType
735 gtk_sheet_range_get_type (void)
737 static GType sheet_range_type;
739 if(!sheet_range_type)
741 sheet_range_type = g_boxed_type_register_static("GtkSheetRange", (GBoxedCopyFunc)gtk_sheet_range_copy, (GBoxedFreeFunc)gtk_sheet_range_free);
743 return sheet_range_type;
747 static void
748 gtk_sheet_class_init (GtkSheetClass * klass)
750 GtkObjectClass *object_class;
751 GtkWidgetClass *widget_class;
752 GtkContainerClass *container_class;
753 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
755 object_class = (GtkObjectClass *) klass;
756 widget_class = (GtkWidgetClass *) klass;
757 container_class = (GtkContainerClass *) klass;
759 parent_class = g_type_class_peek_parent (klass);
761 sheet_signals[SELECT_ROW] =
762 gtk_signal_new ("select_row",
763 GTK_RUN_LAST,
764 GTK_CLASS_TYPE(object_class),
765 GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
766 gtkextra_VOID__INT,
767 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
769 sheet_signals[SELECT_COLUMN] =
770 gtk_signal_new ("select_column",
771 GTK_RUN_LAST,
772 GTK_CLASS_TYPE(object_class),
773 GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
774 gtkextra_VOID__INT,
775 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
777 sheet_signals[SELECT_RANGE] =
778 gtk_signal_new ("select_range",
779 GTK_RUN_LAST,
780 GTK_CLASS_TYPE(object_class),
781 GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
782 gtkextra_VOID__BOXED,
783 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
785 sheet_signals[CLIP_RANGE] =
786 gtk_signal_new ("clip_range",
787 GTK_RUN_LAST,
788 GTK_CLASS_TYPE(object_class),
789 GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
790 gtkextra_VOID__BOXED,
791 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
793 sheet_signals[RESIZE_RANGE] =
794 gtk_signal_new ("resize_range",
795 GTK_RUN_LAST,
796 GTK_CLASS_TYPE(object_class),
797 GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
798 gtkextra_VOID__BOXED_BOXED,
799 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
800 sheet_signals[MOVE_RANGE] =
801 gtk_signal_new ("move_range",
802 GTK_RUN_LAST,
803 GTK_CLASS_TYPE(object_class),
804 GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
805 gtkextra_VOID__BOXED_BOXED,
806 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
807 sheet_signals[TRAVERSE] =
808 gtk_signal_new ("traverse",
809 GTK_RUN_LAST,
810 GTK_CLASS_TYPE(object_class),
811 GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
812 gtkextra_BOOLEAN__INT_INT_POINTER_POINTER,
813 GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
814 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
816 sheet_signals[DEACTIVATE] =
817 gtk_signal_new ("deactivate",
818 GTK_RUN_LAST,
819 GTK_CLASS_TYPE(object_class),
820 GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
821 gtkextra_BOOLEAN__INT_INT,
822 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
824 sheet_signals[ACTIVATE] =
825 gtk_signal_new ("activate",
826 GTK_RUN_LAST,
827 GTK_CLASS_TYPE(object_class),
828 GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
829 gtkextra_BOOLEAN__INT_INT,
830 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
832 sheet_signals[SET_CELL] =
833 gtk_signal_new ("set_cell",
834 GTK_RUN_LAST,
835 GTK_CLASS_TYPE(object_class),
836 GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
837 gtkextra_VOID__INT_INT,
838 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
840 sheet_signals[CLEAR_CELL] =
841 gtk_signal_new ("clear_cell",
842 GTK_RUN_LAST,
843 GTK_CLASS_TYPE(object_class),
844 GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
845 gtkextra_VOID__INT_INT,
846 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
848 sheet_signals[CHANGED] =
849 gtk_signal_new ("changed",
850 GTK_RUN_LAST,
851 GTK_CLASS_TYPE(object_class),
852 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
853 gtkextra_VOID__INT_INT,
854 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
856 sheet_signals[NEW_COL_WIDTH] =
857 gtk_signal_new ("new_column_width",
858 GTK_RUN_LAST,
859 GTK_CLASS_TYPE(object_class),
860 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
861 gtkextra_VOID__INT_INT,
862 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
864 sheet_signals[NEW_ROW_HEIGHT] =
865 gtk_signal_new ("new_row_height",
866 GTK_RUN_LAST,
867 GTK_CLASS_TYPE(object_class),
868 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
869 gtkextra_VOID__INT_INT,
870 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
874 widget_class->set_scroll_adjustments_signal =
875 gtk_signal_new ("set_scroll_adjustments",
876 GTK_RUN_LAST,
877 GTK_CLASS_TYPE(object_class),
878 GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
879 gtkextra_VOID__OBJECT_OBJECT,
880 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
883 container_class->add = NULL;
884 container_class->remove = gtk_sheet_remove;
885 container_class->forall = gtk_sheet_forall;
887 object_class->destroy = gtk_sheet_destroy;
888 gobject_class->finalize = gtk_sheet_finalize;
890 widget_class->realize = gtk_sheet_realize;
891 widget_class->unrealize = gtk_sheet_unrealize;
892 widget_class->map = gtk_sheet_map;
893 widget_class->unmap = gtk_sheet_unmap;
894 widget_class->style_set = gtk_sheet_style_set;
895 widget_class->button_press_event = gtk_sheet_button_press;
896 widget_class->button_release_event = gtk_sheet_button_release;
897 widget_class->motion_notify_event = gtk_sheet_motion;
898 widget_class->key_press_event = gtk_sheet_key_press;
899 widget_class->expose_event = gtk_sheet_expose;
900 widget_class->size_request = gtk_sheet_size_request;
901 widget_class->size_allocate = gtk_sheet_size_allocate;
902 widget_class->focus_in_event = NULL;
903 widget_class->focus_out_event = NULL;
905 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
906 klass->select_row = NULL;
907 klass->select_column = NULL;
908 klass->select_range = NULL;
909 klass->clip_range = NULL;
910 klass->resize_range = NULL;
911 klass->move_range = NULL;
912 klass->traverse = NULL;
913 klass->deactivate = NULL;
914 klass->activate = NULL;
915 klass->set_cell = NULL;
916 klass->clear_cell = NULL;
917 klass->changed = NULL;
919 gtk_widget_class_install_style_property (widget_class,
920 g_param_spec_boxed ("default-border",
921 NULL, /* P_("Default Spacing"),*/
922 NULL, /* P_("Extra space to add for CAN_DEFAULT buttons"), */
923 GTK_TYPE_BORDER,
924 G_PARAM_READABLE));
926 gtk_widget_class_install_style_property (widget_class,
927 g_param_spec_boxed ("default-outside-border",
928 NULL, /* P_("Default Outside Spacing"), */
929 NULL, /* P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"), */
930 GTK_TYPE_BORDER,
931 G_PARAM_READABLE));
934 static void
935 gtk_sheet_init (GtkSheet *sheet)
937 sheet->children = NULL;
939 sheet->flags = 0;
940 sheet->selection_mode = GTK_SELECTION_BROWSE;
941 sheet->freeze_count = 0;
942 sheet->state = GTK_SHEET_NORMAL;
944 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
945 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
947 sheet->maxrow = 0;
948 sheet->maxcol = 0;
950 sheet->view.row0 = 0;
951 sheet->view.col0 = 0;
952 sheet->view.rowi = 0;
953 sheet->view.coli = 0;
955 sheet->maxallocrow = 0;
956 sheet->maxalloccol = 0;
958 sheet->column_title_window=NULL;
959 sheet->column_title_area.x=0;
960 sheet->column_title_area.y=0;
961 sheet->column_title_area.width=0;
962 sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
964 sheet->row_title_window=NULL;
965 sheet->row_title_area.x=0;
966 sheet->row_title_area.y=0;
967 sheet->row_title_area.width=DEFAULT_COLUMN_WIDTH;
968 sheet->row_title_area.height=0;
970 sheet->active_cell.row=0;
971 sheet->active_cell.col=0;
972 sheet->selection_cell.row=0;
973 sheet->selection_cell.col=0;
975 sheet->sheet_entry=NULL;
976 sheet->pixmap=NULL;
978 sheet->range.row0=0;
979 sheet->range.rowi=0;
980 sheet->range.col0=0;
981 sheet->range.coli=0;
983 sheet->state=GTK_SHEET_NORMAL;
985 sheet->sheet_window = NULL;
986 sheet->sheet_window_width = 0;
987 sheet->sheet_window_height = 0;
988 sheet->sheet_entry = NULL;
989 sheet->button = NULL;
991 sheet->hoffset = 0;
992 sheet->voffset = 0;
994 sheet->hadjustment = NULL;
995 sheet->vadjustment = NULL;
997 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
998 sheet->xor_gc = NULL;
999 sheet->fg_gc = NULL;
1000 sheet->bg_gc = NULL;
1001 sheet->x_drag = 0;
1002 sheet->y_drag = 0;
1004 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
1005 gdk_color_parse("gray", &sheet->grid_color);
1006 gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
1007 sheet->show_grid = TRUE;
1010 GtkWidget *
1011 gtk_sheet_new (guint rows, guint columns, const gchar *title)
1013 GtkWidget *widget;
1015 /* sanity check */
1016 g_return_val_if_fail (columns >= MINCOLS, NULL);
1017 g_return_val_if_fail (rows >= MINROWS, NULL);
1019 widget = gtk_type_new (gtk_sheet_get_type ());
1021 gtk_sheet_construct(GTK_SHEET(widget), rows, columns, title);
1023 return widget;
1026 void
1027 gtk_sheet_construct (GtkSheet *sheet, guint rows, guint columns, const gchar *title)
1029 sheet->row=(GtkSheetRow *)g_malloc(sizeof(GtkSheetRow));
1030 sheet->column=(GtkSheetColumn *)g_malloc(sizeof(GtkSheetColumn));
1031 sheet->data=(GtkSheetCell ***)g_malloc(sizeof(GtkSheetCell **));
1033 sheet->data[0] = (GtkSheetCell **)g_malloc(sizeof(GtkSheetCell *)+sizeof(gdouble));
1034 sheet->data[0][0] = NULL;
1036 sheet->columns_resizable = TRUE;
1037 sheet->rows_resizable = TRUE;
1038 sheet->row_titles_visible = TRUE;
1039 sheet->column_titles_visible = TRUE;
1040 sheet->autoscroll = TRUE;
1041 sheet->justify_entry = TRUE;
1042 sheet->locked = FALSE;
1044 /* set number of rows and columns */
1045 GrowSheet(sheet, MINROWS, MINCOLS);
1047 /* Init row an column zero */
1048 AddRow(sheet,-1);
1049 AddColumn(sheet,-1);
1051 /* Add rows and columns */
1052 AddRow(sheet,rows-1);
1053 AddColumn(sheet,columns-1);
1055 /* create sheet entry */
1056 sheet->entry_type = 0;
1057 create_sheet_entry (sheet);
1059 /* create global selection button */
1060 create_global_button(sheet);
1062 if(title)
1063 sheet->name = g_strdup(title);
1068 GtkWidget *
1069 gtk_sheet_new_browser(guint rows, guint columns, const gchar *title)
1071 GtkWidget *widget;
1073 widget = gtk_type_new (gtk_sheet_get_type ());
1075 gtk_sheet_construct_browser(GTK_SHEET(widget), rows, columns, title);
1077 return widget;
1080 void
1081 gtk_sheet_construct_browser(GtkSheet *sheet, guint rows, guint columns,
1082 const gchar *title)
1084 gtk_sheet_construct(sheet, rows, columns, title);
1086 gtk_sheet_set_locked(sheet, TRUE);
1087 sheet->autoresize = TRUE;
1090 GtkWidget *
1091 gtk_sheet_new_with_custom_entry (guint rows, guint columns, const gchar *title,
1092 GtkType entry_type)
1094 GtkWidget *widget;
1096 widget = gtk_type_new (gtk_sheet_get_type ());
1098 gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget),
1099 rows, columns, title, entry_type);
1101 return widget;
1104 void
1105 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
1106 guint rows, guint columns,
1107 const gchar *title,
1108 GtkType entry_type)
1110 gtk_sheet_construct(sheet, rows, columns, title);
1112 sheet->entry_type = entry_type;
1113 create_sheet_entry(sheet);
1117 void
1118 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
1120 gint state;
1122 g_return_if_fail (sheet != NULL);
1123 g_return_if_fail (GTK_IS_SHEET (sheet));
1125 state = sheet->state;
1127 if(sheet->state == GTK_SHEET_NORMAL)
1128 gtk_sheet_hide_active_cell(sheet);
1130 sheet->entry_type = entry_type;
1132 create_sheet_entry(sheet);
1134 if(state == GTK_SHEET_NORMAL)
1136 gtk_sheet_show_active_cell(sheet);
1137 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1138 "changed",
1139 (GtkSignalFunc)gtk_sheet_entry_changed,
1140 GTK_OBJECT(GTK_WIDGET(sheet)));
1145 void
1146 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
1148 g_return_if_fail (sheet != NULL);
1149 g_return_if_fail (GTK_IS_SHEET (sheet));
1151 if(show == sheet->show_grid) return;
1153 sheet->show_grid = show;
1155 if(!GTK_SHEET_IS_FROZEN(sheet))
1156 gtk_sheet_range_draw(sheet, NULL);
1159 gboolean
1160 gtk_sheet_grid_visible(GtkSheet *sheet)
1162 g_return_val_if_fail (sheet != NULL, 0);
1163 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1165 return sheet->show_grid;
1168 void
1169 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
1171 g_return_if_fail (sheet != NULL);
1172 g_return_if_fail (GTK_IS_SHEET (sheet));
1174 if(!color)
1175 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
1176 else
1177 sheet->bg_color = *color;
1179 if(!GTK_SHEET_IS_FROZEN(sheet))
1180 gtk_sheet_range_draw(sheet, NULL);
1183 void
1184 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
1186 g_return_if_fail (sheet != NULL);
1187 g_return_if_fail (GTK_IS_SHEET (sheet));
1189 if(!color)
1190 gdk_color_black(gdk_colormap_get_system(), &sheet->grid_color);
1191 else
1192 sheet->grid_color = *color;
1194 if(!GTK_SHEET_IS_FROZEN(sheet))
1195 gtk_sheet_range_draw(sheet, NULL);
1198 guint
1199 gtk_sheet_get_columns_count(GtkSheet *sheet)
1201 g_return_val_if_fail (sheet != NULL, 0);
1202 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1204 return sheet->maxcol + 1;
1207 guint
1208 gtk_sheet_get_rows_count(GtkSheet *sheet)
1210 g_return_val_if_fail (sheet != NULL, 0);
1211 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1213 return sheet->maxrow + 1;
1216 gint
1217 gtk_sheet_get_state(GtkSheet *sheet)
1219 g_return_val_if_fail (sheet != NULL, 0);
1220 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1222 return (sheet->state);
1225 void
1226 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
1228 g_return_if_fail (sheet != NULL);
1229 g_return_if_fail (GTK_IS_SHEET (sheet));
1231 if(GTK_WIDGET_REALIZED(sheet))
1232 gtk_sheet_real_unselect_range(sheet, NULL);
1234 sheet->selection_mode = mode;
1237 void
1238 gtk_sheet_set_autoresize (GtkSheet *sheet, gboolean autoresize)
1240 g_return_if_fail (sheet != NULL);
1241 g_return_if_fail (GTK_IS_SHEET (sheet));
1243 sheet->autoresize = autoresize;
1246 gboolean
1247 gtk_sheet_autoresize (GtkSheet *sheet)
1249 g_return_val_if_fail (sheet != NULL, FALSE);
1250 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1252 return sheet->autoresize;
1255 void
1256 gtk_sheet_set_autoscroll (GtkSheet *sheet, gboolean autoscroll)
1258 g_return_if_fail (sheet != NULL);
1259 g_return_if_fail (GTK_IS_SHEET (sheet));
1261 sheet->autoscroll = autoscroll;
1264 gboolean
1265 gtk_sheet_autoscroll (GtkSheet *sheet)
1267 g_return_val_if_fail (sheet != NULL, FALSE);
1268 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1270 return sheet->autoscroll;
1273 void
1274 gtk_sheet_set_clip_text (GtkSheet *sheet, gboolean clip_text)
1276 g_return_if_fail (sheet != NULL);
1277 g_return_if_fail (GTK_IS_SHEET (sheet));
1279 sheet->clip_text = clip_text;
1282 gboolean
1283 gtk_sheet_clip_text (GtkSheet *sheet)
1285 g_return_val_if_fail (sheet != NULL, FALSE);
1286 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1288 return sheet->clip_text;
1291 void
1292 gtk_sheet_set_justify_entry (GtkSheet *sheet, gboolean justify)
1294 g_return_if_fail (sheet != NULL);
1295 g_return_if_fail (GTK_IS_SHEET (sheet));
1297 sheet->justify_entry = justify;
1300 gboolean
1301 gtk_sheet_justify_entry (GtkSheet *sheet)
1303 g_return_val_if_fail (sheet != NULL, FALSE);
1304 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1306 return sheet->justify_entry;
1309 void
1310 gtk_sheet_set_locked (GtkSheet *sheet, gboolean locked)
1312 g_return_if_fail (sheet != NULL);
1313 g_return_if_fail (GTK_IS_SHEET (sheet));
1315 sheet->locked = locked;
1318 gboolean
1319 gtk_sheet_locked (GtkSheet *sheet)
1321 g_return_val_if_fail (sheet != NULL, FALSE);
1322 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1324 return sheet->locked;
1327 /* This routine has problems with gtk+-1.2 related with the
1328 * label/button drawing - I think it's a bug in gtk+-1.2 */
1330 void
1331 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
1333 /* GtkWidget *old_widget;
1334 */ GtkWidget *label;
1336 g_return_if_fail (sheet != NULL);
1337 g_return_if_fail (title != NULL);
1338 g_return_if_fail (GTK_IS_SHEET (sheet));
1340 if (sheet->name)
1341 g_free (sheet->name);
1343 sheet->name = g_strdup (title);
1345 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
1347 if(GTK_BIN(sheet->button)->child)
1348 label = GTK_BIN(sheet->button)->child;
1350 gtk_label_set_text(GTK_LABEL(label), title);
1352 size_allocate_global_button(sheet);
1354 /* remove and destroy the old widget */
1356 old_widget = GTK_BIN (sheet->button)->child;
1357 if (old_widget)
1359 gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
1362 label = gtk_label_new (title);
1363 gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
1365 gtk_container_add (GTK_CONTAINER (sheet->button), label);
1366 gtk_widget_show (label);
1368 size_allocate_global_button(sheet);
1370 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
1372 if(old_widget)
1373 gtk_widget_destroy (old_widget);
1377 void
1378 gtk_sheet_freeze (GtkSheet *sheet)
1380 g_return_if_fail (sheet != NULL);
1381 g_return_if_fail (GTK_IS_SHEET (sheet));
1383 sheet->freeze_count++;
1384 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1387 void
1388 gtk_sheet_thaw(GtkSheet *sheet)
1390 g_return_if_fail (sheet != NULL);
1391 g_return_if_fail (GTK_IS_SHEET (sheet));
1393 if(sheet->freeze_count == 0) return;
1395 sheet->freeze_count--;
1396 if(sheet->freeze_count > 0) return;
1398 adjust_scrollbars(sheet);
1400 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1402 sheet->old_vadjustment = -1.;
1403 sheet->old_hadjustment = -1.;
1405 if(sheet->hadjustment)
1406 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1407 "value_changed");
1408 if(sheet->vadjustment)
1409 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1410 "value_changed");
1412 if(sheet->state == GTK_STATE_NORMAL)
1413 if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
1414 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
1416 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1417 "changed",
1418 (GtkSignalFunc)gtk_sheet_entry_changed,
1419 GTK_OBJECT(GTK_WIDGET(sheet)));
1420 gtk_sheet_show_active_cell(sheet);
1426 void
1427 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
1429 if(width < COLUMN_MIN_WIDTH) return;
1431 sheet->row_title_area.width = width;
1432 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
1433 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1434 gtk_sheet_recalc_top_ypixels(sheet, 0);
1435 gtk_sheet_recalc_left_xpixels(sheet, 0);
1436 adjust_scrollbars(sheet);
1438 sheet->old_hadjustment = -1.;
1439 if(sheet->hadjustment)
1440 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1441 "value_changed");
1442 size_allocate_global_button(sheet);
1445 void
1446 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
1448 if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
1450 sheet->column_title_area.height = height;
1451 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
1452 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
1453 gtk_sheet_recalc_top_ypixels(sheet, 0);
1454 gtk_sheet_recalc_left_xpixels(sheet, 0);
1455 adjust_scrollbars(sheet);
1457 sheet->old_vadjustment = -1.;
1458 if(sheet->vadjustment)
1459 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1460 "value_changed");
1461 size_allocate_global_button(sheet);
1464 void
1465 gtk_sheet_show_column_titles(GtkSheet *sheet)
1467 gint col;
1469 if(sheet->column_titles_visible) return;
1471 sheet->column_titles_visible = TRUE;
1472 gtk_sheet_recalc_top_ypixels(sheet, 0);
1473 gtk_sheet_recalc_left_xpixels(sheet, 0);
1474 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1475 gdk_window_show(sheet->column_title_window);
1476 gdk_window_move_resize (sheet->column_title_window,
1477 sheet->column_title_area.x,
1478 sheet->column_title_area.y,
1479 sheet->column_title_area.width,
1480 sheet->column_title_area.height);
1482 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1483 GtkSheetChild *child;
1484 child = sheet->column[col].button.child;
1485 if(child){
1486 gtk_sheet_child_show(child);
1489 adjust_scrollbars(sheet);
1492 sheet->old_vadjustment = -1.;
1493 if(sheet->vadjustment)
1494 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1495 "value_changed");
1496 size_allocate_global_button(sheet);
1499 void
1500 gtk_sheet_show_row_titles(GtkSheet *sheet)
1502 gint row;
1504 if(sheet->row_titles_visible) return;
1506 sheet->row_titles_visible = TRUE;
1507 gtk_sheet_recalc_top_ypixels(sheet, 0);
1508 gtk_sheet_recalc_left_xpixels(sheet, 0);
1509 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1510 gdk_window_show(sheet->row_title_window);
1511 gdk_window_move_resize (sheet->row_title_window,
1512 sheet->row_title_area.x,
1513 sheet->row_title_area.y,
1514 sheet->row_title_area.width,
1515 sheet->row_title_area.height);
1517 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1518 GtkSheetChild *child;
1519 child = sheet->row[row].button.child;
1520 if(child){
1521 gtk_sheet_child_show(child);
1524 adjust_scrollbars(sheet);
1527 sheet->old_hadjustment = -1.;
1528 if(sheet->hadjustment)
1529 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1530 "value_changed");
1531 size_allocate_global_button(sheet);
1534 void
1535 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1537 gint col;
1539 if(!sheet->column_titles_visible) return;
1541 sheet->column_titles_visible = FALSE;
1542 gtk_sheet_recalc_top_ypixels(sheet, 0);
1543 gtk_sheet_recalc_left_xpixels(sheet, 0);
1544 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1545 if(sheet->column_title_window)
1546 gdk_window_hide(sheet->column_title_window);
1547 if(GTK_WIDGET_VISIBLE(sheet->button))
1548 gtk_widget_hide(sheet->button);
1550 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1551 GtkSheetChild *child;
1552 child = sheet->column[col].button.child;
1553 if(child){
1554 gtk_sheet_child_hide(child);
1557 adjust_scrollbars(sheet);
1560 sheet->old_vadjustment = -1.;
1561 if(sheet->vadjustment)
1562 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1563 "value_changed");
1566 void
1567 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1569 gint row;
1571 if(!sheet->row_titles_visible) return;
1573 sheet->row_titles_visible = FALSE;
1574 gtk_sheet_recalc_top_ypixels(sheet, 0);
1575 gtk_sheet_recalc_left_xpixels(sheet, 0);
1576 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1577 if(sheet->row_title_window)
1578 gdk_window_hide(sheet->row_title_window);
1579 if(GTK_WIDGET_VISIBLE(sheet->button))
1580 gtk_widget_hide(sheet->button);
1581 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1582 GtkSheetChild *child;
1583 child = sheet->row[row].button.child;
1584 if(child){
1585 gtk_sheet_child_hide(child);
1588 adjust_scrollbars(sheet);
1591 sheet->old_hadjustment = -1.;
1592 if(sheet->hadjustment)
1593 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1594 "value_changed");
1597 gboolean
1598 gtk_sheet_column_titles_visible(GtkSheet *sheet)
1600 g_return_val_if_fail (sheet != NULL, FALSE);
1601 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1602 return sheet->column_titles_visible;
1605 gboolean
1606 gtk_sheet_row_titles_visible(GtkSheet *sheet)
1608 g_return_val_if_fail (sheet != NULL, FALSE);
1609 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1610 return sheet->row_titles_visible;
1613 void
1614 gtk_sheet_set_column_title (GtkSheet * sheet,
1615 gint column,
1616 const gchar * title)
1618 g_return_if_fail (sheet != NULL);
1619 g_return_if_fail (GTK_IS_SHEET (sheet));
1621 if (sheet->column[column].name)
1622 g_free (sheet->column[column].name);
1624 sheet->column[column].name = g_strdup(title);
1627 void
1628 gtk_sheet_set_row_title (GtkSheet * sheet,
1629 gint row,
1630 const gchar * title)
1632 g_return_if_fail (sheet != NULL);
1633 g_return_if_fail (GTK_IS_SHEET (sheet));
1635 if (sheet->row[row].name)
1636 g_free (sheet->row[row].name);
1638 sheet->row[row].name = g_strdup (title);
1641 const gchar *
1642 gtk_sheet_get_row_title (GtkSheet * sheet,
1643 gint row)
1645 g_return_val_if_fail (sheet != NULL, NULL);
1646 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1648 return(sheet->row[row].name);
1651 const gchar *
1652 gtk_sheet_get_column_title (GtkSheet * sheet,
1653 gint column)
1655 g_return_val_if_fail (sheet != NULL, NULL);
1656 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1658 return(sheet->column[column].name);
1661 void
1662 gtk_sheet_row_button_add_label(GtkSheet *sheet, gint row, const gchar *label)
1664 GtkSheetButton *button;
1665 GtkRequisition req;
1666 gboolean aux;
1668 g_return_if_fail (sheet != NULL);
1669 g_return_if_fail (GTK_IS_SHEET (sheet));
1671 if(row < 0 || row > sheet->maxrow) return;
1673 button = &sheet->row[row].button;
1674 if (button->label) g_free (button->label);
1675 button->label = g_strdup (label);
1677 aux = gtk_sheet_autoresize(sheet);
1678 gtk_sheet_set_autoresize(sheet, TRUE);
1679 gtk_sheet_button_size_request(sheet, button, &req);
1680 gtk_sheet_set_autoresize(sheet, aux);
1682 if(req.height > sheet->row[row].height)
1683 gtk_sheet_set_row_height(sheet, row, req.height);
1685 if(req.width > sheet->row_title_area.width){
1686 gtk_sheet_set_row_titles_width(sheet, req.width);
1689 if(!GTK_SHEET_IS_FROZEN(sheet)){
1690 gtk_sheet_button_draw(sheet, row, -1);
1691 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1695 const gchar *
1696 gtk_sheet_row_button_get_label(GtkSheet *sheet, gint row)
1698 g_return_val_if_fail (sheet != NULL, NULL);
1699 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1701 if(row < 0 || row > sheet->maxrow) return NULL;
1703 return (sheet->row[row].button.label);
1706 void
1707 gtk_sheet_row_label_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
1709 g_return_if_fail (sheet != NULL);
1710 g_return_if_fail (GTK_IS_SHEET (sheet));
1712 if(row < 0 || row > sheet->maxrow) return;
1714 sheet->row[row].button.label_visible = visible;
1716 if(!GTK_SHEET_IS_FROZEN(sheet)){
1717 gtk_sheet_button_draw(sheet, row, -1);
1718 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1722 void
1723 gtk_sheet_rows_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1725 gint i;
1727 g_return_if_fail (sheet != NULL);
1728 g_return_if_fail (GTK_IS_SHEET (sheet));
1730 for(i = 0; i <= sheet->maxrow; i++)
1731 gtk_sheet_row_label_set_visibility(sheet, i, visible);
1735 void
1736 gtk_sheet_column_button_add_label(GtkSheet *sheet, gint column, const gchar *label)
1738 GtkSheetButton *button;
1739 GtkRequisition req;
1740 gboolean aux;
1742 g_return_if_fail (sheet != NULL);
1743 g_return_if_fail (GTK_IS_SHEET (sheet));
1745 if(column < 0 || column >sheet->maxcol) return;
1747 button = &sheet->column[column].button;
1748 if (button->label) g_free (button->label);
1749 button->label = g_strdup (label);
1751 aux = gtk_sheet_autoresize(sheet);
1752 gtk_sheet_set_autoresize(sheet, TRUE);
1753 gtk_sheet_button_size_request(sheet, button, &req);
1754 gtk_sheet_set_autoresize(sheet, aux);
1756 if(req.width > sheet->column[column].width)
1757 gtk_sheet_set_column_width(sheet, column, req.width);
1759 if(req.height > sheet->column_title_area.height)
1760 gtk_sheet_set_column_titles_height(sheet, req.height);
1762 if(!GTK_SHEET_IS_FROZEN(sheet)){
1763 gtk_sheet_button_draw(sheet, -1, column);
1764 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1768 const gchar *
1769 gtk_sheet_column_button_get_label(GtkSheet *sheet, gint column)
1771 g_return_val_if_fail (sheet != NULL, NULL);
1772 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
1774 if(column < 0 || column >sheet->maxcol) return NULL;
1776 return(sheet->column[column].button.label);
1779 void
1780 gtk_sheet_column_label_set_visibility(GtkSheet *sheet, gint col, gboolean visible)
1782 g_return_if_fail (sheet != NULL);
1783 g_return_if_fail (GTK_IS_SHEET (sheet));
1785 if(col < 0 || col > sheet->maxcol) return;
1787 sheet->column[col].button.label_visible = visible;
1789 if(!GTK_SHEET_IS_FROZEN(sheet)){
1790 gtk_sheet_button_draw(sheet, -1, col);
1791 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, col);
1795 void
1796 gtk_sheet_columns_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1798 gint i;
1800 g_return_if_fail (sheet != NULL);
1801 g_return_if_fail (GTK_IS_SHEET (sheet));
1803 for(i = 0; i <= sheet->maxcol; i++)
1804 gtk_sheet_column_label_set_visibility(sheet, i, visible);
1807 void
1808 gtk_sheet_row_button_justify(GtkSheet *sheet, gint row,
1809 GtkJustification justification)
1811 GtkSheetButton *button;
1813 g_return_if_fail (sheet != NULL);
1814 g_return_if_fail (GTK_IS_SHEET (sheet));
1816 if(row < 0 || row > sheet->maxrow) return;
1818 button = &sheet->row[row].button;
1819 button->justification = justification;
1821 if(!GTK_SHEET_IS_FROZEN(sheet)){
1822 gtk_sheet_button_draw(sheet, row, -1);
1823 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1827 void
1828 gtk_sheet_column_button_justify(GtkSheet *sheet, gint column,
1829 GtkJustification justification)
1831 GtkSheetButton *button;
1833 g_return_if_fail (sheet != NULL);
1834 g_return_if_fail (GTK_IS_SHEET (sheet));
1836 if(column < 0 || column > sheet->maxcol) return;
1838 button = &sheet->column[column].button;
1839 button->justification = justification;
1841 if(!GTK_SHEET_IS_FROZEN(sheet)){
1842 gtk_sheet_button_draw(sheet, -1, column);
1843 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1848 void
1849 gtk_sheet_moveto (GtkSheet * sheet,
1850 gint row,
1851 gint column,
1852 gfloat row_align,
1853 gfloat col_align)
1855 gint x, y;
1856 guint width, height;
1857 gint adjust;
1858 gint min_row, min_col;
1860 g_return_if_fail (sheet != NULL);
1861 g_return_if_fail (GTK_IS_SHEET (sheet));
1862 g_return_if_fail (sheet->hadjustment != NULL);
1863 g_return_if_fail (sheet->vadjustment != NULL);
1865 if (row < 0 || row > sheet->maxrow)
1866 return;
1867 if (column < 0 || column > sheet->maxcol)
1868 return;
1870 height = sheet->sheet_window_height;
1871 width = sheet->sheet_window_width;
1873 /* adjust vertical scrollbar */
1875 if (row >= 0 && row_align >=0.)
1877 y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
1878 row_align*height-
1879 (1.-row_align)*sheet->row[row].height;
1881 /* This forces the sheet to scroll when you don't see the entire cell */
1882 min_row = row;
1883 adjust = 0;
1884 if(row_align == 1.){
1885 while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
1886 if(sheet->row[min_row].is_visible)
1887 adjust += sheet->row[min_row].height;
1888 if(adjust >= height){
1889 break;
1891 min_row--;
1893 min_row = MAX(min_row, 0);
1894 y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
1895 sheet->row[min_row].height - 1;
1898 if (y < 0)
1899 sheet->vadjustment->value = 0.0;
1900 else
1901 sheet->vadjustment->value = y;
1903 sheet->old_vadjustment = -1.;
1904 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1905 "value_changed");
1909 /* adjust horizontal scrollbar */
1910 if (column >= 0 && col_align >= 0.)
1912 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
1913 col_align*width -
1914 (1.-col_align)*sheet->column[column].width;
1916 /* This forces the sheet to scroll when you don't see the entire cell */
1917 min_col = column;
1918 adjust = 0;
1919 if(col_align == 1.){
1920 while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
1921 if(sheet->column[min_col].is_visible)
1922 adjust += sheet->column[min_col].width;
1923 if(adjust >= width){
1924 break;
1926 min_col--;
1928 min_col = MAX(min_col, 0);
1929 x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
1930 sheet->column[min_col].width - 1;
1933 if (x < 0)
1934 sheet->hadjustment->value = 0.0;
1935 else
1936 sheet->hadjustment->value = x;
1938 sheet->old_vadjustment = -1.;
1939 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1940 "value_changed");
1945 void
1946 gtk_sheet_column_set_sensitivity(GtkSheet *sheet, gint column, gboolean sensitive)
1948 g_return_if_fail (sheet != NULL);
1949 g_return_if_fail (GTK_IS_SHEET (sheet));
1951 if(column < 0 || column > sheet->maxcol) return;
1953 sheet->column[column].is_sensitive=sensitive;
1954 if(!sensitive)
1955 sheet->column[column].button.state=GTK_STATE_INSENSITIVE;
1956 else
1957 sheet->column[column].button.state=GTK_STATE_NORMAL;
1959 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
1960 gtk_sheet_button_draw(sheet, -1, column);
1964 void
1965 gtk_sheet_columns_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
1967 gint i;
1969 g_return_if_fail (sheet != NULL);
1970 g_return_if_fail (GTK_IS_SHEET (sheet));
1972 for(i=0; i<=sheet->maxcol; i++)
1973 gtk_sheet_column_set_sensitivity(sheet, i, sensitive);
1976 void
1977 gtk_sheet_columns_set_resizable (GtkSheet *sheet, gboolean resizable)
1979 g_return_if_fail (sheet != NULL);
1980 g_return_if_fail (GTK_IS_SHEET (sheet));
1982 sheet->columns_resizable = resizable;
1985 gboolean
1986 gtk_sheet_columns_resizable (GtkSheet *sheet)
1988 g_return_val_if_fail (sheet != NULL, FALSE);
1989 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
1991 return sheet->columns_resizable;
1994 void
1995 gtk_sheet_row_set_sensitivity(GtkSheet *sheet, gint row, gboolean sensitive)
1998 g_return_if_fail (sheet != NULL);
1999 g_return_if_fail (GTK_IS_SHEET (sheet));
2001 if(row < 0 || row > sheet->maxrow) return;
2003 sheet->row[row].is_sensitive=sensitive;
2004 if(!sensitive)
2005 sheet->row[row].button.state=GTK_STATE_INSENSITIVE;
2006 else
2007 sheet->row[row].button.state=GTK_STATE_NORMAL;
2009 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
2010 gtk_sheet_button_draw(sheet, row, -1);
2013 void
2014 gtk_sheet_rows_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
2016 gint i;
2018 g_return_if_fail (sheet != NULL);
2019 g_return_if_fail (GTK_IS_SHEET (sheet));
2021 for(i=0; i<=sheet->maxrow; i++)
2022 gtk_sheet_row_set_sensitivity(sheet, i, sensitive);
2026 void
2027 gtk_sheet_rows_set_resizable (GtkSheet *sheet, gboolean resizable)
2029 g_return_if_fail (sheet != NULL);
2030 g_return_if_fail (GTK_IS_SHEET (sheet));
2032 sheet->rows_resizable = resizable;
2035 gboolean
2036 gtk_sheet_rows_resizable (GtkSheet *sheet)
2038 g_return_val_if_fail (sheet != NULL, FALSE);
2039 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2041 return sheet->rows_resizable;
2044 void
2045 gtk_sheet_column_set_visibility(GtkSheet *sheet, gint column, gboolean visible)
2047 g_return_if_fail (sheet != NULL);
2048 g_return_if_fail (GTK_IS_SHEET (sheet));
2050 if(column < 0 || column > sheet->maxcol) return;
2051 if(sheet->column[column].is_visible == visible) return;
2053 sheet->column[column].is_visible = visible;
2055 gtk_sheet_recalc_left_xpixels(sheet, column);
2057 if(!GTK_SHEET_IS_FROZEN(sheet) &&
2058 gtk_sheet_cell_isvisible(sheet, MIN_VISIBLE_ROW(sheet), column)){
2059 gtk_sheet_range_draw(sheet, NULL);
2060 size_allocate_column_title_buttons(sheet);
2064 void
2065 gtk_sheet_row_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
2067 g_return_if_fail (sheet != NULL);
2068 g_return_if_fail (GTK_IS_SHEET (sheet));
2070 if(row < 0 || row > sheet->maxrow) return;
2071 if(sheet->row[row].is_visible == visible) return;
2073 sheet->row[row].is_visible = visible;
2075 gtk_sheet_recalc_top_ypixels(sheet, row);
2077 if(!GTK_SHEET_IS_FROZEN(sheet) &&
2078 gtk_sheet_cell_isvisible(sheet, row, MIN_VISIBLE_COLUMN(sheet))){
2079 gtk_sheet_range_draw(sheet, NULL);
2080 size_allocate_row_title_buttons(sheet);
2084 void
2085 gtk_sheet_select_row (GtkSheet * sheet,
2086 gint row)
2088 g_return_if_fail (sheet != NULL);
2089 g_return_if_fail (GTK_IS_SHEET (sheet));
2091 if (row < 0 || row > sheet->maxrow)
2092 return;
2094 if(sheet->state != GTK_SHEET_NORMAL)
2095 gtk_sheet_real_unselect_range(sheet, NULL);
2096 else
2098 gboolean veto = TRUE;
2099 veto = gtk_sheet_deactivate_cell(sheet);
2100 if(!veto) return;
2103 sheet->state=GTK_SHEET_ROW_SELECTED;
2104 sheet->range.row0=row;
2105 sheet->range.col0=0;
2106 sheet->range.rowi=row;
2107 sheet->range.coli=sheet->maxcol;
2108 sheet->active_cell.row=row;
2109 sheet->active_cell.col=0;
2111 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
2112 gtk_sheet_real_select_range(sheet, NULL);
2117 void
2118 gtk_sheet_select_column (GtkSheet * sheet,
2119 gint column)
2122 g_return_if_fail (sheet != NULL);
2123 g_return_if_fail (GTK_IS_SHEET (sheet));
2125 if (column < 0 || column > sheet->maxcol)
2126 return;
2128 if(sheet->state != GTK_SHEET_NORMAL)
2129 gtk_sheet_real_unselect_range(sheet, NULL);
2130 else
2132 gboolean veto = TRUE;
2133 veto = gtk_sheet_deactivate_cell(sheet);
2134 if(!veto) return;
2137 sheet->state=GTK_SHEET_COLUMN_SELECTED;
2138 sheet->range.row0=0;
2139 sheet->range.col0=column;
2140 sheet->range.rowi=sheet->maxrow;
2141 sheet->range.coli=column;
2142 sheet->active_cell.row=0;
2143 sheet->active_cell.col=column;
2145 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
2146 gtk_sheet_real_select_range(sheet, NULL);
2150 void
2151 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
2154 g_return_if_fail (sheet != NULL);
2155 g_return_if_fail (GTK_IS_SHEET (sheet));
2157 if(GTK_SHEET_IN_CLIP(sheet)) return;
2159 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2161 if(range == NULL)
2162 sheet->clip_range = sheet->range;
2163 else
2164 sheet->clip_range=*range;
2166 sheet->interval=0;
2167 sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, sheet);
2169 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
2170 &sheet->clip_range);
2174 void
2175 gtk_sheet_unclip_range(GtkSheet *sheet)
2178 g_return_if_fail (sheet != NULL);
2179 g_return_if_fail (GTK_IS_SHEET (sheet));
2181 if(!GTK_SHEET_IN_CLIP(sheet)) return;
2183 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
2184 gtk_timeout_remove(sheet->clip_timer);
2185 gtk_sheet_range_draw(sheet, &sheet->clip_range);
2187 if(gtk_sheet_range_isvisible(sheet, sheet->range))
2188 gtk_sheet_range_draw(sheet, &sheet->range);
2191 gboolean
2192 gtk_sheet_in_clip (GtkSheet *sheet)
2194 g_return_val_if_fail (sheet != NULL, FALSE);
2195 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
2197 return GTK_SHEET_IN_CLIP(sheet);
2200 static gint
2201 gtk_sheet_flash(gpointer data)
2203 GtkSheet *sheet;
2204 gint x,y,width,height;
2205 GdkRectangle clip_area;
2207 sheet=GTK_SHEET(data);
2209 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
2210 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
2211 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
2212 if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE;
2213 if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE;
2215 GDK_THREADS_ENTER();
2217 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2218 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2219 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2220 sheet->column[sheet->clip_range.coli].width-1;
2221 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2222 sheet->row[sheet->clip_range.rowi].height-1;
2224 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2225 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2226 clip_area.width=sheet->sheet_window_width;
2227 clip_area.height=sheet->sheet_window_height;
2229 if(x<0) {
2230 width=width+x+1;
2231 x=-1;
2233 if(width>clip_area.width) width=clip_area.width+10;
2234 if(y<0) {
2235 height=height+y+1;
2236 y=-1;
2238 if(height>clip_area.height) height=clip_area.height+10;
2240 gdk_draw_pixmap(sheet->sheet_window,
2241 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2242 sheet->pixmap,
2243 x, y,
2244 x, y,
2245 1, height);
2247 gdk_draw_pixmap(sheet->sheet_window,
2248 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2249 sheet->pixmap,
2250 x, y,
2251 x, y,
2252 width, 1);
2254 gdk_draw_pixmap(sheet->sheet_window,
2255 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2256 sheet->pixmap,
2257 x, y+height,
2258 x, y+height,
2259 width, 1);
2261 gdk_draw_pixmap(sheet->sheet_window,
2262 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2263 sheet->pixmap,
2264 x+width, y,
2265 x+width, y,
2266 1, height);
2269 sheet->interval=sheet->interval+1;
2270 if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
2272 gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, (gint8*)"\4\4", 2);
2273 gtk_sheet_draw_flashing_range(sheet,sheet->clip_range);
2274 gdk_gc_set_dashes(sheet->xor_gc, 0, (gint8*)"\4\4", 2);
2276 GDK_THREADS_LEAVE();
2278 return TRUE;
2282 static void
2283 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
2285 GdkRectangle clip_area;
2286 gint x,y,width,height;
2288 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
2290 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
2291 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
2292 clip_area.width=sheet->sheet_window_width;
2293 clip_area.height=sheet->sheet_window_height;
2295 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
2297 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
2298 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
2299 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
2300 sheet->column[sheet->clip_range.coli].width-1;
2301 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
2302 sheet->row[sheet->clip_range.rowi].height-1;
2304 if(x<0) {
2305 width=width+x+1;
2306 x=-1;
2308 if(width>clip_area.width) width=clip_area.width+10;
2309 if(y<0) {
2310 height=height+y+1;
2311 y=-1;
2313 if(height>clip_area.height) height=clip_area.height+10;
2315 gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
2317 gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE,
2318 x, y,
2319 width, height);
2321 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
2323 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
2327 static gint
2328 gtk_sheet_range_isvisible (GtkSheet * sheet,
2329 GtkSheetRange range)
2331 g_return_val_if_fail (sheet != NULL, FALSE);
2333 if (range.row0 < 0 || range.row0 > sheet->maxrow)
2334 return FALSE;
2336 if (range.rowi < 0 || range.rowi > sheet->maxrow)
2337 return FALSE;
2339 if (range.col0 < 0 || range.col0 > sheet->maxcol)
2340 return FALSE;
2342 if (range.coli < 0 || range.coli > sheet->maxcol)
2343 return FALSE;
2345 if (range.rowi < MIN_VISIBLE_ROW (sheet))
2346 return FALSE;
2348 if (range.row0 > MAX_VISIBLE_ROW (sheet))
2349 return FALSE;
2351 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2352 return FALSE;
2354 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2355 return FALSE;
2357 return TRUE;
2360 static gint
2361 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2362 gint row, gint column)
2364 GtkSheetRange range;
2366 range.row0 = row;
2367 range.col0 = column;
2368 range.rowi = row;
2369 range.coli = column;
2371 return gtk_sheet_range_isvisible(sheet, range);
2374 void
2375 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2378 g_return_if_fail (sheet != NULL);
2379 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2380 g_return_if_fail (range != NULL);
2382 range->row0 = MIN_VISIBLE_ROW(sheet);
2383 range->col0 = MIN_VISIBLE_COLUMN(sheet);
2384 range->rowi = MAX_VISIBLE_ROW(sheet);
2385 range->coli = MAX_VISIBLE_COLUMN(sheet);
2389 GtkAdjustment *
2390 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2392 g_return_val_if_fail (sheet != NULL, NULL);
2393 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2395 return sheet->vadjustment;
2398 GtkAdjustment *
2399 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2401 g_return_val_if_fail (sheet != NULL, NULL);
2402 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2404 return sheet->hadjustment;
2407 void
2408 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2409 GtkAdjustment *adjustment)
2411 GtkAdjustment *old_adjustment;
2413 g_return_if_fail (sheet != NULL);
2414 g_return_if_fail (GTK_IS_SHEET (sheet));
2415 if (adjustment)
2416 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2418 if (sheet->vadjustment == adjustment)
2419 return;
2421 old_adjustment = sheet->vadjustment;
2423 if (sheet->vadjustment)
2425 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2426 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2429 sheet->vadjustment = adjustment;
2431 if (sheet->vadjustment)
2433 gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2434 gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2436 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2437 (GtkSignalFunc) vadjustment_changed,
2438 (gpointer) sheet);
2439 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2440 (GtkSignalFunc) vadjustment_value_changed,
2441 (gpointer) sheet);
2444 if (!sheet->vadjustment || !old_adjustment)
2446 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2447 return;
2450 sheet->old_vadjustment = sheet->vadjustment->value;
2453 void
2454 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2455 GtkAdjustment *adjustment)
2457 GtkAdjustment *old_adjustment;
2459 g_return_if_fail (sheet != NULL);
2460 g_return_if_fail (GTK_IS_SHEET (sheet));
2461 if (adjustment)
2462 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2464 if (sheet->hadjustment == adjustment)
2465 return;
2467 old_adjustment = sheet->hadjustment;
2469 if (sheet->hadjustment)
2471 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2472 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2475 sheet->hadjustment = adjustment;
2477 if (sheet->hadjustment)
2479 gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2480 gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2482 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2483 (GtkSignalFunc) hadjustment_changed,
2484 (gpointer) sheet);
2485 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2486 (GtkSignalFunc) hadjustment_value_changed,
2487 (gpointer) sheet);
2490 if (!sheet->hadjustment || !old_adjustment)
2492 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2493 return;
2496 sheet->old_hadjustment = sheet->hadjustment->value;
2499 static void
2500 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2501 GtkAdjustment *hadjustment,
2502 GtkAdjustment *vadjustment)
2504 if(sheet->hadjustment != hadjustment)
2505 gtk_sheet_set_hadjustment (sheet, hadjustment);
2506 if(sheet->vadjustment != vadjustment)
2507 gtk_sheet_set_vadjustment (sheet, vadjustment);
2510 static void
2511 gtk_sheet_finalize (GObject * object)
2513 GtkSheet *sheet;
2515 g_return_if_fail (object != NULL);
2516 g_return_if_fail (GTK_IS_SHEET (object));
2518 sheet = GTK_SHEET (object);
2520 /* get rid of all the cells */
2521 gtk_sheet_range_clear (sheet, NULL);
2522 gtk_sheet_range_delete(sheet, NULL);
2524 gtk_sheet_delete_rows (sheet, 0, sheet->maxrow + 1);
2525 gtk_sheet_delete_columns (sheet, 0, sheet->maxcol + 1);
2527 DeleteRow (sheet, 0, sheet->maxrow + 1);
2528 DeleteColumn (sheet, 0, sheet->maxcol + 1);
2530 g_free(sheet->row);
2531 sheet->row = NULL;
2532 g_free(sheet->column);
2533 sheet->column = NULL;
2534 g_free(sheet->data);
2535 sheet->data = NULL;
2537 if(sheet->name){
2538 g_free(sheet->name);
2539 sheet->name = NULL;
2542 if (G_OBJECT_CLASS (parent_class)->finalize)
2543 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
2546 static void
2547 gtk_sheet_destroy (GtkObject * object)
2549 GtkSheet *sheet;
2550 GList *children;
2552 g_return_if_fail (object != NULL);
2553 g_return_if_fail (GTK_IS_SHEET (object));
2555 sheet = GTK_SHEET (object);
2557 /* destroy the entry */
2558 if(sheet->sheet_entry && GTK_IS_WIDGET(sheet->sheet_entry)){
2559 gtk_widget_destroy (sheet->sheet_entry);
2560 sheet->sheet_entry = NULL;
2563 /* destroy the global selection button */
2564 if(sheet->button && GTK_IS_WIDGET(sheet->button)){
2565 gtk_widget_destroy (sheet->button);
2566 sheet->button = NULL;
2569 if(sheet->timer){
2570 gtk_timeout_remove(sheet->timer);
2571 sheet->timer = 0;
2574 if(sheet->clip_timer){
2575 gtk_timeout_remove(sheet->clip_timer);
2576 sheet->clip_timer = 0;
2579 /* unref adjustments */
2580 if (sheet->hadjustment)
2582 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2583 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2584 sheet->hadjustment = NULL;
2586 if (sheet->vadjustment)
2588 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2589 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2590 sheet->vadjustment = NULL;
2593 children = sheet->children;
2594 while(children){
2595 GtkSheetChild *child = (GtkSheetChild *)children->data;
2596 if(child && child->widget)
2597 gtk_sheet_remove(GTK_CONTAINER(sheet), child->widget);
2598 children = sheet->children;
2600 sheet->children = NULL;
2602 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2603 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2606 static void
2607 gtk_sheet_style_set (GtkWidget *widget,
2608 GtkStyle *previous_style)
2610 GtkSheet *sheet;
2612 g_return_if_fail (widget != NULL);
2613 g_return_if_fail (GTK_IS_SHEET (widget));
2615 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2616 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2618 sheet = GTK_SHEET (widget);
2620 if(GTK_WIDGET_REALIZED(widget))
2622 gtk_style_set_background (widget->style, widget->window, widget->state);
2627 static void
2628 gtk_sheet_realize (GtkWidget * widget)
2630 GtkSheet *sheet;
2631 GdkWindowAttr attributes;
2632 gint attributes_mask;
2633 GdkGCValues values, auxvalues;
2634 GdkColormap *colormap;
2635 gchar *name;
2636 GtkSheetChild *child;
2637 GList *children;
2639 g_return_if_fail (widget != NULL);
2640 g_return_if_fail (GTK_IS_SHEET (widget));
2642 sheet = GTK_SHEET (widget);
2644 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2646 attributes.window_type = GDK_WINDOW_CHILD;
2647 attributes.x = widget->allocation.x;
2648 attributes.y = widget->allocation.y;
2649 attributes.width = widget->allocation.width;
2650 attributes.height = widget->allocation.height;
2651 attributes.wclass = GDK_INPUT_OUTPUT;
2653 attributes.visual = gtk_widget_get_visual (widget);
2654 attributes.colormap = gtk_widget_get_colormap (widget);
2656 attributes.event_mask = gtk_widget_get_events (widget);
2657 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2658 GDK_BUTTON_PRESS_MASK |
2659 GDK_BUTTON_RELEASE_MASK |
2660 GDK_KEY_PRESS_MASK |
2661 GDK_POINTER_MOTION_MASK |
2662 GDK_POINTER_MOTION_HINT_MASK);
2663 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2664 GDK_WA_CURSOR;
2666 attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2668 /* main window */
2669 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2671 gdk_window_set_user_data (widget->window, sheet);
2673 widget->style = gtk_style_attach (widget->style, widget->window);
2675 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2677 attributes.x = 0;
2678 if(sheet->row_titles_visible)
2679 attributes.x = sheet->row_title_area.width;
2680 attributes.y = 0;
2681 attributes.width = sheet->column_title_area.width;
2682 attributes.height = sheet->column_title_area.height;
2684 /* column-title window */
2685 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2686 gdk_window_set_user_data (sheet->column_title_window, sheet);
2687 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2689 attributes.x = 0;
2690 attributes.y = 0;
2691 if(sheet->column_titles_visible)
2692 attributes.y = sheet->column_title_area.height;
2693 attributes.width = sheet->row_title_area.width;
2694 attributes.height = sheet->row_title_area.height;
2696 /* row-title window */
2697 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2698 gdk_window_set_user_data (sheet->row_title_window, sheet);
2699 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2701 /* sheet-window */
2702 attributes.cursor = gdk_cursor_new(GDK_PLUS);
2704 attributes.x = 0;
2705 attributes.y = 0;
2706 attributes.width = sheet->sheet_window_width,
2707 attributes.height = sheet->sheet_window_height;
2709 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2710 gdk_window_set_user_data (sheet->sheet_window, sheet);
2712 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2713 gdk_window_show (sheet->sheet_window);
2715 /* backing_pixmap */
2716 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
2718 /* GCs */
2719 if(sheet->fg_gc)
2720 gdk_gc_unref(sheet->fg_gc);
2721 if(sheet->bg_gc)
2722 gdk_gc_unref(sheet->bg_gc);
2723 sheet->fg_gc = gdk_gc_new (widget->window);
2724 sheet->bg_gc = gdk_gc_new (widget->window);
2726 colormap = gtk_widget_get_colormap(widget);
2728 gdk_color_white(colormap, &widget->style->white);
2729 gdk_color_black(colormap, &widget->style->black);
2731 gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2733 values.foreground = widget->style->white;
2734 values.function = GDK_INVERT;
2735 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2736 if(sheet->xor_gc)
2737 gdk_gc_unref(sheet->xor_gc);
2738 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2739 &values,
2740 GDK_GC_FOREGROUND |
2741 GDK_GC_FUNCTION |
2742 GDK_GC_SUBWINDOW);
2744 if(sheet->sheet_entry->parent){
2745 gtk_widget_ref(sheet->sheet_entry);
2746 gtk_widget_unparent(sheet->sheet_entry);
2748 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
2749 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2751 if(sheet->button && sheet->button->parent){
2752 gtk_widget_ref(sheet->button);
2753 gtk_widget_unparent(sheet->button);
2755 gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2756 gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2759 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2761 if(!sheet->cursor_drag)
2762 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2764 if(sheet->column_titles_visible)
2765 gdk_window_show(sheet->column_title_window);
2766 if(sheet->row_titles_visible)
2767 gdk_window_show(sheet->row_title_window);
2769 size_allocate_row_title_buttons(sheet);
2770 size_allocate_column_title_buttons(sheet);
2772 name = g_strdup(sheet->name);
2773 gtk_sheet_set_title(sheet, name);
2775 g_free(name);
2777 children = sheet->children;
2778 while(children)
2780 child = children->data;
2781 children = g_list_next(children);
2783 gtk_sheet_realize_child(sheet, child);
2787 static void
2788 create_global_button(GtkSheet *sheet)
2790 sheet->button = gtk_button_new_with_label(" ");
2792 gtk_signal_connect (GTK_OBJECT (sheet->button),
2793 "pressed",
2794 (GtkSignalFunc) global_button_clicked,
2795 (gpointer) sheet);
2798 static void
2799 size_allocate_global_button(GtkSheet *sheet)
2801 GtkAllocation allocation;
2803 if(!sheet->column_titles_visible) return;
2804 if(!sheet->row_titles_visible) return;
2806 gtk_widget_size_request(sheet->button, NULL);
2808 allocation.x=0;
2809 allocation.y=0;
2810 allocation.width=sheet->row_title_area.width;
2811 allocation.height=sheet->column_title_area.height;
2813 gtk_widget_size_allocate(sheet->button, &allocation);
2814 gtk_widget_show(sheet->button);
2817 static void
2818 global_button_clicked(GtkWidget *widget, gpointer data)
2820 gboolean veto;
2822 gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2823 gtk_widget_grab_focus(GTK_WIDGET(data));
2827 static void
2828 gtk_sheet_unrealize (GtkWidget * widget)
2830 GtkSheet *sheet;
2832 g_return_if_fail (widget != NULL);
2833 g_return_if_fail (GTK_IS_SHEET (widget));
2835 sheet = GTK_SHEET (widget);
2837 gdk_cursor_destroy (sheet->cursor_drag);
2839 gdk_gc_destroy (sheet->xor_gc);
2840 gdk_gc_destroy (sheet->fg_gc);
2841 gdk_gc_destroy (sheet->bg_gc);
2843 gdk_window_destroy (sheet->sheet_window);
2844 gdk_window_destroy (sheet->column_title_window);
2845 gdk_window_destroy (sheet->row_title_window);
2847 if (sheet->pixmap){
2848 g_object_unref (sheet->pixmap);
2849 sheet->pixmap = NULL;
2852 sheet->column_title_window=NULL;
2853 sheet->sheet_window = NULL;
2854 sheet->cursor_drag = NULL;
2855 sheet->xor_gc = NULL;
2856 sheet->fg_gc = NULL;
2857 sheet->bg_gc = NULL;
2859 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
2860 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2863 static void
2864 gtk_sheet_map (GtkWidget * widget)
2866 GtkSheet *sheet;
2867 GtkSheetChild *child;
2868 GList *children;
2870 g_return_if_fail (widget != NULL);
2871 g_return_if_fail (GTK_IS_SHEET (widget));
2873 sheet = GTK_SHEET (widget);
2875 if (!GTK_WIDGET_MAPPED (widget))
2877 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2879 if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2881 gdk_window_show (widget->window);
2883 gdk_window_show (sheet->sheet_window);
2885 if(sheet->column_titles_visible){
2886 gdk_window_show (sheet->column_title_window);
2888 if(sheet->row_titles_visible){
2889 gdk_window_show (sheet->row_title_window);
2892 if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)){
2893 gtk_widget_show (sheet->sheet_entry);
2894 gtk_widget_map (sheet->sheet_entry);
2897 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2898 !GTK_WIDGET_MAPPED (sheet->button)){
2899 gtk_widget_show(sheet->button);
2900 gtk_widget_map (sheet->button);
2903 if(GTK_BIN(sheet->button)->child)
2904 if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2905 !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2906 gtk_widget_map (GTK_BIN(sheet->button)->child);
2908 gtk_sheet_range_draw(sheet, NULL);
2909 gtk_sheet_activate_cell(sheet,
2910 sheet->active_cell.row,
2911 sheet->active_cell.col);
2913 children = sheet->children;
2914 while (children)
2916 child = children->data;
2917 children = g_list_next(children);
2919 if (GTK_WIDGET_VISIBLE (child->widget) &&
2920 !GTK_WIDGET_MAPPED (child->widget)){
2921 gtk_widget_map (child->widget);
2922 gtk_sheet_position_child(sheet, child);
2929 static void
2930 gtk_sheet_unmap (GtkWidget * widget)
2932 GtkSheet *sheet;
2933 GtkSheetChild *child;
2934 GList *children;
2936 g_return_if_fail (widget != NULL);
2937 g_return_if_fail (GTK_IS_SHEET (widget));
2939 sheet = GTK_SHEET (widget);
2941 if (GTK_WIDGET_MAPPED (widget))
2943 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2945 gdk_window_hide (sheet->sheet_window);
2946 if(sheet->column_titles_visible)
2947 gdk_window_hide (sheet->column_title_window);
2948 if(sheet->row_titles_visible)
2949 gdk_window_hide (sheet->row_title_window);
2950 gdk_window_hide (widget->window);
2952 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2953 gtk_widget_unmap (sheet->sheet_entry);
2955 if (GTK_WIDGET_MAPPED (sheet->button))
2956 gtk_widget_unmap (sheet->button);
2958 children = sheet->children;
2959 while (children)
2961 child = children->data;
2962 children = g_list_next(children);
2964 if (GTK_WIDGET_VISIBLE (child->widget) &&
2965 GTK_WIDGET_MAPPED (child->widget))
2967 gtk_widget_unmap (child->widget);
2975 static void
2976 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2978 GtkWidget *widget;
2979 GdkGC *fg_gc, *bg_gc;
2980 GtkSheetCellAttr attributes;
2981 GdkRectangle area;
2983 g_return_if_fail (sheet != NULL);
2985 /* bail now if we arn't drawable yet */
2986 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2988 if (row < 0 || row > sheet->maxrow) return;
2989 if (col < 0 || col > sheet->maxcol) return;
2990 if (!sheet->column[col].is_visible) return;
2991 if (!sheet->row[row].is_visible) return;
2993 widget = GTK_WIDGET (sheet);
2995 gtk_sheet_get_attributes(sheet, row, col, &attributes);
2997 /* select GC for background rectangle */
2998 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2999 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3001 fg_gc = sheet->fg_gc;
3002 bg_gc = sheet->bg_gc;
3004 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3005 area.y=ROW_TOP_YPIXEL(sheet,row);
3006 area.width=sheet->column[col].width;
3007 area.height=sheet->row[row].height;
3009 gdk_draw_rectangle (sheet->pixmap,
3010 bg_gc,
3011 TRUE,
3012 area.x,
3013 area.y,
3014 area.width,
3015 area.height);
3017 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
3019 if(sheet->show_grid){
3020 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
3022 gdk_draw_rectangle (sheet->pixmap,
3023 sheet->bg_gc,
3024 FALSE,
3025 area.x, area.y,
3026 area.width, area.height);
3030 static void
3031 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
3033 GtkWidget *widget;
3034 GdkGC *fg_gc, *bg_gc;
3035 GtkSheetCellAttr attributes;
3036 GdkRectangle area;
3037 guint width;
3039 g_return_if_fail (sheet != NULL);
3041 /* bail now if we arn't drawable yet */
3042 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
3044 if (row < 0 || row > sheet->maxrow) return;
3045 if (col < 0 || col > sheet->maxcol) return;
3046 if (!sheet->column[col].is_visible) return;
3047 if (!sheet->row[row].is_visible) return;
3049 widget = GTK_WIDGET (sheet);
3051 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3053 /* select GC for background rectangle */
3054 gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
3055 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3057 fg_gc = sheet->fg_gc;
3058 bg_gc = sheet->bg_gc;
3060 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3061 area.y=ROW_TOP_YPIXEL(sheet,row);
3062 area.width=sheet->column[col].width;
3063 area.height=sheet->row[row].height;
3065 width = attributes.border.width;
3066 gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
3067 attributes.border.line_style,
3068 attributes.border.cap_style,
3069 attributes.border.join_style);
3070 if(width>0){
3072 if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
3073 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3074 area.x, area.y-width/2,
3075 area.x, area.y+area.height+width/2+1);
3077 if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
3078 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3079 area.x+area.width, area.y-width/2,
3080 area.x+area.width,
3081 area.y+area.height+width/2+1);
3083 if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
3084 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3085 area.x-width/2,area.y,
3086 area.x+area.width+width/2+1,
3087 area.y);
3089 if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
3090 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
3091 area.x-width/2, area.y+area.height,
3092 area.x+area.width+width/2+1,
3093 area.y+area.height);
3099 static void
3100 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
3102 GtkWidget *widget;
3103 GdkRectangle area, clip_area;
3104 gint i;
3105 gint text_width, text_height, y;
3106 gint xoffset=0;
3107 gint size, sizel, sizer;
3108 GdkGC *fg_gc, *bg_gc;
3109 GtkSheetCellAttr attributes;
3110 PangoLayout *layout;
3111 PangoRectangle rect;
3112 PangoRectangle logical_rect;
3113 PangoLayoutLine *line;
3114 PangoFontMetrics *metrics;
3115 PangoContext *context = gtk_widget_get_pango_context(GTK_WIDGET(sheet));
3116 gint ascent, descent, y_pos;
3118 char *label;
3120 g_return_if_fail (sheet != NULL);
3122 /* bail now if we aren't drawable yet */
3123 if (!GTK_WIDGET_DRAWABLE (sheet))
3124 return;
3126 if (row > sheet->maxallocrow) return;
3127 if (col > sheet->maxalloccol) return;
3128 if (!sheet->data[row]) return;
3129 if (!sheet->data[row][col]) return;
3130 if (!sheet->data[row][col]->text || strlen(sheet->data[row][col]->text)==0)
3131 return;
3133 if (row < 0 || row > sheet->maxrow) return;
3134 if (col < 0 || col > sheet->maxcol) return;
3135 if (!sheet->column[col].is_visible) return;
3136 if (!sheet->row[row].is_visible) return;
3139 widget = GTK_WIDGET(sheet);
3141 label = sheet->data[row][col]->text;
3143 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3145 /* select GC for background rectangle */
3146 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
3147 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
3149 fg_gc = sheet->fg_gc;
3150 bg_gc = sheet->bg_gc;
3152 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
3153 area.y=ROW_TOP_YPIXEL(sheet,row);
3154 area.width=sheet->column[col].width;
3155 area.height=sheet->row[row].height;
3157 clip_area = area;
3159 layout = gtk_widget_create_pango_layout (GTK_WIDGET(sheet), label);
3160 pango_layout_set_font_description (layout, attributes.font_desc);
3162 pango_layout_get_pixel_extents (layout, NULL, &rect);
3164 line = pango_layout_get_lines (layout)->data;
3165 pango_layout_line_get_extents (line, NULL, &logical_rect);
3167 metrics = pango_context_get_metrics(context,
3168 attributes.font_desc,
3169 pango_context_get_language(context));
3171 ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
3172 descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
3174 pango_font_metrics_unref(metrics);
3176 /* Align primarily for locale's ascent/descent */
3178 logical_rect.height /= PANGO_SCALE;
3179 logical_rect.y /= PANGO_SCALE;
3180 y_pos = area.height - logical_rect.height;
3182 if (logical_rect.height > area.height)
3183 y_pos = (logical_rect.height - area.height - 2*CELLOFFSET) / 2;
3184 else if (y_pos < 0)
3185 y_pos = 0;
3186 else if (y_pos + logical_rect.height > area.height)
3187 y_pos = area.height - logical_rect.height;
3189 text_width = rect.width;
3190 text_height = rect.height;
3191 y = area.y + y_pos - CELLOFFSET;
3193 switch(attributes.justification){
3194 case GTK_JUSTIFY_RIGHT:
3195 size=area.width;
3196 area.x+=area.width;
3197 if(!gtk_sheet_clip_text(sheet)){
3198 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3199 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3200 if(size>=text_width+CELLOFFSET) break;
3201 size+=sheet->column[i].width;
3202 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
3204 area.width=size;
3206 area.x-=size;
3207 xoffset+=area.width-text_width - 2 * CELLOFFSET -
3208 attributes.border.width/2;
3209 break;
3210 case GTK_JUSTIFY_CENTER:
3211 sizel=area.width/2;
3212 sizer=area.width/2;
3213 area.x+=area.width/2;
3214 if(!gtk_sheet_clip_text(sheet)){
3215 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3216 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3217 if(sizer>=text_width/2) break;
3218 sizer+=sheet->column[i].width;
3219 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
3221 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
3222 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3223 if(sizel>=text_width/2) break;
3224 sizel+=sheet->column[i].width;
3225 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
3227 size=MIN(sizel, sizer);
3229 area.x-=sizel;
3230 xoffset+= sizel - text_width/2 - CELLOFFSET;
3231 area.width=sizel+sizer;
3232 break;
3233 case GTK_JUSTIFY_LEFT:
3234 default:
3235 size=area.width;
3236 if(!gtk_sheet_clip_text(sheet)){
3237 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
3238 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
3239 if(size>=text_width+CELLOFFSET) break;
3240 size+=sheet->column[i].width;
3241 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
3243 area.width=size;
3245 xoffset += attributes.border.width/2;
3246 break;
3249 if(!gtk_sheet_clip_text(sheet)) clip_area = area;
3250 gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
3253 gdk_draw_layout (sheet->pixmap, fg_gc,
3254 area.x + xoffset + CELLOFFSET,
3256 layout);
3258 gdk_gc_set_clip_rectangle(fg_gc, NULL);
3259 g_object_unref(G_OBJECT(layout));
3261 gdk_draw_pixmap(sheet->sheet_window,
3262 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3263 sheet->pixmap,
3264 area.x,
3265 area.y,
3266 area.x,
3267 area.y,
3268 area.width,
3269 area.height);
3275 static void
3276 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
3278 gint i,j;
3279 GtkSheetRange drawing_range;
3280 GdkRectangle area;
3282 g_return_if_fail(sheet != NULL);
3283 g_return_if_fail(GTK_SHEET(sheet));
3285 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3286 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3287 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
3289 if(range == NULL)
3291 drawing_range.row0=MIN_VISIBLE_ROW(sheet);
3292 drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
3293 drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
3294 drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
3296 gdk_draw_rectangle (sheet->pixmap,
3297 GTK_WIDGET(sheet)->style->white_gc,
3298 TRUE,
3299 0,0,
3300 sheet->sheet_window_width,sheet->sheet_window_height);
3303 else
3305 drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3306 drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3307 drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3308 drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3311 if(drawing_range.coli == sheet->maxcol){
3312 area.x=COLUMN_LEFT_XPIXEL(sheet,sheet->maxcol)+
3313 sheet->column[sheet->maxcol].width+1;
3314 area.y=0;
3316 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3318 gdk_draw_rectangle (sheet->pixmap,
3319 sheet->fg_gc,
3320 TRUE,
3321 area.x,area.y,
3322 sheet->sheet_window_width - area.x,
3323 sheet->sheet_window_height);
3325 gdk_draw_pixmap(sheet->sheet_window,
3326 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3327 sheet->pixmap,
3328 area.x,
3329 area.y,
3330 area.x,
3331 area.y,
3332 sheet->sheet_window_width - area.x,
3333 sheet->sheet_window_height);
3335 if(drawing_range.rowi == sheet->maxrow){
3336 area.x=0;
3337 area.y=ROW_TOP_YPIXEL(sheet,sheet->maxrow)+sheet->row[sheet->maxrow].height+1;
3339 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
3341 gdk_draw_rectangle (sheet->pixmap,
3342 sheet->fg_gc,
3343 TRUE,
3344 area.x,area.y,
3345 sheet->sheet_window_width,
3346 sheet->sheet_window_height - area.y);
3348 gdk_draw_pixmap(sheet->sheet_window,
3349 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3350 sheet->pixmap,
3351 area.x,
3352 area.y,
3353 area.x,
3354 area.y,
3355 sheet->sheet_window_width,
3356 sheet->sheet_window_height - area.y);
3359 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3360 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3361 gtk_sheet_cell_draw_default(sheet, i, j);
3364 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3365 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3366 gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3367 gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3368 gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3369 gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3370 gtk_sheet_cell_draw_border(sheet, i, j, 15);
3373 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3374 for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3375 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3376 sheet->data[i] && sheet->data[i][j])
3377 gtk_sheet_cell_draw_label (sheet, i, j);
3379 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3380 for(j=sheet->column[drawing_range.col0].left_text_column; j<drawing_range.col0; j++)
3381 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3382 sheet->data[i] && sheet->data[i][j])
3383 gtk_sheet_cell_draw_label (sheet, i, j);
3385 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3386 for(j=drawing_range.coli+1; j<=sheet->column[drawing_range.coli].right_text_column; j++)
3387 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3388 sheet->data[i] && sheet->data[i][j])
3389 gtk_sheet_cell_draw_label (sheet, i, j);
3391 gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3393 if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
3394 gtk_sheet_range_draw_selection(sheet, drawing_range);
3396 if(sheet->state == GTK_STATE_NORMAL &&
3397 sheet->active_cell.row >= drawing_range.row0 &&
3398 sheet->active_cell.row <= drawing_range.rowi &&
3399 sheet->active_cell.col >= drawing_range.col0 &&
3400 sheet->active_cell.col <= drawing_range.coli)
3401 gtk_sheet_show_active_cell(sheet);
3405 static void
3406 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3408 GdkRectangle area;
3409 gint i,j;
3410 GtkSheetRange aux;
3412 if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3413 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3414 return;
3416 if(!gtk_sheet_range_isvisible(sheet, range)) return;
3417 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3419 aux=range;
3421 range.col0=MAX(sheet->range.col0, range.col0);
3422 range.coli=MIN(sheet->range.coli, range.coli);
3423 range.row0=MAX(sheet->range.row0, range.row0);
3424 range.rowi=MIN(sheet->range.rowi, range.rowi);
3426 range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3427 range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3428 range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3429 range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3431 for(i=range.row0; i<=range.rowi; i++){
3432 for(j=range.col0; j<=range.coli; j++){
3434 if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED &&
3435 sheet->column[j].is_visible && sheet->row[i].is_visible){
3437 row_button_set(sheet, i);
3438 column_button_set(sheet, j);
3440 area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3441 area.y=ROW_TOP_YPIXEL(sheet,i);
3442 area.width=sheet->column[j].width;
3443 area.height=sheet->row[i].height;
3445 if(i==sheet->range.row0){
3446 area.y=area.y+2;
3447 area.height=area.height-2;
3449 if(i==sheet->range.rowi) area.height=area.height-3;
3450 if(j==sheet->range.col0){
3451 area.x=area.x+2;
3452 area.width=area.width-2;
3454 if(j==sheet->range.coli) area.width=area.width-3;
3456 if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
3457 gdk_draw_rectangle (sheet->sheet_window,
3458 sheet->xor_gc,
3459 TRUE,
3460 area.x+1,area.y+1,
3461 area.width,area.height);
3468 gtk_sheet_draw_border(sheet, sheet->range);
3472 static void
3473 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3475 gint x,y,width,height;
3477 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3479 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
3480 y=ROW_TOP_YPIXEL(sheet, range.row0);
3481 width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-x+sheet->column[range.coli].width;
3482 height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+sheet->row[range.rowi].height;
3484 if(range.row0==sheet->range.row0){
3485 y=y-5;
3486 height=height+5;
3488 if(range.rowi==sheet->range.rowi) height=height+5;
3489 if(range.col0==sheet->range.col0){
3490 x=x-5;
3491 width=width+5;
3493 if(range.coli==sheet->range.coli) width=width+5;
3496 width=MIN(width, sheet->sheet_window_width-x);
3497 height=MIN(height, sheet->sheet_window_height-y);
3499 x--;
3500 y--;
3501 width+=2;
3502 height+=2;
3504 x = (sheet->row_titles_visible)
3505 ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3506 y = (sheet->column_titles_visible)
3507 ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3509 if(range.coli==sheet->maxcol) width=sheet->sheet_window_width-x;
3510 if(range.rowi==sheet->maxrow) height=sheet->sheet_window_height-y;
3512 gdk_draw_pixmap(sheet->sheet_window,
3513 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3514 sheet->pixmap,
3519 width+1,
3520 height+1);
3523 static GtkSheetCell *
3524 gtk_sheet_cell_new()
3526 GtkSheetCell *cell;
3527 cell = g_new(GtkSheetCell, 1);
3528 cell->text = NULL;
3529 cell->link = NULL;
3530 cell->attributes = NULL;
3531 return cell;
3534 void
3535 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3537 GtkSheetCellAttr attributes;
3539 g_return_if_fail (sheet != NULL);
3540 g_return_if_fail (GTK_IS_SHEET (sheet));
3541 if (col > sheet->maxcol || row > sheet->maxrow) return;
3542 if (col < 0 || row < 0) return;
3544 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3545 gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3548 void
3549 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col,
3550 GtkJustification justification,
3551 const gchar *text)
3553 GtkSheetCell **cell;
3554 GtkSheetRange range;
3555 gint text_width;
3556 GtkSheetCellAttr attributes;
3558 g_return_if_fail (sheet != NULL);
3559 g_return_if_fail (GTK_IS_SHEET (sheet));
3560 if (col > sheet->maxcol || row > sheet->maxrow) return;
3561 if (col < 0 || row < 0) return;
3563 CheckBounds(sheet, row, col);
3565 cell=&sheet->data[row][col];
3567 if(*cell==NULL)
3568 (*cell) = gtk_sheet_cell_new();
3570 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3572 (*cell)->row = row;
3573 (*cell)->col = col;
3575 attributes.justification = justification;
3576 gtk_sheet_set_cell_attributes(sheet, row, col, attributes);
3578 if((*cell)->text){
3579 g_free((*cell)->text);
3580 (*cell)->text = NULL;
3583 if(text)
3584 (*cell)->text=g_strdup(text);
3586 if(attributes.is_visible){
3588 text_width = 0;
3589 if((*cell)->text && strlen((*cell)->text) > 0) {
3590 text_width = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, (*cell)->text);
3593 range.row0 = row;
3594 range.rowi = row;
3595 range.col0 = sheet->view.col0;
3596 range.coli = sheet->view.coli;
3598 if(gtk_sheet_autoresize(sheet) &&
3599 text_width > sheet->column[col].width-2*CELLOFFSET-attributes.border.width){
3600 gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3601 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
3603 else
3604 if(!GTK_SHEET_IS_FROZEN(sheet))
3605 gtk_sheet_range_draw(sheet, &range);
3607 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3612 void
3613 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3615 GtkSheetRange range;
3617 g_return_if_fail (sheet != NULL);
3618 g_return_if_fail (GTK_IS_SHEET (sheet));
3619 if (column > sheet->maxcol || row > sheet->maxrow) return;
3620 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3621 if (column < 0 || row < 0) return;
3623 range.row0 = row;
3624 range.rowi = row;
3625 range.col0 = sheet->view.col0;
3626 range.coli = sheet->view.coli;
3628 gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3630 if(!GTK_SHEET_IS_FROZEN(sheet)){
3631 gtk_sheet_range_draw(sheet, &range);
3635 void
3636 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3638 GtkSheetRange range;
3640 g_return_if_fail (sheet != NULL);
3641 g_return_if_fail (GTK_IS_SHEET (sheet));
3642 if (column > sheet->maxcol || row > sheet->maxrow) return;
3643 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3644 if (column < 0 || row < 0) return;
3646 range.row0 = row;
3647 range.rowi = row;
3648 range.col0 = sheet->view.col0;
3649 range.coli = sheet->view.coli;
3651 gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3653 if(!GTK_SHEET_IS_FROZEN(sheet)){
3654 gtk_sheet_range_draw(sheet, &range);
3658 static void
3659 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3661 gchar *text;
3662 gpointer link;
3664 if(row > sheet->maxallocrow || column > sheet->maxalloccol) return;
3665 if(!sheet->data[row]) return;
3666 if(!sheet->data[row][column]) return;
3668 text = gtk_sheet_cell_get_text(sheet, row, column);
3669 link = gtk_sheet_get_link(sheet, row, column);
3671 if(text){
3672 g_free(sheet->data[row][column]->text);
3673 sheet->data[row][column]->text = NULL;
3675 if(GTK_IS_OBJECT(sheet) && G_OBJECT(sheet)->ref_count > 0)
3676 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], row, column);
3678 sheet_head->CHANGED = 1;
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 sheet_head->CHANGED = 1;
3983 if(sheet->freeze_count == 0)
3984 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3986 sheet->active_cell.row=row;;
3987 sheet->active_cell.col=col;
3992 static gboolean
3993 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3995 gboolean veto = TRUE;
3997 g_return_val_if_fail (sheet != NULL, FALSE);
3998 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4000 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
4001 if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
4003 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE],
4004 sheet->active_cell.row,
4005 sheet->active_cell.col, &veto);
4007 if(!veto) return FALSE;
4009 gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
4010 (GtkSignalFunc) gtk_sheet_entry_changed,
4011 GTK_OBJECT(GTK_WIDGET(sheet)));
4013 gtk_sheet_hide_active_cell(sheet);
4014 sheet->active_cell.row=-1;
4015 sheet->active_cell.col=-1;
4017 if(GTK_SHEET_REDRAW_PENDING(sheet)){
4018 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_REDRAW_PENDING);
4019 gtk_sheet_range_draw(sheet, NULL);
4022 return TRUE;
4025 static void
4026 gtk_sheet_hide_active_cell(GtkSheet *sheet)
4028 const char *text;
4029 gint row,col;
4030 GtkJustification justification;
4031 GtkSheetCellAttr attributes;
4033 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4035 row=sheet->active_cell.row;
4036 col=sheet->active_cell.col;
4038 if(row < 0 || col < 0) return;
4040 if(sheet->freeze_count == 0)
4041 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
4043 text=gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
4045 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4046 justification=attributes.justification;
4048 if(text && strlen(text)!=0){
4049 gtk_sheet_set_cell(sheet, row, col, justification, text);
4050 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
4052 else
4054 gtk_sheet_cell_clear(sheet, row, col);
4057 row=sheet->active_cell.row;
4058 col=sheet->active_cell.col;
4060 column_button_release(sheet, col);
4061 row_button_release(sheet, row);
4063 gtk_widget_unmap(sheet->sheet_entry);
4065 if(row != -1 && col != -1)
4066 gdk_draw_pixmap(sheet->sheet_window,
4067 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4068 sheet->pixmap,
4069 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4070 ROW_TOP_YPIXEL(sheet,row)-1,
4071 COLUMN_LEFT_XPIXEL(sheet,col)-1,
4072 ROW_TOP_YPIXEL(sheet,row)-1,
4073 sheet->column[col].width+4,
4074 sheet->row[row].height+4);
4076 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4077 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
4078 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4080 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4084 static gboolean
4085 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
4087 gboolean veto = TRUE;
4089 g_return_val_if_fail (sheet != NULL, FALSE);
4090 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
4092 if(row < 0 || col < 0) return FALSE;
4093 if(row > sheet->maxrow || col > sheet->maxcol) return FALSE;
4095 /* _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4096 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
4099 if(!veto) return FALSE;
4100 if(sheet->state != GTK_SHEET_NORMAL){
4101 sheet->state=GTK_SHEET_NORMAL;
4102 gtk_sheet_real_unselect_range(sheet, NULL);
4105 sheet->range.row0=row;
4106 sheet->range.col0=col;
4107 sheet->range.rowi=row;
4108 sheet->range.coli=col;
4109 sheet->active_cell.row=row;
4110 sheet->active_cell.col=col;
4111 sheet->selection_cell.row=row;
4112 sheet->selection_cell.col=col;
4113 row_button_set(sheet, row);
4114 column_button_set(sheet, col);
4116 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4117 gtk_sheet_show_active_cell(sheet);
4119 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
4120 "changed",
4121 (GtkSignalFunc)gtk_sheet_entry_changed,
4122 GTK_OBJECT(GTK_WIDGET(sheet)));
4124 _gtkextra_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
4126 return TRUE;
4129 static void
4130 gtk_sheet_show_active_cell(GtkSheet *sheet)
4132 GtkSheetCell *cell;
4133 GtkEntry *sheet_entry;
4134 GtkSheetCellAttr attributes;
4135 gchar *text = NULL;
4136 GtkJustification justification;
4137 gint row, col;
4139 g_return_if_fail (sheet != NULL);
4140 g_return_if_fail (GTK_IS_SHEET (sheet));
4142 row = sheet->active_cell.row;
4143 col = sheet->active_cell.col;
4145 /* Don't show the active cell, if there is no active cell: */
4146 if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
4147 return;
4149 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4150 if(sheet->state != GTK_SHEET_NORMAL) return;
4151 if(GTK_SHEET_IN_SELECTION(sheet)) return;
4153 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
4155 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
4157 gtk_sheet_get_attributes(sheet, row, col, &attributes);
4159 justification = GTK_JUSTIFY_LEFT;
4161 if(gtk_sheet_justify_entry(sheet))
4162 justification = attributes.justification;
4164 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol) {
4165 if(sheet->data[row]) {
4166 if(sheet->data[row][col]) {
4167 cell = sheet->data[row][col];
4168 if(cell->text)
4169 text = g_strdup(cell->text);
4174 if(!text) text = g_strdup("");
4176 gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
4178 if(gtk_sheet_locked(sheet) || !attributes.is_editable){
4179 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
4180 }else{
4181 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
4185 gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
4188 gtk_sheet_size_allocate_entry(sheet);
4190 gtk_widget_map(sheet->sheet_entry);
4191 gtk_sheet_draw_active_cell(sheet);
4193 gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
4194 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet_entry), GTK_HAS_FOCUS);
4195 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
4197 g_free(text);
4200 static void
4201 gtk_sheet_draw_active_cell(GtkSheet *sheet)
4203 gint row, col;
4205 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
4206 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4208 row = sheet->active_cell.row;
4209 col = sheet->active_cell.col;
4211 if(row<0 || col<0) return;
4213 if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
4215 row_button_set(sheet, row);
4216 column_button_set(sheet, col);
4218 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4219 gtk_sheet_draw_border(sheet, sheet->range);
4224 static void
4225 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
4227 gint pixmap_width, pixmap_height;
4229 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
4231 if(width == 0 && height == 0){
4232 width=sheet->sheet_window_width+80;
4233 height=sheet->sheet_window_height+80;
4236 if (!sheet->pixmap)
4238 /* allocate */
4239 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4240 width, height,
4241 -1);
4242 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4244 else
4246 /* reallocate if sizes don't match */
4247 gdk_window_get_size (sheet->pixmap,
4248 &pixmap_width, &pixmap_height);
4249 if ((pixmap_width != width) || (pixmap_height != height))
4251 gdk_pixmap_unref(sheet->pixmap); /* replaced by SDB on 7.31.2006 */
4252 /* g_free(sheet->pixmap); */
4253 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
4254 width, height,
4255 -1);
4256 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
4261 static void
4262 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
4264 gint i,j, mask1, mask2;
4265 gint state, selected;
4266 gint x,y,width,height;
4267 GtkSheetRange new_range, aux_range;
4269 g_return_if_fail (sheet != NULL);
4271 if(range==NULL) range=&sheet->range;
4273 new_range=*range;
4275 range->row0=MIN(range->row0, sheet->range.row0);
4276 range->rowi=MAX(range->rowi, sheet->range.rowi);
4277 range->col0=MIN(range->col0, sheet->range.col0);
4278 range->coli=MAX(range->coli, sheet->range.coli);
4280 range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
4281 range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
4282 range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
4283 range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
4285 aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
4286 aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
4287 aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
4288 aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
4290 for(i=range->row0; i<=range->rowi; i++){
4291 for(j=range->col0; j<=range->coli; j++){
4293 state=gtk_sheet_cell_get_state(sheet, i, j);
4294 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4295 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4297 if(state==GTK_STATE_SELECTED && selected &&
4298 sheet->column[j].is_visible && sheet->row[i].is_visible &&
4299 (i==sheet->range.row0 || i==sheet->range.rowi ||
4300 j==sheet->range.col0 || j==sheet->range.coli ||
4301 i==new_range.row0 || i==new_range.rowi ||
4302 j==new_range.col0 || j==new_range.coli)){
4304 mask1 = i==sheet->range.row0 ? 1 : 0;
4305 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4306 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4307 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4309 mask2 = i==new_range.row0 ? 1 : 0;
4310 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4311 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4312 mask2 = j==new_range.coli ? mask2+8 : mask2;
4314 if(mask1 != mask2){
4315 x=COLUMN_LEFT_XPIXEL(sheet,j);
4316 y=ROW_TOP_YPIXEL(sheet, i);
4317 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4318 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4320 if(i==sheet->range.row0){
4321 y=y-3;
4322 height=height+3;
4324 if(i==sheet->range.rowi) height=height+3;
4325 if(j==sheet->range.col0){
4326 x=x-3;
4327 width=width+3;
4329 if(j==sheet->range.coli) width=width+3;
4331 gdk_draw_pixmap(sheet->sheet_window,
4332 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4333 sheet->pixmap,
4334 x+1,
4335 y+1,
4336 x+1,
4337 y+1,
4338 width,
4339 height);
4341 if(i != sheet->active_cell.row || j != sheet->active_cell.col){
4342 x=COLUMN_LEFT_XPIXEL(sheet,j);
4343 y=ROW_TOP_YPIXEL(sheet, i);
4344 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4345 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4347 if(i==new_range.row0){
4348 y=y+2;
4349 height=height-2;
4351 if(i==new_range.rowi) height=height-3;
4352 if(j==new_range.col0){
4353 x=x+2;
4354 width=width-2;
4356 if(j==new_range.coli) width=width-3;
4358 gdk_draw_rectangle (sheet->sheet_window,
4359 sheet->xor_gc,
4360 TRUE,
4361 x+1,y+1,
4362 width,height);
4369 for(i=range->row0; i<=range->rowi; i++){
4370 for(j=range->col0; j<=range->coli; j++){
4372 state=gtk_sheet_cell_get_state(sheet, i, j);
4373 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4374 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4376 if(state==GTK_STATE_SELECTED && !selected &&
4377 sheet->column[j].is_visible && sheet->row[i].is_visible){
4379 x=COLUMN_LEFT_XPIXEL(sheet,j);
4380 y=ROW_TOP_YPIXEL(sheet, i);
4381 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4382 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4384 if(i==sheet->range.row0){
4385 y=y-3;
4386 height=height+3;
4388 if(i==sheet->range.rowi) height=height+3;
4389 if(j==sheet->range.col0){
4390 x=x-3;
4391 width=width+3;
4393 if(j==sheet->range.coli) width=width+3;
4395 gdk_draw_pixmap(sheet->sheet_window,
4396 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4397 sheet->pixmap,
4398 x+1,
4399 y+1,
4400 x+1,
4401 y+1,
4402 width,
4403 height);
4408 for(i=range->row0; i<=range->rowi; i++){
4409 for(j=range->col0; j<=range->coli; j++){
4411 state=gtk_sheet_cell_get_state(sheet, i, j);
4412 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4413 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4415 if(state!=GTK_STATE_SELECTED && selected &&
4416 sheet->column[j].is_visible && sheet->row[i].is_visible &&
4417 (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4419 x=COLUMN_LEFT_XPIXEL(sheet,j);
4420 y=ROW_TOP_YPIXEL(sheet, i);
4421 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4422 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4424 if(i==new_range.row0){
4425 y=y+2;
4426 height=height-2;
4428 if(i==new_range.rowi) height=height-3;
4429 if(j==new_range.col0){
4430 x=x+2;
4431 width=width-2;
4433 if(j==new_range.coli) width=width-3;
4435 gdk_draw_rectangle (sheet->sheet_window,
4436 sheet->xor_gc,
4437 TRUE,
4438 x+1,y+1,
4439 width,height);
4446 for(i=aux_range.row0; i<=aux_range.rowi; i++){
4447 for(j=aux_range.col0; j<=aux_range.coli; j++){
4449 if(sheet->column[j].is_visible && sheet->row[i].is_visible){
4451 state=gtk_sheet_cell_get_state(sheet, i, j);
4453 mask1 = i==sheet->range.row0 ? 1 : 0;
4454 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4455 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4456 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4458 mask2 = i==new_range.row0 ? 1 : 0;
4459 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4460 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4461 mask2 = j==new_range.coli ? mask2+8 : mask2;
4462 if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4463 x=COLUMN_LEFT_XPIXEL(sheet,j);
4464 y=ROW_TOP_YPIXEL(sheet, i);
4465 width=sheet->column[j].width;
4466 height=sheet->row[i].height;
4467 if(mask2 & 1)
4468 gdk_draw_rectangle (sheet->sheet_window,
4469 sheet->xor_gc,
4470 TRUE,
4471 x+1,y-1,
4472 width,3);
4475 if(mask2 & 2)
4476 gdk_draw_rectangle (sheet->sheet_window,
4477 sheet->xor_gc,
4478 TRUE,
4479 x+1,y+height-1,
4480 width,3);
4482 if(mask2 & 4)
4483 gdk_draw_rectangle (sheet->sheet_window,
4484 sheet->xor_gc,
4485 TRUE,
4486 x-1,y+1,
4487 3,height);
4490 if(mask2 & 8)
4491 gdk_draw_rectangle (sheet->sheet_window,
4492 sheet->xor_gc,
4493 TRUE,
4494 x+width-1,y+1,
4495 3,height);
4507 *range=new_range;
4508 gtk_sheet_draw_corners(sheet, new_range);
4512 static void
4513 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4515 GtkWidget *widget;
4516 GdkRectangle area;
4517 gint i;
4518 gint x,y,width,height;
4520 widget = GTK_WIDGET(sheet);
4522 x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4523 y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4524 width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+
4525 sheet->column[new_range.coli].width;
4526 height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4527 sheet->row[new_range.rowi].height;
4529 area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4530 area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4531 area.width=sheet->sheet_window_width;
4532 area.height=sheet->sheet_window_height;
4534 if(x<0) {
4535 width=width+x;
4536 x=0;
4538 if(width>area.width) width=area.width+10;
4539 if(y<0) {
4540 height=height+y;
4541 y=0;
4543 if(height>area.height) height=area.height+10;
4545 gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4547 for(i=-1; i<=1; ++i)
4548 gdk_draw_rectangle (sheet->sheet_window,
4549 sheet->xor_gc,
4550 FALSE,
4551 x+i,y+i,
4552 width-2*i,height-2*i);
4554 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4556 gtk_sheet_draw_corners(sheet, new_range);
4560 static void
4561 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4563 gint x,y;
4564 guint width = 1;
4566 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4567 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4568 y=ROW_TOP_YPIXEL(sheet,range.row0);
4569 gdk_draw_pixmap(sheet->sheet_window,
4570 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4571 sheet->pixmap,
4572 x-1,
4573 y-1,
4574 x-1,
4575 y-1,
4577 3);
4578 gdk_draw_rectangle (sheet->sheet_window,
4579 sheet->xor_gc,
4580 TRUE,
4581 x-1,y-1,
4582 3,3);
4585 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4586 sheet->state == GTK_SHEET_COLUMN_SELECTED){
4587 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4588 sheet->column[range.coli].width;
4589 y=ROW_TOP_YPIXEL(sheet,range.row0);
4590 width = 1;
4591 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4593 y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4594 width = 3;
4596 gdk_draw_pixmap(sheet->sheet_window,
4597 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4598 sheet->pixmap,
4599 x-width,
4600 y-width,
4601 x-width,
4602 y-width,
4603 2*width+1,
4604 2*width+1);
4605 gdk_draw_rectangle (sheet->sheet_window,
4606 sheet->xor_gc,
4607 TRUE,
4608 x-width+width/2,y-width+width/2,
4609 2+width,2+width);
4612 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4613 sheet->state == GTK_SHEET_ROW_SELECTED){
4614 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4615 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4616 sheet->row[range.rowi].height;
4617 width = 1;
4618 if(sheet->state == GTK_SHEET_ROW_SELECTED)
4620 x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4621 width = 3;
4623 gdk_draw_pixmap(sheet->sheet_window,
4624 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4625 sheet->pixmap,
4626 x-width,
4627 y-width,
4628 x-width,
4629 y-width,
4630 2*width+1,
4631 2*width+1);
4632 gdk_draw_rectangle (sheet->sheet_window,
4633 sheet->xor_gc,
4634 TRUE,
4635 x-width+width/2,y-width+width/2,
4636 2+width,2+width);
4639 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4640 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4641 sheet->column[range.coli].width;
4642 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4643 sheet->row[range.rowi].height;
4644 width = 1;
4645 if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4646 if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4647 gdk_draw_pixmap(sheet->sheet_window,
4648 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4649 sheet->pixmap,
4650 x-width,
4651 y-width,
4652 x-width,
4653 y-width,
4654 2*width+1,
4655 2*width+1);
4656 gdk_draw_rectangle (sheet->sheet_window,
4657 sheet->xor_gc,
4658 TRUE,
4659 x-width+width/2,y-width+width/2,
4660 2+width,2+width);
4667 static void
4668 gtk_sheet_real_select_range (GtkSheet * sheet,
4669 GtkSheetRange * range)
4671 gint i;
4672 gint state;
4674 g_return_if_fail (sheet != NULL);
4676 if(range==NULL) range=&sheet->range;
4678 if(range->row0 < 0 || range->rowi < 0) return;
4679 if(range->col0 < 0 || range->coli < 0) return;
4681 state=sheet->state;
4683 if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4684 for(i=sheet->range.col0; i< range->col0; i++)
4685 column_button_release(sheet, i);
4686 for(i=range->coli+1; i<= sheet->range.coli; i++)
4687 column_button_release(sheet, i);
4688 for(i=range->col0; i<=range->coli; i++){
4689 column_button_set(sheet, i);
4693 if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4694 for(i=sheet->range.row0; i< range->row0; i++)
4695 row_button_release(sheet, i);
4696 for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4697 row_button_release(sheet, i);
4698 for(i=range->row0; i<=range->rowi; i++){
4699 row_button_set(sheet, i);
4703 if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4704 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4707 gtk_sheet_new_selection(sheet, range);
4709 sheet->range.col0=range->col0;
4710 sheet->range.coli=range->coli;
4711 sheet->range.row0=range->row0;
4712 sheet->range.rowi=range->rowi;
4715 else
4717 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4718 gtk_sheet_range_draw_selection(sheet, sheet->range);
4721 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4724 void
4725 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4727 g_return_if_fail (sheet != NULL);
4729 if(range==NULL) range=&sheet->range;
4731 if(range->row0 < 0 || range->rowi < 0) return;
4732 if(range->col0 < 0 || range->coli < 0) return;
4734 if(sheet->state != GTK_SHEET_NORMAL)
4735 gtk_sheet_real_unselect_range(sheet, NULL);
4736 else
4738 gboolean veto = TRUE;
4739 veto = gtk_sheet_deactivate_cell(sheet);
4740 if(!veto) return;
4743 sheet->range.row0=range->row0;
4744 sheet->range.rowi=range->rowi;
4745 sheet->range.col0=range->col0;
4746 sheet->range.coli=range->coli;
4747 sheet->active_cell.row=range->row0;
4748 sheet->active_cell.col=range->col0;
4749 sheet->selection_cell.row=range->rowi;
4750 sheet->selection_cell.col=range->coli;
4752 sheet->state = GTK_SHEET_RANGE_SELECTED;
4753 gtk_sheet_real_select_range(sheet, NULL);
4757 void
4758 gtk_sheet_unselect_range (GtkSheet * sheet)
4760 gtk_sheet_real_unselect_range(sheet, NULL);
4761 sheet->state = GTK_STATE_NORMAL;
4762 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4766 static void
4767 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4768 const GtkSheetRange *range)
4770 gint i;
4772 g_return_if_fail (sheet != NULL);
4773 g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4775 if(range==NULL){
4776 range=&sheet->range;
4779 if(range->row0 < 0 || range->rowi < 0) return;
4780 if(range->col0 < 0 || range->coli < 0) return;
4782 if (gtk_sheet_range_isvisible (sheet, *range)){
4783 gtk_sheet_draw_backing_pixmap(sheet, *range);
4786 for(i=range->col0; i<=range->coli; i++){
4787 column_button_release(sheet, i);
4790 for(i=range->row0; i<=range->rowi; i++){
4791 row_button_release(sheet, i);
4797 static gint
4798 gtk_sheet_expose (GtkWidget * widget,
4799 GdkEventExpose * event)
4801 GtkSheet *sheet;
4802 GtkSheetRange range;
4804 #ifdef DEBUG
4805 printf("---> Entered gtk_sheet_expose ... must have received expose_event\n");
4806 #endif
4808 g_return_val_if_fail (widget != NULL, FALSE);
4809 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4810 g_return_val_if_fail (event != NULL, FALSE);
4812 sheet = GTK_SHEET (widget);
4814 if (GTK_WIDGET_DRAWABLE (widget))
4816 range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4817 range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4818 range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4819 range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4821 /* exposure events on the sheet */
4823 if( (event->window == sheet->row_title_window) && sheet->row_titles_visible){
4824 size_allocate_row_title_buttons(sheet);
4827 if( (event->window == sheet->column_title_window) && sheet->column_titles_visible){
4828 size_allocate_column_title_buttons(sheet);
4831 if (event->window == sheet->sheet_window){
4832 gtk_sheet_draw_backing_pixmap(sheet, range);
4834 if(sheet->state != GTK_SHEET_NORMAL){
4835 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4836 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4837 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4838 gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4840 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4841 gtk_sheet_range_draw_selection(sheet, sheet->range);
4842 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4843 draw_xor_rectangle(sheet, sheet->drag_range);
4846 if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4847 if(sheet->state == GTK_SHEET_NORMAL){
4848 gtk_sheet_draw_active_cell(sheet);
4849 if(!GTK_SHEET_IN_SELECTION(sheet))
4850 gtk_widget_queue_draw(sheet->sheet_entry);
4859 if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4860 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4862 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
4864 #ifdef DEBUG
4865 printf("<--- Leaving gtk_sheet_expose\n");
4866 #endif
4868 return FALSE;
4872 static gint
4873 gtk_sheet_button_press (GtkWidget * widget,
4874 GdkEventButton * event)
4876 GtkSheet *sheet;
4877 GdkModifierType mods;
4878 gint x, y, row, column;
4879 gboolean veto;
4881 g_return_val_if_fail (widget != NULL, FALSE);
4882 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4883 g_return_val_if_fail (event != NULL, FALSE);
4885 if(event->type != GDK_BUTTON_PRESS) return TRUE;
4886 gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4887 if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4889 sheet = GTK_SHEET (widget);
4891 /* press on resize windows */
4892 if (event->window == sheet->column_title_window &&
4893 gtk_sheet_columns_resizable(sheet))
4895 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4896 if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4897 guint req;
4898 gtk_sheet_column_size_request(sheet, sheet->drag_cell.col, &req);
4899 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4900 gdk_pointer_grab (sheet->column_title_window, FALSE,
4901 GDK_POINTER_MOTION_HINT_MASK |
4902 GDK_BUTTON1_MOTION_MASK |
4903 GDK_BUTTON_RELEASE_MASK,
4904 NULL, NULL, event->time);
4906 draw_xor_vline (sheet);
4907 return TRUE;
4911 if (event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet))
4913 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4915 if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4916 guint req;
4917 gtk_sheet_row_size_request(sheet, sheet->drag_cell.row, &req);
4918 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4919 gdk_pointer_grab (sheet->row_title_window, FALSE,
4920 GDK_POINTER_MOTION_HINT_MASK |
4921 GDK_BUTTON1_MOTION_MASK |
4922 GDK_BUTTON_RELEASE_MASK,
4923 NULL, NULL, event->time);
4925 draw_xor_hline (sheet);
4926 return TRUE;
4930 /* selections on the sheet */
4931 if(event->window == sheet->sheet_window){
4932 gtk_widget_get_pointer (widget, &x, &y);
4933 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4934 gdk_pointer_grab (sheet->sheet_window, FALSE,
4935 GDK_POINTER_MOTION_HINT_MASK |
4936 GDK_BUTTON1_MOTION_MASK |
4937 GDK_BUTTON_RELEASE_MASK,
4938 NULL, NULL, event->time);
4939 gtk_grab_add(GTK_WIDGET(sheet));
4940 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
4941 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4942 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
4943 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4945 if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4946 sheet->cursor_drag->type==GDK_SIZING &&
4947 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4948 if(sheet->state==GTK_STATE_NORMAL) {
4949 row=sheet->active_cell.row;
4950 column=sheet->active_cell.col;
4951 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4952 sheet->active_cell.row=row;
4953 sheet->active_cell.col=column;
4954 sheet->drag_range=sheet->range;
4955 sheet->state=GTK_SHEET_RANGE_SELECTED;
4956 gtk_sheet_select_range(sheet, &sheet->drag_range);
4958 sheet->x_drag=x;
4959 sheet->y_drag=y;
4960 if(row > sheet->range.rowi) row--;
4961 if(column > sheet->range.coli) column--;
4962 sheet->drag_cell.row = row;
4963 sheet->drag_cell.col = column;
4964 sheet->drag_range=sheet->range;
4965 draw_xor_rectangle(sheet, sheet->drag_range);
4966 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4968 else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4969 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_DRAG(sheet)) {
4970 if(sheet->state==GTK_STATE_NORMAL) {
4971 row=sheet->active_cell.row;
4972 column=sheet->active_cell.col;
4973 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4974 sheet->active_cell.row=row;
4975 sheet->active_cell.col=column;
4976 sheet->drag_range=sheet->range;
4977 sheet->state=GTK_SHEET_RANGE_SELECTED;
4978 gtk_sheet_select_range(sheet, &sheet->drag_range);
4980 sheet->x_drag=x;
4981 sheet->y_drag=y;
4982 if(row < sheet->range.row0) row++;
4983 if(row > sheet->range.rowi) row--;
4984 if(column < sheet->range.col0) column++;
4985 if(column > sheet->range.coli) column--;
4986 sheet->drag_cell.row=row;
4987 sheet->drag_cell.col=column;
4988 sheet->drag_range=sheet->range;
4989 draw_xor_rectangle(sheet, sheet->drag_range);
4990 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
4992 else
4994 gtk_sheet_click_cell(sheet, row, column, &veto);
4995 if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5000 if(event->window == sheet->column_title_window){
5001 gtk_widget_get_pointer (widget, &x, &y);
5002 column = COLUMN_FROM_XPIXEL(sheet, x);
5003 if(sheet->column[column].is_sensitive){;
5004 gtk_sheet_click_cell(sheet, -1, column, &veto);
5005 gtk_grab_add(GTK_WIDGET(sheet));
5006 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5007 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
5008 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
5009 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5010 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5014 if(event->window == sheet->row_title_window){
5015 gtk_widget_get_pointer (widget, &x, &y);
5016 row = ROW_FROM_YPIXEL(sheet, y);
5017 if(sheet->row[row].is_sensitive){
5018 gtk_sheet_click_cell(sheet, row, -1, &veto);
5019 gtk_grab_add(GTK_WIDGET(sheet));
5020 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, sheet);
5021 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
5022 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
5023 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5024 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5028 return TRUE;
5031 static gint
5032 gtk_sheet_scroll(gpointer data)
5034 GtkSheet *sheet;
5035 gint x,y,row,column;
5036 gint move;
5038 sheet=GTK_SHEET(data);
5040 GDK_THREADS_ENTER();
5042 gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
5043 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5045 move=TRUE;
5047 if(GTK_SHEET_IN_SELECTION(sheet))
5048 gtk_sheet_extend_selection(sheet, row, column);
5050 if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
5051 move=gtk_sheet_move_query(sheet, row, column);
5052 if(move) draw_xor_rectangle(sheet, sheet->drag_range);
5055 GDK_THREADS_LEAVE();
5057 return TRUE;
5061 static void
5062 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
5064 *veto = TRUE;
5066 if(row > sheet->maxrow || column > sheet->maxcol){
5067 *veto = FALSE;
5068 return;
5071 if(column >= 0 && row >= 0)
5072 if(!sheet->column[column].is_visible || !sheet->row[row].is_visible)
5074 *veto = FALSE;
5075 return;
5078 _gtkextra_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
5079 sheet->active_cell.row, sheet->active_cell.col,
5080 &row, &column, veto);
5082 if(!*veto){
5083 if(sheet->state == GTK_STATE_NORMAL) return;
5085 row = sheet->active_cell.row;
5086 column = sheet->active_cell.col;
5087 gtk_sheet_activate_cell(sheet, row, column);
5088 return;
5091 if(row == -1 && column >= 0){
5092 if(gtk_sheet_autoscroll(sheet))
5093 gtk_sheet_move_query(sheet, row, column);
5094 gtk_sheet_select_column(sheet, column);
5095 return;
5097 if(column == -1 && row >= 0){
5098 if(gtk_sheet_autoscroll(sheet))
5099 gtk_sheet_move_query(sheet, row, column);
5100 gtk_sheet_select_row(sheet, row);
5101 return;
5104 if(row==-1 && column ==-1){
5105 sheet->range.row0=0;
5106 sheet->range.col0=0;
5107 sheet->range.rowi=sheet->maxrow;
5108 sheet->range.coli=sheet->maxcol;
5109 sheet->active_cell.row=0;
5110 sheet->active_cell.col=0;
5111 gtk_sheet_select_range(sheet, NULL);
5112 return;
5115 if(row!=-1 && column !=-1){
5116 if(sheet->state != GTK_SHEET_NORMAL){
5117 sheet->state = GTK_SHEET_NORMAL;
5118 gtk_sheet_real_unselect_range(sheet, NULL);
5120 else
5122 if(!gtk_sheet_deactivate_cell(sheet)){
5123 *veto = FALSE;
5124 return;
5128 if(gtk_sheet_autoscroll(sheet))
5129 gtk_sheet_move_query(sheet, row, column);
5130 sheet->active_cell.row=row;
5131 sheet->active_cell.col=column;
5132 sheet->selection_cell.row=row;
5133 sheet->selection_cell.col=column;
5134 sheet->range.row0=row;
5135 sheet->range.col0=column;
5136 sheet->range.rowi=row;
5137 sheet->range.coli=column;
5138 sheet->state=GTK_SHEET_NORMAL;
5139 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5140 gtk_sheet_draw_active_cell(sheet);
5141 return;
5144 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5145 sheet->active_cell.col);
5148 static gint
5149 gtk_sheet_button_release (GtkWidget * widget,
5150 GdkEventButton * event)
5152 GtkSheet *sheet;
5153 gint x,y;
5155 sheet=GTK_SHEET(widget);
5157 /* release on resize windows */
5158 if (GTK_SHEET_IN_XDRAG (sheet)){
5159 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
5160 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5161 gtk_widget_get_pointer (widget, &x, NULL);
5162 gdk_pointer_ungrab (event->time);
5163 draw_xor_vline (sheet);
5165 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
5166 sheet->old_hadjustment = -1.;
5167 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
5168 return TRUE;
5171 if (GTK_SHEET_IN_YDRAG (sheet)){
5172 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
5173 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
5174 gtk_widget_get_pointer (widget, NULL, &y);
5175 gdk_pointer_ungrab (event->time);
5176 draw_xor_hline (sheet);
5178 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
5179 sheet->old_vadjustment = -1.;
5180 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
5181 return TRUE;
5185 if (GTK_SHEET_IN_DRAG(sheet)){
5186 GtkSheetRange old_range;
5187 draw_xor_rectangle(sheet, sheet->drag_range);
5188 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
5189 gdk_pointer_ungrab (event->time);
5191 gtk_sheet_real_unselect_range(sheet, NULL);
5193 sheet->active_cell.row = sheet->active_cell.row +
5194 (sheet->drag_range.row0 - sheet->range.row0);
5195 sheet->active_cell.col = sheet->active_cell.col +
5196 (sheet->drag_range.col0 - sheet->range.col0);
5197 sheet->selection_cell.row = sheet->selection_cell.row +
5198 (sheet->drag_range.row0 - sheet->range.row0);
5199 sheet->selection_cell.col = sheet->selection_cell.col +
5200 (sheet->drag_range.col0 - sheet->range.col0);
5201 old_range=sheet->range;
5202 sheet->range=sheet->drag_range;
5203 sheet->drag_range=old_range;
5204 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
5205 &sheet->drag_range, &sheet->range);
5206 gtk_sheet_select_range(sheet, &sheet->range);
5209 if (GTK_SHEET_IN_RESIZE(sheet)){
5210 GtkSheetRange old_range;
5211 draw_xor_rectangle(sheet, sheet->drag_range);
5212 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
5213 gdk_pointer_ungrab (event->time);
5215 gtk_sheet_real_unselect_range(sheet, NULL);
5217 sheet->active_cell.row = sheet->active_cell.row +
5218 (sheet->drag_range.row0 - sheet->range.row0);
5219 sheet->active_cell.col = sheet->active_cell.col +
5220 (sheet->drag_range.col0 - sheet->range.col0);
5221 if(sheet->drag_range.row0 < sheet->range.row0)
5222 sheet->selection_cell.row = sheet->drag_range.row0;
5223 if(sheet->drag_range.rowi >= sheet->range.rowi)
5224 sheet->selection_cell.row = sheet->drag_range.rowi;
5225 if(sheet->drag_range.col0 < sheet->range.col0)
5226 sheet->selection_cell.col = sheet->drag_range.col0;
5227 if(sheet->drag_range.coli >= sheet->range.coli)
5228 sheet->selection_cell.col = sheet->drag_range.coli;
5229 old_range = sheet->range;
5230 sheet->range = sheet->drag_range;
5231 sheet->drag_range = old_range;
5233 if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
5234 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
5235 &sheet->drag_range, &sheet->range);
5236 gtk_sheet_select_range(sheet, &sheet->range);
5239 if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
5240 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5241 gdk_pointer_ungrab (event->time);
5242 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5243 sheet->active_cell.col);
5246 if(GTK_SHEET_IN_SELECTION)
5247 gdk_pointer_ungrab (event->time);
5248 if(sheet->timer)
5249 gtk_timeout_remove(sheet->timer);
5250 gtk_grab_remove(GTK_WIDGET(sheet));
5252 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5254 return TRUE;
5257 static gint
5258 gtk_sheet_motion (GtkWidget * widget,
5259 GdkEventMotion * event)
5261 GtkSheet *sheet;
5262 GdkModifierType mods;
5263 GdkCursorType new_cursor;
5264 gint x, y, row, column;
5266 g_return_val_if_fail (widget != NULL, FALSE);
5267 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5268 g_return_val_if_fail (event != NULL, FALSE);
5271 sheet = GTK_SHEET (widget);
5274 /* selections on the sheet */
5275 x = event->x;
5276 y = event->y;
5278 if(event->window == sheet->column_title_window && gtk_sheet_columns_resizable(sheet)){
5279 gtk_widget_get_pointer(widget, &x, &y);
5280 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5281 new_cursor=GDK_SB_H_DOUBLE_ARROW;
5282 if(new_cursor != sheet->cursor_drag->type){
5283 gdk_cursor_destroy(sheet->cursor_drag);
5284 sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5285 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5287 }else{
5288 new_cursor=GDK_TOP_LEFT_ARROW;
5289 if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5290 gdk_cursor_destroy(sheet->cursor_drag);
5291 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5292 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5297 if(event->window == sheet->row_title_window && gtk_sheet_rows_resizable(sheet)){
5298 gtk_widget_get_pointer(widget, &x, &y);
5299 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5300 new_cursor=GDK_SB_V_DOUBLE_ARROW;
5301 if(new_cursor != sheet->cursor_drag->type){
5302 gdk_cursor_destroy(sheet->cursor_drag);
5303 sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5304 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5306 }else{
5307 new_cursor=GDK_TOP_LEFT_ARROW;
5308 if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5309 gdk_cursor_destroy(sheet->cursor_drag);
5310 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5311 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5316 new_cursor=GDK_PLUS;
5317 if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5318 !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5319 event->window == sheet->sheet_window &&
5320 new_cursor != sheet->cursor_drag->type){
5321 gdk_cursor_destroy(sheet->cursor_drag);
5322 sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5323 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5326 new_cursor=GDK_TOP_LEFT_ARROW;
5327 if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5328 (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) &&
5329 event->window == sheet->sheet_window &&
5330 new_cursor != sheet->cursor_drag->type){
5331 gdk_cursor_destroy(sheet->cursor_drag);
5332 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5333 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5336 new_cursor=GDK_SIZING;
5337 if(!GTK_SHEET_IN_DRAG(sheet) &&
5338 (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5339 event->window == sheet->sheet_window &&
5340 new_cursor != sheet->cursor_drag->type){
5341 gdk_cursor_destroy(sheet->cursor_drag);
5342 sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5343 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5346 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5347 if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5349 if (GTK_SHEET_IN_XDRAG (sheet)){
5350 if (event->is_hint || event->window != widget->window)
5351 gtk_widget_get_pointer (widget, &x, NULL);
5352 else
5353 x = event->x;
5355 new_column_width (sheet, sheet->drag_cell.col, &x);
5356 if (x != sheet->x_drag)
5358 draw_xor_vline (sheet);
5359 sheet->x_drag = x;
5360 draw_xor_vline (sheet);
5362 return TRUE;
5365 if (GTK_SHEET_IN_YDRAG (sheet)){
5366 if (event->is_hint || event->window != widget->window)
5367 gtk_widget_get_pointer (widget, NULL, &y);
5368 else
5369 y = event->y;
5371 new_row_height (sheet, sheet->drag_cell.row, &y);
5372 if (y != sheet->y_drag)
5374 draw_xor_hline (sheet);
5375 sheet->y_drag = y;
5376 draw_xor_hline (sheet);
5378 return TRUE;
5381 if (GTK_SHEET_IN_DRAG(sheet)){
5382 GtkSheetRange aux;
5383 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5384 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5385 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5386 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5387 sheet->x_drag=x;
5388 sheet->y_drag=y;
5389 aux=sheet->range;
5390 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5391 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5392 aux=sheet->drag_range;
5393 sheet->drag_range.row0=sheet->range.row0+row;
5394 sheet->drag_range.col0=sheet->range.col0+column;
5395 sheet->drag_range.rowi=sheet->range.rowi+row;
5396 sheet->drag_range.coli=sheet->range.coli+column;
5397 if(aux.row0 != sheet->drag_range.row0 ||
5398 aux.col0 != sheet->drag_range.col0){
5399 draw_xor_rectangle (sheet, aux);
5400 draw_xor_rectangle (sheet, sheet->drag_range);
5403 return TRUE;
5406 if (GTK_SHEET_IN_RESIZE(sheet)){
5407 GtkSheetRange aux;
5408 gint v_h;
5409 v_h=1;
5410 if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5411 abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5413 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5414 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5415 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5416 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5417 sheet->x_drag=x;
5418 sheet->y_drag=y;
5419 aux=sheet->range;
5421 if(row < sheet->range.row0 - sheet->range.rowi - 1)
5422 row=row+(sheet->range.rowi-sheet->range.row0 + 1);
5423 else if(row<0) row=0;
5425 if(column < sheet->range.col0 - sheet->range.coli - 1)
5426 column=column+(sheet->range.coli-sheet->range.col0 + 1);
5427 else if(column<0) column=0;
5429 if(v_h==1)
5430 column=0;
5431 else
5432 row=0;
5434 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5435 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5437 aux=sheet->drag_range;
5438 sheet->drag_range=sheet->range;
5440 if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5441 if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5442 if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5443 if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5445 if(aux.row0 != sheet->drag_range.row0 ||
5446 aux.rowi != sheet->drag_range.rowi ||
5447 aux.col0 != sheet->drag_range.col0 ||
5448 aux.coli != sheet->drag_range.coli){
5449 draw_xor_rectangle (sheet, aux);
5450 draw_xor_rectangle (sheet, sheet->drag_range);
5453 return TRUE;
5458 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5460 if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5461 column==sheet->active_cell.col) return TRUE;
5463 if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5464 gtk_sheet_extend_selection(sheet, row, column);
5466 return TRUE;
5469 static gint
5470 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5472 gint row_move, column_move;
5473 gfloat row_align, col_align;
5474 guint height, width;
5475 gint new_row = row;
5476 gint new_col = column;
5478 row_move=FALSE;
5479 column_move=FALSE;
5480 row_align=-1.;
5481 col_align=-1.;
5483 height = sheet->sheet_window_height;
5484 width = sheet->sheet_window_width;
5486 if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5487 row_align = 1.;
5488 new_row = MIN(sheet->maxrow, row + 1);
5489 row_move = TRUE;
5490 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow &&
5491 ROW_TOP_YPIXEL(sheet, sheet->maxrow) +
5492 sheet->row[sheet->maxrow].height < height){
5493 row_move = FALSE;
5494 row_align = -1.;
5497 if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5498 row_align= 0.;
5499 row_move = TRUE;
5501 if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5502 col_align = 1.;
5503 new_col = MIN(sheet->maxcol, column + 1);
5504 column_move = TRUE;
5505 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol &&
5506 COLUMN_LEFT_XPIXEL(sheet, sheet->maxcol) +
5507 sheet->column[sheet->maxcol].width < width){
5508 column_move = FALSE;
5509 col_align = -1.;
5512 if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5513 col_align = 0.;
5514 column_move = TRUE;
5517 if(row_move || column_move){
5518 gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5521 return(row_move || column_move);
5524 static void
5525 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5527 GtkSheetRange range;
5528 gint state;
5529 gint r,c;
5531 if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5532 return;
5534 if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5536 gtk_sheet_move_query(sheet, row, column);
5537 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5539 if(GTK_SHEET_IN_DRAG(sheet)) return;
5541 state=sheet->state;
5543 switch(sheet->state){
5544 case GTK_SHEET_ROW_SELECTED:
5545 column = sheet->maxcol;
5546 break;
5547 case GTK_SHEET_COLUMN_SELECTED:
5548 row = sheet->maxrow;
5549 break;
5550 case GTK_SHEET_NORMAL:
5551 sheet->state=GTK_SHEET_RANGE_SELECTED;
5552 r=sheet->active_cell.row;
5553 c=sheet->active_cell.col;
5554 sheet->range.col0=c;
5555 sheet->range.row0=r;
5556 sheet->range.coli=c;
5557 sheet->range.rowi=r;
5558 gdk_draw_pixmap(sheet->sheet_window,
5559 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5560 sheet->pixmap,
5561 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5562 ROW_TOP_YPIXEL(sheet,r)-1,
5563 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5564 ROW_TOP_YPIXEL(sheet,r)-1,
5565 sheet->column[c].width+4,
5566 sheet->row[r].height+4);
5567 gtk_sheet_range_draw_selection(sheet, sheet->range);
5568 case GTK_SHEET_RANGE_SELECTED:
5569 sheet->state=GTK_SHEET_RANGE_SELECTED;
5572 sheet->selection_cell.row = row;
5573 sheet->selection_cell.col = column;
5575 range.col0=MIN(column,sheet->active_cell.col);
5576 range.coli=MAX(column,sheet->active_cell.col);
5577 range.row0=MIN(row,sheet->active_cell.row);
5578 range.rowi=MAX(row,sheet->active_cell.row);
5580 if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5581 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5582 state==GTK_SHEET_NORMAL)
5583 gtk_sheet_real_select_range(sheet, &range);
5587 /* Removed by SDB while cleaning up key press behavior */
5588 #if 0
5589 static gint
5590 gtk_sheet_entry_key_press(GtkWidget *widget,
5591 GdkEventKey *key)
5593 gboolean focus;
5594 #ifdef DEBUG
5595 printf("Entered gtk_sheet_entry_key_press. . . . . \n");
5596 #endif
5598 gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5599 return focus;
5601 #endif
5603 static gint
5604 gtk_sheet_key_press(GtkWidget *widget,
5605 GdkEventKey *key)
5607 GtkSheet *sheet;
5608 gint row, col;
5609 gint state;
5610 gboolean extend_selection = FALSE;
5611 #if 0
5612 gboolean force_move = FALSE;
5613 #endif
5614 gboolean in_selection = FALSE;
5615 gboolean veto = TRUE;
5616 gint scroll = 1;
5618 sheet = GTK_SHEET(widget);
5620 #ifdef DEBUG
5621 printf("\n\nJust entered gtk_sheet_key_press. . . . \n");
5622 #endif
5625 if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5626 key->keyval==GDK_Control_R) return FALSE;
5630 if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5631 gtk_sheet_clip_range(sheet, sheet->range);
5632 if(key->keyval=='x' || key->keyval == 'X')
5633 gtk_sheet_unclip_range(sheet);
5634 return FALSE;
5638 /* extend_selection is set when shift, ctrl, etc is pressed & held down */
5639 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L
5640 || key->keyval==GDK_Shift_R;
5642 #ifdef DEBUG
5643 printf(". . . . extend_selection = %d\n", extend_selection);
5644 #endif
5646 state=sheet->state;
5647 in_selection = GTK_SHEET_IN_SELECTION(sheet);
5648 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5650 #ifdef DEBUG
5651 printf("We are about to enter the switch statement. . .\n");
5652 #endif
5654 switch(key->keyval){
5655 case GDK_Return: case GDK_KP_Enter:
5656 if(sheet->state == GTK_SHEET_NORMAL &&
5657 !GTK_SHEET_IN_SELECTION(sheet))
5658 gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
5659 "key_press_event");
5660 row = sheet->active_cell.row;
5661 col = sheet->active_cell.col;
5662 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5663 row = MIN_VISIBLE_ROW(sheet)-1;
5664 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5665 col = MIN_VISIBLE_COLUMN(sheet);
5666 if(row < sheet->maxrow){
5667 row = row + scroll;
5668 while(!sheet->row[row].is_visible && row<sheet->maxrow) row++;
5670 gtk_sheet_click_cell(sheet, row, col, &veto);
5671 extend_selection = FALSE;
5672 break;
5674 case GDK_ISO_Left_Tab:
5675 case GDK_Left: /* Left arrow */
5676 #ifdef DEBUG
5677 printf("In gtk_sheet_key_press, received GDK_Left.\n");
5678 #endif
5679 row = sheet->active_cell.row;
5680 col = sheet->active_cell.col;
5681 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5682 col = MIN_VISIBLE_COLUMN(sheet)-1;
5683 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5684 row = MIN_VISIBLE_ROW(sheet);
5685 if(col > 0){
5686 col = col - scroll;
5687 while(!sheet->column[col].is_visible && col>0) col--;
5688 col=MAX(0, col);
5690 gtk_sheet_click_cell(sheet, row, col, &veto);
5691 extend_selection = FALSE;
5692 break;
5694 case GDK_Tab:
5695 case GDK_Right: /* Right arrow */
5696 #ifdef DEBUG
5697 printf("In gtk_sheet_key_press, received GDK_Right.\n");
5698 #endif
5699 row = sheet->active_cell.row;
5700 col = sheet->active_cell.col;
5701 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5702 col = MIN_VISIBLE_COLUMN(sheet)-1;
5703 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5704 row = MIN_VISIBLE_ROW(sheet);
5705 if(col < sheet->maxcol){
5706 col = col + scroll;
5707 while(!sheet->column[col].is_visible && col<sheet->maxcol) col++;
5709 gtk_sheet_click_cell(sheet, row, col, &veto);
5710 extend_selection = FALSE;
5711 break;
5713 /* case GDK_BackSpace:
5714 if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5715 if(sheet->active_cell.col > 0){
5716 col = sheet->active_cell.col - scroll;
5717 row = sheet->active_cell.row;
5718 while(!sheet->column[col].is_visible && col > 0) col--;
5721 gtk_sheet_click_cell(sheet, row, col, &veto);
5722 extend_selection = FALSE;
5723 break;
5726 case GDK_Page_Up:
5727 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5728 case GDK_Up: /* arrow key up */
5729 if(extend_selection){
5730 if(state==GTK_STATE_NORMAL){
5731 row=sheet->active_cell.row;
5732 col=sheet->active_cell.col;
5733 gtk_sheet_click_cell(sheet, row, col, &veto);
5734 if(!veto) break;
5736 if(sheet->selection_cell.row > 0){
5737 row = sheet->selection_cell.row - scroll;
5738 while(!sheet->row[row].is_visible && row > 0) row--;
5739 row = MAX(0, row);
5740 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5742 return TRUE;
5744 col = sheet->active_cell.col;
5745 row = sheet->active_cell.row;
5746 if(state==GTK_SHEET_COLUMN_SELECTED)
5747 row = MIN_VISIBLE_ROW(sheet);
5748 if(state==GTK_SHEET_ROW_SELECTED)
5749 col = MIN_VISIBLE_COLUMN(sheet);
5750 row = row - scroll;
5751 while(!sheet->row[row].is_visible && row > 0) row--;
5752 row = MAX(0,row);
5753 gtk_sheet_click_cell(sheet, row, col, &veto);
5754 extend_selection = FALSE;
5755 break;
5757 case GDK_Page_Down:
5758 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5759 case GDK_Down: /* arrow key down */
5760 if(extend_selection){
5761 if(state==GTK_STATE_NORMAL){
5762 row=sheet->active_cell.row;
5763 col=sheet->active_cell.col;
5764 gtk_sheet_click_cell(sheet, row, col, &veto);
5765 if(!veto) break;
5767 if(sheet->selection_cell.row < sheet->maxrow){
5768 row = sheet->selection_cell.row + scroll;
5769 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5770 row = MIN(sheet->maxrow, row);
5771 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5773 return TRUE;
5775 col = sheet->active_cell.col;
5776 row = sheet->active_cell.row;
5777 if(sheet->active_cell.row < sheet->maxrow){
5778 if(state==GTK_SHEET_COLUMN_SELECTED)
5779 row = MIN_VISIBLE_ROW(sheet)-1;
5780 if(state==GTK_SHEET_ROW_SELECTED)
5781 col = MIN_VISIBLE_COLUMN(sheet);
5782 row = row + scroll;
5783 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5784 row = MIN(sheet->maxrow, row);
5786 gtk_sheet_click_cell(sheet, row, col, &veto);
5787 extend_selection = FALSE;
5788 break;
5790 #if 0
5791 case GDK_Right:
5792 if(extend_selection){
5793 if(state==GTK_STATE_NORMAL){
5794 row=sheet->active_cell.row;
5795 col=sheet->active_cell.col;
5796 gtk_sheet_click_cell(sheet, row, col, &veto);
5797 if(!veto) break;
5799 if(sheet->selection_cell.col < sheet->maxcol){
5800 col = sheet->selection_cell.col + 1;
5801 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5802 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5804 return TRUE;
5806 col = sheet->active_cell.col;
5807 row = sheet->active_cell.row;
5808 if(sheet->active_cell.col < sheet->maxcol){
5809 col ++;
5810 if(state==GTK_SHEET_ROW_SELECTED)
5811 col = MIN_VISIBLE_COLUMN(sheet)-1;
5812 if(state==GTK_SHEET_COLUMN_SELECTED)
5813 row = MIN_VISIBLE_ROW(sheet);
5814 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5815 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5816 || force_move) {
5817 gtk_sheet_click_cell(sheet, row, col, &veto);
5819 else
5820 return FALSE;
5822 extend_selection = FALSE;
5823 break;
5826 case GDK_Left:
5827 if(extend_selection){
5828 if(state==GTK_STATE_NORMAL){
5829 row=sheet->active_cell.row;
5830 col=sheet->active_cell.col;
5831 gtk_sheet_click_cell(sheet, row, col, &veto);
5832 if(!veto) break;
5834 if(sheet->selection_cell.col > 0){
5835 col = sheet->selection_cell.col - 1;
5836 while(!sheet->column[col].is_visible && col > 0) col--;
5837 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5839 return TRUE;
5841 col = sheet->active_cell.col - 1;
5842 row = sheet->active_cell.row;
5843 if(state==GTK_SHEET_ROW_SELECTED)
5844 col = MIN_VISIBLE_COLUMN(sheet)-1;
5845 if(state==GTK_SHEET_COLUMN_SELECTED)
5846 row = MIN_VISIBLE_ROW(sheet);
5847 while(!sheet->column[col].is_visible && col > 0) col--;
5848 col = MAX(0, col);
5850 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5851 || force_move){
5852 gtk_sheet_click_cell(sheet, row, col, &veto);
5854 else
5855 return FALSE;
5856 extend_selection = FALSE;
5857 break;
5858 #endif
5861 case GDK_Home:
5862 row=0;
5863 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5864 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5865 extend_selection = FALSE;
5866 break;
5868 case GDK_End:
5869 row=sheet->maxrow;
5870 while(!sheet->row[row].is_visible && row > 0) row--;
5871 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5872 extend_selection = FALSE;
5873 break;
5875 default:
5876 #ifdef DEBUG
5877 printf("In gtk_sheet_key_press, after switch, found default case.\n");
5878 printf(" User probably typed letter key or DEL.\n");
5879 #endif
5880 if(in_selection) {
5881 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5882 if(extend_selection) return TRUE;
5884 if(state == GTK_SHEET_ROW_SELECTED)
5885 sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5886 if(state == GTK_SHEET_COLUMN_SELECTED)
5887 sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5888 return FALSE;
5889 } /* switch */
5891 if(extend_selection) return TRUE;
5893 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5894 sheet->active_cell.col);
5896 return TRUE;
5899 static void
5900 gtk_sheet_size_request (GtkWidget * widget,
5901 GtkRequisition * requisition)
5903 GtkSheet *sheet;
5904 GList *children;
5905 GtkSheetChild *child;
5906 GtkRequisition child_requisition;
5908 g_return_if_fail (widget != NULL);
5909 g_return_if_fail (GTK_IS_SHEET (widget));
5910 g_return_if_fail (requisition != NULL);
5912 sheet = GTK_SHEET (widget);
5914 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5915 requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5917 /* compute the size of the column title area */
5918 if(sheet->column_titles_visible)
5919 requisition->height += sheet->column_title_area.height;
5921 /* compute the size of the row title area */
5922 if(sheet->row_titles_visible)
5923 requisition->width += sheet->row_title_area.width;
5925 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5926 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5927 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5928 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5930 if(!sheet->column_titles_visible)
5931 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5933 if(!sheet->row_titles_visible)
5934 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5936 children = sheet->children;
5937 while (children)
5939 child = children->data;
5940 children = g_list_next(children);
5942 gtk_widget_size_request(child->widget, &child_requisition);
5947 static void
5948 gtk_sheet_size_allocate (GtkWidget * widget,
5949 GtkAllocation * allocation)
5951 GtkSheet *sheet;
5952 GtkAllocation sheet_allocation;
5953 gint border_width;
5955 g_return_if_fail (widget != NULL);
5956 g_return_if_fail (GTK_IS_SHEET (widget));
5957 g_return_if_fail (allocation != NULL);
5959 sheet = GTK_SHEET (widget);
5960 widget->allocation = *allocation;
5961 border_width = GTK_CONTAINER(widget)->border_width;
5963 if (GTK_WIDGET_REALIZED (widget))
5964 gdk_window_move_resize (widget->window,
5965 allocation->x + border_width,
5966 allocation->y + border_width,
5967 allocation->width - 2*border_width,
5968 allocation->height - 2*border_width);
5970 /* use internal allocation structure for all the math
5971 * because it's easier than always subtracting the container
5972 * border width */
5973 sheet->internal_allocation.x = 0;
5974 sheet->internal_allocation.y = 0;
5975 sheet->internal_allocation.width = allocation->width - 2*border_width;
5976 sheet->internal_allocation.height = allocation->height - 2*border_width;
5978 sheet_allocation.x = 0;
5979 sheet_allocation.y = 0;
5980 sheet_allocation.width = allocation->width - 2*border_width;
5981 sheet_allocation.height = allocation->height - 2*border_width;
5983 sheet->sheet_window_width = sheet_allocation.width;
5984 sheet->sheet_window_height = sheet_allocation.height;
5986 if (GTK_WIDGET_REALIZED (widget))
5987 gdk_window_move_resize (sheet->sheet_window,
5988 sheet_allocation.x,
5989 sheet_allocation.y,
5990 sheet_allocation.width,
5991 sheet_allocation.height);
5993 /* position the window which holds the column title buttons */
5994 sheet->column_title_area.x = 0;
5995 sheet->column_title_area.y = 0;
5996 if(sheet->row_titles_visible)
5997 sheet->column_title_area.x = sheet->row_title_area.width;
5998 sheet->column_title_area.width = sheet_allocation.width -
5999 sheet->column_title_area.x;
6000 if(GTK_WIDGET_REALIZED(widget) && sheet->column_titles_visible)
6001 gdk_window_move_resize (sheet->column_title_window,
6002 sheet->column_title_area.x,
6003 sheet->column_title_area.y,
6004 sheet->column_title_area.width,
6005 sheet->column_title_area.height);
6007 sheet->sheet_window_width = sheet_allocation.width;
6008 sheet->sheet_window_height = sheet_allocation.height;
6010 /* column button allocation */
6011 size_allocate_column_title_buttons (sheet);
6013 /* position the window which holds the row title buttons */
6014 sheet->row_title_area.x = 0;
6015 sheet->row_title_area.y = 0;
6016 if(sheet->column_titles_visible)
6017 sheet->row_title_area.y = sheet->column_title_area.height;
6018 sheet->row_title_area.height = sheet_allocation.height -
6019 sheet->row_title_area.y;
6021 if(GTK_WIDGET_REALIZED(widget) && sheet->row_titles_visible)
6022 gdk_window_move_resize (sheet->row_title_window,
6023 sheet->row_title_area.x,
6024 sheet->row_title_area.y,
6025 sheet->row_title_area.width,
6026 sheet->row_title_area.height);
6029 /* row button allocation */
6030 size_allocate_row_title_buttons (sheet);
6032 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6033 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6034 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6035 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6037 if(!sheet->column_titles_visible)
6038 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6040 if(!sheet->row_titles_visible)
6041 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6043 size_allocate_column_title_buttons(sheet);
6044 size_allocate_row_title_buttons(sheet);
6046 /* re-scale backing pixmap */
6047 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
6048 gtk_sheet_position_children(sheet);
6050 /* set the scrollbars adjustments */
6051 adjust_scrollbars (sheet);
6054 static void
6055 size_allocate_column_title_buttons (GtkSheet * sheet)
6057 gint i;
6058 gint x,width;
6060 if (!sheet->column_titles_visible) return;
6061 if (!GTK_WIDGET_REALIZED (sheet))
6062 return;
6064 width = sheet->sheet_window_width;
6065 x = 0;
6067 if(sheet->row_titles_visible)
6069 width -= sheet->row_title_area.width;
6070 x = sheet->row_title_area.width;
6073 if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
6075 sheet->column_title_area.width = width;
6076 sheet->column_title_area.x = x;
6077 gdk_window_move_resize (sheet->column_title_window,
6078 sheet->column_title_area.x,
6079 sheet->column_title_area.y,
6080 sheet->column_title_area.width,
6081 sheet->column_title_area.height);
6085 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol)
6086 gdk_window_clear_area (sheet->column_title_window,
6087 0,0,
6088 sheet->column_title_area.width,
6089 sheet->column_title_area.height);
6091 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6093 for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
6094 gtk_sheet_button_draw(sheet,-1,i);
6097 static void
6098 size_allocate_row_title_buttons (GtkSheet * sheet)
6100 gint i;
6101 gint y, height;
6103 if (!sheet->row_titles_visible) return;
6104 if (!GTK_WIDGET_REALIZED (sheet))
6105 return;
6107 height = sheet->sheet_window_height;
6108 y = 0;
6110 if(sheet->column_titles_visible)
6112 height -= sheet->column_title_area.height;
6113 y = sheet->column_title_area.height;
6116 if(sheet->row_title_area.height != height || sheet->row_title_area.y != y){
6117 sheet->row_title_area.y = y;
6118 sheet->row_title_area.height = height;
6119 gdk_window_move_resize (sheet->row_title_window,
6120 sheet->row_title_area.x,
6121 sheet->row_title_area.y,
6122 sheet->row_title_area.width,
6123 sheet->row_title_area.height);
6125 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow)
6126 gdk_window_clear_area (sheet->row_title_window,
6127 0,0,
6128 sheet->row_title_area.width,
6129 sheet->row_title_area.height);
6131 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
6133 for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
6134 gtk_sheet_button_draw(sheet,i,-1);
6137 static void
6138 gtk_sheet_recalc_top_ypixels(GtkSheet *sheet, gint row)
6140 gint i, cy;
6142 cy = sheet->column_title_area.height;
6143 if(!sheet->column_titles_visible) cy = 0;
6144 for(i=0; i<=sheet->maxrow; i++){
6145 sheet->row[i].top_ypixel=cy;
6146 if(sheet->row[i].is_visible) cy+=sheet->row[i].height;
6150 static void
6151 gtk_sheet_recalc_left_xpixels(GtkSheet *sheet, gint column)
6153 gint i, cx;
6155 cx = sheet->row_title_area.width;
6156 if(!sheet->row_titles_visible) cx = 0;
6157 for(i=0; i<=sheet->maxcol; i++){
6158 sheet->column[i].left_xpixel=cx;
6159 if(sheet->column[i].is_visible) cx+=sheet->column[i].width;
6166 static void
6167 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
6169 GtkAllocation shentry_allocation;
6170 GtkSheetCellAttr attributes;
6171 GtkEntry *sheet_entry;
6172 GtkStyle *style = NULL, *previous_style = NULL;
6173 gint row, col;
6174 gint size, max_size, text_size, column_width;
6175 const gchar *text;
6177 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6178 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
6180 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
6182 gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes);
6184 if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
6186 if(!GTK_WIDGET(sheet_entry)->style)
6187 gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
6189 previous_style = GTK_WIDGET(sheet_entry)->style;
6191 style = gtk_style_copy(previous_style);
6192 style->bg[GTK_STATE_NORMAL] = attributes.background;
6193 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
6194 style->text[GTK_STATE_NORMAL] = attributes.foreground;
6195 style->bg[GTK_STATE_ACTIVE] = attributes.background;
6196 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
6197 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
6199 pango_font_description_free(style->font_desc);
6200 style->font_desc = pango_font_description_copy(attributes.font_desc);
6202 GTK_WIDGET(sheet_entry)->style = style;
6203 gtk_widget_size_request(sheet->sheet_entry, NULL);
6204 GTK_WIDGET(sheet_entry)->style = previous_style;
6206 if(style != previous_style){
6207 style->bg[GTK_STATE_NORMAL] = previous_style->bg[GTK_STATE_NORMAL];
6208 style->fg[GTK_STATE_NORMAL] = previous_style->fg[GTK_STATE_NORMAL];
6209 style->bg[GTK_STATE_ACTIVE] = previous_style->bg[GTK_STATE_ACTIVE];
6210 style->fg[GTK_STATE_ACTIVE] = previous_style->fg[GTK_STATE_ACTIVE];
6211 gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
6215 max_size = 0;
6217 text_size = 0;
6218 text = gtk_entry_get_text(GTK_ENTRY(sheet_entry));
6219 if(text && strlen(text) > 0){
6220 text_size = STRING_WIDTH(GTK_WIDGET(sheet), attributes.font_desc, text);
6223 column_width=sheet->column[sheet->active_cell.col].width;
6225 size=MIN(text_size, max_size);
6226 size=MAX(size,column_width-2*CELLOFFSET);
6228 row=sheet->active_cell.row;
6229 col=sheet->active_cell.col;
6231 shentry_allocation.x = COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
6232 shentry_allocation.y = ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
6233 shentry_allocation.width = column_width;
6234 shentry_allocation.height = sheet->row[sheet->active_cell.row].height;
6236 shentry_allocation.x += 2;
6237 shentry_allocation.y += 2;
6238 shentry_allocation.width -= MIN(shentry_allocation.width, 3);
6239 shentry_allocation.height -= MIN(shentry_allocation.height, 3);
6241 gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
6243 if(previous_style == style) gtk_style_unref(previous_style);
6247 static void
6248 create_sheet_entry(GtkSheet *sheet)
6250 GtkWidget *widget;
6251 GtkWidget *parent;
6252 GtkWidget *entry;
6253 GtkStyle *style;
6254 gint found_entry = FALSE;
6256 widget = GTK_WIDGET(sheet);
6258 style = gtk_style_copy(GTK_WIDGET(sheet)->style);
6260 if(sheet->sheet_entry){
6261 /* avoids warnings */
6262 gtk_widget_ref(sheet->sheet_entry);
6263 gtk_widget_unparent(sheet->sheet_entry);
6264 gtk_widget_destroy(sheet->sheet_entry);
6267 if(sheet->entry_type){
6269 if(!gtk_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6271 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6273 sheet->sheet_entry = parent;
6275 entry = gtk_sheet_get_entry (sheet);
6276 if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6278 } else {
6280 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6281 entry = parent;
6282 found_entry = TRUE;
6286 if(!found_entry){
6288 g_warning ("Entry type must be GtkEntry subclass, using default");
6289 entry = gtk_entry_new ();
6290 sheet->sheet_entry = entry;
6292 } else {
6294 sheet->sheet_entry = parent;
6299 } else {
6301 entry = gtk_entry_new ();
6302 sheet->sheet_entry = entry;
6306 gtk_widget_size_request(sheet->sheet_entry, NULL);
6308 if(GTK_WIDGET_REALIZED(sheet))
6310 gtk_widget_set_parent_window (sheet->sheet_entry, sheet->sheet_window);
6311 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6312 gtk_widget_realize(sheet->sheet_entry);
6315 /* #if 0 */
6316 /* SDB says: I need to work out the event passing system */
6317 gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6318 (GtkSignalFunc) gtk_sheet_key_press,
6319 GTK_OBJECT(sheet));
6320 /* gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6321 (GtkSignalFunc) gtk_sheet_entry_key_press,
6322 GTK_OBJECT(sheet));
6324 /* #endif */
6326 gtk_widget_show (sheet->sheet_entry);
6330 GtkWidget *
6331 gtk_sheet_get_entry(GtkSheet *sheet)
6333 GtkWidget *parent;
6334 GtkWidget *entry = NULL;
6335 GtkTableChild *table_child;
6336 GtkBoxChild *box_child;
6337 GList *children = NULL;
6339 g_return_val_if_fail (sheet != NULL, NULL);
6340 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6341 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6343 if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6345 parent = GTK_WIDGET(sheet->sheet_entry);
6347 if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6348 if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6350 if(!children) return NULL;
6352 while(children){
6353 if(GTK_IS_TABLE(parent)) {
6354 table_child = children->data;
6355 entry = table_child->widget;
6357 if(GTK_IS_BOX(parent)){
6358 box_child = children->data;
6359 entry = box_child->widget;
6362 if(GTK_IS_ENTRY(entry))
6363 break;
6364 children = g_list_next(children);
6368 if(!GTK_IS_ENTRY(entry)) return NULL;
6370 return (entry);
6374 GtkWidget *
6375 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6377 g_return_val_if_fail (sheet != NULL, NULL);
6378 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6379 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6381 return (sheet->sheet_entry);
6384 /* BUTTONS */
6385 static void
6386 row_button_set (GtkSheet *sheet, gint row)
6388 if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6390 sheet->row[row].button.state = GTK_STATE_ACTIVE;
6391 gtk_sheet_button_draw(sheet, row, -1);
6395 static void
6396 column_button_set (GtkSheet *sheet, gint column)
6398 if(sheet->column[column].button.state == GTK_STATE_ACTIVE) return;
6400 sheet->column[column].button.state = GTK_STATE_ACTIVE;
6401 gtk_sheet_button_draw(sheet, -1, column);
6405 static void
6406 row_button_release (GtkSheet *sheet, gint row)
6408 if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6410 sheet->row[row].button.state = GTK_STATE_NORMAL;
6411 gtk_sheet_button_draw(sheet, row, -1);
6414 static void
6415 column_button_release (GtkSheet *sheet, gint column)
6417 if(sheet->column[column].button.state == GTK_STATE_NORMAL) return;
6419 sheet->column[column].button.state = GTK_STATE_NORMAL;
6420 gtk_sheet_button_draw(sheet, -1, column);
6423 static void
6424 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6426 GdkWindow *window = NULL;
6427 GtkShadowType shadow_type;
6428 guint width = 0, height = 0;
6429 gint x = 0, y = 0;
6430 gint index = 0;
6431 gint text_width = 0, text_height = 0;
6432 GtkSheetButton *button = NULL;
6433 GtkSheetChild *child = NULL;
6434 GdkRectangle allocation;
6435 gboolean is_sensitive = FALSE;
6436 gint state = 0;
6437 gint len = 0;
6438 gchar *line = 0;
6439 gchar *words = 0;
6440 gchar label[10];
6442 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6444 if(row >= 0 && !sheet->row[row].is_visible) return;
6445 if(column >= 0 && !sheet->column[column].is_visible) return;
6446 if(row >= 0 && !sheet->row_titles_visible) return;
6447 if(column >= 0 && !sheet->column_titles_visible) return;
6448 if(column>=0 && column <MIN_VISIBLE_COLUMN(sheet)) return;
6449 if(column>=0 && column >MAX_VISIBLE_COLUMN(sheet)) return;
6450 if(row>=0 && row <MIN_VISIBLE_ROW(sheet)) return;
6451 if(row>=0 && row >MAX_VISIBLE_ROW(sheet)) return;
6452 if( (row == -1) && (column == -1) ) return;
6454 if(row==-1){
6455 window=sheet->column_title_window;
6456 button=&sheet->column[column].button;
6457 index=column;
6458 x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6459 if(sheet->row_titles_visible) x -= sheet->row_title_area.width;
6460 y = 0;
6461 width = sheet->column[column].width;
6462 height = sheet->column_title_area.height;
6463 is_sensitive=sheet->column[column].is_sensitive;
6465 else if(column==-1){
6466 window=sheet->row_title_window;
6467 button=&sheet->row[row].button;
6468 index=row;
6469 x = 0;
6470 y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6471 if(sheet->column_titles_visible) y-=sheet->column_title_area.height;
6472 width = sheet->row_title_area.width;
6473 height = sheet->row[row].height;
6474 is_sensitive=sheet->row[row].is_sensitive;
6477 allocation.x = x;
6478 allocation.y = y;
6479 allocation.width = width;
6480 allocation.height = height;
6482 gdk_window_clear_area (window,
6483 x, y,
6484 width, height);
6486 gtk_paint_box (sheet->button->style, window,
6487 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6488 &allocation, GTK_WIDGET(sheet),
6489 "buttondefault", x, y, width, height);
6491 state = button->state;
6492 if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6494 if (state == GTK_STATE_ACTIVE)
6495 shadow_type = GTK_SHADOW_IN;
6496 else
6497 shadow_type = GTK_SHADOW_OUT;
6499 if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6500 gtk_paint_box (sheet->button->style, window,
6501 button->state, shadow_type,
6502 &allocation, GTK_WIDGET(sheet),
6503 "button", x, y, width, height);
6505 if(button->label_visible){
6507 text_height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))-2*CELLOFFSET;
6509 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6510 &allocation);
6511 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6513 y += DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))/2 + sheet->button->style->ythickness + DEFAULT_FONT_DESCENT(GTK_WIDGET(sheet));
6515 if(button->label && strlen(button->label)>0){
6517 words=button->label;
6518 line = g_new(gchar, 1);
6519 line[0]='\0';
6521 while(words && *words != '\0'){
6522 if(*words != '\n'){
6523 len=strlen(line);
6524 line=g_realloc(line, len+2);
6525 line[len]=*words;
6526 line[len+1]='\0';
6528 if(*words == '\n' || *(words+1) == '\0'){
6529 text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, line);
6531 switch(button->justification){
6532 case GTK_JUSTIFY_LEFT:
6533 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6534 &allocation, GTK_WIDGET(sheet), "label",
6535 x + CELLOFFSET, y,
6536 line);
6537 break;
6538 case GTK_JUSTIFY_RIGHT:
6539 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6540 &allocation, GTK_WIDGET(sheet), "label",
6541 x + width - text_width - CELLOFFSET, y,
6542 line);
6543 break;
6544 case GTK_JUSTIFY_CENTER:
6545 default:
6546 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6547 &allocation, GTK_WIDGET(sheet), "label",
6548 x + (width - text_width) /2, y,
6549 line);
6552 y += text_height + 2;
6554 g_free(line);
6555 line = g_new(gchar, 1);
6556 line[0]='\0';
6558 words++;
6560 g_free(line);
6561 }else{
6562 sprintf(label,"%d",index);
6563 text_width = STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, label);
6565 switch(button->justification){
6566 case GTK_JUSTIFY_LEFT:
6567 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6568 &allocation, GTK_WIDGET(sheet), "label",
6569 x + CELLOFFSET, y,
6570 label);
6571 break;
6572 case GTK_JUSTIFY_RIGHT:
6573 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6574 &allocation, GTK_WIDGET(sheet), "label",
6575 x + width - text_width - CELLOFFSET, y,
6576 label);
6577 break;
6578 case GTK_JUSTIFY_CENTER:
6579 default:
6580 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6581 &allocation, GTK_WIDGET(sheet), "label",
6582 x + (width - text_width) /2, y,
6583 label);
6588 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6589 NULL);
6590 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6594 if((child = button->child) && (child->widget)){
6595 child->x = allocation.x;
6596 child->y = allocation.y;
6598 child->x += (width - child->widget->requisition.width) / 2;
6599 child->y += (height - child->widget->requisition.height) / 2;
6600 allocation.x = child->x;
6601 allocation.y = child->y;
6602 allocation.width = child->widget->requisition.width;
6603 allocation.height = child->widget->requisition.height;
6605 x = child->x;
6606 y = child->y;
6608 gtk_widget_set_state(child->widget, button->state);
6610 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6611 GTK_WIDGET_MAPPED(child->widget))
6613 gtk_widget_size_allocate(child->widget,
6614 &allocation);
6615 gtk_widget_queue_draw(child->widget);
6622 /* SCROLLBARS
6624 * functions:
6625 * adjust_scrollbars
6626 * vadjustment_changed
6627 * hadjustment_changed
6628 * vadjustment_value_changed
6629 * hadjustment_value_changed */
6631 static void
6632 adjust_scrollbars (GtkSheet * sheet)
6635 if(sheet->vadjustment){
6636 sheet->vadjustment->page_size = sheet->sheet_window_height;
6637 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6638 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6639 sheet->vadjustment->lower = 0;
6640 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6642 if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6644 sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) -
6645 sheet->sheet_window_height);
6646 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
6647 "value_changed");
6650 gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6654 if(sheet->hadjustment){
6655 sheet->hadjustment->page_size = sheet->sheet_window_width;
6656 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6657 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6658 sheet->hadjustment->lower = 0;
6659 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6661 if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6663 sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) -
6664 sheet->sheet_window_width);
6665 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment),
6666 "value_changed");
6669 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6673 if(GTK_WIDGET_REALIZED(sheet))
6675 if(sheet->row_titles_visible){
6676 size_allocate_row_title_buttons(sheet);
6677 gdk_window_show(sheet->row_title_window);
6680 if(sheet->column_titles_visible){
6681 size_allocate_column_title_buttons(sheet);
6682 gdk_window_show(sheet->column_title_window);
6685 gtk_sheet_range_draw(sheet, NULL);
6691 static void
6692 vadjustment_changed (GtkAdjustment * adjustment,
6693 gpointer data)
6695 GtkSheet *sheet;
6697 g_return_if_fail (adjustment != NULL);
6698 g_return_if_fail (data != NULL);
6700 sheet = GTK_SHEET (data);
6704 static void
6705 hadjustment_changed (GtkAdjustment * adjustment,
6706 gpointer data)
6708 GtkSheet *sheet;
6710 g_return_if_fail (adjustment != NULL);
6711 g_return_if_fail (data != NULL);
6713 sheet = GTK_SHEET (data);
6718 static void
6719 vadjustment_value_changed (GtkAdjustment * adjustment,
6720 gpointer data)
6722 GtkSheet *sheet;
6723 gint diff, value, old_value;
6724 gint i;
6725 gint row, new_row;
6726 gint y=0;
6728 g_return_if_fail (adjustment != NULL);
6729 g_return_if_fail (data != NULL);
6730 g_return_if_fail (GTK_IS_SHEET (data));
6732 sheet = GTK_SHEET (data);
6734 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6736 row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6737 if(!sheet->column_titles_visible)
6738 row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6740 old_value = -sheet->voffset;
6742 for(i=0; i<= sheet->maxrow; i++){
6743 if(sheet->row[i].is_visible) y+=sheet->row[i].height;
6744 if(y > adjustment->value) break;
6746 y-=sheet->row[i].height;
6747 new_row=i;
6749 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6750 sheet->row[i].height > sheet->vadjustment->step_increment){
6751 /* This avoids embarrassing twitching */
6752 if(row == new_row && row != sheet->maxrow &&
6753 adjustment->value - sheet->old_vadjustment >=
6754 sheet->vadjustment->step_increment &&
6755 new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6756 new_row+=1;
6757 y=y+sheet->row[row].height;
6761 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6762 if(sheet->old_vadjustment >= 0. && row == new_row){
6763 sheet->old_vadjustment = sheet->vadjustment->value;
6764 return;
6767 sheet->old_vadjustment = sheet->vadjustment->value;
6768 adjustment->value=y;
6771 if(new_row == 0){
6772 sheet->vadjustment->step_increment=
6773 sheet->row[0].height;
6774 }else{
6775 sheet->vadjustment->step_increment=
6776 MIN(sheet->row[new_row].height, sheet->row[new_row-1].height);
6779 sheet->vadjustment->value=adjustment->value;
6781 value = adjustment->value;
6783 if (value >= -sheet->voffset)
6785 /* scroll down */
6786 diff = value + sheet->voffset;
6788 else
6790 /* scroll up */
6791 diff = -sheet->voffset - value;
6794 sheet->voffset = -value;
6796 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6797 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6798 if(!sheet->column_titles_visible)
6799 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6801 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6802 sheet->state == GTK_SHEET_NORMAL &&
6803 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6804 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6805 sheet->active_cell.col))
6807 const gchar *text;
6809 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6811 if(!text || strlen(text)==0)
6812 gtk_sheet_cell_clear(sheet,
6813 sheet->active_cell.row,
6814 sheet->active_cell.col);
6815 gtk_widget_unmap(sheet->sheet_entry);
6818 gtk_sheet_position_children(sheet);
6820 gtk_sheet_range_draw(sheet, NULL);
6821 size_allocate_row_title_buttons(sheet);
6822 size_allocate_global_button(sheet);
6825 static void
6826 hadjustment_value_changed (GtkAdjustment * adjustment,
6827 gpointer data)
6829 GtkSheet *sheet;
6830 gint i, diff, value, old_value;
6831 gint column, new_column;
6832 gint x=0;
6834 g_return_if_fail (adjustment != NULL);
6835 g_return_if_fail (data != NULL);
6836 g_return_if_fail (GTK_IS_SHEET (data));
6838 sheet = GTK_SHEET (data);
6840 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6842 column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6843 if(!sheet->row_titles_visible)
6844 column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6846 old_value = -sheet->hoffset;
6848 for(i=0; i<= sheet->maxcol; i++){
6849 if(sheet->column[i].is_visible) x+=sheet->column[i].width;
6850 if(x > adjustment->value) break;
6852 x-=sheet->column[i].width;
6853 new_column=i;
6855 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6856 sheet->column[i].width > sheet->hadjustment->step_increment){
6857 /* This avoids embarrassing twitching */
6858 if(column == new_column && column != sheet->maxcol &&
6859 adjustment->value - sheet->old_hadjustment >=
6860 sheet->hadjustment->step_increment &&
6861 new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6862 new_column+=1;
6863 x=x+sheet->column[column].width;
6867 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6868 if(sheet->old_hadjustment >= 0. && new_column == column){
6869 sheet->old_hadjustment = sheet->hadjustment->value;
6870 return;
6873 sheet->old_hadjustment = sheet->hadjustment->value;
6874 adjustment->value=x;
6876 if(new_column == 0){
6877 sheet->hadjustment->step_increment=
6878 sheet->column[0].width;
6879 }else{
6880 sheet->hadjustment->step_increment=
6881 MIN(sheet->column[new_column].width, sheet->column[new_column-1].width);
6885 sheet->hadjustment->value=adjustment->value;
6887 value = adjustment->value;
6889 if (value >= -sheet->hoffset)
6891 /* scroll right */
6892 diff = value + sheet->hoffset;
6894 else
6896 /* scroll left */
6897 diff = -sheet->hoffset - value;
6900 sheet->hoffset = -value;
6902 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6903 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6904 if(!sheet->row_titles_visible)
6905 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6907 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6908 sheet->state == GTK_SHEET_NORMAL &&
6909 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6910 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6911 sheet->active_cell.col))
6913 const gchar *text;
6915 text = gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6916 if(!text || strlen(text)==0)
6917 gtk_sheet_cell_clear(sheet,
6918 sheet->active_cell.row,
6919 sheet->active_cell.col);
6921 gtk_widget_unmap(sheet->sheet_entry);
6924 gtk_sheet_position_children(sheet);
6926 gtk_sheet_range_draw(sheet, NULL);
6927 size_allocate_column_title_buttons(sheet);
6931 /* COLUMN RESIZING */
6932 static void
6933 draw_xor_vline (GtkSheet * sheet)
6935 GtkWidget *widget;
6937 g_return_if_fail (sheet != NULL);
6939 widget = GTK_WIDGET (sheet);
6941 gdk_draw_line (widget->window, sheet->xor_gc,
6942 sheet->x_drag,
6943 sheet->column_title_area.height,
6944 sheet->x_drag,
6945 sheet->sheet_window_height + 1);
6948 /* ROW RESIZING */
6949 static void
6950 draw_xor_hline (GtkSheet * sheet)
6952 GtkWidget *widget;
6954 g_return_if_fail (sheet != NULL);
6956 widget = GTK_WIDGET (sheet);
6958 gdk_draw_line (widget->window, sheet->xor_gc,
6959 sheet->row_title_area.width,
6960 sheet->y_drag,
6962 sheet->sheet_window_width + 1,
6963 sheet->y_drag);
6966 /* SELECTED RANGE */
6967 static void
6968 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
6970 gint i;
6971 GdkRectangle clip_area, area;
6972 GdkGCValues values;
6974 area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
6975 area.y=ROW_TOP_YPIXEL(sheet, range.row0);
6976 area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
6977 sheet->column[range.coli].width;
6978 area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
6979 sheet->row[range.rowi].height;
6981 clip_area.x=sheet->row_title_area.width;
6982 clip_area.y=sheet->column_title_area.height;
6983 clip_area.width=sheet->sheet_window_width;
6984 clip_area.height=sheet->sheet_window_height;
6986 if(!sheet->row_titles_visible) clip_area.x = 0;
6987 if(!sheet->column_titles_visible) clip_area.y = 0;
6989 if(area.x<0) {
6990 area.width=area.width+area.x;
6991 area.x=0;
6993 if(area.width>clip_area.width) area.width=clip_area.width+10;
6994 if(area.y<0) {
6995 area.height=area.height+area.y;
6996 area.y=0;
6998 if(area.height>clip_area.height) area.height=clip_area.height+10;
7000 clip_area.x--;
7001 clip_area.y--;
7002 clip_area.width+=3;
7003 clip_area.height+=3;
7005 gdk_gc_get_values(sheet->xor_gc, &values);
7007 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
7009 for(i=-1;i<=1;i++)
7010 gdk_draw_rectangle(sheet->sheet_window,
7011 sheet->xor_gc,
7012 FALSE,
7013 area.x+i, area.y+i,
7014 area.width-2*i, area.height-2*i);
7017 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
7019 gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
7024 /* this function returns the new width of the column being resized given
7025 * the column and x position of the cursor; the x cursor position is passed
7026 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7027 static guint
7028 new_column_width (GtkSheet * sheet,
7029 gint column,
7030 gint * x)
7032 gint cx, width;
7033 GtkRequisition requisition;
7035 cx = *x;
7037 requisition.width = sheet->column[column].requisition;
7039 /* you can't shrink a column to less than its minimum width */
7040 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width)
7042 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width;
7045 /* don't grow past the end of the window */
7047 if (cx > sheet->sheet_window_width)
7049 *x = cx = sheet->sheet_window_width;
7052 /* calculate new column width making sure it doesn't end up
7053 * less than the minimum width */
7054 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
7055 if (width < requisition.width)
7056 width = requisition.width;
7058 sheet->column[column].width = width;
7059 gtk_sheet_recalc_left_xpixels(sheet, column+1);
7060 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
7061 size_allocate_column_title_buttons (sheet);
7063 return width;
7066 /* this function returns the new height of the row being resized given
7067 * the row and y position of the cursor; the y cursor position is passed
7068 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
7069 static guint
7070 new_row_height (GtkSheet * sheet,
7071 gint row,
7072 gint * y)
7074 GtkRequisition requisition;
7075 gint cy, height;
7077 cy = *y;
7079 requisition.height = sheet->row[row].requisition;
7081 /* you can't shrink a row to less than its minimum height */
7082 if (cy < ROW_TOP_YPIXEL (sheet, row) + requisition.height)
7085 *y = cy = ROW_TOP_YPIXEL (sheet, row) + requisition.height;
7088 /* don't grow past the end of the window */
7090 if (cy > sheet->sheet_window_height)
7092 *y = cy = sheet->sheet_window_height;
7095 /* calculate new row height making sure it doesn't end up
7096 * less than the minimum height */
7097 height = (cy - ROW_TOP_YPIXEL (sheet, row));
7098 if (height < requisition.height)
7099 height = requisition.height;
7101 sheet->row[row].height = height;
7102 gtk_sheet_recalc_top_ypixels(sheet, row);
7103 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
7104 size_allocate_row_title_buttons (sheet);
7106 return height;
7109 void
7110 gtk_sheet_set_column_width (GtkSheet * sheet,
7111 gint column,
7112 guint width)
7114 guint min_width;
7116 g_return_if_fail (sheet != NULL);
7117 g_return_if_fail (GTK_IS_SHEET (sheet));
7119 if (column < 0 || column > sheet->maxcol)
7120 return;
7122 gtk_sheet_column_size_request(sheet, column, &min_width);
7123 if(width < min_width) return;
7125 sheet->column[column].width = width;
7127 gtk_sheet_recalc_left_xpixels(sheet, column+1);
7129 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7130 size_allocate_column_title_buttons (sheet);
7131 adjust_scrollbars (sheet);
7132 gtk_sheet_size_allocate_entry(sheet);
7133 gtk_sheet_range_draw (sheet, NULL);
7134 } else
7136 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
7137 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
7141 void
7142 gtk_sheet_set_row_height (GtkSheet * sheet,
7143 gint row,
7144 guint height)
7146 guint min_height;
7148 g_return_if_fail (sheet != NULL);
7149 g_return_if_fail (GTK_IS_SHEET (sheet));
7151 if (row < 0 || row > sheet->maxrow)
7152 return;
7154 gtk_sheet_row_size_request(sheet, row, &min_height);
7155 if(height < min_height) return;
7157 sheet->row[row].height = height;
7159 gtk_sheet_recalc_top_ypixels(sheet, row+1);
7161 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
7162 size_allocate_row_title_buttons (sheet);
7163 adjust_scrollbars (sheet);
7164 gtk_sheet_size_allocate_entry(sheet);
7165 gtk_sheet_range_draw (sheet, NULL);
7168 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7169 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7174 void
7175 gtk_sheet_add_column(GtkSheet *sheet, guint ncols)
7178 g_return_if_fail (sheet != NULL);
7179 g_return_if_fail (GTK_IS_SHEET (sheet));
7181 AddColumn(sheet, ncols);
7183 if(!GTK_WIDGET_REALIZED(sheet)) return;
7185 adjust_scrollbars(sheet);
7187 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7189 sheet->old_hadjustment = -1.;
7190 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7191 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7192 "value_changed");
7195 void
7196 gtk_sheet_add_row(GtkSheet *sheet, guint nrows)
7199 g_return_if_fail (sheet != NULL);
7200 g_return_if_fail (GTK_IS_SHEET (sheet));
7202 AddRow(sheet, nrows);
7204 if(!GTK_WIDGET_REALIZED(sheet)) return;
7206 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7208 adjust_scrollbars(sheet);
7210 sheet->old_vadjustment = -1.;
7211 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7212 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7213 "value_changed");
7216 void
7217 gtk_sheet_insert_rows(GtkSheet *sheet, guint row, guint nrows)
7219 GList *children;
7220 GtkSheetChild *child;
7222 g_return_if_fail (sheet != NULL);
7223 g_return_if_fail (GTK_IS_SHEET (sheet));
7225 if(GTK_WIDGET_REALIZED(sheet))
7226 gtk_sheet_real_unselect_range(sheet, NULL);
7228 InsertRow(sheet, row, nrows);
7230 children = sheet->children;
7231 while(children)
7233 child = (GtkSheetChild *)children->data;
7235 if(child->attached_to_cell)
7236 if(child->row >= row) child->row += nrows;
7238 children = g_list_next(children);
7241 if(!GTK_WIDGET_REALIZED(sheet)) return;
7243 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7244 adjust_scrollbars(sheet);
7246 sheet->old_vadjustment = -1.;
7247 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7248 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7249 "value_changed");
7253 void
7254 gtk_sheet_insert_columns(GtkSheet *sheet, guint col, guint ncols)
7256 GList *children;
7257 GtkSheetChild *child;
7259 g_return_if_fail (sheet != NULL);
7260 g_return_if_fail (GTK_IS_SHEET (sheet));
7262 if(GTK_WIDGET_REALIZED(sheet))
7263 gtk_sheet_real_unselect_range(sheet, NULL);
7265 InsertColumn(sheet, col, ncols);
7267 children = sheet->children;
7268 while(children)
7270 child = (GtkSheetChild *)children->data;
7272 if(child->attached_to_cell)
7273 if(child->col >= col) child->col += ncols;
7275 children = g_list_next(children);
7278 if(!GTK_WIDGET_REALIZED(sheet)) return;
7280 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7281 adjust_scrollbars(sheet);
7283 sheet->old_hadjustment = -1.;
7284 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7285 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7286 "value_changed");
7290 void
7291 gtk_sheet_delete_rows(GtkSheet *sheet, guint row, guint nrows)
7293 GList *children;
7294 GtkSheetChild *child;
7295 gint irow, icol;
7296 gboolean veto;
7298 g_return_if_fail (sheet != NULL);
7299 g_return_if_fail (GTK_IS_SHEET (sheet));
7301 nrows = MIN(nrows, sheet->maxrow-row+1);
7303 if(GTK_WIDGET_REALIZED(sheet))
7304 gtk_sheet_real_unselect_range(sheet, NULL);
7306 DeleteRow(sheet, row, nrows);
7308 children = sheet->children;
7309 while(children)
7311 child = (GtkSheetChild *)children->data;
7313 if(child->attached_to_cell &&
7314 child->row >= row && child->row < row+nrows){
7315 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7316 children = sheet->children;
7317 } else
7318 children = g_list_next(children);
7321 children = sheet->children;
7322 while(children)
7324 child = (GtkSheetChild *)children->data;
7326 if(child->attached_to_cell && child->row > row) child->row -= nrows;
7327 children = g_list_next(children);
7330 if(!GTK_WIDGET_REALIZED(sheet)) return;
7332 irow = sheet->active_cell.row;
7333 icol = sheet->active_cell.col;
7335 sheet->active_cell.row = -1;
7336 sheet->active_cell.col = -1;
7338 /* if(sheet->state == GTK_SHEET_ROW_SELECTED)
7341 irow = MIN(irow, sheet->maxrow);
7342 irow = MAX(irow, 0);
7343 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7345 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7346 sheet->active_cell.col);
7348 adjust_scrollbars(sheet);
7350 sheet->old_vadjustment = -1.;
7351 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7352 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7353 "value_changed");
7357 void
7358 gtk_sheet_delete_columns(GtkSheet *sheet, guint col, guint ncols)
7360 GList *children;
7361 GtkSheetChild *child;
7362 gint irow, icol;
7363 gboolean veto;
7365 g_return_if_fail (sheet != NULL);
7366 g_return_if_fail (GTK_IS_SHEET (sheet));
7368 ncols = MIN(ncols, sheet->maxcol-col+1);
7370 if(GTK_WIDGET_REALIZED(sheet))
7371 gtk_sheet_real_unselect_range(sheet, NULL);
7373 DeleteColumn(sheet, col, ncols);
7375 children = sheet->children;
7376 while(children)
7378 child = (GtkSheetChild *)children->data;
7380 if(child->attached_to_cell &&
7381 child->col >= col && child->col < col+ncols){
7382 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7383 children = sheet->children;
7384 } else
7385 children = g_list_next(children);
7388 children = sheet->children;
7389 while(children)
7391 child = (GtkSheetChild *)children->data;
7393 if(child->attached_to_cell && child->col > col) child->col -= ncols;
7394 children = g_list_next(children);
7397 if(!GTK_WIDGET_REALIZED(sheet)) return;
7399 irow = sheet->active_cell.row;
7400 icol = sheet->active_cell.col;
7402 sheet->active_cell.row = -1;
7403 sheet->active_cell.col = -1;
7405 /* if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
7408 icol = MIN(icol, sheet->maxcol);
7409 icol = MAX(icol, 0);
7410 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7412 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7413 sheet->active_cell.col);
7415 adjust_scrollbars(sheet);
7417 sheet->old_hadjustment = -1.;
7418 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7419 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7420 "value_changed");
7424 void
7425 gtk_sheet_range_set_background(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7427 gint i, j;
7428 GtkSheetCellAttr attributes;
7429 GtkSheetRange range;
7431 g_return_if_fail (sheet != NULL);
7432 g_return_if_fail (GTK_IS_SHEET (sheet));
7434 if(!urange)
7435 range = sheet->range;
7436 else
7437 range = *urange;
7439 for (i=range.row0; i<=range.rowi; i++)
7440 for (j=range.col0; j<=range.coli; j++){
7441 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7442 if(color != NULL)
7443 attributes.background = *color;
7444 else
7445 attributes.background = sheet->bg_color;
7447 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7450 range.row0--;
7451 range.col0--;
7452 range.rowi++;
7453 range.coli++;
7455 if(!GTK_SHEET_IS_FROZEN(sheet))
7456 gtk_sheet_range_draw(sheet, &range);
7460 void
7461 gtk_sheet_range_set_foreground(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7463 gint i, j;
7464 GtkSheetCellAttr attributes;
7465 GtkSheetRange range;
7467 g_return_if_fail (sheet != NULL);
7468 g_return_if_fail (GTK_IS_SHEET (sheet));
7470 if(!urange)
7471 range = sheet->range;
7472 else
7473 range = *urange;
7475 for (i=range.row0; i<=range.rowi; i++)
7476 for (j=range.col0; j<=range.coli; j++){
7477 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7479 if(color != NULL)
7480 attributes.foreground = *color;
7481 else
7482 gdk_color_black(gdk_colormap_get_system(), &attributes.foreground);
7484 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7487 if(!GTK_SHEET_IS_FROZEN(sheet))
7488 gtk_sheet_range_draw(sheet, &range);
7492 void
7493 gtk_sheet_range_set_justification(GtkSheet *sheet, const GtkSheetRange *urange,
7494 GtkJustification just)
7496 gint i, j;
7497 GtkSheetCellAttr attributes;
7498 GtkSheetRange range;
7500 g_return_if_fail (sheet != NULL);
7501 g_return_if_fail (GTK_IS_SHEET (sheet));
7503 if(!urange)
7504 range = sheet->range;
7505 else
7506 range = *urange;
7508 for (i=range.row0; i<=range.rowi; i++)
7509 for (j=range.col0; j<=range.coli; j++){
7510 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7511 attributes.justification = just;
7512 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7515 range.col0 = sheet->view.col0;
7516 range.coli = sheet->view.coli;
7518 if(!GTK_SHEET_IS_FROZEN(sheet))
7519 gtk_sheet_range_draw(sheet, &range);
7523 void
7524 gtk_sheet_column_set_justification(GtkSheet *sheet, gint col,
7525 GtkJustification justification)
7527 g_return_if_fail (sheet != NULL);
7528 g_return_if_fail (GTK_IS_SHEET (sheet));
7530 if(col > sheet->maxcol) return;
7532 sheet->column[col].justification = justification;
7534 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet) &&
7535 col >= MIN_VISIBLE_COLUMN(sheet) && col <= MAX_VISIBLE_COLUMN(sheet))
7536 gtk_sheet_range_draw(sheet, NULL);
7540 void
7541 gtk_sheet_range_set_editable(GtkSheet *sheet, const GtkSheetRange *urange, gboolean editable)
7543 gint i, j;
7544 GtkSheetCellAttr attributes;
7545 GtkSheetRange range;
7547 g_return_if_fail (sheet != NULL);
7548 g_return_if_fail (GTK_IS_SHEET (sheet));
7550 if(!urange)
7551 range = sheet->range;
7552 else
7553 range = *urange;
7555 for (i=range.row0; i<=range.rowi; i++)
7556 for (j=range.col0; j<=range.coli; j++){
7557 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7558 attributes.is_editable = editable;
7559 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7562 if(!GTK_SHEET_IS_FROZEN(sheet))
7563 gtk_sheet_range_draw(sheet, &range);
7567 void
7568 gtk_sheet_range_set_visible(GtkSheet *sheet, const GtkSheetRange *urange, gboolean visible)
7570 gint i, j;
7571 GtkSheetCellAttr attributes;
7572 GtkSheetRange range;
7574 g_return_if_fail (sheet != NULL);
7575 g_return_if_fail (GTK_IS_SHEET (sheet));
7577 if(!urange)
7578 range = sheet->range;
7579 else
7580 range = *urange;
7582 for (i=range.row0; i<=range.rowi; i++)
7583 for (j=range.col0; j<=range.coli; j++){
7584 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7585 attributes.is_visible=visible;
7586 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7589 if(!GTK_SHEET_IS_FROZEN(sheet))
7590 gtk_sheet_range_draw(sheet, &range);
7594 void
7595 gtk_sheet_range_set_border(GtkSheet *sheet, const GtkSheetRange *urange, gint mask,
7596 guint width, gint line_style)
7598 gint i, j;
7599 GtkSheetCellAttr attributes;
7600 GtkSheetRange range;
7602 g_return_if_fail (sheet != NULL);
7603 g_return_if_fail (GTK_IS_SHEET (sheet));
7605 if(!urange)
7606 range = sheet->range;
7607 else
7608 range = *urange;
7610 for (i=range.row0; i<=range.rowi; i++)
7611 for (j=range.col0; j<=range.coli; j++){
7612 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7613 attributes.border.mask = mask;
7614 attributes.border.width = width;
7615 attributes.border.line_style=line_style;
7616 attributes.border.cap_style=GDK_CAP_NOT_LAST;
7617 attributes.border.join_style=GDK_JOIN_MITER;
7618 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7621 range.row0--;
7622 range.col0--;
7623 range.rowi++;
7624 range.coli++;
7626 if(!GTK_SHEET_IS_FROZEN(sheet))
7627 gtk_sheet_range_draw(sheet, &range);
7631 void
7632 gtk_sheet_range_set_border_color(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7634 gint i, j;
7635 GtkSheetCellAttr attributes;
7636 GtkSheetRange range;
7638 g_return_if_fail (sheet != NULL);
7639 g_return_if_fail (GTK_IS_SHEET (sheet));
7641 if(!urange)
7642 range = sheet->range;
7643 else
7644 range = *urange;
7646 for (i=range.row0; i<=range.rowi; i++)
7647 for (j=range.col0; j<=range.coli; j++){
7648 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7649 attributes.border.color = *color;
7650 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7653 if(!GTK_SHEET_IS_FROZEN(sheet))
7654 gtk_sheet_range_draw(sheet, &range);
7658 void
7659 gtk_sheet_range_set_font(GtkSheet *sheet, const GtkSheetRange *urange, PangoFontDescription *font)
7661 gint i, j;
7662 gint font_height;
7663 GtkSheetCellAttr attributes;
7664 GtkSheetRange range;
7665 PangoContext *context;
7666 PangoFontMetrics *metrics;
7668 g_return_if_fail (sheet != NULL);
7669 g_return_if_fail (GTK_IS_SHEET (sheet));
7671 if(!urange)
7672 range = sheet->range;
7673 else
7674 range = *urange;
7676 gtk_sheet_freeze(sheet);
7678 context = gtk_widget_get_pango_context(GTK_WIDGET(sheet));
7679 metrics = pango_context_get_metrics(context,
7680 font,
7681 pango_context_get_language(context));
7682 font_height = pango_font_metrics_get_descent(metrics) +
7683 pango_font_metrics_get_ascent(metrics);
7684 font_height = PANGO_PIXELS(font_height) + 2*CELLOFFSET;
7686 for (i=range.row0; i<=range.rowi; i++)
7687 for (j=range.col0; j<=range.coli; j++){
7688 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7689 attributes.font_desc = font;
7690 if(font_height > sheet->row[i].height){
7691 sheet->row[i].height = font_height;
7692 gtk_sheet_recalc_top_ypixels(sheet, i);
7695 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7698 gtk_sheet_thaw(sheet);
7699 pango_font_metrics_unref(metrics);
7702 static void
7703 gtk_sheet_set_cell_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr attributes)
7705 GtkSheetCell **cell;
7707 if(row > sheet->maxrow || col >sheet->maxcol) return;
7709 CheckBounds(sheet, row, col);
7711 cell = &sheet->data[row][col];
7713 if(*cell==NULL){
7714 (*cell) = gtk_sheet_cell_new();
7715 (*cell)->row = row;
7716 (*cell)->col = col;
7719 if((*cell)->attributes == NULL)
7720 (*cell)->attributes = g_new(GtkSheetCellAttr, 1);
7722 *((*cell)->attributes) = attributes;
7725 gboolean
7726 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7728 GtkSheetCell **cell = NULL;
7730 g_return_val_if_fail (sheet != NULL, FALSE);
7731 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7733 if(row < 0 || col < 0) return FALSE;
7735 if(row > sheet->maxallocrow || col > sheet->maxalloccol){
7736 init_attributes(sheet, col, attributes);
7737 return FALSE;
7740 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol){
7741 if(sheet->data[row] && sheet->data[row][col])
7742 cell = &sheet->data[row][col];
7743 if(cell == NULL || *cell == NULL){
7744 init_attributes(sheet, col, attributes);
7745 return FALSE;
7746 } else
7747 if((*cell)->attributes == NULL){
7748 init_attributes(sheet, col, attributes);
7749 return FALSE;
7750 }else{
7751 *attributes = *(sheet->data[row][col]->attributes);
7752 if(sheet->column[col].justification != GTK_JUSTIFY_FILL)
7753 attributes->justification = sheet->column[col].justification;
7757 return TRUE;
7760 static void
7761 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7763 /* DEFAULT VALUES */
7764 attributes->foreground = GTK_WIDGET(sheet)->style->black;
7765 attributes->background = sheet->bg_color;
7766 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7767 GdkColormap *colormap;
7768 colormap=gdk_colormap_get_system();
7769 gdk_color_black(colormap, &attributes->foreground);
7770 attributes->background = sheet->bg_color;
7772 attributes->justification = sheet->column[col].justification;
7773 attributes->border.width = 0;
7774 attributes->border.line_style = GDK_LINE_SOLID;
7775 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7776 attributes->border.join_style = GDK_JOIN_MITER;
7777 attributes->border.mask = 0;
7778 attributes->border.color = GTK_WIDGET(sheet)->style->black;
7779 attributes->is_editable = TRUE;
7780 attributes->is_visible = TRUE;
7781 attributes->font = GTK_WIDGET(sheet)->style->private_font;
7782 attributes->font_desc = GTK_WIDGET(sheet)->style->font_desc;
7786 /**********************************************************************
7787 * Memory allocation routines:
7788 * AddRow & AddColumn allocate memory for GtkSheetColumn & GtkSheetRow structs.
7789 * InsertRow
7790 * InsertColumn
7791 * DeleteRow
7792 * DeleteColumn
7793 * GrowSheet allocates memory for the sheet cells contents using an array of
7794 * pointers. Alternative to this could be a linked list or a hash table.
7795 * CheckBounds checks whether the given cell is currently allocated or not.
7796 * If not, it calls to GrowSheet.
7797 **********************************************************************/
7799 static gint
7800 AddColumn(GtkSheet *tbl, gint ncols)
7802 gint i;
7804 if(ncols == -1 && tbl->maxcol == 0)
7806 ncols = 1;
7808 else
7810 tbl->maxcol += ncols;
7811 tbl->column = (GtkSheetColumn *)g_realloc(tbl->column,(tbl->maxcol+1)*
7812 sizeof(GtkSheetColumn));
7815 for(i=tbl->maxcol-ncols+1; i<= tbl->maxcol; i++){
7816 tbl->column[i].width=DEFAULT_COLUMN_WIDTH;
7817 tbl->column[i].button.label=NULL;
7818 tbl->column[i].button.child=NULL;
7819 tbl->column[i].button.state=GTK_STATE_NORMAL;
7820 tbl->column[i].button.justification=GTK_JUSTIFY_CENTER;
7821 tbl->column[i].button.label_visible = TRUE;
7822 tbl->column[i].name=NULL;
7823 tbl->column[i].is_visible=TRUE;
7824 tbl->column[i].is_sensitive=TRUE;
7825 tbl->column[i].left_text_column=i;
7826 tbl->column[i].right_text_column=i;
7827 tbl->column[i].justification=GTK_JUSTIFY_FILL;
7828 tbl->column[i].requisition=DEFAULT_COLUMN_WIDTH;
7829 if(i>0)
7831 tbl->column[i].left_text_column=tbl->column[i-1].left_text_column;
7832 tbl->column[i].left_xpixel=tbl->column[i-1].left_xpixel +
7833 tbl->column[i-1].width;
7835 else
7837 tbl->column[i].left_xpixel=tbl->row_title_area.width;
7838 if(!tbl->row_titles_visible)
7839 tbl->column[i].left_xpixel=0;
7842 return TRUE;
7845 static gint
7846 AddRow(GtkSheet *tbl, gint nrows)
7848 gint i;
7850 if(nrows == -1 && tbl->maxrow == 0)
7852 nrows = 1;
7854 else
7856 tbl->maxrow += nrows;
7857 tbl->row = (GtkSheetRow *)g_realloc(tbl->row,(tbl->maxrow+1)*
7858 sizeof(GtkSheetRow));
7861 for(i=tbl->maxrow-nrows+1; i<= tbl->maxrow; i++){
7862 tbl->row[i].requisition=tbl->row[i].height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7863 tbl->row[i].button.label=NULL;
7864 tbl->row[i].button.child=NULL;
7865 tbl->row[i].button.state=GTK_STATE_NORMAL;
7866 tbl->row[i].button.justification=GTK_JUSTIFY_CENTER;
7867 tbl->row[i].button.label_visible = TRUE;
7868 tbl->row[i].name=NULL;
7869 tbl->row[i].is_visible=TRUE;
7870 tbl->row[i].is_sensitive=TRUE;
7871 if(i>0)
7872 tbl->row[i].top_ypixel=tbl->row[i-1].top_ypixel+tbl->row[i-1].height;
7873 else
7875 tbl->row[i].top_ypixel=tbl->column_title_area.height;
7876 if(!tbl->column_titles_visible)
7877 tbl->row[i].top_ypixel=0;
7880 return TRUE;
7883 static gint
7884 InsertRow(GtkSheet *tbl, gint row, gint nrows)
7886 GtkSheetCell **pp;
7887 gint i,j;
7888 GtkSheetCell **auxdata;
7889 GtkSheetRow auxrow;
7891 AddRow(tbl,nrows);
7893 for(i=tbl->maxrow; i>=row+nrows; i--){
7894 auxrow = tbl->row[i];
7895 tbl->row[i]=tbl->row[i-nrows];
7896 tbl->row[i].is_visible=tbl->row[i-nrows].is_visible;
7897 tbl->row[i].is_sensitive=tbl->row[i-nrows].is_sensitive;
7898 if(auxrow.is_visible)
7899 tbl->row[i].top_ypixel+=nrows*DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7900 tbl->row[i-nrows]=auxrow;
7903 if(row <= tbl->maxallocrow){
7905 GrowSheet(tbl,nrows,0);
7907 for(i=tbl->maxallocrow; i>=row+nrows; i--){
7908 auxdata = tbl->data[i];
7909 tbl->data[i]=tbl->data[i-nrows];
7911 pp= tbl->data[i];
7912 for(j=0; j<=tbl->maxalloccol; j++,pp++){
7913 if(*pp!=(GtkSheetCell *)NULL)
7914 (*pp)->row=i;
7917 tbl->data[i-nrows]=auxdata;
7920 gtk_sheet_recalc_top_ypixels(tbl, 0);
7921 return TRUE;
7924 static gint
7925 InsertColumn(GtkSheet *tbl, gint col, gint ncols)
7927 gint i,j;
7928 GtkSheetColumn auxcol;
7930 AddColumn(tbl,ncols);
7932 for(i=tbl->maxcol; i>=col+ncols; i--){
7933 auxcol = tbl->column[i];
7934 tbl->column[i]=tbl->column[i-ncols];
7935 tbl->column[i].is_visible=tbl->column[i-ncols].is_visible;
7936 tbl->column[i].is_sensitive=tbl->column[i-ncols].is_sensitive;
7937 tbl->column[i].left_text_column=tbl->column[i-ncols].left_text_column;
7938 tbl->column[i].right_text_column=tbl->column[i-ncols].right_text_column;
7939 tbl->column[i].justification=tbl->column[i-ncols].justification;
7940 if(auxcol.is_visible) tbl->column[i].left_xpixel+=ncols*DEFAULT_COLUMN_WIDTH;
7941 tbl->column[i-ncols]=auxcol;
7944 if(col <= tbl->maxalloccol){
7946 GrowSheet(tbl,0,ncols);
7948 for(i=0; i<=tbl->maxallocrow; i++){
7949 for(j=tbl->maxalloccol; j>=col+ncols; j--){
7950 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
7951 tbl->data[i][j]=tbl->data[i][j-ncols];
7952 if(tbl->data[i][j]) tbl->data[i][j]->col=j;
7953 tbl->data[i][j-ncols]=NULL;
7957 gtk_sheet_recalc_left_xpixels(tbl, 0);
7958 return TRUE;
7961 static gint
7962 DeleteRow(GtkSheet *tbl, gint row, gint nrows)
7964 GtkSheetCell **auxdata = NULL;
7965 gint i,j;
7967 if(nrows <= 0 || row > tbl->maxrow) return TRUE;
7969 nrows=MIN(nrows,tbl->maxrow-row+1);
7971 for(i=row; i<row+nrows; i++){
7972 if(tbl->row[i].name){
7973 g_free(tbl->row[i].name);
7974 tbl->row[i].name = NULL;
7976 if(tbl->row[i].button.label){
7977 g_free(tbl->row[i].button.label);
7978 tbl->row[i].button.label = NULL;
7982 for(i=row; i<=tbl->maxrow-nrows; i++){
7983 if(i+nrows <= tbl->maxrow){
7984 tbl->row[i]=tbl->row[i+nrows];
7988 if(row <= tbl->maxallocrow){
7990 for(i=row; i<=tbl->maxrow-nrows; i++){
7991 if(i<=tbl->maxallocrow){
7992 auxdata=tbl->data[i];
7993 for(j=0; j<=tbl->maxalloccol; j++){
7994 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
7997 if(i+nrows<=tbl->maxallocrow){
7998 tbl->data[i]=tbl->data[i+nrows];
7999 tbl->data[i+nrows]=auxdata;
8000 for(j=0; j<=tbl->maxalloccol; j++){
8001 if(tbl->data[i][j]) tbl->data[i][j]->row=i;
8006 for(i=tbl->maxrow-nrows+1; i<=tbl->maxallocrow; i++){
8007 if(i > 0 && tbl->data[i]){
8008 g_free(tbl->data[i]);
8009 tbl->data[i] = NULL;
8013 tbl->maxallocrow-=MIN(nrows,tbl->maxallocrow-row+1);
8014 tbl->maxallocrow = MIN(tbl->maxallocrow, tbl->maxrow);
8018 tbl->maxrow-=nrows;
8019 gtk_sheet_recalc_top_ypixels(tbl, 0);
8020 return TRUE;
8023 static gint
8024 DeleteColumn(GtkSheet *tbl, gint column, gint ncols)
8026 gint i,j;
8027 GtkSheetColumn auxcol;
8029 ncols = MIN(ncols,tbl->maxcol-column+1);
8031 if(ncols <= 0 || column > tbl->maxcol) return TRUE;
8033 for(i=column; i<column+ncols; i++){
8034 auxcol=tbl->column[i];
8035 if(tbl->column[i].name){
8036 g_free(tbl->column[i].name);
8037 tbl->column[i].name = NULL;
8039 if(tbl->column[i].button.label){
8040 g_free(tbl->column[i].button.label);
8041 tbl->column[i].button.label = NULL;
8045 for(i=column; i<=tbl->maxcol-ncols; i++){
8046 if(i+ncols <= tbl->maxcol){
8047 tbl->column[i]=tbl->column[i+ncols];
8051 if(column <= tbl->maxalloccol){
8053 for(i=column; i<=tbl->maxcol-ncols; i++){
8054 if(i<=tbl->maxalloccol){
8055 for(j=0; j<=tbl->maxallocrow; j++){
8056 gtk_sheet_real_cell_clear(tbl, j, i, TRUE);
8057 if(i+ncols <= tbl->maxalloccol){
8058 tbl->data[j][i] = tbl->data[j][i+ncols];
8059 tbl->data[j][i+ncols] = NULL;
8060 if(tbl->data[j][i]) tbl->data[j][i]->col=i;
8067 tbl->maxalloccol-=MIN(ncols,tbl->maxalloccol-column+1);
8068 tbl->maxalloccol = MIN(tbl->maxalloccol, tbl->maxcol);
8070 tbl->maxcol-=ncols;
8071 gtk_sheet_recalc_left_xpixels(tbl, 0);
8072 return TRUE;
8075 static gint
8076 GrowSheet(GtkSheet *tbl, gint newrows, gint newcols)
8078 gint i,j;
8079 gint inirow, inicol;
8081 inirow = tbl->maxallocrow + 1;
8082 inicol = tbl->maxalloccol + 1;
8084 tbl->maxalloccol = tbl->maxalloccol + newcols;
8085 tbl->maxallocrow = tbl->maxallocrow + newrows;
8087 if(newrows>0){
8088 tbl->data = (GtkSheetCell***)
8089 g_realloc(tbl->data,(tbl->maxallocrow+1)*sizeof(GtkSheetCell **)+sizeof(double));
8091 for(i=inirow; i <= tbl->maxallocrow; i++){
8092 tbl->data[i] = (GtkSheetCell **) \
8093 g_malloc((tbl->maxcol+1)*sizeof(GtkSheetCell *)+sizeof(double));
8094 for(j=0; j<inicol; j++) {
8095 tbl->data[i][j] = NULL;
8101 if(newcols>0){
8102 for(i=0; i <= tbl->maxallocrow; i++) {
8103 tbl->data[i] = (GtkSheetCell **) \
8104 g_realloc(tbl->data[i],(tbl->maxalloccol+1)*sizeof(GtkSheetCell *)+sizeof(double));
8105 for(j=inicol; j <= tbl->maxalloccol; j++) {
8106 tbl->data[i][j] = NULL;
8111 return(0);
8114 static gint
8115 CheckBounds(GtkSheet *tbl, gint row, gint col)
8117 gint newrows=0,newcols=0;
8119 if(col>tbl->maxalloccol) newcols=col-tbl->maxalloccol;
8120 if(row>tbl->maxallocrow) newrows=row-tbl->maxallocrow;
8121 if(newrows>0 || newcols>0) GrowSheet(tbl, newrows, newcols);
8122 return(0);
8125 /********************************************************************
8126 * Container Functions:
8127 * gtk_sheet_add
8128 * gtk_sheet_put
8129 * gtk_sheet_attach
8130 * gtk_sheet_remove
8131 * gtk_sheet_move_child
8132 * gtk_sheet_position_child
8133 * gtk_sheet_position_children
8134 * gtk_sheet_realize_child
8135 * gtk_sheet_get_child_at
8136 ********************************************************************/
8138 GtkSheetChild *
8139 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
8141 GtkRequisition child_requisition;
8142 GtkSheetChild *child_info;
8144 g_return_val_if_fail(sheet != NULL, NULL);
8145 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
8146 g_return_val_if_fail(child != NULL, NULL);
8147 g_return_val_if_fail(child->parent == NULL, NULL);
8149 child_info = g_new (GtkSheetChild, 1);
8150 child_info->widget = child;
8151 child_info->x = x;
8152 child_info->y = y;
8153 child_info->attached_to_cell = FALSE;
8154 child_info->floating = TRUE;
8155 child_info->xpadding = child_info->ypadding = 0;
8156 child_info->xexpand = child_info->yexpand = FALSE;
8157 child_info->xshrink = child_info->yshrink = FALSE;
8158 child_info->xfill = child_info->yfill = FALSE;
8160 sheet->children = g_list_append(sheet->children, child_info);
8162 gtk_widget_set_parent (child, GTK_WIDGET(sheet));
8164 gtk_widget_size_request(child, &child_requisition);
8166 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8168 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8169 (!GTK_WIDGET_REALIZED(child) || GTK_WIDGET_NO_WINDOW(child)))
8170 gtk_sheet_realize_child(sheet, child_info);
8172 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8173 !GTK_WIDGET_MAPPED(child))
8174 gtk_widget_map(child);
8177 gtk_sheet_position_child(sheet, child_info);
8179 /* This will avoid drawing on the titles */
8181 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
8183 if(sheet->row_titles_visible)
8184 gdk_window_show(sheet->row_title_window);
8185 if(sheet->column_titles_visible)
8186 gdk_window_show(sheet->column_title_window);
8189 return (child_info);
8192 void
8193 gtk_sheet_attach_floating (GtkSheet *sheet,
8194 GtkWidget *widget,
8195 gint row, gint col)
8197 GdkRectangle area;
8198 GtkSheetChild *child;
8200 if(row < 0 || col < 0){
8201 gtk_sheet_button_attach(sheet, widget, row, col);
8202 return;
8205 gtk_sheet_get_cell_area(sheet, row, col, &area);
8206 child = gtk_sheet_put(sheet, widget, area.x, area.y);
8207 child->attached_to_cell = TRUE;
8208 child->row = row;
8209 child->col = col;
8212 void
8213 gtk_sheet_attach_default (GtkSheet *sheet,
8214 GtkWidget *widget,
8215 gint row, gint col)
8217 if(row < 0 || col < 0){
8218 gtk_sheet_button_attach(sheet, widget, row, col);
8219 return;
8222 gtk_sheet_attach(sheet, widget, row, col, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
8225 void
8226 gtk_sheet_attach (GtkSheet *sheet,
8227 GtkWidget *widget,
8228 gint row, gint col,
8229 gint xoptions,
8230 gint yoptions,
8231 gint xpadding,
8232 gint ypadding)
8234 GdkRectangle area;
8235 GtkSheetChild *child = NULL;
8237 if(row < 0 || col < 0){
8238 gtk_sheet_button_attach(sheet, widget, row, col);
8239 return;
8242 child = g_new0(GtkSheetChild, 1);
8243 child->attached_to_cell = TRUE;
8244 child->floating = FALSE;
8245 child->widget = widget;
8246 child->row = row;
8247 child->col = col;
8248 child->xpadding = xpadding;
8249 child->ypadding = ypadding;
8250 child->xexpand = (xoptions & GTK_EXPAND) != 0;
8251 child->yexpand = (yoptions & GTK_EXPAND) != 0;
8252 child->xshrink = (xoptions & GTK_SHRINK) != 0;
8253 child->yshrink = (yoptions & GTK_SHRINK) != 0;
8254 child->xfill = (xoptions & GTK_FILL) != 0;
8255 child->yfill = (yoptions & GTK_FILL) != 0;
8257 sheet->children = g_list_append(sheet->children, child);
8259 gtk_sheet_get_cell_area(sheet, row, col, &area);
8261 child->x = area.x + child->xpadding;
8262 child->y = area.y + child->ypadding;
8264 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8266 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8267 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
8268 gtk_sheet_realize_child(sheet, child);
8270 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8271 !GTK_WIDGET_MAPPED(widget))
8272 gtk_widget_map(widget);
8275 gtk_sheet_position_child(sheet, child);
8277 /* This will avoid drawing on the titles */
8279 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
8281 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
8282 gdk_window_show(sheet->row_title_window);
8283 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
8284 gdk_window_show(sheet->column_title_window);
8289 void
8290 gtk_sheet_button_attach (GtkSheet *sheet,
8291 GtkWidget *widget,
8292 gint row, gint col)
8294 GtkSheetButton *button;
8295 GtkSheetChild *child;
8296 GtkRequisition button_requisition;
8298 if(row >= 0 && col >= 0) return;
8299 if(row < 0 && col < 0) return;
8301 child = g_new (GtkSheetChild, 1);
8302 child->widget = widget;
8303 child->x = 0;
8304 child->y = 0;
8305 child->attached_to_cell = TRUE;
8306 child->floating = FALSE;
8307 child->row = row;
8308 child->col = col;
8309 child->xpadding = child->ypadding = 0;
8310 child->xshrink = child->yshrink = FALSE;
8311 child->xfill = child->yfill = FALSE;
8313 if(row == -1){
8314 button = &sheet->column[col].button;
8315 button->child = child;
8317 else
8319 button = &sheet->row[row].button;
8320 button->child = child;
8323 sheet->children = g_list_append(sheet->children, child);
8325 gtk_sheet_button_size_request(sheet, button, &button_requisition);
8327 if(row == -1){
8328 if(button_requisition.height > sheet->column_title_area.height)
8329 sheet->column_title_area.height = button_requisition.height;
8330 if(button_requisition.width > sheet->column[col].width)
8331 sheet->column[col].width = button_requisition.width;
8334 if(col == -1){
8335 if(button_requisition.width > sheet->row_title_area.width)
8336 sheet->row_title_area.width = button_requisition.width;
8337 if(button_requisition.height > sheet->row[row].height)
8338 sheet->row[row].height = button_requisition.height;
8341 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8343 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8344 (!GTK_WIDGET_REALIZED(widget) || GTK_WIDGET_NO_WINDOW(widget)))
8345 gtk_sheet_realize_child(sheet, child);
8347 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8348 !GTK_WIDGET_MAPPED(widget))
8349 gtk_widget_map(widget);
8352 if(row == -1) size_allocate_column_title_buttons(sheet);
8353 if(col == -1) size_allocate_row_title_buttons(sheet);
8357 static void
8358 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
8360 gchar *words;
8361 gchar word[1000];
8362 gint n = 0;
8363 gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
8365 req->height = 0;
8366 req->width = 0;
8367 words=label;
8369 while(words && *words != '\0'){
8370 if(*words == '\n' || *(words+1) == '\0'){
8371 req->height += row_height;
8373 word[n] = '\0';
8374 req->width = MAX(req->width, STRING_WIDTH(GTK_WIDGET(sheet), GTK_WIDGET(sheet)->style->font_desc, word));
8375 n = 0;
8376 } else {
8377 word[n++] = *words;
8379 words++;
8382 if(n > 0) req->height -= 2;
8385 static void
8386 gtk_sheet_button_size_request (GtkSheet *sheet,
8387 GtkSheetButton *button,
8388 GtkRequisition *button_requisition)
8390 GtkRequisition requisition;
8391 GtkRequisition label_requisition;
8393 if(gtk_sheet_autoresize(sheet) && button->label && strlen(button->label) > 0){
8394 label_size_request(sheet, button->label, &label_requisition);
8395 label_requisition.width += 2*CELLOFFSET;
8396 label_requisition.height += 2*CELLOFFSET;
8397 } else {
8398 label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8399 label_requisition.width = COLUMN_MIN_WIDTH;
8402 if(button->child)
8404 gtk_widget_size_request(button->child->widget, &requisition);
8405 requisition.width += 2*button->child->xpadding;
8406 requisition.height += 2*button->child->ypadding;
8407 requisition.width += 2*sheet->button->style->xthickness;
8408 requisition.height += 2*sheet->button->style->ythickness;
8410 else
8412 requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8413 requisition.width = COLUMN_MIN_WIDTH;
8416 *button_requisition = requisition;
8417 button_requisition->width = MAX(requisition.width, label_requisition.width);
8418 button_requisition->height = MAX(requisition.height, label_requisition.height);
8422 static void
8423 gtk_sheet_row_size_request (GtkSheet *sheet,
8424 gint row,
8425 guint *requisition)
8427 GtkRequisition button_requisition;
8428 GList *children;
8430 gtk_sheet_button_size_request(sheet, &sheet->row[row].button, &button_requisition);
8432 *requisition = button_requisition.height;
8434 children = sheet->children;
8435 while(children){
8436 GtkSheetChild *child = (GtkSheetChild *)children->data;
8437 GtkRequisition child_requisition;
8439 if(child->attached_to_cell && child->row == row && child->col != -1 && !child->floating && !child->yshrink){
8440 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8442 if(child_requisition.height + 2 * child->ypadding > *requisition)
8443 *requisition = child_requisition.height + 2 * child->ypadding;
8445 children = g_list_next(children);
8448 sheet->row[row].requisition = *requisition;
8451 static void
8452 gtk_sheet_column_size_request (GtkSheet *sheet,
8453 gint col,
8454 guint *requisition)
8456 GtkRequisition button_requisition;
8457 GList *children;
8459 gtk_sheet_button_size_request(sheet, &sheet->column[col].button, &button_requisition);
8461 *requisition = button_requisition.width;
8463 children = sheet->children;
8464 while(children){
8465 GtkSheetChild *child = (GtkSheetChild *)children->data;
8466 GtkRequisition child_requisition;
8468 if(child->attached_to_cell && child->col == col && child->row != -1 && !child->floating && !child->xshrink){
8469 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8471 if(child_requisition.width + 2 * child->xpadding > *requisition)
8472 *requisition = child_requisition.width + 2 * child->xpadding;
8474 children = g_list_next(children);
8477 sheet->column[col].requisition = *requisition;
8480 void
8481 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
8483 GtkSheetChild *child;
8484 GList *children;
8486 g_return_if_fail(sheet != NULL);
8487 g_return_if_fail(GTK_IS_SHEET(sheet));
8489 children = sheet->children;
8490 while(children)
8492 child = children->data;
8494 if(child->widget == widget){
8495 child->x = x;
8496 child->y = y;
8497 child->row = ROW_FROM_YPIXEL(sheet, y);
8498 child->col = COLUMN_FROM_XPIXEL(sheet, x);
8499 gtk_sheet_position_child(sheet, child);
8500 return;
8503 children = g_list_next(children);
8506 g_warning("Widget must be a GtkSheet child");
8510 static void
8511 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
8513 GtkRequisition child_requisition;
8514 GtkAllocation child_allocation;
8515 gint xoffset = 0;
8516 gint yoffset = 0;
8517 gint x = 0, y = 0;
8518 GdkRectangle area;
8520 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8522 if(sheet->column_titles_visible)
8523 yoffset = sheet->column_title_area.height;
8525 if(sheet->row_titles_visible)
8526 xoffset = sheet->row_title_area.width;
8528 if(child->attached_to_cell){
8530 child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
8531 child->y = ROW_TOP_YPIXEL(sheet, child->row);
8533 if(sheet->row_titles_visible)
8534 child->x-=sheet->row_title_area.width;
8535 if(sheet->column_titles_visible)
8536 child->y-=sheet->column_title_area.height;
8538 width = sheet->column[child->col].width;
8539 height = sheet->row[child->row].height;
8542 gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
8543 child->x = area.x + child->xpadding;
8544 child->y = area.y + child->ypadding;
8546 if(!child->floating){
8547 if(child_requisition.width + 2*child->xpadding <= sheet->column[child->col].width){
8548 if(child->xfill){
8549 child_requisition.width = child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
8550 } else {
8551 if(child->xexpand){
8552 child->x = area.x + sheet->column[child->col].width / 2 -
8553 child_requisition.width / 2;
8555 child_allocation.width = child_requisition.width;
8557 } else {
8558 if(!child->xshrink){
8559 gtk_sheet_set_column_width(sheet, child->col, child_requisition.width + 2 * child->xpadding);
8561 child_allocation.width = sheet->column[child->col].width - 2*child->xpadding;
8564 if(child_requisition.height + 2*child->ypadding <= sheet->row[child->row].height){
8565 if(child->yfill){
8566 child_requisition.height = child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
8567 } else {
8568 if(child->yexpand){
8569 child->y = area.y + sheet->row[child->row].height / 2 -
8570 child_requisition.height / 2;
8572 child_allocation.height = child_requisition.height;
8574 } else {
8575 if(!child->yshrink){
8576 gtk_sheet_set_row_height(sheet, child->row, child_requisition.height + 2 * child->ypadding);
8578 child_allocation.height = sheet->row[child->row].height - 2*child->ypadding;
8580 } else {
8581 child_allocation.width = child_requisition.width;
8582 child_allocation.height = child_requisition.height;
8585 x = child_allocation.x = child->x + xoffset;
8586 y = child_allocation.y = child->y + yoffset;
8588 else
8590 x = child_allocation.x = child->x + sheet->hoffset + xoffset;
8591 x = child_allocation.x = child->x + xoffset;
8592 y = child_allocation.y = child->y + sheet->voffset + yoffset;
8593 y = child_allocation.y = child->y + yoffset;
8594 child_allocation.width = child_requisition.width;
8595 child_allocation.height = child_requisition.height;
8598 gtk_widget_size_allocate(child->widget, &child_allocation);
8599 gtk_widget_queue_draw(child->widget);
8602 static void
8603 gtk_sheet_forall (GtkContainer *container,
8604 gboolean include_internals,
8605 GtkCallback callback,
8606 gpointer callback_data)
8608 GtkSheet *sheet;
8609 GtkSheetChild *child;
8610 GList *children;
8612 g_return_if_fail (GTK_IS_SHEET (container));
8613 g_return_if_fail (callback != NULL);
8615 sheet = GTK_SHEET (container);
8617 children = sheet->children;
8618 while (children)
8620 child = children->data;
8621 children = g_list_next(children);
8623 (* callback) (child->widget, callback_data);
8625 if(sheet->button)
8626 (* callback) (sheet->button, callback_data);
8627 if(sheet->sheet_entry)
8628 (* callback) (sheet->sheet_entry, callback_data);
8632 static void
8633 gtk_sheet_position_children(GtkSheet *sheet)
8635 GList *children;
8636 GtkSheetChild *child;
8638 children = sheet->children;
8640 while(children)
8642 child = (GtkSheetChild *)children->data;
8644 if(child->col !=-1 && child->row != -1)
8645 gtk_sheet_position_child(sheet, child);
8647 if(child->row == -1){
8648 if(child->col < MIN_VISIBLE_COLUMN(sheet) ||
8649 child->col > MAX_VISIBLE_COLUMN(sheet))
8650 gtk_sheet_child_hide(child);
8651 else
8652 gtk_sheet_child_show(child);
8654 if(child->col == -1){
8655 if(child->row < MIN_VISIBLE_ROW(sheet) ||
8656 child->row > MAX_VISIBLE_ROW(sheet))
8657 gtk_sheet_child_hide(child);
8658 else
8659 gtk_sheet_child_show(child);
8662 children = g_list_next(children);
8667 static void
8668 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
8670 GtkSheet *sheet;
8671 GList *children;
8672 GtkSheetChild *child = 0;
8674 g_return_if_fail(container != NULL);
8675 g_return_if_fail(GTK_IS_SHEET(container));
8677 sheet = GTK_SHEET(container);
8679 children = sheet->children;
8681 while(children)
8683 child = (GtkSheetChild *)children->data;
8685 if(child->widget == widget) break;
8687 children = g_list_next(children);
8690 if (children)
8692 if(child->row == -1)
8693 sheet->row[child->col].button.child = NULL;
8695 if(child->col == -1)
8696 sheet->column[child->row].button.child = NULL;
8698 gtk_widget_unparent (widget);
8699 child->widget = NULL;
8701 sheet->children = g_list_remove_link (sheet->children, children);
8702 g_list_free_1 (children);
8703 g_free(child);
8708 static void
8709 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
8711 GtkWidget *widget;
8713 widget = GTK_WIDGET(sheet);
8715 if(GTK_WIDGET_REALIZED(widget)){
8716 if(child->row == -1)
8717 gtk_widget_set_parent_window(child->widget, sheet->column_title_window);
8718 else if(child->col == -1)
8719 gtk_widget_set_parent_window(child->widget, sheet->row_title_window);
8720 else
8721 gtk_widget_set_parent_window(child->widget, sheet->sheet_window);
8724 gtk_widget_set_parent(child->widget, widget);
8729 GtkSheetChild *
8730 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
8732 GList *children;
8733 GtkSheetChild *child = 0;
8735 g_return_val_if_fail(sheet != NULL, NULL);
8736 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
8738 children = sheet->children;
8740 while(children)
8742 child = (GtkSheetChild *)children->data;
8744 if(child->attached_to_cell)
8745 if(child->row == row && child->col == col) break;
8747 children = g_list_next(children);
8750 if(children) return child;
8752 return NULL;
8755 static void
8756 gtk_sheet_child_hide(GtkSheetChild *child)
8758 g_return_if_fail(child != NULL);
8759 gtk_widget_hide(child->widget);
8762 static void
8763 gtk_sheet_child_show(GtkSheetChild *child)
8765 g_return_if_fail(child != NULL);
8767 gtk_widget_show(child->widget);