Initial import of gattrib 20040806
[geda-gaf/whiteaudio.git] / gattrib / src / gtksheet_1_2.c
blob62230397e8a5ceff9c4dd5317782ab0695e7bbfe
1 /* GtkSheet widget for Gtk+.
2 * Copyright (C) 1999-2001 Adrian E. Feiguin <adrian@ifir.ifir.edu.ar>
4 * Based on GtkClist widget by Jay Painter, but major changes.
5 * Memory allocation routines inspired on SC (Spreadsheet Calculator)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
34 #include <glib.h>
36 #include <gdk/gdk.h>
37 #include <gdk/gdkkeysyms.h>
38 #include <gtk/gtksignal.h>
39 #include <gtk/gtklabel.h>
40 #include <gtk/gtkbutton.h>
41 #include <gtk/gtkadjustment.h>
42 #include <gtk/gtktable.h>
43 #include <gtk/gtkbox.h>
44 #include <gtk/gtkmain.h>
45 #include <gtk/gtktypeutils.h>
46 #include <gtk/gtkentry.h>
47 #include <gtk/gtkcontainer.h>
48 #include <gtk/gtkpixmap.h>
51 #include "gtksheet_1_2.h"
52 #include "gtkitementry_1_2.h"
55 #define CELL_SPACING 1
56 #define DRAG_WIDTH 6
57 #define TIMEOUT_SCROLL 20
58 #define TIMEOUT_FLASH 200
59 #define TIME_INTERVAL 8
60 #define COLUMN_MIN_WIDTH 10
61 #define MINROWS 1
62 #define MINCOLS 1
63 #define MAXLENGTH 30
64 #define CELLOFFSET 4
65 #define DEFAULT_COLUMN_WIDTH 80
68 #define DEFAULT_ROW_HEIGHT(widget) (widget->style->font->ascent + 2*widget->style->font->descent + 2*CELLOFFSET)
69 #define DEFAULT_LABEL_HEIGHT(widget) (widget->style->font->ascent+\
70 2*widget->style->font->descent)
71 #define DEFAULT_FONT_ASCENT(widget) (widget->style->font->ascent)
72 #define DEFAULT_FONT_DESCENT(widget) (widget->style->font->descent)
74 /*-----------------------------------------------------------------------------*/
75 /* scrollbar spacing class macro */
76 #define SCROLLBAR_SPACING(w) (GTK_SHEET_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
79 /*-----------------------------------------------------------------------------*/
80 /* gives the top pixel of the given row in context of
81 * the sheet's voffset */
82 static inline gint
83 ROW_TOP_YPIXEL(GtkSheet *sheet, gint nrow)
85 return (sheet->voffset + sheet->row[nrow].top_ypixel);
88 /*-----------------------------------------------------------------------------*/
89 /* returns the row index from a y pixel location in the
90 * context of the sheet's voffset */
91 static inline gint
92 ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
94 gint i, cy;
96 cy = sheet->voffset;
97 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)) cy += sheet->column_title_area.height;
98 if(y < cy) return 0;
99 for (i = 0; i <= sheet->maxrow; i++)
101 if (y >= cy && y <= (cy + sheet->row[i].height) && sheet->row[i].is_visible)
102 return i;
103 if(sheet->row[i].is_visible) cy += sheet->row[i].height;
107 /* no match */
108 return sheet->maxrow;
112 /*-----------------------------------------------------------------------------*/
113 /* gives the left pixel of the given column in context of
114 * the sheet's hoffset */
115 static inline gint
116 COLUMN_LEFT_XPIXEL(GtkSheet *sheet, gint ncol)
118 return (sheet->hoffset + sheet->column[ncol].left_xpixel);
122 /*-----------------------------------------------------------------------------*/
123 /* returns the column index from a x pixel location in the
124 * context of the sheet's hoffset */
125 static inline gint
126 COLUMN_FROM_XPIXEL (GtkSheet * sheet,
127 gint x)
129 gint i, cx;
131 cx = sheet->hoffset;
132 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) cx += sheet->row_title_area.width;
133 if(x < cx) return 0;
134 for (i = 0; i <= sheet->maxcol; i++)
136 if (x >= cx && x <= (cx + sheet->column[i].width) && sheet->column[i].is_visible)
137 return i;
138 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
142 /* no match */
143 return sheet->maxcol;
147 /*-----------------------------------------------------------------------------*/
148 /* returns the total height of the sheet */
149 static inline gint SHEET_HEIGHT(GtkSheet *sheet)
151 gint i,cx;
153 cx = 0;
154 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)) cx += sheet->column_title_area.height;
155 for (i=0;i<=sheet->maxrow; i++)
156 if(sheet->row[i].is_visible) cx += sheet->row[i].height;
158 return cx;
162 /*-----------------------------------------------------------------------------*/
163 /* returns the total width of the sheet */
164 static inline gint SHEET_WIDTH(GtkSheet *sheet)
166 gint i,cx;
168 cx = 0;
169 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) cx += sheet->row_title_area.width;
170 for (i=0;i<=sheet->maxcol; i++)
171 if(sheet->column[i].is_visible) cx += sheet->column[i].width;
173 return cx;
176 #define MIN_VISIBLE_ROW(sheet) sheet->view.row0
177 #define MAX_VISIBLE_ROW(sheet) sheet->view.rowi
178 #define MIN_VISIBLE_COLUMN(sheet) sheet->view.col0
179 #define MAX_VISIBLE_COLUMN(sheet) sheet->view.coli
181 /*-----------------------------------------------------------------------------*/
182 static inline gint
183 POSSIBLE_XDRAG(GtkSheet *sheet, gint x, gint *drag_column)
185 gint column, xdrag;
187 column=COLUMN_FROM_XPIXEL(sheet, x);
188 *drag_column=column;
190 xdrag=COLUMN_LEFT_XPIXEL(sheet,column)+CELL_SPACING;
191 if(x <= xdrag+DRAG_WIDTH/2 && column != 0){
192 while(!sheet->column[column-1].is_visible && column>0) column--;
193 *drag_column=column-1;
194 return sheet->column[column-1].is_sensitive;
197 xdrag+=sheet->column[column].width;
198 if(x >= xdrag-DRAG_WIDTH/2 && x <= xdrag+DRAG_WIDTH/2)
199 return sheet->column[column].is_sensitive;
201 return FALSE;
205 /*-----------------------------------------------------------------------------*/
206 static inline gint
207 POSSIBLE_YDRAG(GtkSheet *sheet, gint y, gint *drag_row)
209 gint row, ydrag;
211 row=ROW_FROM_YPIXEL(sheet, y);
212 *drag_row=row;
214 ydrag=ROW_TOP_YPIXEL(sheet,row)+CELL_SPACING;
215 if(y <= ydrag+DRAG_WIDTH/2 && row != 0){
216 while(!sheet->row[row-1].is_visible && row>0) row--;
217 *drag_row=row-1;
218 return sheet->row[row-1].is_sensitive;
221 ydrag+=sheet->row[row].height;
223 if(y >= ydrag-DRAG_WIDTH/2 && y <= ydrag+DRAG_WIDTH/2)
224 return sheet->row[row].is_sensitive;
227 return FALSE;
231 /*-----------------------------------------------------------------------------*/
232 static inline gint POSSIBLE_DRAG(GtkSheet *sheet, gint x, gint y,
233 gint *drag_row, gint *drag_column)
235 gint ydrag, xdrag;
237 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
238 *drag_row=ROW_FROM_YPIXEL(sheet,y);
240 if(x>=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0)-DRAG_WIDTH/2 &&
241 x<=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
242 sheet->column[sheet->range.coli].width+DRAG_WIDTH/2){
243 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.row0);
244 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
245 *drag_row=sheet->range.row0;
246 return TRUE;
248 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
249 sheet->row[sheet->range.rowi].height;
250 if(y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2){
251 *drag_row=sheet->range.rowi;
252 return TRUE;
256 if(y>=ROW_TOP_YPIXEL(sheet,sheet->range.row0)-DRAG_WIDTH/2 &&
257 y<=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
258 sheet->row[sheet->range.rowi].height+DRAG_WIDTH/2){
259 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.col0);
260 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
261 *drag_column=sheet->range.col0;
262 return TRUE;
264 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
265 sheet->column[sheet->range.coli].width;
266 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2){
267 *drag_column=sheet->range.coli;
268 return TRUE;
271 return FALSE;
275 /*-----------------------------------------------------------------------------*/
276 static inline gint POSSIBLE_RESIZE(GtkSheet *sheet, gint x, gint y,
277 gint *drag_row, gint *drag_column)
279 gint xdrag, ydrag;
281 xdrag=COLUMN_LEFT_XPIXEL(sheet,sheet->range.coli)+
282 sheet->column[sheet->range.coli].width;
284 ydrag=ROW_TOP_YPIXEL(sheet,sheet->range.rowi)+
285 sheet->row[sheet->range.rowi].height;
287 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
288 ydrag = ROW_TOP_YPIXEL(sheet, sheet->view.row0);
290 if(sheet->state == GTK_SHEET_ROW_SELECTED)
291 xdrag = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0);
293 *drag_column=COLUMN_FROM_XPIXEL(sheet,x);
294 *drag_row=ROW_FROM_YPIXEL(sheet,y);
296 if(x>=xdrag-DRAG_WIDTH/2 && x<=xdrag+DRAG_WIDTH/2 &&
297 y>=ydrag-DRAG_WIDTH/2 && y<=ydrag+DRAG_WIDTH/2) return TRUE;
299 return FALSE;
302 /*-----------------------------------------------------------------------------*/
303 /* Typedefs and function prototypes */
304 /*-----------------------------------------------------------------------------*/
305 typedef gboolean (*GtkSheetSignal1) (GtkObject *object,
306 gint arg1, gint arg2, gint *arg3, gint *arg4,
307 gpointer user_data);
309 typedef gboolean (*GtkSheetSignal2) (GtkObject *object,
310 gint arg1, gint arg2,
311 gpointer user_data);
313 static void gtk_sheet_class_init (GtkSheetClass * klass);
314 static void gtk_sheet_init (GtkSheet * sheet);
315 static void gtk_sheet_destroy (GtkObject * object);
316 static void gtk_sheet_finalize (GtkObject * object);
317 static void gtk_sheet_style_set (GtkWidget *widget,
318 GtkStyle *previous_style);
319 static void gtk_sheet_realize (GtkWidget * widget);
320 static void gtk_sheet_unrealize (GtkWidget * widget);
321 static void gtk_sheet_map (GtkWidget * widget);
322 static void gtk_sheet_unmap (GtkWidget * widget);
323 static void gtk_sheet_draw (GtkWidget * widget,
324 GdkRectangle * area);
325 static gint gtk_sheet_expose (GtkWidget * widget,
326 GdkEventExpose * event);
327 /*static void gtk_sheet_forall (GtkContainer *container,
328 gboolean include_internals,
329 GtkCallback callback,
330 gpointer callback_data);
332 static void gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
333 GtkAdjustment *hadjustment,
334 GtkAdjustment *vadjustment);
336 static gint gtk_sheet_button_press (GtkWidget * widget,
337 GdkEventButton * event);
338 static gint gtk_sheet_button_release (GtkWidget * widget,
339 GdkEventButton * event);
340 static gint gtk_sheet_motion (GtkWidget * widget,
341 GdkEventMotion * event);
342 static gint gtk_sheet_entry_key_press (GtkWidget *widget,
343 GdkEventKey *key);
344 static gint gtk_sheet_key_press (GtkWidget *widget,
345 GdkEventKey *key);
346 static void gtk_sheet_size_request (GtkWidget * widget,
347 GtkRequisition * requisition);
348 static void gtk_sheet_size_allocate (GtkWidget * widget,
349 GtkAllocation * allocation);
351 /* Sheet queries */
353 static gint gtk_sheet_range_isvisible (GtkSheet * sheet,
354 GtkSheetRange range);
355 static gint gtk_sheet_cell_isvisible (GtkSheet * sheet,
356 gint row, gint column);
357 /* Clipped Range */
359 static gint gtk_sheet_scroll (gpointer data);
360 static gint gtk_sheet_flash (gpointer data);
362 /* Drawing Routines */
364 /* draw cell background and frame */
365 static void gtk_sheet_cell_draw_default (GtkSheet *sheet,
366 gint row, gint column);
368 /* draw cell border */
369 static void gtk_sheet_cell_draw_border (GtkSheet *sheet,
370 gint row, gint column,
371 gint mask);
373 /* draw cell contents */
374 static void gtk_sheet_cell_draw_label (GtkSheet *sheet,
375 gint row, gint column);
377 /* draw visible part of range. If range==NULL then draw the whole screen */
378 static void gtk_sheet_range_draw (GtkSheet *sheet,
379 const GtkSheetRange *range);
381 /* highlight the visible part of the selected range */
382 static void gtk_sheet_range_draw_selection (GtkSheet *sheet,
383 GtkSheetRange range);
385 /* Selection */
387 static gint gtk_sheet_move_query (GtkSheet *sheet,
388 gint row, gint column);
389 static void gtk_sheet_real_select_range (GtkSheet * sheet,
390 GtkSheetRange * range);
391 static void gtk_sheet_real_unselect_range (GtkSheet * sheet,
392 const GtkSheetRange * range);
393 static void gtk_sheet_extend_selection (GtkSheet *sheet,
394 gint row, gint column);
395 static void gtk_sheet_new_selection (GtkSheet *sheet,
396 GtkSheetRange *range);
397 static void gtk_sheet_draw_border (GtkSheet *sheet,
398 GtkSheetRange range);
399 static void gtk_sheet_draw_corners (GtkSheet *sheet,
400 GtkSheetRange range);
403 /* Active Cell handling */
405 static void gtk_sheet_entry_changed (GtkWidget *widget,
406 gpointer data);
407 static gboolean gtk_sheet_deactivate_cell (GtkSheet *sheet);
408 static void gtk_sheet_hide_active_cell (GtkSheet *sheet);
409 static gboolean gtk_sheet_activate_cell (GtkSheet *sheet,
410 gint row, gint col);
411 static void gtk_sheet_draw_active_cell (GtkSheet *sheet);
412 static void gtk_sheet_show_active_cell (GtkSheet *sheet);
413 static void gtk_sheet_click_cell (GtkSheet *sheet,
414 gint row,
415 gint column,
416 gboolean *veto);
418 /* Backing Pixmap */
420 static void gtk_sheet_make_backing_pixmap (GtkSheet *sheet,
421 guint width, guint height);
422 static void gtk_sheet_draw_backing_pixmap (GtkSheet *sheet,
423 GtkSheetRange range);
424 /* Scrollbars */
426 static void adjust_scrollbars (GtkSheet * sheet);
427 static void vadjustment_changed (GtkAdjustment * adjustment,
428 gpointer data);
429 static void hadjustment_changed (GtkAdjustment * adjustment,
430 gpointer data);
431 static void vadjustment_value_changed (GtkAdjustment * adjustment,
432 gpointer data);
433 static void hadjustment_value_changed (GtkAdjustment * adjustment,
434 gpointer data);
437 static void draw_xor_vline (GtkSheet * sheet);
438 static void draw_xor_hline (GtkSheet * sheet);
439 static void draw_xor_rectangle (GtkSheet *sheet,
440 GtkSheetRange range);
441 static void gtk_sheet_draw_flashing_range (GtkSheet *sheet,
442 GtkSheetRange range);
443 static guint new_column_width (GtkSheet * sheet,
444 gint column,
445 gint * x);
446 static guint new_row_height (GtkSheet * sheet,
447 gint row,
448 gint * y);
449 /* Sheet Button */
451 static void create_global_button (GtkSheet *sheet);
452 static void global_button_clicked (GtkWidget *widget,
453 gpointer data);
454 /* Sheet Entry */
456 static void create_sheet_entry (GtkSheet *sheet);
457 static void gtk_sheet_size_allocate_entry (GtkSheet *sheet);
458 static void gtk_sheet_entry_set_max_size (GtkSheet *sheet);
460 /* Sheet button gadgets */
462 static void size_allocate_column_title_buttons (GtkSheet * sheet);
463 static void size_allocate_row_title_buttons (GtkSheet * sheet);
464 static void gtk_sheet_recalc_top_ypixels (GtkSheet *sheet,
465 gint row);
466 static void gtk_sheet_recalc_left_xpixels (GtkSheet *sheet,
467 gint column);
468 static void row_button_set (GtkSheet *sheet,
469 gint row);
470 static void column_button_set (GtkSheet *sheet,
471 gint column);
472 static void row_button_release (GtkSheet *sheet,
473 gint row);
474 static void column_button_release (GtkSheet *sheet,
475 gint column);
476 static void gtk_sheet_button_draw (GtkSheet *sheet,
477 gint row, gint column);
478 static void size_allocate_global_button (GtkSheet *sheet);
479 static void label_size_request (GtkSheet *sheet, gchar *label,
480 GtkRequisition *req);
481 static void gtk_sheet_button_size_request (GtkSheet *sheet,
482 GtkSheetButton *button,
483 GtkRequisition *requisition);
485 /* Attributes routines */
487 static void gtk_sheet_set_cell_attributes (GtkSheet *sheet,
488 gint row, gint col,
489 GtkSheetCellAttr attributes);
491 static void init_attributes (GtkSheet *sheet, gint col,
492 GtkSheetCellAttr *attributes);
493 /* Memory allocation routines */
494 static void gtk_sheet_real_range_clear (GtkSheet *sheet,
495 const GtkSheetRange *range,
496 gboolean delete);
497 static void gtk_sheet_real_cell_clear (GtkSheet *sheet,
498 gint row,
499 gint column,
500 gboolean delete);
501 static GtkSheetCell * gtk_sheet_cell_new (void);
502 static gint AddRow (GtkSheet *sheet, gint nrows);
503 static gint AddColumn (GtkSheet *sheet, gint ncols);
504 static gint InsertRow (GtkSheet *sheet, gint row, gint nrows);
505 static gint InsertColumn (GtkSheet *sheet, gint col, gint ncols);
506 static gint DeleteRow (GtkSheet *sheet, gint row, gint nrows);
507 static gint DeleteColumn (GtkSheet *sheet, gint col, gint ncols);
508 static gint GrowSheet (GtkSheet *sheet,
509 gint newrows, gint newcols);
510 static gint CheckBounds (GtkSheet *sheet,
511 gint row, gint col);
513 /* Container Functions */
514 static void gtk_sheet_remove (GtkContainer *container,
515 GtkWidget *widget);
516 static void gtk_sheet_realize_child (GtkSheet *sheet,
517 GtkSheetChild *child);
518 static void gtk_sheet_position_child (GtkSheet *sheet,
519 GtkSheetChild *child);
520 static void gtk_sheet_position_children (GtkSheet *sheet);
521 static void gtk_sheet_child_show (GtkSheetChild *child);
522 static void gtk_sheet_child_hide (GtkSheetChild *child);
524 /* Signals */
526 enum {
527 SELECT_ROW,
528 SELECT_COLUMN,
529 SELECT_RANGE,
530 CLIP_RANGE,
531 RESIZE_RANGE,
532 MOVE_RANGE,
533 TRAVERSE,
534 DEACTIVATE,
535 ACTIVATE,
536 SET_CELL,
537 CLEAR_CELL,
538 CHANGED,
539 NEW_COL_WIDTH,
540 NEW_ROW_HEIGHT,
541 LAST_SIGNAL
544 static void
545 gtk_sheet_marshal_BOOL__INT_INT (GtkObject *object,
546 GtkSignalFunc func,
547 gpointer func_data,
548 GtkArg * args);
549 static void
550 gtk_sheet_marshal_BOOL__INT_INT_POINTER_POINTER (GtkObject *object,
551 GtkSignalFunc func,
552 gpointer func_data,
553 GtkArg * args);
555 static GtkContainerClass *parent_class = NULL;
556 static guint sheet_signals[LAST_SIGNAL] = {0};
558 GtkType gtk_sheet_get_type ()
560 static guint sheet_type = 0;
561 if(!sheet_type){
562 GtkTypeInfo sheet_info =
564 "GtkSheet",
565 sizeof(GtkSheet),
566 sizeof(GtkSheetClass),
567 (GtkClassInitFunc) gtk_sheet_class_init,
568 (GtkObjectInitFunc) gtk_sheet_init,
569 /* reserved_1 */ NULL,
570 /* reserved_2 */ NULL,
571 (GtkClassInitFunc) NULL,
573 sheet_type = gtk_type_unique (GTK_TYPE_CONTAINER, &sheet_info);
575 return sheet_type;
579 GtkType
580 gtk_sheet_range_get_type (void)
582 static GtkType sheet_range_type = 0;
583 if (!sheet_range_type){
584 static const GtkTypeInfo sheet_range_info =
586 "GtkSheetRange",
589 (GtkClassInitFunc) NULL,
590 (GtkObjectInitFunc) NULL,
591 /* reserved_1 */ NULL,
592 /* reserved_2 */ NULL,
593 (GtkClassInitFunc) NULL,
595 sheet_range_type = gtk_type_unique(GTK_TYPE_BOXED, &sheet_range_info);
597 return sheet_range_type;
600 static void
601 gtk_sheet_class_init (GtkSheetClass * klass)
604 GtkType object_class_type; /* SDB addition for GTK-2.X */
606 GtkObjectClass *object_class;
607 GtkWidgetClass *widget_class;
608 GtkContainerClass *container_class;
610 object_class = (GtkObjectClass *) klass;
611 widget_class = (GtkWidgetClass *) klass;
612 container_class = (GtkContainerClass *) klass;
614 /* This was introduced by SDB in order to enable compilation under GTK-2.X */
616 object_class_type = object_class->type;
617 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
619 sheet_signals[SELECT_ROW] =
620 gtk_signal_new ("select_row",
621 GTK_RUN_LAST,
622 object_class_type,
623 GTK_SIGNAL_OFFSET (GtkSheetClass, select_row),
624 gtk_marshal_NONE__INT,
625 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
626 sheet_signals[SELECT_COLUMN] =
627 gtk_signal_new ("select_column",
628 GTK_RUN_LAST,
629 object_class_type,
630 GTK_SIGNAL_OFFSET (GtkSheetClass, select_column),
631 gtk_marshal_NONE__INT,
632 GTK_TYPE_NONE, 1, GTK_TYPE_INT);
633 sheet_signals[SELECT_RANGE] =
634 gtk_signal_new ("select_range",
635 GTK_RUN_LAST,
636 object_class_type,
637 GTK_SIGNAL_OFFSET (GtkSheetClass, select_range),
638 gtk_marshal_NONE__POINTER,
639 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
640 sheet_signals[CLIP_RANGE] =
641 gtk_signal_new ("clip_range",
642 GTK_RUN_LAST,
643 object_class_type,
644 GTK_SIGNAL_OFFSET (GtkSheetClass, clip_range),
645 gtk_marshal_NONE__POINTER,
646 GTK_TYPE_NONE, 1, GTK_TYPE_SHEET_RANGE);
647 sheet_signals[RESIZE_RANGE] =
648 gtk_signal_new ("resize_range",
649 GTK_RUN_LAST,
650 object_class_type,
651 GTK_SIGNAL_OFFSET (GtkSheetClass, resize_range),
652 gtk_marshal_NONE__POINTER_POINTER,
653 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
654 sheet_signals[MOVE_RANGE] =
655 gtk_signal_new ("move_range",
656 GTK_RUN_LAST,
657 object_class_type,
658 GTK_SIGNAL_OFFSET (GtkSheetClass, move_range),
659 gtk_marshal_NONE__POINTER_POINTER,
660 GTK_TYPE_NONE, 2, GTK_TYPE_SHEET_RANGE, GTK_TYPE_SHEET_RANGE);
662 sheet_signals[TRAVERSE] =
663 gtk_signal_new ("traverse",
664 GTK_RUN_LAST,
665 object_class_type,
666 GTK_SIGNAL_OFFSET (GtkSheetClass, traverse),
667 gtk_sheet_marshal_BOOL__INT_INT_POINTER_POINTER,
668 GTK_TYPE_BOOL, 4, GTK_TYPE_INT, GTK_TYPE_INT,
669 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
671 sheet_signals[DEACTIVATE] =
672 gtk_signal_new ("deactivate",
673 GTK_RUN_LAST,
674 object_class_type,
675 GTK_SIGNAL_OFFSET (GtkSheetClass, deactivate),
676 gtk_sheet_marshal_BOOL__INT_INT,
677 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
679 sheet_signals[ACTIVATE] =
680 gtk_signal_new ("activate",
681 GTK_RUN_LAST,
682 object_class_type,
683 GTK_SIGNAL_OFFSET (GtkSheetClass, activate),
684 gtk_sheet_marshal_BOOL__INT_INT,
685 GTK_TYPE_BOOL, 2, GTK_TYPE_INT, GTK_TYPE_INT);
687 sheet_signals[SET_CELL] =
688 gtk_signal_new ("set_cell",
689 GTK_RUN_LAST,
690 object_class_type,
691 GTK_SIGNAL_OFFSET (GtkSheetClass, set_cell),
692 gtk_marshal_NONE__INT_INT,
693 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
694 sheet_signals[CLEAR_CELL] =
695 gtk_signal_new ("clear_cell",
696 GTK_RUN_LAST,
697 object_class_type,
698 GTK_SIGNAL_OFFSET (GtkSheetClass, clear_cell),
699 gtk_marshal_NONE__INT_INT,
700 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
701 sheet_signals[CHANGED] =
702 gtk_signal_new ("changed",
703 GTK_RUN_LAST,
704 object_class_type,
705 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
706 gtk_marshal_NONE__INT_INT,
707 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
708 sheet_signals[NEW_COL_WIDTH] =
709 gtk_signal_new ("new_column_width",
710 GTK_RUN_LAST,
711 object_class_type,
712 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
713 gtk_marshal_NONE__INT_INT,
714 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
715 sheet_signals[NEW_ROW_HEIGHT] =
716 gtk_signal_new ("new_row_height",
717 GTK_RUN_LAST,
718 object_class_type,
719 GTK_SIGNAL_OFFSET (GtkSheetClass, changed),
720 gtk_marshal_NONE__INT_INT,
721 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
723 widget_class->set_scroll_adjustments_signal =
724 gtk_signal_new ("set_scroll_adjustments",
725 GTK_RUN_LAST,
726 object_class_type,
727 GTK_SIGNAL_OFFSET (GtkSheetClass, set_scroll_adjustments),
728 gtk_marshal_NONE__POINTER_POINTER,
729 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
731 container_class->add = NULL;
732 container_class->remove = gtk_sheet_remove;
733 container_class->forall = NULL;
735 object_class->destroy = gtk_sheet_destroy;
737 widget_class->realize = gtk_sheet_realize;
738 widget_class->unrealize = gtk_sheet_unrealize;
739 widget_class->map = gtk_sheet_map;
740 widget_class->unmap = gtk_sheet_unmap;
741 widget_class->draw = gtk_sheet_draw;
742 widget_class->style_set = gtk_sheet_style_set;
743 widget_class->button_press_event = gtk_sheet_button_press;
744 widget_class->button_release_event = gtk_sheet_button_release;
745 widget_class->motion_notify_event = gtk_sheet_motion;
746 widget_class->key_press_event = gtk_sheet_key_press;
747 widget_class->expose_event = gtk_sheet_expose;
748 widget_class->size_request = gtk_sheet_size_request;
749 widget_class->size_allocate = gtk_sheet_size_allocate;
750 widget_class->focus_in_event = NULL;
751 widget_class->focus_out_event = NULL;
753 klass->set_scroll_adjustments = gtk_sheet_set_scroll_adjustments;
754 klass->select_row = NULL;
755 klass->select_column = NULL;
756 klass->select_range = NULL;
757 klass->clip_range = NULL;
758 klass->resize_range = NULL;
759 klass->move_range = NULL;
760 klass->traverse = NULL;
761 klass->deactivate = NULL;
762 klass->activate = NULL;
763 klass->set_cell = NULL;
764 klass->clear_cell = NULL;
765 klass->changed = NULL;
769 static void
770 gtk_sheet_marshal_BOOL__INT_INT_POINTER_POINTER (GtkObject *object,
771 GtkSignalFunc func,
772 gpointer func_data,
773 GtkArg * args)
775 GtkSheetSignal1 rfunc;
776 gboolean *veto;
777 veto = GTK_RETLOC_BOOL (args[4]);
779 rfunc = (GtkSheetSignal1) func;
781 *veto = (*rfunc) (object, GTK_VALUE_INT (args[0]),
782 GTK_VALUE_INT (args[1]),
783 GTK_VALUE_POINTER (args[2]),
784 GTK_VALUE_POINTER (args[3]),
785 func_data);
788 static void
789 gtk_sheet_marshal_BOOL__INT_INT (GtkObject *object,
790 GtkSignalFunc func,
791 gpointer func_data,
792 GtkArg * args)
794 GtkSheetSignal2 rfunc;
795 gboolean *veto;
796 veto = GTK_RETLOC_BOOL (args[2]);
798 rfunc = (GtkSheetSignal2) func;
800 *veto = (*rfunc) (object, GTK_VALUE_INT (args[0]),
801 GTK_VALUE_INT (args[1]),
802 func_data);
807 static void
808 gtk_sheet_init (GtkSheet *sheet)
810 sheet->children = NULL;
812 sheet->flags = 0;
813 sheet->selection_mode = GTK_SELECTION_BROWSE;
814 sheet->freeze_count = 0;
815 sheet->state = GTK_SHEET_NORMAL;
817 GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
818 GTK_WIDGET_SET_FLAGS (sheet, GTK_CAN_FOCUS);
820 sheet->maxrow = 0;
821 sheet->maxcol = 0;
823 sheet->view.row0 = 0;
824 sheet->view.col0 = 0;
825 sheet->view.rowi = 0;
826 sheet->view.coli = 0;
828 sheet->maxallocrow = 0;
829 sheet->maxalloccol = 0;
831 sheet->column_title_window=NULL;
832 sheet->column_title_area.x=0;
833 sheet->column_title_area.y=0;
834 sheet->column_title_area.width=0;
835 sheet->column_title_area.height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
837 sheet->row_title_window=NULL;
838 sheet->row_title_area.x=0;
839 sheet->row_title_area.y=0;
840 sheet->row_title_area.width=DEFAULT_COLUMN_WIDTH;
841 sheet->row_title_area.height=0;
843 sheet->active_cell.row=0;
844 sheet->active_cell.col=0;
845 sheet->selection_cell.row=0;
846 sheet->selection_cell.col=0;
848 sheet->sheet_entry=NULL;
849 sheet->pixmap=NULL;
851 sheet->range.row0=0;
852 sheet->range.rowi=0;
853 sheet->range.col0=0;
854 sheet->range.coli=0;
856 sheet->state=GTK_SHEET_NORMAL;
858 sheet->sheet_window = NULL;
859 sheet->sheet_window_width = 0;
860 sheet->sheet_window_height = 0;
861 sheet->sheet_entry = NULL;
862 sheet->button = NULL;
864 sheet->hoffset = 0;
865 sheet->voffset = 0;
867 sheet->hadjustment = NULL;
868 sheet->vadjustment = NULL;
870 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
871 sheet->xor_gc = NULL;
872 sheet->fg_gc = NULL;
873 sheet->bg_gc = NULL;
874 sheet->x_drag = 0;
875 sheet->y_drag = 0;
877 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
878 gdk_color_parse("gray", &sheet->grid_color);
879 gdk_color_alloc(gdk_colormap_get_system(), &sheet->grid_color);
880 sheet->show_grid = TRUE;
883 GtkSheet *
884 gtk_sheet_new (guint rows, guint columns, const gchar *title)
886 GtkWidget *widget;
888 /* sanity check */
889 g_return_val_if_fail(columns >= MINCOLS, NULL);
890 g_return_val_if_fail(rows >= MINROWS, NULL);
892 widget = GTK_WIDGET( gtk_type_new(gtk_sheet_get_type ()) );
894 gtk_sheet_construct(GTK_SHEET(widget), rows, columns, title);
896 return GTK_SHEET(widget);
899 void
900 gtk_sheet_construct (GtkSheet *sheet, guint rows, guint columns, const gchar *title)
902 sheet->row=(GtkSheetRow *)g_malloc(sizeof(GtkSheetRow));
903 sheet->column=(GtkSheetColumn *)g_malloc(sizeof(GtkSheetColumn));
904 sheet->data=(GtkSheetCell ***)g_malloc(sizeof(GtkSheetCell **));
906 sheet->data[0] = (GtkSheetCell **)g_malloc(sizeof(GtkSheetCell *)+sizeof(gdouble));
907 sheet->data[0][0] = NULL;
909 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_ROW_TITLES_VISIBLE);
910 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_COL_TITLES_VISIBLE);
911 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_AUTO_SCROLL);
912 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_JUSTIFY_ENTRY);
914 /* set number of rows and columns */
915 GrowSheet(sheet, MINROWS, MINCOLS);
917 /* Init row an column zero */
918 AddRow(sheet,-1);
919 AddColumn(sheet,-1);
921 /* Add rows and columns */
922 AddRow(sheet,rows-1);
923 AddColumn(sheet,columns-1);
925 /* create sheet entry */
926 sheet->entry_type = 0;
927 create_sheet_entry (sheet);
929 /* create global selection button */
930 create_global_button(sheet);
932 if(title)
933 sheet->name = g_strdup(title);
938 GtkWidget *
939 gtk_sheet_new_with_custom_entry (guint rows, guint columns, const gchar *title,
940 GtkType entry_type)
942 GtkWidget *widget;
944 widget = gtk_type_new (gtk_sheet_get_type ());
946 gtk_sheet_construct_with_custom_entry(GTK_SHEET(widget),
947 rows, columns, title, entry_type);
949 return widget;
952 void
953 gtk_sheet_construct_with_custom_entry (GtkSheet *sheet,
954 guint rows, guint columns,
955 const gchar *title,
956 GtkType entry_type)
958 gtk_sheet_construct(sheet, rows, columns, title);
960 sheet->entry_type = entry_type;
961 create_sheet_entry(sheet);
965 void
966 gtk_sheet_change_entry(GtkSheet *sheet, GtkType entry_type)
968 gint state;
970 g_return_if_fail (sheet != NULL);
971 g_return_if_fail (GTK_IS_SHEET (sheet));
973 state = sheet->state;
975 if(sheet->state == GTK_SHEET_NORMAL)
976 gtk_sheet_hide_active_cell(sheet);
978 sheet->entry_type = entry_type;
980 create_sheet_entry(sheet);
982 if(state == GTK_SHEET_NORMAL)
984 gtk_sheet_show_active_cell(sheet);
985 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
986 "changed",
987 (GtkSignalFunc)gtk_sheet_entry_changed,
988 GTK_OBJECT(GTK_WIDGET(sheet)));
993 void
994 gtk_sheet_show_grid(GtkSheet *sheet, gboolean show)
996 g_return_if_fail (sheet != NULL);
997 g_return_if_fail (GTK_IS_SHEET (sheet));
999 if(show == sheet->show_grid) return;
1001 sheet->show_grid = show;
1003 if(!GTK_SHEET_IS_FROZEN(sheet))
1004 gtk_sheet_range_draw(sheet, NULL);
1007 gboolean
1008 gtk_sheet_grid_visible(GtkSheet *sheet)
1010 g_return_val_if_fail (sheet != NULL, 0);
1011 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1013 return sheet->show_grid;
1016 void
1017 gtk_sheet_set_background(GtkSheet *sheet, GdkColor *color)
1019 g_return_if_fail (sheet != NULL);
1020 g_return_if_fail (GTK_IS_SHEET (sheet));
1022 if(!color)
1023 gdk_color_white(gdk_colormap_get_system(), &sheet->bg_color);
1024 else
1025 sheet->bg_color = *color;
1027 if(!GTK_SHEET_IS_FROZEN(sheet))
1028 gtk_sheet_range_draw(sheet, NULL);
1031 void
1032 gtk_sheet_set_grid(GtkSheet *sheet, GdkColor *color)
1034 g_return_if_fail (sheet != NULL);
1035 g_return_if_fail (GTK_IS_SHEET (sheet));
1037 if(!color)
1038 gdk_color_black(gdk_colormap_get_system(), &sheet->grid_color);
1039 else
1040 sheet->grid_color = *color;
1042 if(!GTK_SHEET_IS_FROZEN(sheet))
1043 gtk_sheet_range_draw(sheet, NULL);
1046 guint
1047 gtk_sheet_get_columns_count(GtkSheet *sheet)
1049 g_return_val_if_fail (sheet != NULL, 0);
1050 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1052 return sheet->maxcol + 1;
1055 guint
1056 gtk_sheet_get_rows_count(GtkSheet *sheet)
1058 g_return_val_if_fail (sheet != NULL, 0);
1059 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1061 return sheet->maxrow + 1;
1064 gint
1065 gtk_sheet_get_state(GtkSheet *sheet)
1067 g_return_val_if_fail (sheet != NULL, 0);
1068 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
1070 return (sheet->state);
1073 void
1074 gtk_sheet_set_selection_mode(GtkSheet *sheet, gint mode)
1076 g_return_if_fail (sheet != NULL);
1077 g_return_if_fail (GTK_IS_SHEET (sheet));
1079 if(GTK_WIDGET_REALIZED(sheet))
1080 gtk_sheet_real_unselect_range(sheet, NULL);
1082 sheet->selection_mode = mode;
1085 /* This routine has problems with gtk+-1.2 related with the
1086 * label/button drawing - I think it's a bug in gtk+-1.2 */
1087 void
1088 gtk_sheet_set_title(GtkSheet *sheet, const gchar *title)
1090 /* GtkWidget *old_widget;
1091 */ GtkWidget *label;
1093 g_return_if_fail (sheet != NULL);
1094 g_return_if_fail (title != NULL);
1095 g_return_if_fail (GTK_IS_SHEET (sheet));
1097 if (sheet->name)
1098 g_free (sheet->name);
1100 sheet->name = g_strdup (title);
1102 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) || !title) return;
1104 if(GTK_BIN(sheet->button)->child)
1105 label = GTK_BIN(sheet->button)->child;
1107 gtk_label_set_text(GTK_LABEL(label), title);
1109 size_allocate_global_button(sheet);
1111 /* remove and destroy the old widget */
1113 old_widget = GTK_BIN (sheet->button)->child;
1114 if (old_widget)
1116 gtk_container_remove (GTK_CONTAINER (sheet->button), old_widget);
1119 label = gtk_label_new (title);
1120 gtk_misc_set_alignment(GTK_MISC(label), 0.5 , 0.5 );
1122 gtk_container_add (GTK_CONTAINER (sheet->button), label);
1123 gtk_widget_show (label);
1125 size_allocate_global_button(sheet);
1127 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, -1);
1129 if(old_widget)
1130 gtk_widget_destroy (old_widget);
1134 void
1135 gtk_sheet_freeze (GtkSheet *sheet)
1137 g_return_if_fail (sheet != NULL);
1138 g_return_if_fail (GTK_IS_SHEET (sheet));
1140 sheet->freeze_count++;
1141 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1144 void
1145 gtk_sheet_thaw(GtkSheet *sheet)
1147 g_return_if_fail (sheet != NULL);
1148 g_return_if_fail (GTK_IS_SHEET (sheet));
1150 if(sheet->freeze_count == 0) return;
1152 sheet->freeze_count--;
1153 if(sheet->freeze_count > 0) return;
1155 adjust_scrollbars(sheet);
1157 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
1159 sheet->old_vadjustment = -1.;
1160 sheet->old_hadjustment = -1.;
1162 if(sheet->hadjustment)
1163 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1164 "value_changed");
1165 if(sheet->vadjustment)
1166 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1167 "value_changed");
1169 if(sheet->state == GTK_STATE_NORMAL)
1170 if(sheet->sheet_entry && GTK_WIDGET_MAPPED(sheet->sheet_entry)){
1171 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
1173 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
1174 "changed",
1175 (GtkSignalFunc)gtk_sheet_entry_changed,
1176 GTK_OBJECT(GTK_WIDGET(sheet)));
1177 gtk_sheet_show_active_cell(sheet);
1183 void
1184 gtk_sheet_set_row_titles_width(GtkSheet *sheet, guint width)
1186 if(width < COLUMN_MIN_WIDTH) return;
1188 sheet->row_title_area.width = width;
1189 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
1190 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
1191 gtk_sheet_recalc_top_ypixels(sheet, 0);
1192 gtk_sheet_recalc_left_xpixels(sheet, 0);
1193 adjust_scrollbars(sheet);
1195 sheet->old_hadjustment = -1.;
1196 if(sheet->hadjustment)
1197 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1198 "value_changed");
1199 size_allocate_global_button(sheet);
1202 void
1203 gtk_sheet_set_column_titles_height(GtkSheet *sheet, guint height)
1205 if(height < DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))) return;
1207 sheet->column_title_area.height = height;
1208 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
1209 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
1210 gtk_sheet_recalc_top_ypixels(sheet, 0);
1211 gtk_sheet_recalc_left_xpixels(sheet, 0);
1212 adjust_scrollbars(sheet);
1214 sheet->old_vadjustment = -1.;
1215 if(sheet->vadjustment)
1216 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1217 "value_changed");
1218 size_allocate_global_button(sheet);
1221 void
1222 gtk_sheet_show_column_titles(GtkSheet *sheet)
1224 gint col;
1226 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)) return;
1228 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_COL_TITLES_VISIBLE);
1229 gtk_sheet_recalc_top_ypixels(sheet, 0);
1230 gtk_sheet_recalc_left_xpixels(sheet, 0);
1231 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1232 gdk_window_show(sheet->column_title_window);
1234 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1235 GtkSheetChild *child;
1236 child = sheet->column[col].button.child;
1237 if(child){
1238 gtk_sheet_child_show(child);
1241 adjust_scrollbars(sheet);
1244 sheet->old_vadjustment = -1.;
1245 if(sheet->vadjustment)
1246 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1247 "value_changed");
1248 size_allocate_global_button(sheet);
1251 void
1252 gtk_sheet_show_row_titles(GtkSheet *sheet)
1254 gint row;
1256 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) return;
1258 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_ROW_TITLES_VISIBLE);
1259 gtk_sheet_recalc_top_ypixels(sheet, 0);
1260 gtk_sheet_recalc_left_xpixels(sheet, 0);
1261 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1262 gdk_window_show(sheet->row_title_window);
1264 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1265 GtkSheetChild *child;
1266 child = sheet->row[row].button.child;
1267 if(child){
1268 gtk_sheet_child_show(child);
1271 adjust_scrollbars(sheet);
1274 sheet->old_hadjustment = -1.;
1275 if(sheet->hadjustment)
1276 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1277 "value_changed");
1278 size_allocate_global_button(sheet);
1281 void
1282 gtk_sheet_hide_column_titles(GtkSheet *sheet)
1284 gint col;
1286 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet)) return;
1288 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_COL_TITLES_VISIBLE);
1289 gtk_sheet_recalc_top_ypixels(sheet, 0);
1290 gtk_sheet_recalc_left_xpixels(sheet, 0);
1291 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1292 if(sheet->column_title_window) gdk_window_hide(sheet->column_title_window);
1293 if(GTK_WIDGET_VISIBLE(sheet->button)) gtk_widget_hide(sheet->button);
1295 for(col = MIN_VISIBLE_COLUMN(sheet); col <= MAX_VISIBLE_COLUMN(sheet); col++){
1296 GtkSheetChild *child;
1297 child = sheet->column[col].button.child;
1298 if(child){
1299 gtk_sheet_child_hide(child);
1302 adjust_scrollbars(sheet);
1305 sheet->old_vadjustment = -1.;
1306 if(sheet->vadjustment)
1307 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1308 "value_changed");
1311 void
1312 gtk_sheet_hide_row_titles(GtkSheet *sheet)
1314 gint row;
1316 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) return;
1318 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_ROW_TITLES_VISIBLE);
1319 gtk_sheet_recalc_top_ypixels(sheet, 0);
1320 gtk_sheet_recalc_left_xpixels(sheet, 0);
1321 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
1322 if(sheet->row_title_window) gdk_window_hide(sheet->row_title_window);
1323 if(GTK_WIDGET_VISIBLE(sheet->button)) gtk_widget_hide(sheet->button);
1324 for(row = MIN_VISIBLE_ROW(sheet); row <= MAX_VISIBLE_ROW(sheet); row++){
1325 GtkSheetChild *child;
1326 child = sheet->row[row].button.child;
1327 if(child){
1328 gtk_sheet_child_hide(child);
1331 adjust_scrollbars(sheet);
1334 sheet->old_hadjustment = -1.;
1335 if(sheet->hadjustment)
1336 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1337 "value_changed");
1340 void
1341 gtk_sheet_set_column_title (GtkSheet * sheet,
1342 gint column,
1343 const gchar * title)
1345 g_return_if_fail (sheet != NULL);
1346 g_return_if_fail (GTK_IS_SHEET (sheet));
1348 if (sheet->column[column].name)
1349 g_free (sheet->column[column].name);
1351 sheet->column[column].name = g_strdup(title);
1354 void
1355 gtk_sheet_set_row_title (GtkSheet * sheet,
1356 gint row,
1357 const gchar * title)
1359 g_return_if_fail (sheet != NULL);
1360 g_return_if_fail (GTK_IS_SHEET (sheet));
1362 if (sheet->row[row].name)
1363 g_free (sheet->row[row].name);
1365 sheet->row[row].name = g_strdup (title);
1368 void
1369 gtk_sheet_row_button_add_label(GtkSheet *sheet, gint row, const gchar *label)
1371 GtkSheetButton *button;
1372 gint label_height;
1373 gchar *words;
1375 g_return_if_fail (sheet != NULL);
1376 g_return_if_fail (GTK_IS_SHEET (sheet));
1378 if(row < 0 || row > sheet->maxrow) return;
1381 if (sheet->row[row].button.label)
1382 g_free (sheet->row[row].button.label);
1384 sheet->row[row].button.label = g_strdup (label);
1386 button = &sheet->row[row].button;
1387 label_height = 0;
1388 if(button->label && strlen(button->label)>0){
1389 words=button->label;
1390 while(words && *words != '\0'){
1391 if(*words == '\n' || *(words+1) == '\0'){
1392 label_height += DEFAULT_LABEL_HEIGHT(GTK_WIDGET(sheet));
1394 words++;
1398 if(label_height+2*CELLOFFSET > sheet->column_title_area.height)
1399 gtk_sheet_set_row_height(sheet, row, label_height+2*CELLOFFSET);
1401 if(!GTK_SHEET_IS_FROZEN(sheet)){
1402 gtk_sheet_button_draw(sheet, row, -1);
1403 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1407 void
1408 gtk_sheet_row_label_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
1410 g_return_if_fail (sheet != NULL);
1411 g_return_if_fail (GTK_IS_SHEET (sheet));
1413 if(row < 0 || row > sheet->maxrow) return;
1415 sheet->row[row].button.label_visible = visible;
1417 if(!GTK_SHEET_IS_FROZEN(sheet)){
1418 gtk_sheet_button_draw(sheet, row, -1);
1419 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1423 void
1424 gtk_sheet_rows_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1426 gint i;
1428 g_return_if_fail (sheet != NULL);
1429 g_return_if_fail (GTK_IS_SHEET (sheet));
1431 for(i = 0; i <= sheet->maxrow; i++)
1432 gtk_sheet_row_label_set_visibility(sheet, i, visible);
1436 void
1437 gtk_sheet_column_button_add_label(GtkSheet *sheet, gint column, const gchar *label)
1439 GtkSheetButton *button;
1440 gint label_height = 0;
1441 gchar *words;
1443 g_return_if_fail (sheet != NULL);
1444 g_return_if_fail (GTK_IS_SHEET (sheet));
1446 if(column < 0 || column >sheet->maxcol) return;
1448 if (sheet->column[column].button.label)
1449 g_free (sheet->column[column].button.label);
1452 sheet->column[column].button.label = g_strdup (label);
1454 button = &sheet->column[column].button;
1455 if(button->label && strlen(button->label)>0){
1456 words=button->label;
1457 while(words && *words != '\0'){
1458 if(*words == '\n' || *(words+1) == '\0'){
1459 label_height += DEFAULT_LABEL_HEIGHT(GTK_WIDGET(sheet));
1461 words++;
1465 if(label_height+2*CELLOFFSET > sheet->column_title_area.height)
1466 gtk_sheet_set_column_titles_height(sheet, label_height+2*CELLOFFSET);
1468 if(!GTK_SHEET_IS_FROZEN(sheet)){
1469 gtk_sheet_button_draw(sheet, -1, column);
1470 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1474 void
1475 gtk_sheet_column_label_set_visibility(GtkSheet *sheet, gint col, gboolean visible)
1477 g_return_if_fail (sheet != NULL);
1478 g_return_if_fail (GTK_IS_SHEET (sheet));
1480 if(col < 0 || col > sheet->maxcol) return;
1482 sheet->column[col].button.label_visible = visible;
1484 if(!GTK_SHEET_IS_FROZEN(sheet)){
1485 gtk_sheet_button_draw(sheet, -1, col);
1486 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, col);
1490 void
1491 gtk_sheet_columns_labels_set_visibility(GtkSheet *sheet, gboolean visible)
1493 gint i;
1495 g_return_if_fail (sheet != NULL);
1496 g_return_if_fail (GTK_IS_SHEET (sheet));
1498 for(i = 0; i <= sheet->maxcol; i++)
1499 gtk_sheet_column_label_set_visibility(sheet, i, visible);
1502 void
1503 gtk_sheet_row_button_justify(GtkSheet *sheet, gint row,
1504 GtkJustification justification)
1506 GtkSheetButton *button;
1508 g_return_if_fail (sheet != NULL);
1509 g_return_if_fail (GTK_IS_SHEET (sheet));
1511 if(row < 0 || row > sheet->maxrow) return;
1513 button = &sheet->row[row].button;
1514 button->justification = justification;
1516 if(!GTK_SHEET_IS_FROZEN(sheet)){
1517 gtk_sheet_button_draw(sheet, row, -1);
1518 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, -1);
1522 void
1523 gtk_sheet_column_button_justify(GtkSheet *sheet, gint column,
1524 GtkJustification justification)
1526 GtkSheetButton *button;
1528 g_return_if_fail (sheet != NULL);
1529 g_return_if_fail (GTK_IS_SHEET (sheet));
1531 if(column < 0 || column > sheet->maxcol) return;
1533 button = &sheet->column[column].button;
1534 button->justification = justification;
1536 if(!GTK_SHEET_IS_FROZEN(sheet)){
1537 gtk_sheet_button_draw(sheet, -1, column);
1538 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], -1, column);
1543 void
1544 gtk_sheet_moveto (GtkSheet * sheet,
1545 gint row,
1546 gint column,
1547 gfloat row_align,
1548 gfloat col_align)
1550 gint x, y;
1551 guint width, height;
1552 gint adjust;
1553 gint min_row, min_col;
1555 g_return_if_fail (sheet != NULL);
1556 g_return_if_fail (GTK_IS_SHEET (sheet));
1557 g_return_if_fail (sheet->hadjustment != NULL);
1558 g_return_if_fail (sheet->vadjustment != NULL);
1560 if (row < 0 || row > sheet->maxrow)
1561 return;
1562 if (column < 0 || column > sheet->maxcol)
1563 return;
1565 height = sheet->sheet_window_height;
1566 width = sheet->sheet_window_width;
1568 /* adjust vertical scrollbar */
1570 if (row >= 0 && row_align >=0.)
1572 y = ROW_TOP_YPIXEL(sheet, row) - sheet->voffset -
1573 row_align*height-
1574 (1.-row_align)*sheet->row[row].height;
1576 /* This forces the sheet to scroll when you don't see the entire cell */
1577 min_row = row;
1578 adjust = 0;
1579 if(row_align == 1.){
1580 while(min_row >= 0 && min_row > MIN_VISIBLE_ROW(sheet)){
1581 if(sheet->row[min_row].is_visible)
1582 adjust += sheet->row[min_row].height;
1583 if(adjust >= height){
1584 break;
1586 min_row--;
1588 min_row = MAX(min_row, 0);
1589 y = ROW_TOP_YPIXEL(sheet, min_row) - sheet->voffset +
1590 sheet->row[min_row].height - 1;
1593 if (y < 0)
1594 sheet->vadjustment->value = 0.0;
1595 else
1596 sheet->vadjustment->value = y;
1598 sheet->old_vadjustment = -1.;
1599 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
1600 "value_changed");
1604 /* adjust horizontal scrollbar */
1605 if (column >= 0 && col_align >= 0.)
1607 x = COLUMN_LEFT_XPIXEL (sheet, column) - sheet->hoffset -
1608 col_align*width -
1609 (1.-col_align)*sheet->column[column].width;
1611 /* This forces the sheet to scroll when you don't see the entire cell */
1612 min_col = column;
1613 adjust = 0;
1614 if(col_align == 1.){
1615 while(min_col >= 0 && min_col > MIN_VISIBLE_COLUMN(sheet)){
1616 if(sheet->column[min_col].is_visible)
1617 adjust += sheet->column[min_col].width;
1618 if(adjust >= width){
1619 break;
1621 min_col--;
1623 min_col = MAX(min_col, 0);
1624 x = COLUMN_LEFT_XPIXEL(sheet, min_col) - sheet->hoffset +
1625 sheet->column[min_col].width - 1;
1628 if (x < 0)
1629 sheet->hadjustment->value = 0.0;
1630 else
1631 sheet->hadjustment->value = x;
1633 sheet->old_vadjustment = -1.;
1634 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
1635 "value_changed");
1640 void
1641 gtk_sheet_column_set_sensitivity(GtkSheet *sheet, gint column, gboolean sensitive)
1643 g_return_if_fail (sheet != NULL);
1644 g_return_if_fail (GTK_IS_SHEET (sheet));
1646 if(column < 0 || column > sheet->maxcol) return;
1648 sheet->column[column].is_sensitive=sensitive;
1649 if(!sensitive)
1650 sheet->column[column].button.state=GTK_STATE_INSENSITIVE;
1651 else
1652 sheet->column[column].button.state=GTK_STATE_NORMAL;
1654 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
1655 gtk_sheet_button_draw(sheet, -1, column);
1658 void
1659 gtk_sheet_columns_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
1661 gint i;
1663 g_return_if_fail (sheet != NULL);
1664 g_return_if_fail (GTK_IS_SHEET (sheet));
1666 for(i=0; i<=sheet->maxcol; i++)
1667 gtk_sheet_column_set_sensitivity(sheet, i, sensitive);
1670 void
1671 gtk_sheet_row_set_sensitivity(GtkSheet *sheet, gint row, gboolean sensitive)
1674 g_return_if_fail (sheet != NULL);
1675 g_return_if_fail (GTK_IS_SHEET (sheet));
1677 if(row < 0 || row > sheet->maxrow) return;
1679 sheet->row[row].is_sensitive=sensitive;
1680 if(!sensitive)
1681 sheet->row[row].button.state=GTK_STATE_INSENSITIVE;
1682 else
1683 sheet->row[row].button.state=GTK_STATE_NORMAL;
1685 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet))
1686 gtk_sheet_button_draw(sheet, row, -1);
1689 void
1690 gtk_sheet_rows_set_sensitivity(GtkSheet *sheet, gboolean sensitive)
1692 gint i;
1694 g_return_if_fail (sheet != NULL);
1695 g_return_if_fail (GTK_IS_SHEET (sheet));
1697 for(i=0; i<=sheet->maxrow; i++)
1698 gtk_sheet_row_set_sensitivity(sheet, i, sensitive);
1701 void
1702 gtk_sheet_column_set_visibility(GtkSheet *sheet, gint column, gboolean visible)
1704 g_return_if_fail (sheet != NULL);
1705 g_return_if_fail (GTK_IS_SHEET (sheet));
1707 if(column < 0 || column > sheet->maxcol) return;
1708 if(sheet->column[column].is_visible == visible) return;
1710 sheet->column[column].is_visible = visible;
1712 gtk_sheet_recalc_left_xpixels(sheet, column);
1714 if(!GTK_SHEET_IS_FROZEN(sheet) &&
1715 gtk_sheet_cell_isvisible(sheet, MIN_VISIBLE_ROW(sheet), column)){
1716 gtk_sheet_range_draw(sheet, NULL);
1717 size_allocate_column_title_buttons(sheet);
1721 void
1722 gtk_sheet_row_set_visibility(GtkSheet *sheet, gint row, gboolean visible)
1724 g_return_if_fail (sheet != NULL);
1725 g_return_if_fail (GTK_IS_SHEET (sheet));
1727 if(row < 0 || row > sheet->maxrow) return;
1728 if(sheet->row[row].is_visible == visible) return;
1730 sheet->row[row].is_visible = visible;
1732 gtk_sheet_recalc_top_ypixels(sheet, row);
1734 if(!GTK_SHEET_IS_FROZEN(sheet) &&
1735 gtk_sheet_cell_isvisible(sheet, row, MIN_VISIBLE_COLUMN(sheet))){
1736 gtk_sheet_range_draw(sheet, NULL);
1737 size_allocate_row_title_buttons(sheet);
1741 void
1742 gtk_sheet_select_row (GtkSheet * sheet,
1743 gint row)
1745 g_return_if_fail (sheet != NULL);
1746 g_return_if_fail (GTK_IS_SHEET (sheet));
1748 if (row < 0 || row > sheet->maxrow)
1749 return;
1751 if(sheet->state != GTK_SHEET_NORMAL)
1752 gtk_sheet_real_unselect_range(sheet, NULL);
1753 else
1755 gboolean veto;
1756 veto = gtk_sheet_deactivate_cell(sheet);
1757 if(!veto) return;
1760 sheet->state=GTK_SHEET_ROW_SELECTED;
1761 sheet->range.row0=row;
1762 sheet->range.col0=0;
1763 sheet->range.rowi=row;
1764 sheet->range.coli=sheet->maxcol;
1765 sheet->active_cell.row=row;
1766 sheet->active_cell.col=0;
1768 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_ROW], row);
1769 gtk_sheet_real_select_range(sheet, NULL);
1774 void
1775 gtk_sheet_select_column (GtkSheet * sheet,
1776 gint column)
1779 g_return_if_fail (sheet != NULL);
1780 g_return_if_fail (GTK_IS_SHEET (sheet));
1782 if (column < 0 || column > sheet->maxcol)
1783 return;
1785 if(sheet->state != GTK_SHEET_NORMAL)
1786 gtk_sheet_real_unselect_range(sheet, NULL);
1787 else
1789 gboolean veto;
1790 veto = gtk_sheet_deactivate_cell(sheet);
1791 if(!veto) return;
1794 sheet->state=GTK_SHEET_COLUMN_SELECTED;
1795 sheet->range.row0=0;
1796 sheet->range.col0=column;
1797 sheet->range.rowi=sheet->maxrow;
1798 sheet->range.coli=column;
1799 sheet->active_cell.row=0;
1800 sheet->active_cell.col=column;
1802 gtk_signal_emit (GTK_OBJECT (sheet), sheet_signals[SELECT_COLUMN], column);
1803 gtk_sheet_real_select_range(sheet, NULL);
1807 void
1808 gtk_sheet_clip_range (GtkSheet *sheet, const GtkSheetRange *range)
1811 g_return_if_fail (sheet != NULL);
1812 g_return_if_fail (GTK_IS_SHEET (sheet));
1814 if(GTK_SHEET_IN_CLIP(sheet)) return;
1816 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
1818 if(range == NULL)
1819 sheet->clip_range = sheet->range;
1820 else
1821 sheet->clip_range=*range;
1823 sheet->interval=0;
1824 sheet->clip_timer=gtk_timeout_add(TIMEOUT_FLASH, gtk_sheet_flash, (gpointer) sheet);
1826 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CLIP_RANGE],
1827 &sheet->clip_range);
1831 void
1832 gtk_sheet_unclip_range(GtkSheet *sheet)
1835 g_return_if_fail (sheet != NULL);
1836 g_return_if_fail (GTK_IS_SHEET (sheet));
1838 if(!GTK_SHEET_IN_CLIP(sheet)) return;
1840 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_CLIP);
1841 gtk_timeout_remove(sheet->clip_timer);
1842 gtk_sheet_range_draw(sheet, &sheet->clip_range);
1844 if(gtk_sheet_range_isvisible(sheet, sheet->range))
1845 gtk_sheet_range_draw(sheet, &sheet->range);
1848 static gint
1849 gtk_sheet_flash(gpointer data)
1851 GtkSheet *sheet;
1852 gint x,y,width,height;
1853 GdkRectangle clip_area;
1855 sheet=GTK_SHEET(data);
1857 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return TRUE;
1858 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return TRUE;
1859 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return TRUE;
1860 if(GTK_SHEET_IN_XDRAG(sheet)) return TRUE;
1861 if(GTK_SHEET_IN_YDRAG(sheet)) return TRUE;
1863 GDK_THREADS_ENTER();
1865 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
1866 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
1867 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
1868 sheet->column[sheet->clip_range.coli].width-1;
1869 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
1870 sheet->row[sheet->clip_range.rowi].height-1;
1872 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
1873 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
1874 clip_area.width=sheet->sheet_window_width;
1875 clip_area.height=sheet->sheet_window_height;
1877 if(x<0) {
1878 width=width+x+1;
1879 x=-1;
1881 if(width>clip_area.width) width=clip_area.width+10;
1882 if(y<0) {
1883 height=height+y+1;
1884 y=-1;
1886 if(height>clip_area.height) height=clip_area.height+10;
1888 gdk_draw_pixmap(sheet->sheet_window,
1889 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
1890 sheet->pixmap,
1891 x, y,
1892 x, y,
1893 1, height);
1895 gdk_draw_pixmap(sheet->sheet_window,
1896 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
1897 sheet->pixmap,
1898 x, y,
1899 x, y,
1900 width, 1);
1902 gdk_draw_pixmap(sheet->sheet_window,
1903 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
1904 sheet->pixmap,
1905 x, y+height,
1906 x, y+height,
1907 width, 1);
1909 gdk_draw_pixmap(sheet->sheet_window,
1910 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
1911 sheet->pixmap,
1912 x+width, y,
1913 x+width, y,
1914 1, height);
1917 sheet->interval=sheet->interval+1;
1918 if(sheet->interval==TIME_INTERVAL) sheet->interval=0;
1920 gdk_gc_set_dashes(sheet->xor_gc, sheet->interval, "\4\4", 2);
1921 gtk_sheet_draw_flashing_range(sheet, sheet->clip_range);
1922 gdk_gc_set_dashes(sheet->xor_gc, 0, "\4\4", 2);
1924 GDK_THREADS_LEAVE();
1926 return TRUE;
1930 static void
1931 gtk_sheet_draw_flashing_range(GtkSheet *sheet, GtkSheetRange range)
1933 GdkRectangle clip_area;
1934 gint x,y,width,height;
1936 if(!gtk_sheet_range_isvisible(sheet, sheet->clip_range)) return;
1938 clip_area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
1939 clip_area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
1940 clip_area.width=sheet->sheet_window_width;
1941 clip_area.height=sheet->sheet_window_height;
1943 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
1945 x=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.col0)+1;
1946 y=ROW_TOP_YPIXEL(sheet,sheet->clip_range.row0)+1;
1947 width=COLUMN_LEFT_XPIXEL(sheet,sheet->clip_range.coli)-x+
1948 sheet->column[sheet->clip_range.coli].width-1;
1949 height=ROW_TOP_YPIXEL(sheet,sheet->clip_range.rowi)-y+
1950 sheet->row[sheet->clip_range.rowi].height-1;
1952 if(x<0) {
1953 width=width+x+1;
1954 x=-1;
1956 if(width>clip_area.width) width=clip_area.width+10;
1957 if(y<0) {
1958 height=height+y+1;
1959 y=-1;
1961 if(height>clip_area.height) height=clip_area.height+10;
1963 gdk_gc_set_line_attributes(sheet->xor_gc, 1, 1, 0 ,0 );
1965 gdk_draw_rectangle(sheet->sheet_window, sheet->xor_gc, FALSE,
1966 x, y,
1967 width, height);
1969 gdk_gc_set_line_attributes (sheet->xor_gc, 1, 0, 0, 0);
1971 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
1975 static gint
1976 gtk_sheet_range_isvisible (GtkSheet * sheet,
1977 GtkSheetRange range)
1979 g_return_val_if_fail (sheet != NULL, FALSE);
1981 if (range.row0 < 0 || range.row0 > sheet->maxrow)
1982 return FALSE;
1984 if (range.rowi < 0 || range.rowi > sheet->maxrow)
1985 return FALSE;
1987 if (range.col0 < 0 || range.col0 > sheet->maxcol)
1988 return FALSE;
1990 if (range.coli < 0 || range.coli > sheet->maxcol)
1991 return FALSE;
1993 if (range.rowi < MIN_VISIBLE_ROW (sheet))
1994 return FALSE;
1996 if (range.row0 > MAX_VISIBLE_ROW (sheet))
1997 return FALSE;
1999 if (range.coli < MIN_VISIBLE_COLUMN (sheet))
2000 return FALSE;
2002 if (range.col0 > MAX_VISIBLE_COLUMN (sheet))
2003 return FALSE;
2005 return TRUE;
2008 static gint
2009 gtk_sheet_cell_isvisible (GtkSheet * sheet,
2010 gint row, gint column)
2012 GtkSheetRange range;
2014 range.row0 = row;
2015 range.col0 = column;
2016 range.rowi = row;
2017 range.coli = column;
2019 return gtk_sheet_range_isvisible(sheet, range);
2022 void
2023 gtk_sheet_get_visible_range(GtkSheet *sheet, GtkSheetRange *range)
2026 g_return_if_fail (sheet != NULL);
2027 g_return_if_fail (GTK_IS_SHEET (sheet)) ;
2028 g_return_if_fail (range != NULL);
2030 range->row0 = MIN_VISIBLE_ROW(sheet);
2031 range->col0 = MIN_VISIBLE_COLUMN(sheet);
2032 range->rowi = MAX_VISIBLE_ROW(sheet);
2033 range->coli = MAX_VISIBLE_COLUMN(sheet);
2037 GtkAdjustment *
2038 gtk_sheet_get_vadjustment (GtkSheet * sheet)
2040 g_return_val_if_fail (sheet != NULL, NULL);
2041 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2043 return sheet->vadjustment;
2046 GtkAdjustment *
2047 gtk_sheet_get_hadjustment (GtkSheet * sheet)
2049 g_return_val_if_fail (sheet != NULL, NULL);
2050 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
2052 return sheet->hadjustment;
2055 void
2056 gtk_sheet_set_vadjustment (GtkSheet *sheet,
2057 GtkAdjustment *adjustment)
2059 GtkAdjustment *old_adjustment;
2061 g_return_if_fail (sheet != NULL);
2062 g_return_if_fail (GTK_IS_SHEET (sheet));
2063 if (adjustment)
2064 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2066 if (sheet->vadjustment == adjustment)
2067 return;
2069 old_adjustment = sheet->vadjustment;
2071 if (sheet->vadjustment)
2073 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2074 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2077 sheet->vadjustment = adjustment;
2079 if (sheet->vadjustment)
2081 gtk_object_ref (GTK_OBJECT (sheet->vadjustment));
2082 gtk_object_sink (GTK_OBJECT (sheet->vadjustment));
2084 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "changed",
2085 (GtkSignalFunc) vadjustment_changed,
2086 (gpointer) sheet);
2087 gtk_signal_connect (GTK_OBJECT (sheet->vadjustment), "value_changed",
2088 (GtkSignalFunc) vadjustment_value_changed,
2089 (gpointer) sheet);
2092 if (!sheet->vadjustment || !old_adjustment)
2094 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2095 return;
2098 sheet->old_vadjustment = sheet->vadjustment->value;
2101 void
2102 gtk_sheet_set_hadjustment (GtkSheet *sheet,
2103 GtkAdjustment *adjustment)
2105 GtkAdjustment *old_adjustment;
2107 g_return_if_fail (sheet != NULL);
2108 g_return_if_fail (GTK_IS_SHEET (sheet));
2109 if (adjustment)
2110 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2112 if (sheet->hadjustment == adjustment)
2113 return;
2115 old_adjustment = sheet->hadjustment;
2117 if (sheet->hadjustment)
2119 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2120 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2123 sheet->hadjustment = adjustment;
2125 if (sheet->hadjustment)
2127 gtk_object_ref (GTK_OBJECT (sheet->hadjustment));
2128 gtk_object_sink (GTK_OBJECT (sheet->hadjustment));
2130 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "changed",
2131 (GtkSignalFunc) hadjustment_changed,
2132 (gpointer) sheet);
2133 gtk_signal_connect (GTK_OBJECT (sheet->hadjustment), "value_changed",
2134 (GtkSignalFunc) hadjustment_value_changed,
2135 (gpointer) sheet);
2138 if (!sheet->hadjustment || !old_adjustment)
2140 gtk_widget_queue_resize (GTK_WIDGET (sheet));
2141 return;
2144 sheet->old_hadjustment = sheet->hadjustment->value;
2147 static void
2148 gtk_sheet_set_scroll_adjustments (GtkSheet *sheet,
2149 GtkAdjustment *hadjustment,
2150 GtkAdjustment *vadjustment)
2152 if(sheet->hadjustment != hadjustment)
2153 gtk_sheet_set_hadjustment (sheet, hadjustment);
2154 if(sheet->vadjustment != vadjustment)
2155 gtk_sheet_set_vadjustment (sheet, vadjustment);
2158 static void
2159 gtk_sheet_destroy (GtkObject * object)
2161 GtkSheet *sheet;
2163 g_return_if_fail (object != NULL);
2164 g_return_if_fail (GTK_IS_SHEET (object));
2166 sheet = GTK_SHEET (object);
2168 /* get rid of all the cells */
2169 gtk_sheet_range_clear (sheet, NULL);
2171 /* destroy the entry */
2172 gtk_widget_destroy (sheet->sheet_entry);
2174 /* destroy the global selection button */
2175 gtk_widget_destroy (sheet->button);
2177 if(sheet->timer){
2178 gtk_timeout_remove(sheet->timer);
2179 sheet->timer = 0;
2182 if(sheet->clip_timer){
2183 gtk_timeout_remove(sheet->clip_timer);
2184 sheet->clip_timer = 0;
2187 /* unref adjustments */
2188 if (sheet->hadjustment)
2190 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->hadjustment), sheet);
2191 gtk_object_unref (GTK_OBJECT (sheet->hadjustment));
2192 sheet->hadjustment = NULL;
2194 if (sheet->vadjustment)
2196 gtk_signal_disconnect_by_data (GTK_OBJECT (sheet->vadjustment), sheet);
2197 gtk_object_unref (GTK_OBJECT (sheet->vadjustment));
2198 sheet->vadjustment = NULL;
2202 if (GTK_OBJECT_CLASS (parent_class)->destroy)
2203 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
2205 g_list_free(sheet->children);
2208 #if 0
2209 static void
2210 gtk_sheet_finalize (GtkObject * object)
2212 GtkSheet *sheet;
2214 g_return_if_fail (object != NULL);
2215 g_return_if_fail (GTK_IS_SHEET (object));
2217 sheet = GTK_SHEET(object);
2219 gtk_sheet_range_delete(sheet, NULL);
2221 DeleteRow (sheet, 0, sheet->maxrow + 1);
2222 DeleteColumn (sheet, 0, sheet->maxcol + 1);
2224 g_free(sheet->row);
2225 g_free(sheet->column);
2226 g_free(sheet->data);
2228 if(sheet->name)
2229 g_free(sheet->name);
2231 if (GTK_OBJECT_CLASS (parent_class)->finalize)
2232 (*GTK_OBJECT_CLASS (parent_class)->finalize) (object);
2235 #endif
2237 static void
2238 gtk_sheet_style_set (GtkWidget *widget,
2239 GtkStyle *previous_style)
2241 GtkSheet *sheet;
2243 g_return_if_fail (widget != NULL);
2244 g_return_if_fail (GTK_IS_SHEET (widget));
2246 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2247 (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
2249 sheet = GTK_SHEET (widget);
2251 if(GTK_WIDGET_REALIZED(widget))
2253 gtk_style_set_background (widget->style, widget->window, widget->state);
2258 static void
2259 gtk_sheet_realize (GtkWidget * widget)
2261 GtkSheet *sheet;
2262 GdkWindowAttr attributes;
2263 gint attributes_mask;
2264 GdkGCValues values, auxvalues;
2265 GdkColormap *colormap;
2266 gchar *name;
2267 GtkSheetChild *child;
2268 GList *children;
2270 g_return_if_fail (widget != NULL);
2271 g_return_if_fail (GTK_IS_SHEET (widget));
2273 sheet = GTK_SHEET (widget);
2275 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2277 attributes.window_type = GDK_WINDOW_CHILD;
2278 attributes.x = widget->allocation.x;
2279 attributes.y = widget->allocation.y;
2280 attributes.width = widget->allocation.width;
2281 attributes.height = widget->allocation.height;
2282 attributes.wclass = GDK_INPUT_OUTPUT;
2284 attributes.visual = gtk_widget_get_visual (widget);
2285 attributes.colormap = gtk_widget_get_colormap (widget);
2287 attributes.event_mask = gtk_widget_get_events (widget);
2288 attributes.event_mask |= (GDK_EXPOSURE_MASK |
2289 GDK_BUTTON_PRESS_MASK |
2290 GDK_BUTTON_RELEASE_MASK |
2291 GDK_KEY_PRESS_MASK |
2292 GDK_POINTER_MOTION_MASK |
2293 GDK_POINTER_MOTION_HINT_MASK);
2294 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP |
2295 GDK_WA_CURSOR;
2297 attributes.cursor = gdk_cursor_new(GDK_TOP_LEFT_ARROW);
2299 /* main window */
2300 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2302 gdk_window_set_user_data (widget->window, sheet);
2304 widget->style = gtk_style_attach (widget->style, widget->window);
2306 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2308 attributes.x = 0;
2309 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
2310 attributes.x = sheet->row_title_area.width;
2311 attributes.y = 0;
2312 attributes.width = sheet->column_title_area.width;
2313 attributes.height = sheet->column_title_area.height;
2315 /* column-title window */
2316 sheet->column_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2317 gdk_window_set_user_data (sheet->column_title_window, sheet);
2318 gtk_style_set_background (widget->style, sheet->column_title_window, GTK_STATE_NORMAL);
2320 attributes.x = 0;
2321 attributes.y = 0;
2322 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
2323 attributes.y = sheet->column_title_area.height;
2324 attributes.width = sheet->row_title_area.width;
2325 attributes.height = sheet->row_title_area.height;
2327 /* row-title window */
2328 sheet->row_title_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2329 gdk_window_set_user_data (sheet->row_title_window, sheet);
2330 gtk_style_set_background (widget->style, sheet->row_title_window, GTK_STATE_NORMAL);
2332 /* sheet-window */
2333 attributes.cursor = gdk_cursor_new(GDK_PLUS);
2335 attributes.x = 0;
2336 attributes.y = 0;
2337 attributes.width = sheet->sheet_window_width,
2338 attributes.height = sheet->sheet_window_height;
2340 sheet->sheet_window = gdk_window_new (widget->window, &attributes, attributes_mask);
2341 gdk_window_set_user_data (sheet->sheet_window, sheet);
2343 gdk_window_set_background (sheet->sheet_window, &widget->style->white);
2344 gdk_window_show (sheet->sheet_window);
2346 /* backing_pixmap */
2347 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
2349 /* GCs */
2350 if(sheet->fg_gc)
2351 gdk_gc_unref(sheet->fg_gc);
2352 if(sheet->bg_gc)
2353 gdk_gc_unref(sheet->bg_gc);
2354 sheet->fg_gc = gdk_gc_new (widget->window);
2355 sheet->bg_gc = gdk_gc_new (widget->window);
2357 colormap = gtk_widget_get_colormap(widget);
2359 gdk_color_white(colormap, &widget->style->white);
2360 gdk_color_black(colormap, &widget->style->black);
2362 gdk_gc_get_values(sheet->fg_gc, &auxvalues);
2364 values.foreground = widget->style->white;
2365 values.function = GDK_INVERT;
2366 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
2367 if(sheet->xor_gc)
2368 gdk_gc_unref(sheet->xor_gc);
2369 sheet->xor_gc = gdk_gc_new_with_values (widget->window,
2370 &values,
2371 GDK_GC_FOREGROUND |
2372 GDK_GC_FUNCTION |
2373 GDK_GC_SUBWINDOW);
2375 /* create sheet_entry_window */
2377 if(GTK_WIDGET_NO_WINDOW(sheet->sheet_entry)){
2379 attributes.window_type = GDK_WINDOW_CHILD;
2380 attributes.x = 0;
2381 attributes.y = 0;
2382 attributes.width = sheet->sheet_entry->requisition.width;
2383 attributes.height = sheet->sheet_entry->requisition.height;
2384 attributes.wclass = GDK_INPUT_OUTPUT;
2385 attributes.visual = gtk_widget_get_visual (widget);
2386 attributes.colormap = gtk_widget_get_colormap (widget);
2387 attributes.event_mask = GDK_EXPOSURE_MASK;
2389 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2390 sheet->sheet_entry_window = gdk_window_new (sheet->sheet_window,
2391 &attributes, attributes_mask);
2392 gdk_window_set_user_data (sheet->sheet_entry_window, widget);
2395 if(sheet->sheet_entry->parent){
2396 gtk_widget_ref(sheet->sheet_entry);
2397 gtk_widget_unparent(sheet->sheet_entry);
2399 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
2400 gtk_widget_set_parent_window (sheet->sheet_entry,
2401 sheet->sheet_entry_window ?
2402 sheet->sheet_entry_window :
2403 sheet->sheet_window);
2405 if(sheet->button && sheet->button->parent){
2406 gtk_widget_ref(sheet->button);
2407 gtk_widget_unparent(sheet->button);
2409 gtk_widget_set_parent(sheet->button, GTK_WIDGET(sheet));
2410 gtk_widget_set_parent_window(sheet->button, sheet->sheet_window);
2412 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
2414 if(!sheet->cursor_drag)
2415 sheet->cursor_drag = gdk_cursor_new(GDK_PLUS);
2417 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
2418 gdk_window_show(sheet->column_title_window);
2419 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
2420 gdk_window_show(sheet->row_title_window);
2422 size_allocate_row_title_buttons(sheet);
2423 size_allocate_column_title_buttons(sheet);
2425 name = g_strdup(sheet->name);
2426 gtk_sheet_set_title(sheet, name);
2428 g_free(name);
2430 children = sheet->children;
2431 while(children)
2433 child = children->data;
2434 children = children->next;
2436 gtk_sheet_realize_child(sheet, child);
2440 static void
2441 create_global_button(GtkSheet *sheet)
2443 sheet->button = gtk_button_new_with_label(" ");
2445 gtk_widget_ensure_style(sheet->button);
2446 gtk_widget_show(sheet->button);
2448 gtk_signal_connect (GTK_OBJECT (sheet->button),
2449 "pressed",
2450 (GtkSignalFunc) global_button_clicked,
2451 (gpointer) sheet);
2454 static void
2455 size_allocate_global_button(GtkSheet *sheet)
2457 GtkAllocation allocation;
2459 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet)) return;
2460 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) return;
2462 gtk_widget_size_request(sheet->button, NULL);
2464 allocation.x=0;
2465 allocation.y=0;
2466 allocation.width=sheet->row_title_area.width;
2467 allocation.height=sheet->column_title_area.height;
2469 gtk_widget_size_allocate(sheet->button, &allocation);
2470 gtk_widget_show(sheet->button);
2473 static void
2474 global_button_clicked(GtkWidget *widget, gpointer data)
2476 gboolean veto;
2478 gtk_sheet_click_cell(GTK_SHEET(data), -1, -1, &veto);
2479 gtk_widget_grab_focus(GTK_WIDGET(data));
2483 static void
2484 gtk_sheet_unrealize (GtkWidget * widget)
2486 GtkSheet *sheet;
2487 GtkSheetChild *child;
2488 GList *children;
2490 g_return_if_fail (widget != NULL);
2491 g_return_if_fail (GTK_IS_SHEET (widget));
2493 sheet = GTK_SHEET (widget);
2494 GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
2496 gdk_cursor_destroy (sheet->cursor_drag);
2498 gdk_gc_destroy (sheet->xor_gc);
2499 gdk_gc_destroy (sheet->fg_gc);
2500 gdk_gc_destroy (sheet->bg_gc);
2502 gtk_style_detach (widget->style);
2504 gdk_window_destroy (sheet->sheet_window);
2505 gdk_window_destroy (sheet->column_title_window);
2506 gdk_window_destroy (sheet->row_title_window);
2507 gdk_window_set_user_data (widget->window, NULL);
2508 gdk_window_destroy (widget->window);
2510 if (sheet->pixmap){
2511 g_free (sheet->pixmap);
2512 sheet->pixmap = NULL;
2515 widget->window = NULL;
2516 sheet->column_title_window=NULL;
2517 sheet->sheet_window = NULL;
2518 sheet->sheet_entry_window = NULL;
2519 sheet->cursor_drag = NULL;
2520 sheet->xor_gc = NULL;
2521 sheet->fg_gc = NULL;
2522 sheet->bg_gc = NULL;
2524 children = sheet->children;
2525 while (children)
2527 child = children->data;
2528 children = children->next;
2530 if(child->window)
2532 gdk_window_set_user_data(child->window, NULL);
2533 gdk_window_destroy(child->window);
2534 child->window = NULL;
2541 static void
2542 gtk_sheet_map (GtkWidget * widget)
2544 GtkSheet *sheet;
2545 GtkSheetChild *child;
2546 GList *children;
2548 g_return_if_fail (widget != NULL);
2549 g_return_if_fail (GTK_IS_SHEET (widget));
2551 sheet = GTK_SHEET (widget);
2553 if (!GTK_WIDGET_MAPPED (widget))
2555 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2557 if(!sheet->cursor_drag) sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
2559 gdk_window_show (widget->window);
2561 gdk_window_show (sheet->sheet_window);
2563 if(sheet->sheet_entry_window)
2564 gdk_window_show(sheet->sheet_entry_window);
2566 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)){
2567 gdk_window_show (sheet->column_title_window);
2569 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)){
2570 gdk_window_show (sheet->row_title_window);
2573 if(!GTK_WIDGET_MAPPED (sheet->sheet_entry)){
2574 gtk_widget_show (sheet->sheet_entry);
2575 gtk_widget_map (sheet->sheet_entry);
2578 if (GTK_WIDGET_VISIBLE (sheet->button) &&
2579 !GTK_WIDGET_MAPPED (sheet->button)){
2580 gtk_widget_show(sheet->button);
2581 gtk_widget_map (sheet->button);
2584 if(GTK_BIN(sheet->button)->child)
2585 if (GTK_WIDGET_VISIBLE (GTK_BIN(sheet->button)->child) &&
2586 !GTK_WIDGET_MAPPED (GTK_BIN(sheet->button)->child))
2587 gtk_widget_map (GTK_BIN(sheet->button)->child);
2589 gtk_sheet_range_draw(sheet, NULL);
2590 gtk_sheet_activate_cell(sheet,
2591 sheet->active_cell.row,
2592 sheet->active_cell.col);
2594 children = sheet->children;
2595 while (children)
2597 child = children->data;
2598 children = children->next;
2600 if (GTK_WIDGET_VISIBLE (child->widget) &&
2601 !GTK_WIDGET_MAPPED (child->widget)){
2602 gtk_widget_map (child->widget);
2603 gtk_sheet_position_child(sheet, child);
2604 if (GTK_WIDGET_NO_WINDOW(child->widget) && child->window)
2605 gdk_window_show(child->window);
2612 static void
2613 gtk_sheet_unmap (GtkWidget * widget)
2615 GtkSheet *sheet;
2616 GtkSheetChild *child;
2617 GList *children;
2619 g_return_if_fail (widget != NULL);
2620 g_return_if_fail (GTK_IS_SHEET (widget));
2622 sheet = GTK_SHEET (widget);
2624 if (GTK_WIDGET_MAPPED (widget))
2626 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2628 gdk_window_hide (sheet->sheet_window);
2629 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
2630 gdk_window_hide (sheet->column_title_window);
2631 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
2632 gdk_window_hide (sheet->row_title_window);
2633 gdk_window_hide (widget->window);
2635 if(sheet->sheet_entry_window)
2636 gdk_window_hide (sheet->sheet_entry_window);
2638 if (GTK_WIDGET_MAPPED (sheet->sheet_entry))
2639 gtk_widget_unmap (sheet->sheet_entry);
2641 if (GTK_WIDGET_MAPPED (sheet->button))
2642 gtk_widget_unmap (sheet->button);
2644 children = sheet->children;
2645 while (children)
2647 child = children->data;
2648 children = children->next;
2650 if (GTK_WIDGET_VISIBLE (child->widget) &&
2651 GTK_WIDGET_MAPPED (child->widget))
2653 gtk_widget_unmap (child->widget);
2654 if(child->window) gdk_window_hide(child->window);
2662 static void
2663 gtk_sheet_cell_draw_default (GtkSheet *sheet, gint row, gint col)
2665 GtkWidget *widget;
2666 GdkGC *fg_gc, *bg_gc;
2667 GtkSheetCellAttr attributes;
2668 GdkRectangle area;
2670 g_return_if_fail (sheet != NULL);
2672 /* bail now if we arn't drawable yet */
2673 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2675 if (row < 0 || row > sheet->maxrow) return;
2676 if (col < 0 || col > sheet->maxcol) return;
2677 if (!sheet->column[col].is_visible) return;
2678 if (!sheet->row[row].is_visible) return;
2680 widget = GTK_WIDGET (sheet);
2682 gtk_sheet_get_attributes(sheet, row, col, &attributes);
2684 /* select GC for background rectangle */
2685 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2686 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2688 fg_gc = sheet->fg_gc;
2689 bg_gc = sheet->bg_gc;
2691 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
2692 area.y=ROW_TOP_YPIXEL(sheet,row);
2693 area.width=sheet->column[col].width;
2694 area.height=sheet->row[row].height;
2696 gdk_draw_rectangle (sheet->pixmap,
2697 bg_gc,
2698 TRUE,
2699 area.x,
2700 area.y,
2701 area.width,
2702 area.height);
2704 gdk_gc_set_line_attributes (sheet->fg_gc, 1, 0, 0, 0);
2706 if(sheet->show_grid && attributes.background.pixel == sheet->bg_color.pixel){
2707 gdk_gc_set_foreground (sheet->bg_gc, &sheet->grid_color);
2708 gdk_draw_rectangle (sheet->pixmap,
2709 sheet->bg_gc,
2710 FALSE,
2711 area.x, area.y,
2712 area.width, area.height);
2716 static void
2717 gtk_sheet_cell_draw_border (GtkSheet *sheet, gint row, gint col, gint mask)
2719 GtkWidget *widget;
2720 GdkGC *fg_gc, *bg_gc;
2721 GtkSheetCellAttr attributes;
2722 GdkRectangle area;
2723 guint width;
2725 g_return_if_fail (sheet != NULL);
2727 /* bail now if we arn't drawable yet */
2728 if (!GTK_WIDGET_DRAWABLE (sheet)) return;
2730 if (row < 0 || row > sheet->maxrow) return;
2731 if (col < 0 || col > sheet->maxcol) return;
2732 if (!sheet->column[col].is_visible) return;
2733 if (!sheet->row[row].is_visible) return;
2735 widget = GTK_WIDGET (sheet);
2737 gtk_sheet_get_attributes(sheet, row, col, &attributes);
2739 /* select GC for background rectangle */
2740 gdk_gc_set_foreground (sheet->fg_gc, &attributes.border.color);
2741 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2743 fg_gc = sheet->fg_gc;
2744 bg_gc = sheet->bg_gc;
2746 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
2747 area.y=ROW_TOP_YPIXEL(sheet,row);
2748 area.width=sheet->column[col].width;
2749 area.height=sheet->row[row].height;
2751 width = attributes.border.width;
2752 gdk_gc_set_line_attributes(sheet->fg_gc, attributes.border.width,
2753 attributes.border.line_style,
2754 attributes.border.cap_style,
2755 attributes.border.join_style);
2757 if(width>0){
2758 if(attributes.border.mask & GTK_SHEET_LEFT_BORDER & mask)
2759 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
2760 area.x, area.y-width/2,
2761 area.x, area.y+area.height+width/2+1);
2763 if(attributes.border.mask & GTK_SHEET_RIGHT_BORDER & mask)
2764 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
2765 area.x+area.width, area.y-width/2,
2766 area.x+area.width,
2767 area.y+area.height+width/2+1);
2769 if(attributes.border.mask & GTK_SHEET_TOP_BORDER & mask)
2770 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
2771 area.x-width/2,area.y,
2772 area.x+area.width+width/2+1,
2773 area.y);
2775 if(attributes.border.mask & GTK_SHEET_BOTTOM_BORDER & mask)
2776 gdk_draw_line(sheet->pixmap, sheet->fg_gc,
2777 area.x-width/2, area.y+area.height,
2778 area.x+area.width+width/2+1,
2779 area.y+area.height);
2786 static void
2787 gtk_sheet_cell_draw_label (GtkSheet *sheet, gint row, gint col)
2789 GtkWidget *widget;
2790 GdkRectangle area, clip_area;
2791 gint i;
2792 gint text_width, text_height, y;
2793 gint xoffset=0;
2794 gint size, sizel, sizer;
2795 GdkGC *fg_gc, *bg_gc;
2796 GtkSheetCellAttr attributes;
2797 char *label;
2799 g_return_if_fail (sheet != NULL);
2801 /* bail now if we arn't drawable yet */
2802 if (!GTK_WIDGET_DRAWABLE (sheet))
2803 return;
2805 if (row > sheet->maxallocrow) return;
2806 if (col > sheet->maxalloccol) return;
2807 if (!sheet->data[row]) return;
2808 if (!sheet->data[row][col]) return;
2809 if (!sheet->data[row][col]->text || strlen(sheet->data[row][col]->text)==0)
2810 return;
2812 if (row < 0 || row > sheet->maxrow) return;
2813 if (col < 0 || col > sheet->maxcol) return;
2814 if (!sheet->column[col].is_visible) return;
2815 if (!sheet->row[row].is_visible) return;
2818 widget = GTK_WIDGET(sheet);
2820 label = sheet->data[row][col]->text;
2822 gtk_sheet_get_attributes(sheet, row, col, &attributes);
2824 /* select GC for background rectangle */
2825 gdk_gc_set_foreground (sheet->fg_gc, &attributes.foreground);
2826 gdk_gc_set_foreground (sheet->bg_gc, &attributes.background);
2827 gdk_gc_set_font(sheet->fg_gc, attributes.font);
2829 fg_gc = sheet->fg_gc;
2830 bg_gc = sheet->bg_gc;
2832 area.x=COLUMN_LEFT_XPIXEL(sheet,col);
2833 area.y=ROW_TOP_YPIXEL(sheet,row);
2834 area.width=sheet->column[col].width;
2835 area.height=sheet->row[row].height;
2837 clip_area = area;
2839 text_width = gdk_string_width (attributes.font, label);
2840 text_height = attributes.font->ascent + attributes.font->descent;
2841 y = area.y + area.height - CELLOFFSET;
2842 y = y - text_height + attributes.font->ascent;
2844 switch(attributes.justification){
2845 case GTK_JUSTIFY_RIGHT:
2846 size=area.width;
2847 area.x+=area.width;
2848 if(!GTK_SHEET_CLIP_TEXT(sheet)){
2849 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
2850 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
2851 if(size>=text_width+CELLOFFSET) break;
2852 size+=sheet->column[i].width;
2853 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
2855 area.width=size;
2857 area.x-=size;
2858 xoffset+=area.width-text_width - 2 * CELLOFFSET -
2859 attributes.border.width/2;
2860 break;
2861 case GTK_JUSTIFY_CENTER:
2862 sizel=area.width/2;
2863 sizer=area.width/2;
2864 area.x+=area.width/2;
2865 if(!GTK_SHEET_CLIP_TEXT(sheet)){
2866 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
2867 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
2868 if(sizer>=text_width/2) break;
2869 sizer+=sheet->column[i].width;
2870 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
2872 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
2873 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
2874 if(sizel>=text_width/2) break;
2875 sizel+=sheet->column[i].width;
2876 sheet->column[i].right_text_column = MAX(col, sheet->column[i].right_text_column);
2878 size=MIN(sizel, sizer);
2880 area.x-=sizel;
2881 xoffset+= sizel - text_width/2 - CELLOFFSET;
2882 area.width=sizel+sizer;
2883 break;
2884 case GTK_JUSTIFY_LEFT:
2885 default:
2886 size=area.width;
2887 if(!GTK_SHEET_CLIP_TEXT(sheet)){
2888 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
2889 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
2890 if(size>=text_width+CELLOFFSET) break;
2891 size+=sheet->column[i].width;
2892 sheet->column[i].left_text_column = MIN(col, sheet->column[i].left_text_column);
2894 area.width=size;
2896 xoffset += attributes.border.width/2;
2897 break;
2900 if(!GTK_SHEET_CLIP_TEXT(sheet)) clip_area = area;
2901 gdk_gc_set_clip_rectangle(fg_gc, &clip_area);
2903 gdk_draw_string (sheet->pixmap,
2904 attributes.font,
2905 fg_gc,
2906 area.x + xoffset + CELLOFFSET,
2908 label);
2910 gdk_gc_set_clip_rectangle(fg_gc, NULL);
2912 gdk_draw_pixmap(sheet->sheet_window,
2913 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2914 sheet->pixmap,
2915 area.x,
2916 area.y,
2917 area.x,
2918 area.y,
2919 area.width,
2920 area.height);
2927 static void
2928 gtk_sheet_range_draw(GtkSheet *sheet, const GtkSheetRange *range)
2930 gint i,j;
2931 GtkSheetRange drawing_range;
2932 GdkRectangle area;
2934 g_return_if_fail(sheet != NULL);
2935 g_return_if_fail(GTK_SHEET(sheet));
2937 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
2938 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
2939 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
2941 if(range == NULL)
2943 drawing_range.row0=MIN_VISIBLE_ROW(sheet);
2944 drawing_range.col0=MIN_VISIBLE_COLUMN(sheet);
2945 drawing_range.rowi=MAX_VISIBLE_ROW(sheet);
2946 drawing_range.coli=MAX_VISIBLE_COLUMN(sheet);
2948 gdk_draw_rectangle (sheet->pixmap,
2949 GTK_WIDGET(sheet)->style->white_gc,
2950 TRUE,
2951 0,0,
2952 sheet->sheet_window_width,sheet->sheet_window_height);
2955 else
2957 drawing_range.row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
2958 drawing_range.col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
2959 drawing_range.rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
2960 drawing_range.coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
2963 if(drawing_range.coli == sheet->maxcol){
2964 area.x=COLUMN_LEFT_XPIXEL(sheet,sheet->maxcol)+
2965 sheet->column[sheet->maxcol].width+1;
2966 area.y=0;
2968 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
2969 gdk_draw_rectangle (sheet->pixmap,
2970 sheet->fg_gc,
2971 TRUE,
2972 area.x,area.y,
2973 sheet->sheet_window_width - area.x,
2974 sheet->sheet_window_height);
2975 gdk_draw_pixmap(sheet->sheet_window,
2976 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
2977 sheet->pixmap,
2978 area.x,
2979 area.y,
2980 area.x,
2981 area.y,
2982 sheet->sheet_window_width - area.x,
2983 sheet->sheet_window_height);
2986 if(drawing_range.rowi == sheet->maxrow){
2987 area.x=0;
2988 area.y=ROW_TOP_YPIXEL(sheet,sheet->maxrow)+sheet->row[sheet->maxrow].height+1;
2990 gdk_gc_set_foreground(sheet->fg_gc, &sheet->bg_color);
2991 gdk_draw_rectangle (sheet->pixmap,
2992 sheet->fg_gc,
2993 TRUE,
2994 area.x,area.y,
2995 sheet->sheet_window_width,
2996 sheet->sheet_window_height - area.y);
2998 gdk_draw_pixmap(sheet->sheet_window,
2999 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3000 sheet->pixmap,
3001 area.x,
3002 area.y,
3003 area.x,
3004 area.y,
3005 sheet->sheet_window_width,
3006 sheet->sheet_window_height - area.y);
3009 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3010 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3011 gtk_sheet_cell_draw_default(sheet, i, j);
3014 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3015 for(j=drawing_range.col0; j<=drawing_range.coli; j++){
3016 gtk_sheet_cell_draw_border(sheet, i-1, j, GTK_SHEET_BOTTOM_BORDER);
3017 gtk_sheet_cell_draw_border(sheet, i+1, j, GTK_SHEET_TOP_BORDER);
3018 gtk_sheet_cell_draw_border(sheet, i, j-1, GTK_SHEET_RIGHT_BORDER);
3019 gtk_sheet_cell_draw_border(sheet, i, j+1, GTK_SHEET_LEFT_BORDER);
3020 gtk_sheet_cell_draw_border(sheet, i, j, 15);
3023 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3024 for(j=drawing_range.col0; j<=drawing_range.coli; j++)
3025 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3026 sheet->data[i] && sheet->data[i][j])
3027 gtk_sheet_cell_draw_label (sheet, i, j);
3029 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3030 for(j=sheet->column[drawing_range.col0].left_text_column; j<drawing_range.col0; j++)
3031 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3032 sheet->data[i] && sheet->data[i][j])
3033 gtk_sheet_cell_draw_label (sheet, i, j);
3035 for(i=drawing_range.row0; i<=drawing_range.rowi; i++)
3036 for(j=drawing_range.coli+1; j<=sheet->column[drawing_range.coli].right_text_column; j++)
3037 if(i<=sheet->maxallocrow && j<=sheet->maxalloccol &&
3038 sheet->data[i] && sheet->data[i][j])
3039 gtk_sheet_cell_draw_label (sheet, i, j);
3041 gtk_sheet_draw_backing_pixmap(sheet, drawing_range);
3043 if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range))
3044 gtk_sheet_range_draw_selection(sheet, drawing_range);
3046 if(sheet->state == GTK_STATE_NORMAL &&
3047 sheet->active_cell.row >= drawing_range.row0 &&
3048 sheet->active_cell.row <= drawing_range.rowi &&
3049 sheet->active_cell.col >= drawing_range.col0 &&
3050 sheet->active_cell.col <= drawing_range.coli)
3051 gtk_sheet_show_active_cell(sheet);
3054 static void
3055 gtk_sheet_range_draw_selection(GtkSheet *sheet, GtkSheetRange range)
3057 GdkRectangle area;
3058 gint i,j;
3059 GtkSheetRange aux;
3061 if(range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
3062 range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
3063 return;
3065 if(!gtk_sheet_range_isvisible(sheet, range)) return;
3066 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3068 aux=range;
3070 range.col0=MAX(sheet->range.col0, range.col0);
3071 range.coli=MIN(sheet->range.coli, range.coli);
3072 range.row0=MAX(sheet->range.row0, range.row0);
3073 range.rowi=MIN(sheet->range.rowi, range.rowi);
3075 range.col0=MAX(range.col0, MIN_VISIBLE_COLUMN(sheet));
3076 range.coli=MIN(range.coli, MAX_VISIBLE_COLUMN(sheet));
3077 range.row0=MAX(range.row0, MIN_VISIBLE_ROW(sheet));
3078 range.rowi=MIN(range.rowi, MAX_VISIBLE_ROW(sheet));
3080 for(i=range.row0; i<=range.rowi; i++){
3081 for(j=range.col0; j<=range.coli; j++){
3083 if(gtk_sheet_cell_get_state(sheet, i, j)==GTK_STATE_SELECTED &&
3084 sheet->column[j].is_visible && sheet->row[i].is_visible){
3086 row_button_set(sheet, i);
3087 column_button_set(sheet, j);
3089 area.x=COLUMN_LEFT_XPIXEL(sheet,j);
3090 area.y=ROW_TOP_YPIXEL(sheet,i);
3091 area.width=sheet->column[j].width;
3092 area.height=sheet->row[i].height;
3094 if(i==sheet->range.row0){
3095 area.y=area.y+2;
3096 area.height=area.height-2;
3098 if(i==sheet->range.rowi) area.height=area.height-3;
3099 if(j==sheet->range.col0){
3100 area.x=area.x+2;
3101 area.width=area.width-2;
3103 if(j==sheet->range.coli) area.width=area.width-3;
3105 if(i!=sheet->active_cell.row || j!=sheet->active_cell.col){
3106 gdk_draw_rectangle (sheet->sheet_window,
3107 sheet->xor_gc,
3108 TRUE,
3109 area.x+1,area.y+1,
3110 area.width,area.height);
3117 gtk_sheet_draw_border(sheet, sheet->range);
3121 static void
3122 gtk_sheet_draw_backing_pixmap(GtkSheet *sheet, GtkSheetRange range)
3124 gint x,y,width,height;
3126 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3128 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
3129 y=ROW_TOP_YPIXEL(sheet, range.row0);
3130 width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-x+sheet->column[range.coli].width;
3131 height=ROW_TOP_YPIXEL(sheet, range.rowi)-y+sheet->row[range.rowi].height;
3133 if(range.row0==sheet->range.row0){
3134 y=y-5;
3135 height=height+5;
3137 if(range.rowi==sheet->range.rowi) height=height+5;
3138 if(range.col0==sheet->range.col0){
3139 x=x-5;
3140 width=width+5;
3142 if(range.coli==sheet->range.coli) width=width+5;
3145 width=MIN(width, sheet->sheet_window_width-x);
3146 height=MIN(height, sheet->sheet_window_height-y);
3148 x--;
3149 y--;
3150 width+=2;
3151 height+=2;
3153 x = (GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
3154 ? MAX(x, sheet->row_title_area.width) : MAX(x, 0);
3155 y = (GTK_SHEET_COL_TITLES_VISIBLE(sheet))
3156 ? MAX(y, sheet->column_title_area.height) : MAX(y, 0);
3158 if(range.coli==sheet->maxcol) width=sheet->sheet_window_width-x;
3159 if(range.rowi==sheet->maxrow) height=sheet->sheet_window_height-y;
3161 gdk_draw_pixmap(sheet->sheet_window,
3162 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3163 sheet->pixmap,
3168 width+1,
3169 height+1);
3173 static GtkSheetCell *
3174 gtk_sheet_cell_new()
3176 GtkSheetCell *cell;
3177 cell = g_new(GtkSheetCell, 1);
3178 cell->text = NULL;
3179 cell->link = NULL;
3180 cell->attributes = NULL;
3181 return cell;
3184 void
3185 gtk_sheet_set_cell_text(GtkSheet *sheet, gint row, gint col, const gchar *text)
3187 GtkSheetCellAttr attributes;
3189 g_return_if_fail (sheet != NULL);
3190 g_return_if_fail (GTK_IS_SHEET (sheet));
3191 if (col > sheet->maxcol || row > sheet->maxrow) return;
3192 if (col < 0 || row < 0) return;
3194 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3195 gtk_sheet_set_cell(sheet, row, col, attributes.justification, text);
3198 void
3199 gtk_sheet_set_cell(GtkSheet *sheet, gint row, gint col,
3200 GtkJustification justification,
3201 const gchar *text)
3203 GtkSheetCell **cell;
3204 GtkSheetRange range;
3205 gint text_width;
3206 GtkSheetCellAttr attributes;
3208 g_return_if_fail (sheet != NULL);
3209 g_return_if_fail (GTK_IS_SHEET (sheet));
3210 if (col > sheet->maxcol || row > sheet->maxrow) return;
3211 if (col < 0 || row < 0) return;
3213 CheckBounds(sheet, row, col);
3215 cell=&sheet->data[row][col];
3217 if(*cell==NULL)
3218 (*cell) = gtk_sheet_cell_new();
3220 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3222 (*cell)->row = row;
3223 (*cell)->col = col;
3225 attributes.justification = justification;
3226 gtk_sheet_set_cell_attributes(sheet, row, col, attributes);
3228 if((*cell)->text){
3229 g_free((*cell)->text);
3230 (*cell)->text = NULL;
3233 if(text)
3234 (*cell)->text=g_strdup(text);
3236 if(attributes.is_visible){
3238 text_width = 0;
3239 if((*cell)->text && strlen((*cell)->text) > 0) {
3240 text_width = gdk_string_width (attributes.font, (*cell)->text);
3243 range.row0 = row;
3244 range.rowi = row;
3245 range.col0 = sheet->view.col0;
3246 range.coli = sheet->view.coli;
3248 if(GTK_SHEET_AUTORESIZE(sheet) &&
3249 text_width > sheet->column[col].width-2*CELLOFFSET-attributes.border.width){
3250 gtk_sheet_set_column_width(sheet, col, text_width+2*CELLOFFSET+attributes.border.width);
3252 else
3253 if(!GTK_SHEET_IS_FROZEN(sheet))
3254 gtk_sheet_range_draw(sheet, &range);
3257 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CHANGED], row, col);
3261 void
3262 gtk_sheet_cell_clear (GtkSheet *sheet, gint row, gint column)
3264 GtkSheetRange range;
3266 g_return_if_fail (sheet != NULL);
3267 g_return_if_fail (GTK_IS_SHEET (sheet));
3268 if (column > sheet->maxcol || row > sheet->maxrow) return;
3269 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3270 if (column < 0 || row < 0) return;
3272 range.row0 = row;
3273 range.rowi = row;
3274 range.col0 = sheet->view.col0;
3275 range.coli = sheet->view.coli;
3277 gtk_sheet_real_cell_clear(sheet, row, column, FALSE);
3279 if(!GTK_SHEET_IS_FROZEN(sheet)){
3280 gtk_sheet_range_draw(sheet, &range);
3284 void
3285 gtk_sheet_cell_delete (GtkSheet *sheet, gint row, gint column)
3287 GtkSheetRange range;
3289 g_return_if_fail (sheet != NULL);
3290 g_return_if_fail (GTK_IS_SHEET (sheet));
3291 if (column > sheet->maxcol || row > sheet->maxrow) return;
3292 if (column > sheet->maxalloccol || row > sheet->maxallocrow) return;
3293 if (column < 0 || row < 0) return;
3295 range.row0 = row;
3296 range.rowi = row;
3297 range.col0 = sheet->view.col0;
3298 range.coli = sheet->view.coli;
3300 gtk_sheet_real_cell_clear(sheet, row, column, TRUE);
3302 if(!GTK_SHEET_IS_FROZEN(sheet)){
3303 gtk_sheet_range_draw(sheet, &range);
3307 static void
3308 gtk_sheet_real_cell_clear (GtkSheet *sheet, gint row, gint column, gboolean delete)
3310 gchar *text;
3311 gpointer link;
3313 if(row > sheet->maxallocrow || column > sheet->maxalloccol) return;
3314 if(!sheet->data[row]) return;
3315 if(!sheet->data[row][column]) return;
3317 text = gtk_sheet_cell_get_text(sheet, row, column);
3318 link = gtk_sheet_get_link(sheet, row, column);
3320 if(text){
3321 g_free(sheet->data[row][column]->text);
3322 sheet->data[row][column]->text = NULL;
3324 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[CLEAR_CELL], row, column);
3327 if(delete){
3328 if(sheet->data[row][column]->attributes){
3329 g_free(sheet->data[row][column]->attributes);
3330 sheet->data[row][column]->attributes = NULL;
3332 sheet->data[row][column]->link = NULL;
3334 if(sheet->data[row][column]) g_free(sheet->data[row][column]);
3336 sheet->data[row][column] = NULL;
3341 void
3342 gtk_sheet_range_clear (GtkSheet *sheet, const GtkSheetRange *range)
3344 g_return_if_fail (sheet != NULL);
3345 g_return_if_fail (GTK_IS_SHEET (sheet));
3347 gtk_sheet_real_range_clear(sheet, range, FALSE);
3350 void
3351 gtk_sheet_range_delete (GtkSheet *sheet, const GtkSheetRange *range)
3353 g_return_if_fail (sheet != NULL);
3354 g_return_if_fail (GTK_IS_SHEET (sheet));
3356 gtk_sheet_real_range_clear(sheet, range, TRUE);
3359 static void
3360 gtk_sheet_real_range_clear (GtkSheet *sheet, const GtkSheetRange *range,
3361 gboolean delete)
3363 gint i, j;
3364 GtkSheetRange clear;
3366 if(!range){
3367 clear.row0=0;
3368 clear.rowi=sheet->maxallocrow;
3369 clear.col0=0;
3370 clear.coli=sheet->maxalloccol;
3371 }else
3372 clear=*range;
3374 clear.row0=MAX(clear.row0, 0);
3375 clear.col0=MAX(clear.col0, 0);
3376 clear.rowi=MIN(clear.rowi, sheet->maxallocrow);
3377 clear.coli=MIN(clear.coli, sheet->maxalloccol);
3379 for(i=clear.row0; i<=clear.rowi; i++)
3380 for(j=clear.col0; j<=clear.coli; j++){
3381 gtk_sheet_real_cell_clear(sheet, i, j, delete);
3384 gtk_sheet_range_draw(sheet, NULL);
3388 gchar *
3389 gtk_sheet_cell_get_text (GtkSheet *sheet, gint row, gint col)
3391 g_return_val_if_fail (sheet != NULL, NULL);
3392 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3394 if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
3395 if(col < 0 || row < 0) return NULL;
3396 if(row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL;
3397 if(!sheet->data[row]) return NULL;
3398 if(!sheet->data[row][col]) return NULL;
3399 if(!sheet->data[row][col]->text) return NULL;
3400 if(strlen(sheet->data[row][col]->text) == 0) return NULL;
3402 return (sheet->data[row][col]->text);
3405 void
3406 gtk_sheet_link_cell(GtkSheet *sheet, gint row, gint col, gpointer link)
3408 g_return_if_fail (sheet != NULL);
3409 g_return_if_fail (GTK_IS_SHEET (sheet));
3410 if(col > sheet->maxcol || row > sheet->maxrow) return;
3411 if(col < 0 || row < 0) return;
3413 if(row > sheet->maxallocrow || col > sheet->maxalloccol ||
3414 !sheet->data[row] || !sheet->data[row][col])
3415 gtk_sheet_set_cell_text(sheet, row, col, "");
3417 sheet->data[row][col]->link = link;
3420 gpointer
3421 gtk_sheet_get_link(GtkSheet *sheet, gint row, gint col)
3423 g_return_val_if_fail (sheet != NULL, NULL);
3424 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
3425 if(col > sheet->maxcol || row > sheet->maxrow) return NULL;
3426 if(col < 0 || row < 0) return NULL;
3428 if (row > sheet->maxallocrow || col > sheet->maxalloccol) return NULL;
3429 if (!sheet->data[row]) return NULL; /* Added by Chris Howell */
3430 if (!sheet->data[row][col]) return NULL; /* Added by Bob Lissner */
3432 return(sheet->data[row][col]->link);
3435 void
3436 gtk_sheet_remove_link(GtkSheet *sheet, gint row, gint col)
3438 g_return_if_fail (sheet != NULL);
3439 g_return_if_fail (GTK_IS_SHEET (sheet));
3440 if(col > sheet->maxcol || row > sheet->maxrow) return;
3441 if(col < 0 || row < 0) return;
3443 /* Fixed by Andreas Voegele */
3444 if(row < sheet->maxallocrow && col < sheet->maxalloccol &&
3445 sheet->data[row] && sheet->data[row][col] &&
3446 sheet->data[row][col]->link)
3447 sheet->data[row][col]->link = NULL;
3451 GtkStateType
3452 gtk_sheet_cell_get_state (GtkSheet *sheet, gint row, gint col)
3454 gint state;
3455 GtkSheetRange *range;
3457 g_return_val_if_fail (sheet != NULL, 0);
3458 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3459 if(col > sheet->maxcol || row > sheet->maxrow) return 0;
3460 if(col < 0 || row < 0) return 0;
3462 state = sheet->state;
3463 range = &sheet->range;
3465 switch (state){
3466 case GTK_SHEET_NORMAL:
3467 return GTK_STATE_NORMAL;
3468 break;
3469 case GTK_SHEET_ROW_SELECTED:
3470 if(row>=range->row0 && row<=range->rowi)
3471 return GTK_STATE_SELECTED;
3472 break;
3473 case GTK_SHEET_COLUMN_SELECTED:
3474 if(col>=range->col0 && col<=range->coli)
3475 return GTK_STATE_SELECTED;
3476 break;
3477 case GTK_SHEET_RANGE_SELECTED:
3478 if(row >= range->row0 && row <= range->rowi && \
3479 col >= range->col0 && col <= range->coli)
3480 return GTK_STATE_SELECTED;
3481 break;
3483 return GTK_STATE_NORMAL;
3486 gboolean
3487 gtk_sheet_get_pixel_info (GtkSheet * sheet,
3488 gint x,
3489 gint y,
3490 gint * row,
3491 gint * column)
3493 gint trow, tcol;
3495 g_return_val_if_fail (sheet != NULL, 0);
3496 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3498 /* bounds checking, return false if the user clicked
3499 * on a blank area */
3500 trow = ROW_FROM_YPIXEL (sheet, y);
3501 if (trow > sheet->maxrow)
3502 return FALSE;
3504 *row = trow;
3506 tcol = COLUMN_FROM_XPIXEL (sheet, x);
3507 if (tcol > sheet->maxcol)
3508 return FALSE;
3510 *column = tcol;
3512 return TRUE;
3515 gboolean
3516 gtk_sheet_get_cell_area (GtkSheet * sheet,
3517 gint row,
3518 gint column,
3519 GdkRectangle *area)
3521 g_return_val_if_fail (sheet != NULL, 0);
3522 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3524 if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
3526 area->x = (column == -1) ? 0 : (COLUMN_LEFT_XPIXEL(sheet, column) -
3527 ((GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
3528 ? sheet->row_title_area.width
3529 : 0));
3530 area->y = (row == -1) ? 0 : (ROW_TOP_YPIXEL(sheet, row) -
3531 ((GTK_SHEET_COL_TITLES_VISIBLE(sheet))
3532 ? sheet->column_title_area.height
3533 : 0));
3534 area->width= (column == -1) ? sheet->row_title_area.width
3535 : sheet->column[column].width;
3536 area->height= (row == -1) ? sheet->column_title_area.height
3537 : sheet->row[row].height;
3540 if(row < 0 || column < 0) return FALSE;
3542 area->x = COLUMN_LEFT_XPIXEL(sheet, column);
3543 area->y = ROW_TOP_YPIXEL(sheet, row);
3544 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
3545 area->x -= sheet->row_title_area.width;
3546 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
3547 area->y -= sheet->column_title_area.height;
3549 area->width=sheet->column[column].width;
3550 area->height=sheet->row[row].height;
3552 return TRUE;
3555 gboolean
3556 gtk_sheet_set_active_cell (GtkSheet *sheet, gint row, gint column)
3558 g_return_val_if_fail (sheet != NULL, 0);
3559 g_return_val_if_fail (GTK_IS_SHEET (sheet), 0);
3561 if(row < 0 || column < 0) return FALSE;
3562 if(row > sheet->maxrow || column > sheet->maxcol) return FALSE;
3564 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
3566 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
3569 sheet->active_cell.row=row;
3570 sheet->active_cell.col=column;
3572 if(!gtk_sheet_activate_cell(sheet, row, column)) return FALSE;
3574 return TRUE;
3577 void
3578 gtk_sheet_get_active_cell (GtkSheet *sheet, gint *row, gint *column)
3580 g_return_if_fail (sheet != NULL);
3581 g_return_if_fail (GTK_IS_SHEET (sheet));
3583 *row = sheet->active_cell.row;
3584 *column = sheet->active_cell.col;
3587 static void
3588 gtk_sheet_entry_changed(GtkWidget *widget, gpointer data)
3590 GtkSheet *sheet;
3591 gint row,col;
3592 char *text;
3593 GtkJustification justification;
3594 GtkSheetCellAttr attributes;
3596 g_return_if_fail (data != NULL);
3597 g_return_if_fail (GTK_IS_SHEET (data));
3599 sheet=GTK_SHEET(data);
3601 if(!GTK_WIDGET_VISIBLE(widget)) return;
3602 if(sheet->state != GTK_STATE_NORMAL) return;
3604 row=sheet->active_cell.row;
3605 col=sheet->active_cell.col;
3607 if(row<0 || col<0) return;
3609 sheet->active_cell.row=-1;
3610 sheet->active_cell.col=-1;
3612 text = (gchar *) gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3614 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3616 if(text && strlen(text)!=0){
3617 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3618 justification=attributes.justification;
3619 gtk_sheet_set_cell(sheet, row, col, justification, text);
3621 else
3623 /* Added by Matias Mutchinick */
3624 gtk_sheet_cell_clear(sheet, row, col);
3627 if(sheet->freeze_count == 0)
3628 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3630 sheet->active_cell.row=row;;
3631 sheet->active_cell.col=col;
3636 static gboolean
3637 gtk_sheet_deactivate_cell(GtkSheet *sheet)
3639 gboolean veto = TRUE;
3641 g_return_val_if_fail (sheet != NULL, FALSE);
3642 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3644 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return FALSE;
3645 if(sheet->state != GTK_SHEET_NORMAL) return FALSE;
3646 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[DEACTIVATE],
3647 sheet->active_cell.row,
3648 sheet->active_cell.col, &veto);
3650 if(!veto) return FALSE;
3652 gtk_signal_disconnect_by_func(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
3653 (GtkSignalFunc) gtk_sheet_entry_changed,
3654 GTK_OBJECT(GTK_WIDGET(sheet)));
3656 gtk_sheet_hide_active_cell(sheet);
3658 sheet->active_cell.row=-1;
3659 sheet->active_cell.col=-1;
3661 return TRUE;
3664 static void
3665 gtk_sheet_hide_active_cell(GtkSheet *sheet)
3667 char *text;
3668 gint row,col;
3669 GtkJustification justification;
3670 GtkSheetCellAttr attributes;
3672 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3674 row=sheet->active_cell.row;
3675 col=sheet->active_cell.col;
3677 if(row < 0 || col < 0) return;
3679 if(sheet->freeze_count == 0)
3680 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IS_FROZEN);
3682 text = (gchar *) gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
3684 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3685 justification=attributes.justification;
3687 if(text && strlen(text)!=0){
3688 gtk_sheet_set_cell(sheet, row, col, justification, text);
3689 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[SET_CELL], row, col);
3691 else
3693 gtk_sheet_cell_clear(sheet, row, col);
3696 row=sheet->active_cell.row;
3697 col=sheet->active_cell.col;
3699 column_button_release(sheet, col);
3700 row_button_release(sheet, row);
3702 if(sheet->sheet_entry_window)
3703 gdk_window_hide(sheet->sheet_entry_window);
3704 else
3705 gdk_window_hide(sheet->sheet_entry->window);
3707 if(row != -1 && col != -1)
3708 gdk_draw_pixmap(sheet->sheet_window,
3709 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3710 sheet->pixmap,
3711 COLUMN_LEFT_XPIXEL(sheet,col)-1,
3712 ROW_TOP_YPIXEL(sheet,row)-1,
3713 COLUMN_LEFT_XPIXEL(sheet,col)-1,
3714 ROW_TOP_YPIXEL(sheet,row)-1,
3715 sheet->column[col].width+4,
3716 sheet->row[row].height+4);
3718 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
3719 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
3720 gtk_widget_grab_focus(GTK_WIDGET(sheet));
3722 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
3726 static gboolean
3727 gtk_sheet_activate_cell(GtkSheet *sheet, gint row, gint col)
3729 gboolean veto = TRUE;
3731 g_return_val_if_fail (sheet != NULL, FALSE);
3732 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
3734 if(row < 0 || col < 0) return FALSE;
3735 if(row > sheet->maxrow || col > sheet->maxcol) return FALSE;
3737 /* gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
3738 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return veto;
3741 if(!veto) return FALSE;
3742 if(sheet->state != GTK_SHEET_NORMAL){
3743 sheet->state=GTK_SHEET_NORMAL;
3744 gtk_sheet_real_unselect_range(sheet, NULL);
3747 sheet->range.row0=row;
3748 sheet->range.col0=col;
3749 sheet->range.rowi=row;
3750 sheet->range.coli=col;
3751 sheet->active_cell.row=row;
3752 sheet->active_cell.col=col;
3753 sheet->selection_cell.row=row;
3754 sheet->selection_cell.col=col;
3755 row_button_set(sheet, row);
3756 column_button_set(sheet, col);
3758 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
3759 gtk_sheet_show_active_cell(sheet);
3761 gtk_signal_connect(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
3762 "changed",
3763 (GtkSignalFunc)gtk_sheet_entry_changed,
3764 GTK_OBJECT(GTK_WIDGET(sheet)));
3766 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[ACTIVATE], row, col, &veto);
3768 return TRUE;
3771 static void
3772 gtk_sheet_show_active_cell(GtkSheet *sheet)
3774 GtkSheetCell *cell;
3775 GtkEntry *sheet_entry;
3776 GtkSheetCellAttr attributes;
3777 gchar *text = NULL;
3778 GtkJustification justification;
3779 gint row, col;
3781 g_return_if_fail (sheet != NULL);
3782 g_return_if_fail (GTK_IS_SHEET (sheet));
3784 row = sheet->active_cell.row;
3785 col = sheet->active_cell.col;
3787 /* Don't show the active cell, if there is no active cell: */
3788 if(!(row >= 0 && col >= 0)) /* e.g row or coll == -1. */
3789 return;
3791 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3792 if(sheet->state != GTK_SHEET_NORMAL) return;
3793 if(GTK_SHEET_IN_SELECTION(sheet)) return;
3795 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet->sheet_entry), GTK_VISIBLE);
3797 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
3799 gtk_sheet_get_attributes(sheet, row, col, &attributes);
3801 justification = GTK_JUSTIFY_LEFT;
3803 if(GTK_SHEET_JUSTIFY_ENTRY(sheet))
3804 justification = attributes.justification;
3806 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol) {
3807 if(sheet->data[row]) {
3808 if(sheet->data[row][col]) {
3809 cell = sheet->data[row][col];
3810 if(cell->text)
3811 text = g_strdup(cell->text);
3816 if(!text) text = (gchar *) g_strdup("");
3818 if(!GTK_IS_ITEM_ENTRY(sheet_entry))
3819 gtk_entry_set_text(GTK_ENTRY(sheet_entry), text);
3820 else
3821 gtk_item_entry_set_text(GTK_ITEM_ENTRY(sheet_entry), (const gchar *) text, justification);
3823 if(GTK_SHEET_IS_LOCKED(sheet) || !attributes.is_editable)
3824 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), FALSE);
3825 else
3826 gtk_entry_set_editable(GTK_ENTRY(sheet_entry), TRUE);
3828 gtk_entry_set_visibility(GTK_ENTRY(sheet_entry), attributes.is_visible);
3830 gtk_sheet_entry_set_max_size(sheet);
3831 gtk_sheet_size_allocate_entry(sheet);
3833 if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
3834 if(sheet->sheet_entry_window)
3835 gdk_window_show(sheet->sheet_entry_window);
3836 else
3837 gdk_window_show(sheet->sheet_entry->window);
3838 gtk_widget_queue_draw(sheet->sheet_entry);
3840 gtk_sheet_draw_active_cell(sheet);
3842 gtk_widget_grab_focus(GTK_WIDGET(sheet_entry));
3843 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(sheet_entry), GTK_HAS_FOCUS);
3844 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(sheet), GTK_HAS_FOCUS);
3846 g_free(text);
3849 static void
3850 gtk_sheet_draw_active_cell(GtkSheet *sheet)
3852 gint row, col;
3854 if(!GTK_WIDGET_DRAWABLE(GTK_WIDGET(sheet))) return;
3855 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3857 row = sheet->active_cell.row;
3858 col = sheet->active_cell.col;
3860 if(row<0 || col<0) return;
3862 if(!gtk_sheet_cell_isvisible(sheet, row, col)) return;
3864 row_button_set(sheet, row);
3865 column_button_set(sheet, col);
3867 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
3868 gtk_sheet_draw_border(sheet, sheet->range);
3873 static void
3874 gtk_sheet_make_backing_pixmap (GtkSheet *sheet, guint width, guint height)
3876 gint pixmap_width, pixmap_height;
3878 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
3880 if(width == 0 && height == 0){
3881 width=sheet->sheet_window_width+80;
3882 height=sheet->sheet_window_height+80;
3885 if (!sheet->pixmap)
3887 /* allocate */
3888 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
3889 width, height,
3890 -1);
3891 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
3893 else
3895 /* reallocate if sizes don't match */
3896 gdk_window_get_size (sheet->pixmap,
3897 &pixmap_width, &pixmap_height);
3898 if ((pixmap_width != width) || (pixmap_height != height))
3900 g_free(sheet->pixmap);
3901 sheet->pixmap = gdk_pixmap_new (sheet->sheet_window,
3902 width, height,
3903 -1);
3904 if(!GTK_SHEET_IS_FROZEN(sheet)) gtk_sheet_range_draw(sheet, NULL);
3909 static void
3910 gtk_sheet_new_selection(GtkSheet *sheet, GtkSheetRange *range)
3912 gint i,j, mask1, mask2;
3913 gint state, selected;
3914 gint x,y,width,height;
3915 GtkSheetRange new_range, aux_range;
3917 g_return_if_fail (sheet != NULL);
3919 if(range==NULL) range=&sheet->range;
3921 new_range=*range;
3923 range->row0=MIN(range->row0, sheet->range.row0);
3924 range->rowi=MAX(range->rowi, sheet->range.rowi);
3925 range->col0=MIN(range->col0, sheet->range.col0);
3926 range->coli=MAX(range->coli, sheet->range.coli);
3928 range->row0=MAX(range->row0, MIN_VISIBLE_ROW(sheet));
3929 range->rowi=MIN(range->rowi, MAX_VISIBLE_ROW(sheet));
3930 range->col0=MAX(range->col0, MIN_VISIBLE_COLUMN(sheet));
3931 range->coli=MIN(range->coli, MAX_VISIBLE_COLUMN(sheet));
3933 aux_range.row0=MAX(new_range.row0, MIN_VISIBLE_ROW(sheet));
3934 aux_range.rowi=MIN(new_range.rowi, MAX_VISIBLE_ROW(sheet));
3935 aux_range.col0=MAX(new_range.col0, MIN_VISIBLE_COLUMN(sheet));
3936 aux_range.coli=MIN(new_range.coli, MAX_VISIBLE_COLUMN(sheet));
3938 for(i=range->row0; i<=range->rowi; i++){
3939 for(j=range->col0; j<=range->coli; j++){
3941 state=gtk_sheet_cell_get_state(sheet, i, j);
3942 selected=(i<=new_range.rowi && i>=new_range.row0 &&
3943 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
3945 if(state==GTK_STATE_SELECTED && selected &&
3946 sheet->column[j].is_visible && sheet->row[i].is_visible &&
3947 (i==sheet->range.row0 || i==sheet->range.rowi ||
3948 j==sheet->range.col0 || j==sheet->range.coli ||
3949 i==new_range.row0 || i==new_range.rowi ||
3950 j==new_range.col0 || j==new_range.coli)){
3952 mask1 = i==sheet->range.row0 ? 1 : 0;
3953 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
3954 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
3955 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
3957 mask2 = i==new_range.row0 ? 1 : 0;
3958 mask2 = i==new_range.rowi ? mask2+2 : mask2;
3959 mask2 = j==new_range.col0 ? mask2+4 : mask2;
3960 mask2 = j==new_range.coli ? mask2+8 : mask2;
3962 if(mask1 != mask2){
3963 x=COLUMN_LEFT_XPIXEL(sheet,j);
3964 y=ROW_TOP_YPIXEL(sheet, i);
3965 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
3966 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
3968 if(i==sheet->range.row0){
3969 y=y-3;
3970 height=height+3;
3972 if(i==sheet->range.rowi) height=height+3;
3973 if(j==sheet->range.col0){
3974 x=x-3;
3975 width=width+3;
3977 if(j==sheet->range.coli) width=width+3;
3979 gdk_draw_pixmap(sheet->sheet_window,
3980 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
3981 sheet->pixmap,
3982 x+1,
3983 y+1,
3984 x+1,
3985 y+1,
3986 width,
3987 height);
3989 if(i != sheet->active_cell.row || j != sheet->active_cell.col){
3990 x=COLUMN_LEFT_XPIXEL(sheet,j);
3991 y=ROW_TOP_YPIXEL(sheet, i);
3992 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
3993 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
3995 if(i==new_range.row0){
3996 y=y+2;
3997 height=height-2;
3999 if(i==new_range.rowi) height=height-3;
4000 if(j==new_range.col0){
4001 x=x+2;
4002 width=width-2;
4004 if(j==new_range.coli) width=width-3;
4006 gdk_draw_rectangle (sheet->sheet_window,
4007 sheet->xor_gc,
4008 TRUE,
4009 x+1,y+1,
4010 width,height);
4017 for(i=range->row0; i<=range->rowi; i++){
4018 for(j=range->col0; j<=range->coli; j++){
4020 state=gtk_sheet_cell_get_state(sheet, i, j);
4021 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4022 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4024 if(state==GTK_STATE_SELECTED && !selected &&
4025 sheet->column[j].is_visible && sheet->row[i].is_visible){
4027 x=COLUMN_LEFT_XPIXEL(sheet,j);
4028 y=ROW_TOP_YPIXEL(sheet, i);
4029 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4030 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4032 if(i==sheet->range.row0){
4033 y=y-3;
4034 height=height+3;
4036 if(i==sheet->range.rowi) height=height+3;
4037 if(j==sheet->range.col0){
4038 x=x-3;
4039 width=width+3;
4041 if(j==sheet->range.coli) width=width+3;
4043 gdk_draw_pixmap(sheet->sheet_window,
4044 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4045 sheet->pixmap,
4046 x+1,
4047 y+1,
4048 x+1,
4049 y+1,
4050 width,
4051 height);
4056 for(i=range->row0; i<=range->rowi; i++){
4057 for(j=range->col0; j<=range->coli; j++){
4059 state=gtk_sheet_cell_get_state(sheet, i, j);
4060 selected=(i<=new_range.rowi && i>=new_range.row0 &&
4061 j<=new_range.coli && j>=new_range.col0) ? TRUE : FALSE;
4063 if(state!=GTK_STATE_SELECTED && selected &&
4064 sheet->column[j].is_visible && sheet->row[i].is_visible &&
4065 (i != sheet->active_cell.row || j != sheet->active_cell.col)){
4067 x=COLUMN_LEFT_XPIXEL(sheet,j);
4068 y=ROW_TOP_YPIXEL(sheet, i);
4069 width=COLUMN_LEFT_XPIXEL(sheet, j)-x+sheet->column[j].width;
4070 height=ROW_TOP_YPIXEL(sheet, i)-y+sheet->row[i].height;
4072 if(i==new_range.row0){
4073 y=y+2;
4074 height=height-2;
4076 if(i==new_range.rowi) height=height-3;
4077 if(j==new_range.col0){
4078 x=x+2;
4079 width=width-2;
4081 if(j==new_range.coli) width=width-3;
4083 gdk_draw_rectangle (sheet->sheet_window,
4084 sheet->xor_gc,
4085 TRUE,
4086 x+1,y+1,
4087 width,height);
4094 for(i=aux_range.row0; i<=aux_range.rowi; i++){
4095 for(j=aux_range.col0; j<=aux_range.coli; j++){
4097 if(sheet->column[j].is_visible && sheet->row[i].is_visible){
4099 state=gtk_sheet_cell_get_state(sheet, i, j);
4101 mask1 = i==sheet->range.row0 ? 1 : 0;
4102 mask1 = i==sheet->range.rowi ? mask1+2 : mask1;
4103 mask1 = j==sheet->range.col0 ? mask1+4 : mask1;
4104 mask1 = j==sheet->range.coli ? mask1+8 : mask1;
4106 mask2 = i==new_range.row0 ? 1 : 0;
4107 mask2 = i==new_range.rowi ? mask2+2 : mask2;
4108 mask2 = j==new_range.col0 ? mask2+4 : mask2;
4109 mask2 = j==new_range.coli ? mask2+8 : mask2;
4110 if(mask2!=mask1 || (mask2==mask1 && state!=GTK_STATE_SELECTED)){
4111 x=COLUMN_LEFT_XPIXEL(sheet,j);
4112 y=ROW_TOP_YPIXEL(sheet, i);
4113 width=sheet->column[j].width;
4114 height=sheet->row[i].height;
4115 if(mask2 & 1)
4116 gdk_draw_rectangle (sheet->sheet_window,
4117 sheet->xor_gc,
4118 TRUE,
4119 x+1,y-1,
4120 width,3);
4123 if(mask2 & 2)
4124 gdk_draw_rectangle (sheet->sheet_window,
4125 sheet->xor_gc,
4126 TRUE,
4127 x+1,y+height-1,
4128 width,3);
4130 if(mask2 & 4)
4131 gdk_draw_rectangle (sheet->sheet_window,
4132 sheet->xor_gc,
4133 TRUE,
4134 x-1,y+1,
4135 3,height);
4138 if(mask2 & 8)
4139 gdk_draw_rectangle (sheet->sheet_window,
4140 sheet->xor_gc,
4141 TRUE,
4142 x+width-1,y+1,
4143 3,height);
4155 *range=new_range;
4156 gtk_sheet_draw_corners(sheet, new_range);
4160 static void
4161 gtk_sheet_draw_border (GtkSheet *sheet, GtkSheetRange new_range)
4163 GtkWidget *widget;
4164 GdkRectangle area;
4165 gint i;
4166 gint x,y,width,height;
4168 widget = GTK_WIDGET(sheet);
4170 x=COLUMN_LEFT_XPIXEL(sheet,new_range.col0);
4171 y=ROW_TOP_YPIXEL(sheet,new_range.row0);
4172 width=COLUMN_LEFT_XPIXEL(sheet,new_range.coli)-x+
4173 sheet->column[new_range.coli].width;
4174 height=ROW_TOP_YPIXEL(sheet,new_range.rowi)-y+
4175 sheet->row[new_range.rowi].height;
4177 area.x=COLUMN_LEFT_XPIXEL(sheet, MIN_VISIBLE_COLUMN(sheet));
4178 area.y=ROW_TOP_YPIXEL(sheet, MIN_VISIBLE_ROW(sheet));
4179 area.width=sheet->sheet_window_width;
4180 area.height=sheet->sheet_window_height;
4182 if(x<0) {
4183 width=width+x;
4184 x=0;
4186 if(width>area.width) width=area.width+10;
4187 if(y<0) {
4188 height=height+y;
4189 y=0;
4191 if(height>area.height) height=area.height+10;
4193 gdk_gc_set_clip_rectangle(sheet->xor_gc, &area);
4195 for(i=-1; i<=1; i++)
4196 gdk_draw_rectangle (sheet->sheet_window,
4197 sheet->xor_gc,
4198 FALSE,
4199 x+i,y+i,
4200 width-2*i,height-2*i);
4202 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
4204 gtk_sheet_draw_corners(sheet, new_range);
4208 static void
4209 gtk_sheet_draw_corners(GtkSheet *sheet, GtkSheetRange range)
4211 gint x,y;
4212 guint width = 1;
4214 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.col0)){
4215 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4216 y=ROW_TOP_YPIXEL(sheet,range.row0);
4217 gdk_draw_pixmap(sheet->sheet_window,
4218 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4219 sheet->pixmap,
4220 x-1,
4221 y-1,
4222 x-1,
4223 y-1,
4225 3);
4226 gdk_draw_rectangle (sheet->sheet_window,
4227 sheet->xor_gc,
4228 TRUE,
4229 x-1,y-1,
4230 3,3);
4233 if(gtk_sheet_cell_isvisible(sheet, range.row0, range.coli) ||
4234 sheet->state == GTK_SHEET_COLUMN_SELECTED){
4235 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4236 sheet->column[range.coli].width;
4237 y=ROW_TOP_YPIXEL(sheet,range.row0);
4238 width = 1;
4239 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
4241 y = ROW_TOP_YPIXEL(sheet, sheet->view.row0)+3;
4242 width = 3;
4244 gdk_draw_pixmap(sheet->sheet_window,
4245 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4246 sheet->pixmap,
4247 x-width,
4248 y-width,
4249 x-width,
4250 y-width,
4251 2*width+1,
4252 2*width+1);
4253 gdk_draw_rectangle (sheet->sheet_window,
4254 sheet->xor_gc,
4255 TRUE,
4256 x-width+width/2,y-width+width/2,
4257 2+width,2+width);
4260 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.col0) ||
4261 sheet->state == GTK_SHEET_ROW_SELECTED){
4262 x=COLUMN_LEFT_XPIXEL(sheet,range.col0);
4263 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4264 sheet->row[range.rowi].height;
4265 width = 1;
4266 if(sheet->state == GTK_SHEET_ROW_SELECTED)
4268 x = COLUMN_LEFT_XPIXEL(sheet, sheet->view.col0)+3;
4269 width = 3;
4271 gdk_draw_pixmap(sheet->sheet_window,
4272 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4273 sheet->pixmap,
4274 x-width,
4275 y-width,
4276 x-width,
4277 y-width,
4278 2*width+1,
4279 2*width+1);
4280 gdk_draw_rectangle (sheet->sheet_window,
4281 sheet->xor_gc,
4282 TRUE,
4283 x-width+width/2,y-width+width/2,
4284 2+width,2+width);
4287 if(gtk_sheet_cell_isvisible(sheet, range.rowi, range.coli)){
4288 x=COLUMN_LEFT_XPIXEL(sheet,range.coli)+
4289 sheet->column[range.coli].width;
4290 y=ROW_TOP_YPIXEL(sheet,range.rowi)+
4291 sheet->row[range.rowi].height;
4292 width = 1;
4293 if(sheet->state == GTK_SHEET_RANGE_SELECTED) width = 3;
4294 if(sheet->state == GTK_SHEET_NORMAL) width = 3;
4295 gdk_draw_pixmap(sheet->sheet_window,
4296 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
4297 sheet->pixmap,
4298 x-width,
4299 y-width,
4300 x-width,
4301 y-width,
4302 2*width+1,
4303 2*width+1);
4304 gdk_draw_rectangle (sheet->sheet_window,
4305 sheet->xor_gc,
4306 TRUE,
4307 x-width+width/2,y-width+width/2,
4308 2+width,2+width);
4315 static void
4316 gtk_sheet_real_select_range (GtkSheet * sheet,
4317 GtkSheetRange * range)
4319 gint i;
4320 gint state;
4322 g_return_if_fail (sheet != NULL);
4324 if(range==NULL) range=&sheet->range;
4326 if(range->row0 < 0 || range->rowi < 0) return;
4327 if(range->col0 < 0 || range->coli < 0) return;
4329 state=sheet->state;
4331 if(state==GTK_SHEET_COLUMN_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4332 for(i=sheet->range.col0; i< range->col0; i++)
4333 column_button_release(sheet, i);
4334 for(i=range->coli+1; i<= sheet->range.coli; i++)
4335 column_button_release(sheet, i);
4336 for(i=range->col0; i<=range->coli; i++){
4337 column_button_set(sheet, i);
4341 if(state==GTK_SHEET_ROW_SELECTED || state==GTK_SHEET_RANGE_SELECTED){
4342 for(i=sheet->range.row0; i< range->row0; i++)
4343 row_button_release(sheet, i);
4344 for(i=range->rowi+1; i<= sheet->range.rowi; i++)
4345 row_button_release(sheet, i);
4346 for(i=range->row0; i<=range->rowi; i++){
4347 row_button_set(sheet, i);
4351 if(range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
4352 range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
4355 gtk_sheet_new_selection(sheet, range);
4357 sheet->range.col0=range->col0;
4358 sheet->range.coli=range->coli;
4359 sheet->range.row0=range->row0;
4360 sheet->range.rowi=range->rowi;
4363 else
4365 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4366 gtk_sheet_range_draw_selection(sheet, sheet->range);
4369 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[SELECT_RANGE], range);
4372 void
4373 gtk_sheet_select_range(GtkSheet * sheet, const GtkSheetRange *range)
4375 g_return_if_fail (sheet != NULL);
4377 if(range==NULL) range=&sheet->range;
4379 if(range->row0 < 0 || range->rowi < 0) return;
4380 if(range->col0 < 0 || range->coli < 0) return;
4382 if(sheet->state != GTK_SHEET_NORMAL)
4383 gtk_sheet_real_unselect_range(sheet, NULL);
4384 else
4386 gboolean veto;
4387 veto = gtk_sheet_deactivate_cell(sheet);
4388 if(!veto) return;
4391 sheet->range.row0=range->row0;
4392 sheet->range.rowi=range->rowi;
4393 sheet->range.col0=range->col0;
4394 sheet->range.coli=range->coli;
4395 sheet->active_cell.row=range->row0;
4396 sheet->active_cell.col=range->col0;
4397 sheet->selection_cell.row=range->rowi;
4398 sheet->selection_cell.col=range->coli;
4400 sheet->state = GTK_SHEET_RANGE_SELECTED;
4401 gtk_sheet_real_select_range(sheet, NULL);
4405 void
4406 gtk_sheet_unselect_range (GtkSheet * sheet)
4408 gtk_sheet_real_unselect_range(sheet, NULL);
4409 sheet->state = GTK_STATE_NORMAL;
4410 gtk_sheet_activate_cell(sheet, sheet->active_cell.row, sheet->active_cell.col);
4414 static void
4415 gtk_sheet_real_unselect_range (GtkSheet * sheet,
4416 const GtkSheetRange *range)
4418 gint i;
4420 g_return_if_fail (sheet != NULL);
4421 g_return_if_fail (GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)));
4423 if(range==NULL){
4424 range=&sheet->range;
4427 if(range->row0 < 0 || range->rowi < 0) return;
4428 if(range->col0 < 0 || range->coli < 0) return;
4430 if (gtk_sheet_range_isvisible (sheet, *range)){
4431 gtk_sheet_draw_backing_pixmap(sheet, *range);
4434 for(i=range->col0; i<=range->coli; i++){
4435 column_button_release(sheet, i);
4438 for(i=range->row0; i<=range->rowi; i++){
4439 row_button_release(sheet, i);
4445 static void
4446 gtk_sheet_draw (GtkWidget * widget,
4447 GdkRectangle * area)
4449 GtkSheet *sheet;
4450 GtkSheetRange range;
4451 GtkSheetChild *child;
4452 GdkRectangle child_area;
4453 GList *children;
4455 g_return_if_fail (widget != NULL);
4456 g_return_if_fail (GTK_IS_SHEET (widget));
4457 g_return_if_fail (area != NULL);
4459 if (GTK_WIDGET_DRAWABLE (widget))
4461 sheet = GTK_SHEET (widget);
4463 range.row0=ROW_FROM_YPIXEL(sheet, area->y);
4464 range.rowi=ROW_FROM_YPIXEL(sheet, area->y+area->height);
4465 range.col0=COLUMN_FROM_XPIXEL(sheet, area->x);
4466 range.coli=COLUMN_FROM_XPIXEL(sheet, area->x+area->width);
4468 gtk_sheet_range_draw (sheet, &range);
4470 if(sheet->state != GTK_SHEET_NORMAL && gtk_sheet_range_isvisible(sheet, sheet->range)){
4471 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4472 gtk_sheet_range_draw_selection(sheet, sheet->range);
4475 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
4476 gdk_window_show(sheet->row_title_window);
4478 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
4479 gdk_window_show(sheet->column_title_window);
4481 children = sheet->children;
4482 while (children)
4484 child = children->data;
4485 children = children->next;
4487 if (gtk_widget_intersect (child->widget, area, &child_area))
4488 gtk_widget_draw (child->widget, &child_area);
4491 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)
4492 && GTK_SHEET_COL_TITLES_VISIBLE(sheet))
4493 gtk_widget_draw(sheet->button, NULL);
4500 static gint
4501 gtk_sheet_expose (GtkWidget * widget,
4502 GdkEventExpose * event)
4504 GtkSheet *sheet;
4505 GtkSheetRange range;
4506 GtkSheetChild *child;
4507 GList *children;
4508 GdkEventExpose child_event;
4510 g_return_val_if_fail (widget != NULL, FALSE);
4511 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4512 g_return_val_if_fail (event != NULL, FALSE);
4514 sheet = GTK_SHEET (widget);
4516 if (GTK_WIDGET_DRAWABLE (widget))
4518 range.row0=ROW_FROM_YPIXEL(sheet,event->area.y);
4519 range.col0=COLUMN_FROM_XPIXEL(sheet,event->area.x);
4520 range.rowi=ROW_FROM_YPIXEL(sheet,event->area.y+event->area.height);
4521 range.coli=COLUMN_FROM_XPIXEL(sheet,event->area.x+event->area.width);
4523 /* exposure events on the sheet */
4525 if(event->window == sheet->row_title_window){
4526 size_allocate_row_title_buttons(sheet);
4527 gdk_window_show(sheet->row_title_window);
4530 if(event->window == sheet->column_title_window){
4531 size_allocate_column_title_buttons(sheet);
4532 gdk_window_show(sheet->column_title_window);
4535 if (event->window == sheet->sheet_window){
4536 gtk_sheet_draw_backing_pixmap(sheet, range);
4538 if(sheet->state != GTK_SHEET_NORMAL){
4539 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4540 gtk_sheet_draw_backing_pixmap(sheet, sheet->range);
4541 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4542 gtk_sheet_draw_backing_pixmap(sheet, sheet->drag_range);
4544 if(gtk_sheet_range_isvisible(sheet, sheet->range))
4545 gtk_sheet_range_draw_selection(sheet, sheet->range);
4546 if(GTK_SHEET_IN_RESIZE(sheet) || GTK_SHEET_IN_DRAG(sheet))
4547 draw_xor_rectangle(sheet, sheet->drag_range);
4550 if((!GTK_SHEET_IN_XDRAG(sheet)) && (!GTK_SHEET_IN_YDRAG(sheet))){
4551 if(sheet->state == GTK_SHEET_NORMAL){
4552 gtk_sheet_draw_active_cell(sheet);
4553 if(!GTK_SHEET_IN_SELECTION(sheet))
4554 gtk_widget_queue_draw(sheet->sheet_entry);
4558 /* sheet children events */
4559 child_event = *event;
4560 children = sheet->children;
4561 while (children)
4563 child = children->data;
4564 children = children->next;
4566 if (GTK_WIDGET_NO_WINDOW (child->widget))
4568 GdkRectangle child_area;
4570 child_area.x = child->x;
4571 child_area.y = child->y;
4572 child_area.width = child->widget->allocation.width;
4573 child_area.height = child->widget->allocation.height;
4574 gdk_rectangle_intersect (&child_area, &event->area, &child_event.area);
4575 child_event.window = event->window;
4576 if(child->window) child_event.window = child->window;
4577 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
4586 if(sheet->state != GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet))
4587 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4589 return FALSE;
4593 static void
4594 gtk_sheet_forall (GtkContainer *container,
4595 gboolean include_internals,
4596 GtkCallback callback,
4597 gpointer callback_data)
4599 GtkSheet *sheet;
4601 sheet = GTK_SHEET(container);
4603 (*callback) (sheet->button, callback_data);
4607 static gint
4608 gtk_sheet_button_press (GtkWidget * widget,
4609 GdkEventButton * event)
4611 GtkSheet *sheet;
4612 GdkModifierType mods;
4613 gint x, y, row, column;
4614 gboolean veto;
4616 g_return_val_if_fail (widget != NULL, FALSE);
4617 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
4618 g_return_val_if_fail (event != NULL, FALSE);
4620 if(event->type != GDK_BUTTON_PRESS) return TRUE;
4621 gdk_window_get_pointer(widget->window, NULL, NULL, &mods);
4622 if(!(mods & GDK_BUTTON1_MASK)) return TRUE;
4624 sheet = GTK_SHEET (widget);
4626 /* press on resize windows */
4627 if (event->window == sheet->column_title_window &&
4628 !GTK_SHEET_COLUMN_FROZEN(sheet))
4630 gtk_widget_get_pointer (widget, &sheet->x_drag, NULL);
4631 if(POSSIBLE_XDRAG(sheet, sheet->x_drag, &sheet->drag_cell.col)){
4633 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4634 gdk_pointer_grab (sheet->column_title_window, FALSE,
4635 GDK_POINTER_MOTION_HINT_MASK |
4636 GDK_BUTTON1_MOTION_MASK |
4637 GDK_BUTTON_RELEASE_MASK,
4638 NULL, NULL, event->time);
4640 draw_xor_vline (sheet);
4641 return TRUE;
4645 if (event->window == sheet->row_title_window && !GTK_SHEET_ROW_FROZEN(sheet))
4647 gtk_widget_get_pointer (widget, NULL, &sheet->y_drag);
4649 if(POSSIBLE_YDRAG(sheet, sheet->y_drag, &sheet->drag_cell.row)){
4650 GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4651 gdk_pointer_grab (sheet->row_title_window, FALSE,
4652 GDK_POINTER_MOTION_HINT_MASK |
4653 GDK_BUTTON1_MOTION_MASK |
4654 GDK_BUTTON_RELEASE_MASK,
4655 NULL, NULL, event->time);
4657 draw_xor_hline (sheet);
4658 return TRUE;
4662 /* selections on the sheet */
4663 if(event->window == sheet->sheet_window){
4664 gtk_widget_get_pointer (widget, &x, &y);
4665 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4666 gdk_pointer_grab (sheet->sheet_window, FALSE,
4667 GDK_POINTER_MOTION_HINT_MASK |
4668 GDK_BUTTON1_MOTION_MASK |
4669 GDK_BUTTON_RELEASE_MASK,
4670 NULL, NULL, event->time);
4671 gtk_grab_add(GTK_WIDGET(sheet));
4672 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, (gpointer) sheet);
4673 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4674 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
4675 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4677 if(sheet->selection_mode != GTK_SELECTION_SINGLE &&
4678 sheet->cursor_drag->type==GDK_SIZING &&
4679 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_RESIZE(sheet)){
4680 if(sheet->state==GTK_STATE_NORMAL) {
4681 row=sheet->active_cell.row;
4682 column=sheet->active_cell.col;
4683 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4684 sheet->active_cell.row=row;
4685 sheet->active_cell.col=column;
4686 sheet->drag_range=sheet->range;
4687 sheet->state=GTK_SHEET_RANGE_SELECTED;
4688 gtk_sheet_select_range(sheet, &sheet->drag_range);
4690 sheet->x_drag=x;
4691 sheet->y_drag=y;
4692 if(row > sheet->range.rowi) row--;
4693 if(column > sheet->range.coli) column--;
4694 sheet->drag_cell.row = row;
4695 sheet->drag_cell.col = column;
4696 sheet->drag_range=sheet->range;
4697 draw_xor_rectangle(sheet, sheet->drag_range);
4698 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4700 else if(sheet->cursor_drag->type==GDK_TOP_LEFT_ARROW &&
4701 !GTK_SHEET_IN_SELECTION(sheet) && !GTK_SHEET_IN_DRAG(sheet)) {
4702 if(sheet->state==GTK_STATE_NORMAL) {
4703 row=sheet->active_cell.row;
4704 column=sheet->active_cell.col;
4705 if(!gtk_sheet_deactivate_cell(sheet)) return FALSE;
4706 sheet->active_cell.row=row;
4707 sheet->active_cell.col=column;
4708 sheet->drag_range=sheet->range;
4709 sheet->state=GTK_SHEET_RANGE_SELECTED;
4710 gtk_sheet_select_range(sheet, &sheet->drag_range);
4712 sheet->x_drag=x;
4713 sheet->y_drag=y;
4714 if(row < sheet->range.row0) row++;
4715 if(row > sheet->range.rowi) row--;
4716 if(column < sheet->range.col0) column++;
4717 if(column > sheet->range.coli) column--;
4718 sheet->drag_cell.row=row;
4719 sheet->drag_cell.col=column;
4720 sheet->drag_range=sheet->range;
4721 draw_xor_rectangle(sheet, sheet->drag_range);
4722 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
4724 else
4726 gtk_sheet_click_cell(sheet, row, column, &veto);
4727 if(veto) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4732 if(event->window == sheet->column_title_window){
4733 gtk_widget_get_pointer (widget, &x, &y);
4734 column = COLUMN_FROM_XPIXEL(sheet, x);
4735 if(sheet->column[column].is_sensitive){;
4736 gtk_sheet_click_cell(sheet, -1, column, &veto);
4737 gtk_grab_add(GTK_WIDGET(sheet));
4738 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, (gpointer) sheet);
4739 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4740 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
4741 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4742 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4746 if(event->window == sheet->row_title_window){
4747 gtk_widget_get_pointer (widget, &x, &y);
4748 row = ROW_FROM_YPIXEL(sheet, y);
4749 if(sheet->row[row].is_sensitive){
4750 gtk_sheet_click_cell(sheet, row, -1, &veto);
4751 gtk_grab_add(GTK_WIDGET(sheet));
4752 sheet->timer=gtk_timeout_add(TIMEOUT_SCROLL, gtk_sheet_scroll, (gpointer) sheet);
4753 GTK_WIDGET_UNSET_FLAGS(sheet->sheet_entry, GTK_HAS_FOCUS);
4754 GTK_WIDGET_SET_FLAGS(GTK_SHEET(sheet), GTK_HAS_FOCUS);
4755 gtk_widget_grab_focus(GTK_WIDGET(sheet));
4756 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4760 return TRUE;
4763 static gint
4764 gtk_sheet_scroll(gpointer data)
4766 GtkSheet *sheet;
4767 gint x,y,row,column;
4768 gint move;
4770 sheet=GTK_SHEET(data);
4772 GDK_THREADS_ENTER();
4774 gtk_widget_get_pointer (GTK_WIDGET(sheet), &x, &y);
4775 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
4777 move=TRUE;
4779 if(GTK_SHEET_IN_SELECTION(sheet))
4780 gtk_sheet_extend_selection(sheet, row, column);
4782 if(GTK_SHEET_IN_DRAG(sheet) || GTK_SHEET_IN_RESIZE(sheet)){
4783 move=gtk_sheet_move_query(sheet, row, column);
4784 if(move) draw_xor_rectangle(sheet, sheet->drag_range);
4787 GDK_THREADS_LEAVE();
4789 return TRUE;
4793 static void
4794 gtk_sheet_click_cell(GtkSheet *sheet, gint row, gint column, gboolean *veto)
4796 *veto = TRUE;
4798 if(row > sheet->maxrow || column > sheet->maxcol){
4799 veto = FALSE;
4800 return;
4803 if(column >= 0 && row >= 0)
4804 if(!sheet->column[column].is_visible || !sheet->row[row].is_visible)
4806 veto = FALSE;
4807 return;
4810 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[TRAVERSE],
4811 sheet->active_cell.row,
4812 sheet->active_cell.col,
4813 &row,
4814 &column,
4815 veto);
4816 if(!*veto){
4817 if(sheet->state == GTK_STATE_NORMAL) return;
4819 row = sheet->active_cell.row;
4820 column = sheet->active_cell.col;
4821 gtk_sheet_activate_cell(sheet, row, column);
4822 return;
4825 if(row == -1 && column >= 0){
4826 if(GTK_SHEET_AUTO_SCROLL(sheet))
4827 gtk_sheet_move_query(sheet, row, column);
4828 gtk_sheet_select_column(sheet, column);
4829 return;
4831 if(column == -1 && row >= 0){
4832 if(GTK_SHEET_AUTO_SCROLL(sheet))
4833 gtk_sheet_move_query(sheet, row, column);
4834 gtk_sheet_select_row(sheet, row);
4835 return;
4838 if(row!=-1 && column !=-1){
4839 if(sheet->state != GTK_SHEET_NORMAL){
4840 sheet->state = GTK_SHEET_NORMAL;
4841 gtk_sheet_real_unselect_range(sheet, NULL);
4843 else
4845 if(!gtk_sheet_deactivate_cell(sheet)){
4846 *veto = FALSE;
4847 return;
4851 if(GTK_SHEET_AUTO_SCROLL(sheet))
4852 gtk_sheet_move_query(sheet, row, column);
4853 sheet->active_cell.row=row;
4854 sheet->active_cell.col=column;
4855 sheet->selection_cell.row=row;
4856 sheet->selection_cell.col=column;
4857 sheet->range.row0=row;
4858 sheet->range.col0=column;
4859 sheet->range.rowi=row;
4860 sheet->range.coli=column;
4861 sheet->state=GTK_SHEET_NORMAL;
4862 GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4863 gtk_sheet_draw_active_cell(sheet);
4864 return;
4867 if(row==-1 && column ==-1){
4868 sheet->state=GTK_SHEET_RANGE_SELECTED;
4869 sheet->range.row0=0;
4870 sheet->range.col0=0;
4871 sheet->range.rowi=sheet->maxrow;
4872 sheet->range.coli=sheet->maxcol;
4873 sheet->active_cell.row=0;
4874 sheet->active_cell.col=0;
4875 gtk_sheet_select_range(sheet, NULL);
4876 return;
4879 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
4880 sheet->active_cell.col);
4883 static gint
4884 gtk_sheet_button_release (GtkWidget * widget,
4885 GdkEventButton * event)
4887 GtkSheet *sheet;
4888 gint x,y;
4890 sheet=GTK_SHEET(widget);
4892 /* release on resize windows */
4893 if (GTK_SHEET_IN_XDRAG (sheet)){
4894 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
4895 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4896 gtk_widget_get_pointer (widget, &x, NULL);
4897 gdk_pointer_ungrab (event->time);
4898 draw_xor_vline (sheet);
4900 gtk_sheet_set_column_width (sheet, sheet->drag_cell.col, new_column_width (sheet, sheet->drag_cell.col, &x));
4901 sheet->old_hadjustment = -1.;
4902 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment), "value_changed");
4903 return TRUE;
4906 if (GTK_SHEET_IN_YDRAG (sheet)){
4907 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_YDRAG);
4908 GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_SELECTION);
4909 gtk_widget_get_pointer (widget, NULL, &y);
4910 gdk_pointer_ungrab (event->time);
4911 draw_xor_hline (sheet);
4913 gtk_sheet_set_row_height (sheet, sheet->drag_cell.row, new_row_height (sheet, sheet->drag_cell.row, &y));
4914 sheet->old_vadjustment = -1.;
4915 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment), "value_changed");
4916 return TRUE;
4920 if (GTK_SHEET_IN_DRAG(sheet)){
4921 GtkSheetRange old_range;
4922 draw_xor_rectangle(sheet, sheet->drag_range);
4923 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_DRAG);
4924 gdk_pointer_ungrab (event->time);
4926 gtk_sheet_real_unselect_range(sheet, NULL);
4928 sheet->active_cell.row = sheet->active_cell.row +
4929 (sheet->drag_range.row0 - sheet->range.row0);
4930 sheet->active_cell.col = sheet->active_cell.col +
4931 (sheet->drag_range.col0 - sheet->range.col0);
4932 sheet->selection_cell.row = sheet->selection_cell.row +
4933 (sheet->drag_range.row0 - sheet->range.row0);
4934 sheet->selection_cell.col = sheet->selection_cell.col +
4935 (sheet->drag_range.col0 - sheet->range.col0);
4936 old_range=sheet->range;
4937 sheet->range=sheet->drag_range;
4938 sheet->drag_range=old_range;
4939 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[MOVE_RANGE],
4940 &sheet->drag_range, &sheet->range);
4941 gtk_sheet_select_range(sheet, &sheet->range);
4944 if (GTK_SHEET_IN_RESIZE(sheet)){
4945 GtkSheetRange old_range;
4946 draw_xor_rectangle(sheet, sheet->drag_range);
4947 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_RESIZE);
4948 gdk_pointer_ungrab (event->time);
4950 gtk_sheet_real_unselect_range(sheet, NULL);
4952 sheet->active_cell.row = sheet->active_cell.row +
4953 (sheet->drag_range.row0 - sheet->range.row0);
4954 sheet->active_cell.col = sheet->active_cell.col +
4955 (sheet->drag_range.col0 - sheet->range.col0);
4956 if(sheet->drag_range.row0 < sheet->range.row0)
4957 sheet->selection_cell.row = sheet->drag_range.row0;
4958 if(sheet->drag_range.rowi >= sheet->range.rowi)
4959 sheet->selection_cell.row = sheet->drag_range.rowi;
4960 if(sheet->drag_range.col0 < sheet->range.col0)
4961 sheet->selection_cell.col = sheet->drag_range.col0;
4962 if(sheet->drag_range.coli >= sheet->range.coli)
4963 sheet->selection_cell.col = sheet->drag_range.coli;
4964 old_range = sheet->range;
4965 sheet->range = sheet->drag_range;
4966 sheet->drag_range = old_range;
4968 if(sheet->state==GTK_STATE_NORMAL) sheet->state=GTK_SHEET_RANGE_SELECTED;
4969 gtk_signal_emit(GTK_OBJECT(sheet),sheet_signals[RESIZE_RANGE],
4970 &sheet->drag_range, &sheet->range);
4971 gtk_sheet_select_range(sheet, &sheet->range);
4974 if(sheet->state == GTK_SHEET_NORMAL && GTK_SHEET_IN_SELECTION(sheet)){
4975 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4976 gdk_pointer_ungrab (event->time);
4977 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
4978 sheet->active_cell.col);
4981 if(GTK_SHEET_IN_SELECTION)
4982 gdk_pointer_ungrab (event->time);
4983 if(sheet->timer)
4984 gtk_timeout_remove(sheet->timer);
4985 gtk_grab_remove(GTK_WIDGET(sheet));
4987 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
4989 return TRUE;
4992 static gint
4993 gtk_sheet_motion (GtkWidget * widget,
4994 GdkEventMotion * event)
4996 GtkSheet *sheet;
4997 GdkModifierType mods;
4998 GdkCursorType new_cursor;
4999 gint x, y, row, column;
5001 g_return_val_if_fail (widget != NULL, FALSE);
5002 g_return_val_if_fail (GTK_IS_SHEET (widget), FALSE);
5003 g_return_val_if_fail (event != NULL, FALSE);
5006 sheet = GTK_SHEET (widget);
5009 /* selections on the sheet */
5010 x = event->x;
5011 y = event->y;
5013 if(event->window == sheet->column_title_window && !GTK_SHEET_COLUMN_FROZEN(sheet)){
5014 gtk_widget_get_pointer(widget, &x, &y);
5015 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_XDRAG(sheet, x, &column)){
5016 new_cursor=GDK_SB_H_DOUBLE_ARROW;
5017 if(new_cursor != sheet->cursor_drag->type){
5018 gdk_cursor_destroy(sheet->cursor_drag);
5019 sheet->cursor_drag=gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
5020 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5022 }else{
5023 new_cursor=GDK_TOP_LEFT_ARROW;
5024 if(!GTK_SHEET_IN_XDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5025 gdk_cursor_destroy(sheet->cursor_drag);
5026 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5027 gdk_window_set_cursor(sheet->column_title_window,sheet->cursor_drag);
5032 if(event->window == sheet->row_title_window && !GTK_SHEET_ROW_FROZEN(sheet)){
5033 gtk_widget_get_pointer(widget, &x, &y);
5034 if(!GTK_SHEET_IN_SELECTION(sheet) && POSSIBLE_YDRAG(sheet,y, &column)){
5035 new_cursor=GDK_SB_V_DOUBLE_ARROW;
5036 if(new_cursor != sheet->cursor_drag->type){
5037 gdk_cursor_destroy(sheet->cursor_drag);
5038 sheet->cursor_drag=gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
5039 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5041 }else{
5042 new_cursor=GDK_TOP_LEFT_ARROW;
5043 if(!GTK_SHEET_IN_YDRAG(sheet) && new_cursor != sheet->cursor_drag->type){
5044 gdk_cursor_destroy(sheet->cursor_drag);
5045 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5046 gdk_window_set_cursor(sheet->row_title_window,sheet->cursor_drag);
5051 new_cursor=GDK_PLUS;
5052 if(!POSSIBLE_DRAG(sheet,x,y,&row,&column) && !GTK_SHEET_IN_DRAG(sheet) &&
5053 !POSSIBLE_RESIZE(sheet,x,y,&row,&column) && !GTK_SHEET_IN_RESIZE(sheet) &&
5054 event->window == sheet->sheet_window &&
5055 new_cursor != sheet->cursor_drag->type){
5056 gdk_cursor_destroy(sheet->cursor_drag);
5057 sheet->cursor_drag=gdk_cursor_new(GDK_PLUS);
5058 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5061 new_cursor=GDK_TOP_LEFT_ARROW;
5062 if(!(POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5063 (POSSIBLE_DRAG(sheet, x,y,&row,&column) || GTK_SHEET_IN_DRAG(sheet)) &&
5064 event->window == sheet->sheet_window &&
5065 new_cursor != sheet->cursor_drag->type){
5066 gdk_cursor_destroy(sheet->cursor_drag);
5067 sheet->cursor_drag=gdk_cursor_new(GDK_TOP_LEFT_ARROW);
5068 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5071 new_cursor=GDK_SIZING;
5072 if(!GTK_SHEET_IN_DRAG(sheet) &&
5073 (POSSIBLE_RESIZE(sheet,x,y,&row,&column) || GTK_SHEET_IN_RESIZE(sheet)) &&
5074 event->window == sheet->sheet_window &&
5075 new_cursor != sheet->cursor_drag->type){
5076 gdk_cursor_destroy(sheet->cursor_drag);
5077 sheet->cursor_drag=gdk_cursor_new(GDK_SIZING);
5078 gdk_window_set_cursor(sheet->sheet_window,sheet->cursor_drag);
5081 gdk_window_get_pointer (widget->window, &x, &y, &mods);
5082 if(!(mods & GDK_BUTTON1_MASK)) return FALSE;
5084 if (GTK_SHEET_IN_XDRAG (sheet)){
5085 if (event->is_hint || event->window != widget->window)
5086 gtk_widget_get_pointer (widget, &x, NULL);
5087 else
5088 x = event->x;
5090 new_column_width (sheet, sheet->drag_cell.col, &x);
5091 if (x != sheet->x_drag)
5093 draw_xor_vline (sheet);
5094 sheet->x_drag = x;
5095 draw_xor_vline (sheet);
5097 return TRUE;
5100 if (GTK_SHEET_IN_YDRAG (sheet)){
5101 if (event->is_hint || event->window != widget->window)
5102 gtk_widget_get_pointer (widget, NULL, &y);
5103 else
5104 y = event->y;
5106 new_row_height (sheet, sheet->drag_cell.row, &y);
5107 if (y != sheet->y_drag)
5109 draw_xor_hline (sheet);
5110 sheet->y_drag = y;
5111 draw_xor_hline (sheet);
5113 return TRUE;
5116 if (GTK_SHEET_IN_DRAG(sheet)){
5117 GtkSheetRange aux;
5118 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5119 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5120 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5121 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5122 sheet->x_drag=x;
5123 sheet->y_drag=y;
5124 aux=sheet->range;
5125 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5126 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5127 aux=sheet->drag_range;
5128 sheet->drag_range.row0=sheet->range.row0+row;
5129 sheet->drag_range.col0=sheet->range.col0+column;
5130 sheet->drag_range.rowi=sheet->range.rowi+row;
5131 sheet->drag_range.coli=sheet->range.coli+column;
5132 if(aux.row0 != sheet->drag_range.row0 ||
5133 aux.col0 != sheet->drag_range.col0){
5134 draw_xor_rectangle (sheet, aux);
5135 draw_xor_rectangle (sheet, sheet->drag_range);
5138 return TRUE;
5141 if (GTK_SHEET_IN_RESIZE(sheet)){
5142 GtkSheetRange aux;
5143 gint v_h;
5144 v_h=1;
5145 if(abs(x-COLUMN_LEFT_XPIXEL(sheet,sheet->drag_cell.col)) >
5146 abs(y-ROW_TOP_YPIXEL(sheet,sheet->drag_cell.row))) v_h=2;
5148 column=COLUMN_FROM_XPIXEL(sheet,x)-sheet->drag_cell.col;
5149 row=ROW_FROM_YPIXEL(sheet,y)-sheet->drag_cell.row;
5150 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) row=0;
5151 if(sheet->state==GTK_SHEET_ROW_SELECTED) column=0;
5152 sheet->x_drag=x;
5153 sheet->y_drag=y;
5154 aux=sheet->range;
5156 if(row < sheet->range.row0 - sheet->range.rowi - 1)
5157 row=row+(sheet->range.rowi-sheet->range.row0 + 1);
5158 else if(row<0) row=0;
5160 if(column < sheet->range.col0 - sheet->range.coli - 1)
5161 column=column+(sheet->range.coli-sheet->range.col0 + 1);
5162 else if(column<0) column=0;
5164 if(v_h==1)
5165 column=0;
5166 else
5167 row=0;
5169 if(aux.row0+row >= 0 && aux.rowi+row <= sheet->maxrow &&
5170 aux.col0+column >= 0 && aux.coli+column <= sheet->maxcol){
5172 aux=sheet->drag_range;
5173 sheet->drag_range=sheet->range;
5175 if(row<0) sheet->drag_range.row0=sheet->range.row0+row;
5176 if(row>0) sheet->drag_range.rowi=sheet->range.rowi+row;
5177 if(column<0) sheet->drag_range.col0=sheet->range.col0+column;
5178 if(column>0) sheet->drag_range.coli=sheet->range.coli+column;
5180 if(aux.row0 != sheet->drag_range.row0 ||
5181 aux.rowi != sheet->drag_range.rowi ||
5182 aux.col0 != sheet->drag_range.col0 ||
5183 aux.coli != sheet->drag_range.coli){
5184 draw_xor_rectangle (sheet, aux);
5185 draw_xor_rectangle (sheet, sheet->drag_range);
5188 return TRUE;
5193 gtk_sheet_get_pixel_info (sheet, x, y, &row, &column);
5195 if(sheet->state==GTK_SHEET_NORMAL && row==sheet->active_cell.row &&
5196 column==sheet->active_cell.col) return TRUE;
5198 if(GTK_SHEET_IN_SELECTION(sheet) && mods&GDK_BUTTON1_MASK)
5199 gtk_sheet_extend_selection(sheet, row, column);
5201 return TRUE;
5204 static gint
5205 gtk_sheet_move_query(GtkSheet *sheet, gint row, gint column)
5207 gint row_move, column_move;
5208 gfloat row_align, col_align;
5209 guint height, width;
5210 gint new_row = row;
5211 gint new_col = column;
5213 row_move=FALSE;
5214 column_move=FALSE;
5215 row_align=-1.;
5216 col_align=-1.;
5218 height = sheet->sheet_window_height;
5219 width = sheet->sheet_window_width;
5221 if(row>=MAX_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5222 row_align = 1.;
5223 new_row = MIN(sheet->maxrow, row + 1);
5224 row_move = TRUE;
5225 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow &&
5226 ROW_TOP_YPIXEL(sheet, sheet->maxrow) +
5227 sheet->row[sheet->maxrow].height < height){
5228 row_move = FALSE;
5229 row_align = -1.;
5232 if(row<MIN_VISIBLE_ROW(sheet) && sheet->state!=GTK_SHEET_COLUMN_SELECTED) {
5233 row_align= 0.;
5234 row_move = TRUE;
5236 if(column>=MAX_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5237 col_align = 1.;
5238 new_col = MIN(sheet->maxcol, column + 1);
5239 column_move = TRUE;
5240 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol &&
5241 COLUMN_LEFT_XPIXEL(sheet, sheet->maxcol) +
5242 sheet->column[sheet->maxcol].width < width){
5243 column_move = FALSE;
5244 col_align = -1.;
5247 if(column<MIN_VISIBLE_COLUMN(sheet) && sheet->state!=GTK_SHEET_ROW_SELECTED) {
5248 col_align = 0.;
5249 column_move = TRUE;
5252 if(row_move || column_move){
5253 gtk_sheet_moveto(sheet, new_row, new_col, row_align, col_align);
5256 return(row_move || column_move);
5259 static void
5260 gtk_sheet_extend_selection(GtkSheet *sheet, gint row, gint column)
5262 GtkSheetRange range;
5263 gint state;
5264 gint r,c;
5266 if(row == sheet->selection_cell.row && column == sheet->selection_cell.col)
5267 return;
5269 if(sheet->selection_mode == GTK_SELECTION_SINGLE) return;
5271 gtk_sheet_move_query(sheet, row, column);
5272 gtk_widget_grab_focus(GTK_WIDGET(sheet));
5274 if(GTK_SHEET_IN_DRAG(sheet)) return;
5276 state=sheet->state;
5278 switch(sheet->state){
5279 case GTK_SHEET_ROW_SELECTED:
5280 column = sheet->maxcol;
5281 break;
5282 case GTK_SHEET_COLUMN_SELECTED:
5283 row = sheet->maxrow;
5284 break;
5285 case GTK_SHEET_NORMAL:
5286 sheet->state=GTK_SHEET_RANGE_SELECTED;
5287 r=sheet->active_cell.row;
5288 c=sheet->active_cell.col;
5289 sheet->range.col0=c;
5290 sheet->range.row0=r;
5291 sheet->range.coli=c;
5292 sheet->range.rowi=r;
5293 gdk_draw_pixmap(sheet->sheet_window,
5294 GTK_WIDGET(sheet)->style->fg_gc[GTK_STATE_NORMAL],
5295 sheet->pixmap,
5296 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5297 ROW_TOP_YPIXEL(sheet,r)-1,
5298 COLUMN_LEFT_XPIXEL(sheet,c)-1,
5299 ROW_TOP_YPIXEL(sheet,r)-1,
5300 sheet->column[c].width+4,
5301 sheet->row[r].height+4);
5302 gtk_sheet_range_draw_selection(sheet, sheet->range);
5303 case GTK_SHEET_RANGE_SELECTED:
5304 sheet->state=GTK_SHEET_RANGE_SELECTED;
5307 sheet->selection_cell.row = row;
5308 sheet->selection_cell.col = column;
5310 range.col0=MIN(column,sheet->active_cell.col);
5311 range.coli=MAX(column,sheet->active_cell.col);
5312 range.row0=MIN(row,sheet->active_cell.row);
5313 range.rowi=MAX(row,sheet->active_cell.row);
5315 if(range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
5316 range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
5317 state==GTK_SHEET_NORMAL)
5318 gtk_sheet_real_select_range(sheet, &range);
5322 static gint
5323 gtk_sheet_entry_key_press(GtkWidget *widget,
5324 GdkEventKey *key)
5326 gboolean focus;
5327 gtk_signal_emit_by_name(GTK_OBJECT(widget), "key_press_event", key, &focus);
5328 return focus;
5331 static gint
5332 gtk_sheet_key_press(GtkWidget *widget,
5333 GdkEventKey *key)
5335 GtkSheet *sheet;
5336 gint row, col;
5337 gint state;
5338 gboolean extend_selection = FALSE;
5339 gboolean force_move = FALSE;
5340 gboolean in_selection = FALSE;
5341 gboolean veto = TRUE;
5342 gint scroll = 1;
5344 sheet = GTK_SHEET(widget);
5346 if(key->state & GDK_CONTROL_MASK || key->keyval==GDK_Control_L ||
5347 key->keyval==GDK_Control_R) return FALSE;
5351 if(key->keyval=='c' || key->keyval == 'C' && sheet->state != GTK_STATE_NORMAL)
5352 gtk_sheet_clip_range(sheet, sheet->range);
5353 if(key->keyval=='x' || key->keyval == 'X')
5354 gtk_sheet_unclip_range(sheet);
5355 return FALSE;
5359 extend_selection = (key->state & GDK_SHIFT_MASK) || key->keyval==GDK_Shift_L
5360 || key->keyval==GDK_Shift_R;
5362 state=sheet->state;
5363 in_selection = GTK_SHEET_IN_SELECTION(sheet);
5364 GTK_SHEET_UNSET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5366 switch(key->keyval){
5367 case GDK_Return: case GDK_KP_Enter:
5368 if(sheet->state == GTK_SHEET_NORMAL &&
5369 !GTK_SHEET_IN_SELECTION(sheet))
5370 gtk_signal_emit_stop_by_name(GTK_OBJECT(gtk_sheet_get_entry(sheet)),
5371 "key_press_event");
5372 row = sheet->active_cell.row;
5373 col = sheet->active_cell.col;
5374 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5375 row = MIN_VISIBLE_ROW(sheet)-1;
5376 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5377 col = MIN_VISIBLE_COLUMN(sheet);
5378 if(row < sheet->maxrow){
5379 row = row + scroll;
5380 while(!sheet->row[row].is_visible && row<sheet->maxrow) row++;
5382 gtk_sheet_click_cell(sheet, row, col, &veto);
5383 extend_selection = FALSE;
5384 break;
5385 case GDK_ISO_Left_Tab:
5386 row = sheet->active_cell.row;
5387 col = sheet->active_cell.col;
5388 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5389 col = MIN_VISIBLE_COLUMN(sheet)-1;
5390 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5391 row = MIN_VISIBLE_ROW(sheet);
5392 if(col > 0){
5393 col = col - scroll;
5394 while(!sheet->column[col].is_visible && col>0) col--;
5395 col=MAX(0, col);
5397 gtk_sheet_click_cell(sheet, row, col, &veto);
5398 extend_selection = FALSE;
5399 break;
5400 case GDK_Tab:
5401 row = sheet->active_cell.row;
5402 col = sheet->active_cell.col;
5403 if(sheet->state == GTK_SHEET_ROW_SELECTED)
5404 col = MIN_VISIBLE_COLUMN(sheet)-1;
5405 if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
5406 row = MIN_VISIBLE_ROW(sheet);
5407 if(col < sheet->maxcol){
5408 col = col + scroll;
5409 while(!sheet->column[col].is_visible && col<sheet->maxcol) col++;
5411 gtk_sheet_click_cell(sheet, row, col, &veto);
5412 extend_selection = FALSE;
5413 break;
5414 /* case GDK_BackSpace:
5415 if(sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0){
5416 if(sheet->active_cell.col > 0){
5417 col = sheet->active_cell.col - scroll;
5418 row = sheet->active_cell.row;
5419 while(!sheet->column[col].is_visible && col > 0) col--;
5422 gtk_sheet_click_cell(sheet, row, col, &veto);
5423 extend_selection = FALSE;
5424 break;
5426 case GDK_Page_Up:
5427 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5428 case GDK_Up:
5429 if(extend_selection){
5430 if(state==GTK_STATE_NORMAL){
5431 row=sheet->active_cell.row;
5432 col=sheet->active_cell.col;
5433 gtk_sheet_click_cell(sheet, row, col, &veto);
5434 if(!veto) break;
5436 if(sheet->selection_cell.row > 0){
5437 row = sheet->selection_cell.row - scroll;
5438 while(!sheet->row[row].is_visible && row > 0) row--;
5439 row = MAX(0, row);
5440 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5442 return TRUE;
5444 col = sheet->active_cell.col;
5445 row = sheet->active_cell.row;
5446 if(state==GTK_SHEET_COLUMN_SELECTED)
5447 row = MIN_VISIBLE_ROW(sheet);
5448 if(state==GTK_SHEET_ROW_SELECTED)
5449 col = MIN_VISIBLE_COLUMN(sheet);
5450 row = row - scroll;
5451 while(!sheet->row[row].is_visible && row > 0) row--;
5452 row = MAX(0,row);
5453 gtk_sheet_click_cell(sheet, row, col, &veto);
5454 extend_selection = FALSE;
5455 break;
5456 case GDK_Page_Down:
5457 scroll=MAX_VISIBLE_ROW(sheet)-MIN_VISIBLE_ROW(sheet)+1;
5458 case GDK_Down:
5459 if(extend_selection){
5460 if(state==GTK_STATE_NORMAL){
5461 row=sheet->active_cell.row;
5462 col=sheet->active_cell.col;
5463 gtk_sheet_click_cell(sheet, row, col, &veto);
5464 if(!veto) break;
5466 if(sheet->selection_cell.row < sheet->maxrow){
5467 row = sheet->selection_cell.row + scroll;
5468 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5469 row = MIN(sheet->maxrow, row);
5470 gtk_sheet_extend_selection(sheet, row, sheet->selection_cell.col);
5472 return TRUE;
5474 col = sheet->active_cell.col;
5475 row = sheet->active_cell.row;
5476 if(sheet->active_cell.row < sheet->maxrow){
5477 if(state==GTK_SHEET_COLUMN_SELECTED)
5478 row = MIN_VISIBLE_ROW(sheet)-1;
5479 if(state==GTK_SHEET_ROW_SELECTED)
5480 col = MIN_VISIBLE_COLUMN(sheet);
5481 row = row + scroll;
5482 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5483 row = MIN(sheet->maxrow, row);
5485 gtk_sheet_click_cell(sheet, row, col, &veto);
5486 extend_selection = FALSE;
5487 break;
5488 case GDK_Right:
5489 if(extend_selection){
5490 if(state==GTK_STATE_NORMAL){
5491 row=sheet->active_cell.row;
5492 col=sheet->active_cell.col;
5493 gtk_sheet_click_cell(sheet, row, col, &veto);
5494 if(!veto) break;
5496 if(sheet->selection_cell.col < sheet->maxcol){
5497 col = sheet->selection_cell.col + 1;
5498 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5499 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5501 return TRUE;
5503 col = sheet->active_cell.col;
5504 row = sheet->active_cell.row;
5505 if(sheet->active_cell.col < sheet->maxcol){
5506 col ++;
5507 if(state==GTK_SHEET_ROW_SELECTED)
5508 col = MIN_VISIBLE_COLUMN(sheet)-1;
5509 if(state==GTK_SHEET_COLUMN_SELECTED)
5510 row = MIN_VISIBLE_ROW(sheet);
5511 while(!sheet->column[col].is_visible && col < sheet->maxcol) col++;
5512 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5513 || force_move) {
5514 gtk_sheet_click_cell(sheet, row, col, &veto);
5516 else
5517 return FALSE;
5519 extend_selection = FALSE;
5520 break;
5521 case GDK_Left:
5522 if(extend_selection){
5523 if(state==GTK_STATE_NORMAL){
5524 row=sheet->active_cell.row;
5525 col=sheet->active_cell.col;
5526 gtk_sheet_click_cell(sheet, row, col, &veto);
5527 if(!veto) break;
5529 if(sheet->selection_cell.col > 0){
5530 col = sheet->selection_cell.col - 1;
5531 while(!sheet->column[col].is_visible && col > 0) col--;
5532 gtk_sheet_extend_selection(sheet, sheet->selection_cell.row, col);
5534 return TRUE;
5536 col = sheet->active_cell.col - 1;
5537 row = sheet->active_cell.row;
5538 if(state==GTK_SHEET_ROW_SELECTED)
5539 col = MIN_VISIBLE_COLUMN(sheet)-1;
5540 if(state==GTK_SHEET_COLUMN_SELECTED)
5541 row = MIN_VISIBLE_ROW(sheet);
5542 while(!sheet->column[col].is_visible && col > 0) col--;
5543 col = MAX(0, col);
5545 if(strlen(gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)))) == 0
5546 || force_move){
5547 gtk_sheet_click_cell(sheet, row, col, &veto);
5549 else
5550 return FALSE;
5551 extend_selection = FALSE;
5552 break;
5553 case GDK_Home:
5554 row=0;
5555 while(!sheet->row[row].is_visible && row < sheet->maxrow) row++;
5556 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5557 extend_selection = FALSE;
5558 break;
5559 case GDK_End:
5560 row=sheet->maxrow;
5561 while(!sheet->row[row].is_visible && row > 0) row--;
5562 gtk_sheet_click_cell(sheet, row, sheet->active_cell.col, &veto);
5563 extend_selection = FALSE;
5564 break;
5565 default:
5566 if(in_selection) GTK_SHEET_SET_FLAGS(sheet, GTK_SHEET_IN_SELECTION);
5567 if(extend_selection) return TRUE;
5568 if(state == GTK_SHEET_ROW_SELECTED)
5569 sheet->active_cell.col=MIN_VISIBLE_COLUMN(sheet);
5570 if(state == GTK_SHEET_COLUMN_SELECTED)
5571 sheet->active_cell.row=MIN_VISIBLE_ROW(sheet);
5572 return FALSE;
5575 if(extend_selection) return TRUE;
5577 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
5578 sheet->active_cell.col);
5580 return TRUE;
5583 static void
5584 gtk_sheet_size_request (GtkWidget * widget,
5585 GtkRequisition * requisition)
5587 GtkSheet *sheet;
5588 GList *children;
5589 GtkSheetChild *child;
5590 GtkRequisition child_requisition;
5592 g_return_if_fail (widget != NULL);
5593 g_return_if_fail (GTK_IS_SHEET (widget));
5594 g_return_if_fail (requisition != NULL);
5596 sheet = GTK_SHEET (widget);
5598 requisition->width = 3*DEFAULT_COLUMN_WIDTH;
5599 requisition->height = 3*DEFAULT_ROW_HEIGHT(widget);
5601 /* compute the size of the column title area */
5602 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5603 requisition->height += sheet->column_title_area.height;
5605 /* compute the size of the row title area */
5606 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5607 requisition->width += sheet->row_title_area.width;
5609 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5610 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5611 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5612 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5614 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5615 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5617 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5618 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5620 children = sheet->children;
5621 while (children)
5623 child = children->data;
5624 children = children->next;
5626 gtk_widget_size_request(child->widget, &child_requisition);
5631 static void
5632 gtk_sheet_size_allocate (GtkWidget * widget,
5633 GtkAllocation * allocation)
5635 GtkSheet *sheet;
5636 GtkAllocation sheet_allocation;
5637 gint border_width;
5639 g_return_if_fail (widget != NULL);
5640 g_return_if_fail (GTK_IS_SHEET (widget));
5641 g_return_if_fail (allocation != NULL);
5643 sheet = GTK_SHEET (widget);
5644 widget->allocation = *allocation;
5645 border_width = GTK_CONTAINER(widget)->border_width;
5647 if (GTK_WIDGET_REALIZED (widget))
5648 gdk_window_move_resize (widget->window,
5649 allocation->x + border_width,
5650 allocation->y + border_width,
5651 allocation->width - 2*border_width,
5652 allocation->height - 2*border_width);
5654 /* use internal allocation structure for all the math
5655 * because it's easier than always subtracting the container
5656 * border width */
5657 sheet->internal_allocation.x = 0;
5658 sheet->internal_allocation.y = 0;
5659 sheet->internal_allocation.width = allocation->width - 2*border_width;
5660 sheet->internal_allocation.height = allocation->height - 2*border_width;
5662 sheet_allocation.x = 0;
5663 sheet_allocation.y = 0;
5664 sheet_allocation.width = allocation->width - 2*border_width;
5665 sheet_allocation.height = allocation->height - 2*border_width;
5667 sheet->sheet_window_width = sheet_allocation.width;
5668 sheet->sheet_window_height = sheet_allocation.height;
5670 if (GTK_WIDGET_REALIZED (widget))
5671 gdk_window_move_resize (sheet->sheet_window,
5672 sheet_allocation.x,
5673 sheet_allocation.y,
5674 sheet_allocation.width,
5675 sheet_allocation.height);
5677 /* position the window which holds the column title buttons */
5678 sheet->column_title_area.x = 0;
5679 sheet->column_title_area.y = 0;
5680 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5681 sheet->column_title_area.x = sheet->row_title_area.width;
5682 sheet->column_title_area.width = sheet_allocation.width -
5683 sheet->column_title_area.x;
5684 if(GTK_WIDGET_REALIZED(widget) && GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5685 gdk_window_move_resize (sheet->column_title_window,
5686 sheet->column_title_area.x,
5687 sheet->column_title_area.y,
5688 sheet->column_title_area.width,
5689 sheet->column_title_area.height);
5691 sheet->sheet_window_width = sheet_allocation.width;
5692 sheet->sheet_window_height = sheet_allocation.height;
5694 /* column button allocation */
5695 size_allocate_column_title_buttons (sheet);
5697 /* position the window which holds the row title buttons */
5698 sheet->row_title_area.x = 0;
5699 sheet->row_title_area.y = 0;
5700 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5701 sheet->row_title_area.y = sheet->column_title_area.height;
5702 sheet->row_title_area.height = sheet_allocation.height -
5703 sheet->row_title_area.y;
5705 if(GTK_WIDGET_REALIZED(widget) && GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5706 gdk_window_move_resize (sheet->row_title_window,
5707 sheet->row_title_area.x,
5708 sheet->row_title_area.y,
5709 sheet->row_title_area.width,
5710 sheet->row_title_area.height);
5713 /* row button allocation */
5714 size_allocate_row_title_buttons (sheet);
5716 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
5717 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
5718 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
5719 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
5721 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5722 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
5724 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5725 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
5727 size_allocate_column_title_buttons(sheet);
5728 size_allocate_row_title_buttons(sheet);
5730 /* re-scale backing pixmap */
5731 gtk_sheet_make_backing_pixmap(sheet, 0, 0);
5732 gtk_sheet_position_children(sheet);
5734 /* set the scrollbars adjustments */
5735 adjust_scrollbars (sheet);
5738 static void
5739 size_allocate_column_title_buttons (GtkSheet * sheet)
5741 gint i;
5742 gint x,width;
5744 if (!GTK_SHEET_COL_TITLES_VISIBLE(sheet)) return;
5745 if (!GTK_WIDGET_REALIZED (sheet))
5746 return;
5748 width = sheet->sheet_window_width;
5749 x = 0;
5751 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
5753 width -= sheet->row_title_area.width;
5754 x = sheet->row_title_area.width;
5757 if(sheet->column_title_area.width != width || sheet->column_title_area.x != x)
5759 sheet->column_title_area.width = width;
5760 sheet->column_title_area.x = x;
5761 gdk_window_move_resize (sheet->column_title_window,
5762 sheet->column_title_area.x,
5763 sheet->column_title_area.y,
5764 sheet->column_title_area.width,
5765 sheet->column_title_area.height);
5769 if(MAX_VISIBLE_COLUMN(sheet) == sheet->maxcol)
5770 gdk_window_clear_area (sheet->column_title_window,
5771 0,0,
5772 sheet->column_title_area.width,
5773 sheet->column_title_area.height);
5775 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
5777 for (i = MIN_VISIBLE_COLUMN(sheet); i <= MAX_VISIBLE_COLUMN(sheet); i++)
5778 gtk_sheet_button_draw(sheet,-1,i);
5781 static void
5782 size_allocate_row_title_buttons (GtkSheet * sheet)
5784 gint i;
5785 gint y, height;
5787 if (!GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) return;
5788 if (!GTK_WIDGET_REALIZED (sheet))
5789 return;
5791 height = sheet->sheet_window_height;
5792 y = 0;
5794 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
5796 height -= sheet->column_title_area.height;
5797 y = sheet->column_title_area.height;
5800 if(sheet->row_title_area.height != height || sheet->row_title_area.y != y){
5801 sheet->row_title_area.y = y;
5802 sheet->row_title_area.height = height;
5803 gdk_window_move_resize (sheet->row_title_window,
5804 sheet->row_title_area.x,
5805 sheet->row_title_area.y,
5806 sheet->row_title_area.width,
5807 sheet->row_title_area.height);
5809 if(MAX_VISIBLE_ROW(sheet) == sheet->maxrow)
5810 gdk_window_clear_area (sheet->row_title_window,
5811 0,0,
5812 sheet->row_title_area.width,
5813 sheet->row_title_area.height);
5815 if(!GTK_WIDGET_DRAWABLE(sheet)) return;
5817 for(i = MIN_VISIBLE_ROW(sheet); i <= MAX_VISIBLE_ROW(sheet); i++)
5818 gtk_sheet_button_draw(sheet,i,-1);
5821 static void
5822 gtk_sheet_recalc_top_ypixels(GtkSheet *sheet, gint row)
5824 gint i, cy;
5826 cy = sheet->column_title_area.height;
5827 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet)) cy = 0;
5828 for(i=0; i<=sheet->maxrow; i++){
5829 sheet->row[i].top_ypixel=cy;
5830 if(sheet->row[i].is_visible) cy+=sheet->row[i].height;
5834 static void
5835 gtk_sheet_recalc_left_xpixels(GtkSheet *sheet, gint column)
5837 gint i, cx;
5839 cx = sheet->row_title_area.width;
5840 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) cx = 0;
5841 for(i=0; i<=sheet->maxcol; i++){
5842 sheet->column[i].left_xpixel=cx;
5843 if(sheet->column[i].is_visible) cx+=sheet->column[i].width;
5850 static void
5851 gtk_sheet_size_allocate_entry(GtkSheet *sheet)
5853 GtkAllocation shentry_allocation;
5854 GtkSheetCellAttr attributes;
5855 GtkEntry *sheet_entry;
5856 GtkStyle *style = NULL, *previous_style = NULL;
5857 gint row, col;
5858 gint size, max_size, text_size, column_width;
5859 const gchar *text; /* Needed for Gtk-2.X */
5862 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
5863 if(!GTK_WIDGET_MAPPED(GTK_WIDGET(sheet))) return;
5865 sheet_entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
5867 gtk_sheet_get_attributes(sheet, sheet->active_cell.row, sheet->active_cell.col, &attributes);
5869 if(GTK_WIDGET_REALIZED(sheet->sheet_entry)){
5871 if(!GTK_WIDGET(sheet_entry)->style)
5872 gtk_widget_ensure_style(GTK_WIDGET(sheet_entry));
5874 previous_style = GTK_WIDGET(sheet_entry)->style;
5876 style = gtk_style_copy(previous_style);
5878 style->bg[GTK_STATE_NORMAL] = attributes.background;
5879 style->fg[GTK_STATE_NORMAL] = attributes.foreground;
5880 style->text[GTK_STATE_NORMAL] = attributes.foreground;
5881 style->bg[GTK_STATE_ACTIVE] = attributes.background;
5882 style->fg[GTK_STATE_ACTIVE] = attributes.foreground;
5883 style->text[GTK_STATE_ACTIVE] = attributes.foreground;
5885 if(style->font != attributes.font) {
5886 gdk_font_unref(style->font);
5887 style->font = attributes.font;
5888 gdk_font_ref(style->font);
5891 /* I'm emulating gtk_widget_size_request to avoid the redraw */
5892 GTK_WIDGET(sheet_entry)->style = style;
5893 gtk_widget_size_request(sheet->sheet_entry, NULL);
5894 GTK_WIDGET(sheet_entry)->style = previous_style;
5896 if(style != previous_style)
5897 gtk_widget_set_style(GTK_WIDGET(sheet_entry), style);
5899 if(GTK_IS_ITEM_ENTRY(sheet_entry)){
5900 gdk_gc_set_foreground(GTK_ITEM_ENTRY(sheet_entry)->fg_gc,
5901 &attributes.foreground);
5902 gdk_gc_set_foreground(GTK_ITEM_ENTRY(sheet_entry)->bg_gc,
5903 &attributes.background);
5906 gdk_window_set_background(GTK_ENTRY(sheet_entry)->text_area,
5907 &attributes.background);
5909 if(sheet->sheet_entry_window)
5910 gdk_window_set_background(sheet->sheet_entry_window,
5911 &attributes.background);
5912 else
5913 gdk_window_set_background(GTK_WIDGET(sheet_entry)->window,
5914 &attributes.background);
5918 if(GTK_IS_ITEM_ENTRY(sheet_entry))
5919 max_size = GTK_ITEM_ENTRY(sheet_entry)->text_max_size;
5920 else
5921 max_size = 0;
5923 text_size=GTK_ENTRY(sheet_entry)->text == NULL ? 0 :
5924 gdk_string_width(attributes.font,
5925 gtk_entry_get_text(GTK_ENTRY(sheet_entry)));
5927 column_width=sheet->column[sheet->active_cell.col].width;
5929 size=MIN(text_size, max_size);
5930 size=MAX(size,column_width);
5932 row=sheet->active_cell.row;
5933 col=sheet->active_cell.col;
5935 shentry_allocation.x=COLUMN_LEFT_XPIXEL(sheet,sheet->active_cell.col);
5936 shentry_allocation.y=ROW_TOP_YPIXEL(sheet,sheet->active_cell.row);
5937 shentry_allocation.width=column_width;
5938 shentry_allocation.height=sheet->row[sheet->active_cell.row].height;
5940 /* SDB says: we may need to edit this for gtk-2 */
5941 if(GTK_IS_ITEM_ENTRY(sheet->sheet_entry) && !GTK_SHEET_CLIP_TEXT(sheet)){
5942 switch(GTK_ITEM_ENTRY(sheet_entry)->justification){
5943 case GTK_JUSTIFY_CENTER:
5944 shentry_allocation.width=size;
5945 shentry_allocation.x=shentry_allocation.x+
5946 column_width/2-size/2;
5947 break;
5948 case GTK_JUSTIFY_RIGHT:
5949 shentry_allocation.x=shentry_allocation.x+shentry_allocation.width-size+1;
5950 shentry_allocation.width=size;
5951 break;
5952 case GTK_JUSTIFY_LEFT:
5953 case GTK_JUSTIFY_FILL:
5954 shentry_allocation.width=size;
5955 break;
5956 } /* switch */
5960 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry)){
5961 shentry_allocation.x += 2;
5962 shentry_allocation.y += 2;
5963 shentry_allocation.width -= MIN(shentry_allocation.width, 3);
5964 shentry_allocation.height -= MIN(shentry_allocation.height, 3);
5967 /* SDB says: We may remove this (or rewrite it) for GTK22 */
5968 if(sheet->sheet_entry_window){
5969 gdk_window_move_resize(sheet->sheet_entry_window,
5970 shentry_allocation.x,
5971 shentry_allocation.y,
5972 shentry_allocation.width,
5973 shentry_allocation.height);
5974 shentry_allocation.x = 0;
5975 shentry_allocation.y = 0;
5976 gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
5977 } else {
5978 gtk_widget_size_allocate(sheet->sheet_entry, &shentry_allocation);
5982 if(previous_style == style) gtk_style_unref(previous_style);
5987 static void
5988 gtk_sheet_entry_set_max_size(GtkSheet *sheet)
5990 gint i;
5991 gint size=0;
5992 gint sizel=0, sizer=0;
5993 gint row,col;
5994 GtkJustification justification;
5996 row=sheet->active_cell.row;
5997 col=sheet->active_cell.col;
5999 if(!GTK_IS_ITEM_ENTRY(sheet->sheet_entry) || GTK_SHEET_CLIP_TEXT(sheet)) return;
6001 justification = GTK_ITEM_ENTRY(sheet->sheet_entry)->justification;
6003 switch(justification){
6004 case GTK_JUSTIFY_FILL:
6005 case GTK_JUSTIFY_LEFT:
6006 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6007 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6008 size+=sheet->column[i].width;
6010 size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
6011 break;
6012 case GTK_JUSTIFY_RIGHT:
6013 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6014 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6015 size+=sheet->column[i].width;
6017 break;
6018 case GTK_JUSTIFY_CENTER:
6019 for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
6020 /* if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6022 sizer+=sheet->column[i].width;
6024 for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
6025 if(gtk_sheet_cell_get_text(sheet, row, i)) break;
6026 sizel+=sheet->column[i].width;
6028 size=2*MIN(sizel, sizer);
6029 break;
6032 if(size!=0) size+=sheet->column[col].width;
6033 GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size=size;
6038 static void
6039 create_sheet_entry(GtkSheet *sheet)
6041 GtkWidget *widget;
6042 GtkWidget *parent;
6043 GtkWidget *entry;
6044 GtkStyle *style;
6045 gint found_entry = FALSE;
6047 widget = GTK_WIDGET(sheet);
6049 style = gtk_style_copy(GTK_WIDGET(sheet)->style);
6051 gtk_widget_push_style(style);
6053 if(sheet->sheet_entry){
6054 if(sheet->sheet_entry_window){
6055 gdk_window_set_user_data(sheet->sheet_entry_window, NULL);
6056 gdk_window_destroy(sheet->sheet_entry_window);
6057 sheet->sheet_entry_window = NULL;
6059 /* avoids warnings */
6060 gtk_widget_ref(sheet->sheet_entry);
6061 gtk_widget_unparent(sheet->sheet_entry);
6062 gtk_widget_destroy(sheet->sheet_entry);
6065 if(sheet->entry_type){
6067 if(!gtk_type_is_a (sheet->entry_type, GTK_TYPE_ENTRY)){
6069 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6071 sheet->sheet_entry = parent;
6073 entry = gtk_sheet_get_entry (sheet);
6074 if(GTK_IS_ENTRY(entry)) found_entry = TRUE;
6076 } else {
6078 parent = GTK_WIDGET(gtk_type_new(sheet->entry_type));
6079 entry = parent;
6080 found_entry = TRUE;
6084 if(!found_entry){
6086 g_warning ("Entry type must be GtkEntry subclass, using default");
6087 entry=GTK_WIDGET(gtk_type_new(GTK_TYPE_ITEM_ENTRY));
6088 sheet->sheet_entry = entry;
6090 } else {
6092 sheet->sheet_entry = parent;
6097 } else {
6099 entry=GTK_WIDGET(gtk_type_new(GTK_TYPE_ITEM_ENTRY));
6100 sheet->sheet_entry = entry;
6104 gtk_widget_size_request(sheet->sheet_entry, NULL);
6106 /* --- SDB says: This doesn't appear in the Gtk-2.X version --- */
6107 if (GTK_WIDGET_REALIZED(sheet) && GTK_WIDGET_NO_WINDOW (sheet->sheet_entry))
6109 GdkWindowAttr attributes;
6110 gint attributes_mask;
6112 attributes.window_type = GDK_WINDOW_CHILD;
6113 attributes.x = 0;
6114 attributes.y = 0;
6115 attributes.width = sheet->sheet_entry->requisition.width;
6116 attributes.height = sheet->sheet_entry->requisition.height;
6117 attributes.wclass = GDK_INPUT_OUTPUT;
6118 attributes.visual = gtk_widget_get_visual (widget);
6119 attributes.colormap = gtk_widget_get_colormap (widget);
6120 attributes.event_mask = GDK_EXPOSURE_MASK;
6122 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6123 sheet->sheet_entry_window = gdk_window_new (sheet->sheet_window,
6124 &attributes, attributes_mask);
6125 gdk_window_set_user_data (sheet->sheet_entry_window, widget);
6127 if (sheet->sheet_entry_window)
6128 gtk_style_set_background (widget->style,
6129 sheet->sheet_entry_window,
6130 GTK_STATE_NORMAL);
6133 if(GTK_WIDGET_REALIZED(sheet))
6135 gtk_widget_set_parent(sheet->sheet_entry, GTK_WIDGET(sheet));
6136 gtk_widget_set_parent_window (sheet->sheet_entry,
6137 sheet->sheet_entry_window ?
6138 sheet->sheet_entry_window :
6139 sheet->sheet_window);
6140 gtk_widget_realize(sheet->sheet_entry);
6143 gtk_signal_connect_object(GTK_OBJECT(entry),"key_press_event",
6144 (GtkSignalFunc) gtk_sheet_entry_key_press,
6145 GTK_OBJECT(sheet));
6147 gtk_widget_show (sheet->sheet_entry);
6151 GtkWidget *
6152 gtk_sheet_get_entry(GtkSheet *sheet)
6154 GtkWidget *parent;
6155 GtkWidget *entry = NULL;
6156 GtkTableChild *table_child;
6157 GtkBoxChild *box_child;
6158 GList *children = NULL;
6160 g_return_val_if_fail (sheet != NULL, NULL);
6161 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6162 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6164 if(GTK_IS_ENTRY(sheet->sheet_entry)) return (sheet->sheet_entry);
6166 parent = GTK_WIDGET(sheet->sheet_entry);
6168 if(GTK_IS_TABLE(parent)) children = GTK_TABLE(parent)->children;
6169 if(GTK_IS_BOX(parent)) children = GTK_BOX(parent)->children;
6171 if(!children) return NULL;
6173 while(children){
6174 if(GTK_IS_TABLE(parent)) {
6175 table_child = children->data;
6176 entry = table_child->widget;
6178 if(GTK_IS_BOX(parent)){
6179 box_child = children->data;
6180 entry = box_child->widget;
6183 if(GTK_IS_ENTRY(entry))
6184 break;
6185 children = children->next;
6189 if(!GTK_IS_ENTRY(entry)) return NULL;
6191 return (entry);
6195 GtkWidget *
6196 gtk_sheet_get_entry_widget(GtkSheet *sheet)
6198 g_return_val_if_fail (sheet != NULL, NULL);
6199 g_return_val_if_fail (GTK_IS_SHEET (sheet), NULL);
6200 g_return_val_if_fail (sheet->sheet_entry != NULL, NULL);
6202 return (sheet->sheet_entry);
6205 /* BUTTONS */
6206 static void
6207 row_button_set (GtkSheet *sheet, gint row)
6209 if(sheet->row[row].button.state == GTK_STATE_ACTIVE) return;
6211 sheet->row[row].button.state = GTK_STATE_ACTIVE;
6212 gtk_sheet_button_draw(sheet, row, -1);
6216 static void
6217 column_button_set (GtkSheet *sheet, gint column)
6219 if(sheet->column[column].button.state == GTK_STATE_ACTIVE) return;
6221 sheet->column[column].button.state = GTK_STATE_ACTIVE;
6222 gtk_sheet_button_draw(sheet, -1, column);
6226 static void
6227 row_button_release (GtkSheet *sheet, gint row)
6229 if(sheet->row[row].button.state == GTK_STATE_NORMAL) return;
6231 sheet->row[row].button.state = GTK_STATE_NORMAL;
6232 gtk_sheet_button_draw(sheet, row, -1);
6235 static void
6236 column_button_release (GtkSheet *sheet, gint column)
6238 if(sheet->column[column].button.state == GTK_STATE_NORMAL) return;
6240 sheet->column[column].button.state = GTK_STATE_NORMAL;
6241 gtk_sheet_button_draw(sheet, -1, column);
6244 static void
6245 gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
6247 GdkWindow *window = NULL;
6248 GtkShadowType shadow_type;
6249 guint width = 0, height = 0;
6250 gint x = 0, y = 0;
6251 gint index = 0;
6252 gint text_width = 0, text_height = 0;
6253 GtkSheetButton *button = NULL;
6254 GtkSheetChild *child = NULL;
6255 GdkRectangle allocation;
6256 gboolean is_sensitive = FALSE;
6257 gint state = 0;
6258 gint len = 0;
6259 gchar *line = 0;
6260 gchar *words = 0;
6261 gchar label[10];
6263 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))) return;
6265 if(row >= 0 && !sheet->row[row].is_visible) return;
6266 if(column >= 0 && !sheet->column[column].is_visible) return;
6267 if(row >= 0 && !GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) return;
6268 if(column >= 0 && !GTK_SHEET_COL_TITLES_VISIBLE(sheet)) return;
6269 if(column>=0 && column <MIN_VISIBLE_COLUMN(sheet)) return;
6270 if(column>=0 && column >MAX_VISIBLE_COLUMN(sheet)) return;
6271 if(row>=0 && row <MIN_VISIBLE_ROW(sheet)) return;
6272 if(row>=0 && row >MAX_VISIBLE_ROW(sheet)) return;
6273 if( (row == -1) && (column == -1) ) return; //This seems to cause a crash.
6275 if(row==-1){
6276 window=sheet->column_title_window;
6277 button=&sheet->column[column].button;
6278 index=column;
6279 x = COLUMN_LEFT_XPIXEL(sheet, column)+CELL_SPACING;
6280 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) x -= sheet->row_title_area.width;
6281 y = 0;
6282 width = sheet->column[column].width;
6283 height = sheet->column_title_area.height;
6284 is_sensitive=sheet->column[column].is_sensitive;
6286 else if(column==-1){
6287 window=sheet->row_title_window;
6288 button=&sheet->row[row].button;
6289 index=row;
6290 x = 0;
6291 y = ROW_TOP_YPIXEL(sheet, row)+CELL_SPACING;
6292 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)) y-=sheet->column_title_area.height;
6293 width = sheet->row_title_area.width;
6294 height = sheet->row[row].height;
6295 is_sensitive=sheet->row[row].is_sensitive;
6298 allocation.x = x;
6299 allocation.y = y;
6300 allocation.width = width;
6301 allocation.height = height;
6303 gdk_window_clear_area (window,
6304 x, y,
6305 width, height);
6307 gtk_paint_box (sheet->button->style, window,
6308 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
6309 &allocation, GTK_WIDGET(sheet),
6310 "buttondefault", x, y, width, height);
6312 state = button->state;
6313 if(!is_sensitive) state=GTK_STATE_INSENSITIVE;
6315 if (state == GTK_STATE_ACTIVE)
6316 shadow_type = GTK_SHADOW_IN;
6317 else
6318 shadow_type = GTK_SHADOW_OUT;
6320 if(state != GTK_STATE_NORMAL && state != GTK_STATE_INSENSITIVE)
6321 gtk_paint_box (sheet->button->style, window,
6322 button->state, shadow_type,
6323 &allocation, GTK_WIDGET(sheet),
6324 "button", x, y, width, height);
6326 if(button->label_visible){
6328 text_height=DEFAULT_LABEL_HEIGHT(GTK_WIDGET(sheet));
6330 y += DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet))/2+
6331 DEFAULT_FONT_ASCENT(GTK_WIDGET(sheet))/2;
6333 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6334 &allocation);
6335 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, &allocation);
6337 if(button->label && strlen(button->label)>0){
6338 words=button->label;
6339 line = g_new(gchar, 1);
6340 line[0]='\0';
6342 while(words && *words != '\0'){
6343 if(*words != '\n'){
6344 len=strlen(line);
6345 line=g_realloc(line, len+2);
6346 line[len]=*words;
6347 line[len+1]='\0';
6349 if(*words == '\n' || *(words+1) == '\0'){
6350 text_width = gdk_string_width (GTK_WIDGET (sheet)->style->font, line);
6352 switch(button->justification){
6353 case GTK_JUSTIFY_LEFT:
6354 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6355 &allocation, GTK_WIDGET(sheet), "label",
6356 x + CELLOFFSET, y,
6357 line);
6358 break;
6359 case GTK_JUSTIFY_RIGHT:
6360 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6361 &allocation, GTK_WIDGET(sheet), "label",
6362 x + width - text_width - CELLOFFSET, y,
6363 line);
6364 break;
6365 case GTK_JUSTIFY_CENTER:
6366 default:
6367 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6368 &allocation, GTK_WIDGET(sheet), "label",
6369 x + (width - text_width) /2, y,
6370 line);
6373 y += DEFAULT_FONT_ASCENT(GTK_WIDGET(sheet))+
6374 DEFAULT_FONT_DESCENT(GTK_WIDGET(sheet)) + 2;
6376 g_free(line);
6377 line = g_new(gchar, 1);
6378 line[0]='\0';
6380 words++;
6382 g_free(line);
6383 } else {
6384 sprintf(label,"%d",index);
6386 text_width = gdk_string_width (GTK_WIDGET (sheet)->style->font, label);
6388 switch(button->justification){
6389 case GTK_JUSTIFY_LEFT:
6390 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6391 &allocation, GTK_WIDGET(sheet), "label",
6392 x + CELLOFFSET, y,
6393 label);
6394 break;
6395 case GTK_JUSTIFY_RIGHT:
6396 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6397 &allocation, GTK_WIDGET(sheet), "label",
6398 x + width - text_width - CELLOFFSET, y,
6399 label);
6400 break;
6401 case GTK_JUSTIFY_CENTER:
6402 default:
6403 gtk_paint_string (GTK_WIDGET(sheet)->style, window, state,
6404 &allocation, GTK_WIDGET(sheet), "label",
6405 x + (width - text_width) /2, y,
6406 label);
6411 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->fg_gc[button->state],
6412 NULL);
6413 gdk_gc_set_clip_rectangle(GTK_WIDGET(sheet)->style->white_gc, NULL);
6417 if((child = button->child) && (child->widget)){
6418 child->x = allocation.x;
6419 child->y = allocation.y;
6421 child->x += (width - child->widget->requisition.width) * child->x_align;
6422 child->y += (height - child->widget->requisition.height) * child->y_align;
6423 child->widget->allocation.width = child->widget->requisition.width;
6424 child->widget->allocation.height = child->widget->requisition.height;
6426 x = child->x;
6427 y = child->y;
6429 gtk_widget_set_state(child->widget, button->state);
6430 if(GTK_WIDGET_NO_WINDOW(child->widget))
6432 child->widget->allocation.x = 0;
6433 child->widget->allocation.y = 0;
6436 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
6437 GTK_WIDGET_MAPPED(child->widget))
6439 gtk_widget_size_allocate(child->widget,
6440 &child->widget->allocation);
6441 if(GTK_WIDGET_NO_WINDOW(child->widget) && child->window)
6443 gdk_window_move_resize(child->window,
6444 x, y,
6445 child->widget->allocation.width,
6446 child->widget->allocation.height);
6447 gtk_widget_draw(child->widget, NULL);
6456 /* SCROLLBARS
6458 * functions:
6459 * adjust_scrollbars
6460 * vadjustment_changed
6461 * hadjustment_changed
6462 * vadjustment_value_changed
6463 * hadjustment_value_changed */
6465 static void
6466 adjust_scrollbars (GtkSheet * sheet)
6469 if(sheet->vadjustment){
6470 sheet->vadjustment->page_size = sheet->sheet_window_height;
6471 sheet->vadjustment->page_increment = sheet->sheet_window_height / 2;
6472 sheet->vadjustment->step_increment = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
6473 sheet->vadjustment->lower = 0;
6474 sheet->vadjustment->upper = SHEET_HEIGHT (sheet) + 80;
6476 if (sheet->sheet_window_height - sheet->voffset > SHEET_HEIGHT (sheet))
6478 sheet->vadjustment->value = MAX(0, SHEET_HEIGHT (sheet) -
6479 sheet->sheet_window_height);
6480 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
6481 "value_changed");
6484 gtk_signal_emit_by_name (GTK_OBJECT(sheet->vadjustment), "changed");
6488 if(sheet->hadjustment){
6489 sheet->hadjustment->page_size = sheet->sheet_window_width;
6490 sheet->hadjustment->page_increment = sheet->sheet_window_width / 2;
6491 sheet->hadjustment->step_increment = DEFAULT_COLUMN_WIDTH;
6492 sheet->hadjustment->lower = 0;
6493 sheet->hadjustment->upper = SHEET_WIDTH (sheet)+ 80;
6495 if (sheet->sheet_window_width - sheet->hoffset > SHEET_WIDTH (sheet))
6497 sheet->hadjustment->value = MAX(0, SHEET_WIDTH (sheet) -
6498 sheet->sheet_window_width);
6499 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment),
6500 "value_changed");
6503 gtk_signal_emit_by_name (GTK_OBJECT(sheet->hadjustment), "changed");
6507 if(GTK_WIDGET_REALIZED(sheet))
6509 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet)){
6510 size_allocate_row_title_buttons(sheet);
6511 gdk_window_show(sheet->row_title_window);
6514 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet)){
6515 size_allocate_column_title_buttons(sheet);
6516 gdk_window_show(sheet->column_title_window);
6519 gtk_sheet_range_draw(sheet, NULL);
6525 static void
6526 vadjustment_changed (GtkAdjustment * adjustment,
6527 gpointer data)
6529 GtkSheet *sheet;
6531 g_return_if_fail (adjustment != NULL);
6532 g_return_if_fail (data != NULL);
6534 sheet = GTK_SHEET (data);
6538 static void
6539 hadjustment_changed (GtkAdjustment * adjustment,
6540 gpointer data)
6542 GtkSheet *sheet;
6544 g_return_if_fail (adjustment != NULL);
6545 g_return_if_fail (data != NULL);
6547 sheet = GTK_SHEET (data);
6552 static void
6553 vadjustment_value_changed (GtkAdjustment * adjustment,
6554 gpointer data)
6556 GtkSheet *sheet;
6557 gint diff, value, old_value;
6558 gint i;
6559 gint row, new_row;
6560 gint y=0;
6562 g_return_if_fail (adjustment != NULL);
6563 g_return_if_fail (data != NULL);
6564 g_return_if_fail (GTK_IS_SHEET (data));
6566 sheet = GTK_SHEET (data);
6568 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6570 row=ROW_FROM_YPIXEL(sheet,sheet->column_title_area.height + CELL_SPACING);
6571 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet))
6572 row=ROW_FROM_YPIXEL(sheet,CELL_SPACING);
6574 old_value = -sheet->voffset;
6576 for(i=0; i<= sheet->maxrow; i++){
6577 if(sheet->row[i].is_visible) y+=sheet->row[i].height;
6578 if(y > adjustment->value) break;
6580 y-=sheet->row[i].height;
6581 new_row=i;
6583 if (adjustment->value > sheet->old_vadjustment && sheet->old_vadjustment > 0. &&
6584 sheet->row[i].height > sheet->vadjustment->step_increment){
6585 /* This avoids embarrassing twitching */
6586 if(row == new_row && row != sheet->maxrow &&
6587 adjustment->value - sheet->old_vadjustment >=
6588 sheet->vadjustment->step_increment &&
6589 new_row + 1 != MIN_VISIBLE_ROW(sheet)){
6590 new_row+=1;
6591 y=y+sheet->row[row].height;
6595 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6596 if(sheet->old_vadjustment >= 0. && row == new_row){
6597 sheet->old_vadjustment = sheet->vadjustment->value;
6598 return;
6601 sheet->old_vadjustment = sheet->vadjustment->value;
6602 adjustment->value=y;
6605 if(new_row == 0){
6606 sheet->vadjustment->step_increment=
6607 sheet->row[0].height;
6608 }else{
6609 sheet->vadjustment->step_increment=
6610 MIN(sheet->row[new_row].height, sheet->row[new_row-1].height);
6613 sheet->vadjustment->value=adjustment->value;
6615 value = adjustment->value;
6617 if (value >= -sheet->voffset)
6619 /* scroll down */
6620 diff = value + sheet->voffset;
6622 else
6624 /* scroll up */
6625 diff = -sheet->voffset - value;
6628 sheet->voffset = -value;
6630 sheet->view.row0=ROW_FROM_YPIXEL(sheet, sheet->column_title_area.height+1);
6631 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6632 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet))
6633 sheet->view.row0=ROW_FROM_YPIXEL(sheet, 1);
6635 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6636 sheet->state == GTK_SHEET_NORMAL &&
6637 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6638 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6639 sheet->active_cell.col))
6641 gchar *text;
6643 text = (gchar *) gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6645 if(!text || strlen(text)==0)
6646 gtk_sheet_cell_clear(sheet,
6647 sheet->active_cell.row,
6648 sheet->active_cell.col);
6650 if(sheet->sheet_entry_window)
6651 gdk_window_hide(sheet->sheet_entry_window);
6652 else
6653 gdk_window_hide(sheet->sheet_entry->window);
6656 gtk_sheet_position_children(sheet);
6658 gtk_sheet_range_draw(sheet, NULL);
6659 size_allocate_row_title_buttons(sheet);
6660 size_allocate_global_button(sheet);
6663 static void
6664 hadjustment_value_changed (GtkAdjustment * adjustment,
6665 gpointer data)
6667 GtkSheet *sheet;
6668 gint i, diff, value, old_value;
6669 gint column, new_column;
6670 gint x=0;
6672 g_return_if_fail (adjustment != NULL);
6673 g_return_if_fail (data != NULL);
6674 g_return_if_fail (GTK_IS_SHEET (data));
6676 sheet = GTK_SHEET (data);
6678 if(GTK_SHEET_IS_FROZEN(sheet)) return;
6680 column=COLUMN_FROM_XPIXEL(sheet,sheet->row_title_area.width + CELL_SPACING);
6681 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
6682 column=COLUMN_FROM_XPIXEL(sheet, CELL_SPACING);
6684 old_value = -sheet->hoffset;
6686 for(i=0; i<= sheet->maxcol; i++){
6687 if(sheet->column[i].is_visible) x+=sheet->column[i].width;
6688 if(x > adjustment->value) break;
6690 x-=sheet->column[i].width;
6691 new_column=i;
6693 if (adjustment->value > sheet->old_hadjustment && sheet->old_hadjustment > 0 &&
6694 sheet->column[i].width > sheet->hadjustment->step_increment){
6695 /* This avoids embarrassing twitching */
6696 if(column == new_column && column != sheet->maxcol &&
6697 adjustment->value - sheet->old_hadjustment >=
6698 sheet->hadjustment->step_increment &&
6699 new_column + 1 != MIN_VISIBLE_COLUMN(sheet)){
6700 new_column+=1;
6701 x=x+sheet->column[column].width;
6705 /* Negative old_adjustment enforces the redraw, otherwise avoid spureous redraw */
6706 if(sheet->old_hadjustment >= 0. && new_column == column){
6707 sheet->old_hadjustment = sheet->hadjustment->value;
6708 return;
6711 sheet->old_hadjustment = sheet->hadjustment->value;
6712 adjustment->value=x;
6714 if(new_column == 0){
6715 sheet->hadjustment->step_increment=
6716 sheet->column[0].width;
6717 }else{
6718 sheet->hadjustment->step_increment=
6719 MIN(sheet->column[new_column].width, sheet->column[new_column-1].width);
6723 sheet->hadjustment->value=adjustment->value;
6725 value = adjustment->value;
6727 if (value >= -sheet->hoffset)
6729 /* scroll right */
6730 diff = value + sheet->hoffset;
6732 else
6734 /* scroll left */
6735 diff = -sheet->hoffset - value;
6738 sheet->hoffset = -value;
6740 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, sheet->row_title_area.width+1);
6741 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6742 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
6743 sheet->view.col0=COLUMN_FROM_XPIXEL(sheet, 1);
6745 if(GTK_WIDGET_REALIZED(sheet->sheet_entry) &&
6746 sheet->state == GTK_SHEET_NORMAL &&
6747 sheet->active_cell.row >= 0 && sheet->active_cell.col >= 0 &&
6748 !gtk_sheet_cell_isvisible(sheet, sheet->active_cell.row,
6749 sheet->active_cell.col))
6751 gchar *text;
6753 text = (gchar *) gtk_entry_get_text(GTK_ENTRY(gtk_sheet_get_entry(sheet)));
6754 if(!text || strlen(text)==0)
6755 gtk_sheet_cell_clear(sheet,
6756 sheet->active_cell.row,
6757 sheet->active_cell.col);
6759 if(sheet->sheet_entry_window)
6760 gdk_window_hide(sheet->sheet_entry_window);
6761 else
6762 gdk_window_hide(sheet->sheet_entry->window);
6765 gtk_sheet_position_children(sheet);
6767 gtk_sheet_range_draw(sheet, NULL);
6768 size_allocate_column_title_buttons(sheet);
6772 /* COLUMN RESIZING */
6773 static void
6774 draw_xor_vline (GtkSheet * sheet)
6776 GtkWidget *widget;
6778 g_return_if_fail (sheet != NULL);
6780 widget = GTK_WIDGET (sheet);
6782 gdk_draw_line (widget->window, sheet->xor_gc,
6783 sheet->x_drag,
6784 sheet->column_title_area.height,
6785 sheet->x_drag,
6786 sheet->sheet_window_height + 1);
6789 /* ROW RESIZING */
6790 static void
6791 draw_xor_hline (GtkSheet * sheet)
6793 GtkWidget *widget;
6795 g_return_if_fail (sheet != NULL);
6797 widget = GTK_WIDGET (sheet);
6799 gdk_draw_line (widget->window, sheet->xor_gc,
6800 sheet->row_title_area.width,
6801 sheet->y_drag,
6803 sheet->sheet_window_width + 1,
6804 sheet->y_drag);
6807 /* SELECTED RANGE */
6808 static void
6809 draw_xor_rectangle(GtkSheet *sheet, GtkSheetRange range)
6811 gint i;
6812 GdkRectangle clip_area, area;
6813 GdkGCValues values;
6815 area.x=COLUMN_LEFT_XPIXEL(sheet, range.col0);
6816 area.y=ROW_TOP_YPIXEL(sheet, range.row0);
6817 area.width=COLUMN_LEFT_XPIXEL(sheet, range.coli)-area.x+
6818 sheet->column[range.coli].width;
6819 area.height=ROW_TOP_YPIXEL(sheet, range.rowi)-area.y+
6820 sheet->row[range.rowi].height;
6822 clip_area.x=sheet->row_title_area.width;
6823 clip_area.y=sheet->column_title_area.height;
6824 clip_area.width=sheet->sheet_window_width;
6825 clip_area.height=sheet->sheet_window_height;
6827 if(!GTK_SHEET_ROW_TITLES_VISIBLE(sheet)) clip_area.x = 0;
6828 if(!GTK_SHEET_COL_TITLES_VISIBLE(sheet)) clip_area.y = 0;
6830 if(area.x<0) {
6831 area.width=area.width+area.x;
6832 area.x=0;
6834 if(area.width>clip_area.width) area.width=clip_area.width+10;
6835 if(area.y<0) {
6836 area.height=area.height+area.y;
6837 area.y=0;
6839 if(area.height>clip_area.height) area.height=clip_area.height+10;
6841 clip_area.x--;
6842 clip_area.y--;
6843 clip_area.width+=3;
6844 clip_area.height+=3;
6846 gdk_gc_get_values(sheet->xor_gc, &values);
6848 gdk_gc_set_clip_rectangle(sheet->xor_gc, &clip_area);
6850 for(i=-1; i<=1; i++)
6851 gdk_draw_rectangle(sheet->sheet_window,
6852 sheet->xor_gc,
6853 FALSE,
6854 area.x+i, area.y+i,
6855 area.width-2*i, area.height-2*i);
6858 gdk_gc_set_clip_rectangle(sheet->xor_gc, NULL);
6860 gdk_gc_set_foreground(sheet->xor_gc, &values.foreground);
6865 /* this function returns the new width of the column being resized given
6866 * the column and x position of the cursor; the x cursor position is passed
6867 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
6868 static guint
6869 new_column_width (GtkSheet * sheet,
6870 gint column,
6871 gint * x)
6873 gint cx, width;
6874 GtkRequisition requisition;
6876 cx = *x;
6878 gtk_sheet_button_size_request(sheet, &sheet->column[column].button,
6879 &requisition);
6881 /* you can't shrink a column to less than its minimum width */
6882 if (cx < COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width)
6884 *x = cx = COLUMN_LEFT_XPIXEL (sheet, column) + requisition.width;
6887 /* don't grow past the end of the window */
6889 if (cx > sheet->sheet_window_width)
6891 *x = cx = sheet->sheet_window_width;
6894 /* calculate new column width making sure it doesn't end up
6895 * less than the minimum width */
6896 width = cx - COLUMN_LEFT_XPIXEL (sheet, column);
6897 if (width < requisition.width)
6898 width = requisition.width;
6900 sheet->column[column].width = width;
6901 gtk_sheet_recalc_left_xpixels(sheet, column+1);
6902 sheet->view.coli=COLUMN_FROM_XPIXEL(sheet, sheet->sheet_window_width);
6903 size_allocate_column_title_buttons (sheet);
6905 return width;
6908 /* this function returns the new height of the row being resized given
6909 * the row and y position of the cursor; the y cursor position is passed
6910 * in as a pointer and automaticaly corrected if it's beyond min/max limits */
6911 static guint
6912 new_row_height (GtkSheet * sheet,
6913 gint row,
6914 gint * y)
6916 GtkRequisition requisition;
6917 gint cy, height;
6919 cy = *y;
6921 gtk_sheet_button_size_request(sheet, &sheet->row[row].button,
6922 &requisition);
6924 /* you can't shrink a row to less than its minimum height */
6925 if (cy < ROW_TOP_YPIXEL (sheet, row) + requisition.height)
6928 *y = cy = ROW_TOP_YPIXEL (sheet, row) + requisition.height;
6931 /* don't grow past the end of the window */
6933 if (cy > sheet->sheet_window_height)
6935 *y = cy = sheet->sheet_window_height;
6938 /* calculate new row height making sure it doesn't end up
6939 * less than the minimum height */
6940 height = (cy - ROW_TOP_YPIXEL (sheet, row));
6941 if (height < requisition.height)
6942 height = requisition.height;
6944 sheet->row[row].height = height;
6945 gtk_sheet_recalc_top_ypixels(sheet, row);
6946 sheet->view.rowi=ROW_FROM_YPIXEL(sheet, sheet->sheet_window_height-1);
6947 size_allocate_row_title_buttons (sheet);
6949 return height;
6952 void
6953 gtk_sheet_set_column_width (GtkSheet * sheet,
6954 gint column,
6955 guint width)
6957 g_return_if_fail (sheet != NULL);
6958 g_return_if_fail (GTK_IS_SHEET (sheet));
6960 if (column < 0 || column > sheet->maxcol)
6961 return;
6963 sheet->column[column].width = width;
6965 gtk_sheet_recalc_left_xpixels(sheet, column+1);
6967 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
6968 size_allocate_column_title_buttons (sheet);
6969 adjust_scrollbars (sheet);
6970 gtk_sheet_size_allocate_entry(sheet);
6971 gtk_sheet_range_draw (sheet, NULL);
6974 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], -1, column);
6975 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_COL_WIDTH], column, width);
6979 void
6980 gtk_sheet_set_row_height (GtkSheet * sheet,
6981 gint row,
6982 guint height)
6984 g_return_if_fail (sheet != NULL);
6985 g_return_if_fail (GTK_IS_SHEET (sheet));
6987 if (row < 0 || row > sheet->maxrow)
6988 return;
6990 sheet->row[row].height = height;
6992 gtk_sheet_recalc_top_ypixels(sheet, row+1);
6994 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) && !GTK_SHEET_IS_FROZEN(sheet)){
6995 size_allocate_row_title_buttons (sheet);
6996 adjust_scrollbars (sheet);
6997 gtk_sheet_size_allocate_entry(sheet);
6998 gtk_sheet_range_draw (sheet, NULL);
7001 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[CHANGED], row, -1);
7002 gtk_signal_emit(GTK_OBJECT(sheet), sheet_signals[NEW_ROW_HEIGHT], row, height);
7007 void
7008 gtk_sheet_add_column(GtkSheet *sheet, guint ncols)
7011 g_return_if_fail (sheet != NULL);
7012 g_return_if_fail (GTK_IS_SHEET (sheet));
7014 AddColumn(sheet, ncols);
7016 if(!GTK_WIDGET_REALIZED(sheet)) return;
7018 adjust_scrollbars(sheet);
7020 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7022 sheet->old_hadjustment = -1.;
7023 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7024 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7025 "value_changed");
7028 void
7029 gtk_sheet_add_row(GtkSheet *sheet, guint nrows)
7032 g_return_if_fail (sheet != NULL);
7033 g_return_if_fail (GTK_IS_SHEET (sheet));
7035 AddRow(sheet, nrows);
7037 if(!GTK_WIDGET_REALIZED(sheet)) return;
7039 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7041 adjust_scrollbars(sheet);
7043 sheet->old_vadjustment = -1.;
7044 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7045 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7046 "value_changed");
7049 void
7050 gtk_sheet_insert_rows(GtkSheet *sheet, guint row, guint nrows)
7052 GList *children;
7053 GtkSheetChild *child;
7055 g_return_if_fail (sheet != NULL);
7056 g_return_if_fail (GTK_IS_SHEET (sheet));
7058 if(GTK_WIDGET_REALIZED(sheet))
7059 gtk_sheet_real_unselect_range(sheet, NULL);
7061 InsertRow(sheet, row, nrows);
7063 children = sheet->children;
7064 while(children)
7066 child = (GtkSheetChild *)children->data;
7068 if(child->attached_to_cell)
7069 if(child->row >= row) child->row += nrows;
7071 children = children->next;
7074 if(!GTK_WIDGET_REALIZED(sheet)) return;
7076 if(sheet->state==GTK_SHEET_COLUMN_SELECTED) sheet->range.rowi+=nrows;
7077 adjust_scrollbars(sheet);
7079 sheet->old_vadjustment = -1.;
7080 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7081 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7082 "value_changed");
7086 void
7087 gtk_sheet_insert_columns(GtkSheet *sheet, guint col, guint ncols)
7089 GList *children;
7090 GtkSheetChild *child;
7092 g_return_if_fail (sheet != NULL);
7093 g_return_if_fail (GTK_IS_SHEET (sheet));
7095 if(GTK_WIDGET_REALIZED(sheet))
7096 gtk_sheet_real_unselect_range(sheet, NULL);
7098 InsertColumn(sheet, col, ncols);
7100 children = sheet->children;
7101 while(children)
7103 child = (GtkSheetChild *)children->data;
7105 if(child->attached_to_cell)
7106 if(child->col >= col) child->col += ncols;
7108 children = children->next;
7111 if(!GTK_WIDGET_REALIZED(sheet)) return;
7113 if(sheet->state==GTK_SHEET_ROW_SELECTED) sheet->range.coli+=ncols;
7114 adjust_scrollbars(sheet);
7116 sheet->old_hadjustment = -1.;
7117 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7118 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7119 "value_changed");
7123 void
7124 gtk_sheet_delete_rows(GtkSheet *sheet, guint row, guint nrows)
7126 GList *children;
7127 GtkSheetChild *child;
7128 gint irow, icol;
7129 gboolean veto;
7131 g_return_if_fail (sheet != NULL);
7132 g_return_if_fail (GTK_IS_SHEET (sheet));
7134 nrows = MIN(nrows, sheet->maxrow-row+1);
7136 if(GTK_WIDGET_REALIZED(sheet))
7137 gtk_sheet_real_unselect_range(sheet, NULL);
7139 DeleteRow(sheet, row, nrows);
7141 children = sheet->children;
7142 while(children)
7144 child = (GtkSheetChild *)children->data;
7146 if(child->attached_to_cell){
7147 if(child->row >= row && child->row < row+nrows){
7148 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7149 children = sheet->children;
7151 else
7153 if(child->row >= row) child->row -= nrows;
7154 children = children->next;
7157 else
7158 children = children->next;
7162 if(!GTK_WIDGET_REALIZED(sheet)) return;
7164 irow = sheet->active_cell.row;
7165 icol = sheet->active_cell.col;
7167 sheet->active_cell.row = -1;
7168 sheet->active_cell.col = -1;
7170 /* if(sheet->state == GTK_SHEET_ROW_SELECTED)
7173 irow = MIN(irow, sheet->maxrow);
7174 irow = MAX(irow, 0);
7175 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7177 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7178 sheet->active_cell.col);
7180 adjust_scrollbars(sheet);
7182 sheet->old_vadjustment = -1.;
7183 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->vadjustment)
7184 gtk_signal_emit_by_name (GTK_OBJECT (sheet->vadjustment),
7185 "value_changed");
7189 void
7190 gtk_sheet_delete_columns(GtkSheet *sheet, guint col, guint ncols)
7192 GList *children;
7193 GtkSheetChild *child;
7194 gint irow, icol;
7195 gboolean veto;
7197 g_return_if_fail (sheet != NULL);
7198 g_return_if_fail (GTK_IS_SHEET (sheet));
7200 ncols = MIN(ncols, sheet->maxcol-col+1);
7202 if(GTK_WIDGET_REALIZED(sheet))
7203 gtk_sheet_real_unselect_range(sheet, NULL);
7205 DeleteColumn(sheet, col, ncols);
7207 children = sheet->children;
7208 while(children)
7210 child = (GtkSheetChild *)children->data;
7212 if(child->attached_to_cell){
7213 if(child->col >= col && child->col < col+ncols){
7214 gtk_container_remove(GTK_CONTAINER(sheet), child->widget);
7215 children = sheet->children;
7217 else
7219 if(child->col >= col) child->col -= ncols;
7220 children = children->next;
7223 else
7224 children = children->next;
7228 if(!GTK_WIDGET_REALIZED(sheet)) return;
7230 irow = sheet->active_cell.row;
7231 icol = sheet->active_cell.col;
7233 sheet->active_cell.row = -1;
7234 sheet->active_cell.col = -1;
7236 /* if(sheet->state == GTK_SHEET_COLUMN_SELECTED)
7239 icol = MIN(icol, sheet->maxcol);
7240 icol = MAX(icol, 0);
7241 gtk_sheet_click_cell(sheet, irow, icol, &veto);
7243 gtk_sheet_activate_cell(sheet, sheet->active_cell.row,
7244 sheet->active_cell.col);
7246 adjust_scrollbars(sheet);
7248 sheet->old_hadjustment = -1.;
7249 if(!GTK_SHEET_IS_FROZEN(sheet) && sheet->hadjustment)
7250 gtk_signal_emit_by_name (GTK_OBJECT (sheet->hadjustment),
7251 "value_changed");
7255 void
7256 gtk_sheet_range_set_background(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7258 gint i, j;
7259 GtkSheetCellAttr attributes;
7260 GtkSheetRange range;
7262 g_return_if_fail (sheet != NULL);
7263 g_return_if_fail (GTK_IS_SHEET (sheet));
7265 if(!urange)
7266 range = sheet->range;
7267 else
7268 range = *urange;
7270 for (i=range.row0; i<=range.rowi; i++)
7271 for (j=range.col0; j<=range.coli; j++){
7272 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7273 if(color != NULL)
7274 attributes.background = *color;
7275 else
7276 attributes.background = sheet->bg_color;
7278 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7281 range.row0--;
7282 range.col0--;
7283 range.rowi++;
7284 range.coli++;
7286 if(!GTK_SHEET_IS_FROZEN(sheet))
7287 gtk_sheet_range_draw(sheet, &range);
7291 void
7292 gtk_sheet_range_set_foreground(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7294 gint i, j;
7295 GtkSheetCellAttr attributes;
7296 GtkSheetRange range;
7298 g_return_if_fail (sheet != NULL);
7299 g_return_if_fail (GTK_IS_SHEET (sheet));
7301 if(!urange)
7302 range = sheet->range;
7303 else
7304 range = *urange;
7306 for (i=range.row0; i<=range.rowi; i++)
7307 for (j=range.col0; j<=range.coli; j++){
7308 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7310 if(color != NULL)
7311 attributes.foreground = *color;
7312 else
7313 gdk_color_black(gdk_colormap_get_system(), &attributes.foreground);
7315 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7318 if(!GTK_SHEET_IS_FROZEN(sheet))
7319 gtk_sheet_range_draw(sheet, &range);
7323 void
7324 gtk_sheet_range_set_justification(GtkSheet *sheet, const GtkSheetRange *urange,
7325 GtkJustification just)
7327 gint i, j;
7328 GtkSheetCellAttr attributes;
7329 GtkSheetRange range;
7331 g_return_if_fail (sheet != NULL);
7332 g_return_if_fail (GTK_IS_SHEET (sheet));
7334 if(!urange)
7335 range = sheet->range;
7336 else
7337 range = *urange;
7339 for (i=range.row0; i<=range.rowi; i++)
7340 for (j=range.col0; j<=range.coli; j++){
7341 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7342 attributes.justification = just;
7343 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7346 range.col0 = sheet->view.col0;
7347 range.coli = sheet->view.coli;
7349 if(!GTK_SHEET_IS_FROZEN(sheet))
7350 gtk_sheet_range_draw(sheet, &range);
7354 void
7355 gtk_sheet_column_set_justification(GtkSheet *sheet, gint col,
7356 GtkJustification justification)
7358 g_return_if_fail (sheet != NULL);
7359 g_return_if_fail (GTK_IS_SHEET (sheet));
7361 if(col > sheet->maxcol) return;
7363 sheet->column[col].justification = justification;
7365 if(GTK_WIDGET_REALIZED(sheet) && !GTK_SHEET_IS_FROZEN(sheet) &&
7366 col >= MIN_VISIBLE_COLUMN(sheet) && col <= MAX_VISIBLE_COLUMN(sheet))
7367 gtk_sheet_range_draw(sheet, NULL);
7371 void
7372 gtk_sheet_range_set_editable(GtkSheet *sheet, const GtkSheetRange *urange, gboolean editable)
7374 gint i, j;
7375 GtkSheetCellAttr attributes;
7376 GtkSheetRange range;
7378 g_return_if_fail (sheet != NULL);
7379 g_return_if_fail (GTK_IS_SHEET (sheet));
7381 if(!urange)
7382 range = sheet->range;
7383 else
7384 range = *urange;
7386 for (i=range.row0; i<=range.rowi; i++)
7387 for (j=range.col0; j<=range.coli; j++){
7388 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7389 attributes.is_editable = editable;
7390 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7393 if(!GTK_SHEET_IS_FROZEN(sheet))
7394 gtk_sheet_range_draw(sheet, &range);
7398 void
7399 gtk_sheet_range_set_visible(GtkSheet *sheet, const GtkSheetRange *urange, gboolean visible)
7401 gint i, j;
7402 GtkSheetCellAttr attributes;
7403 GtkSheetRange range;
7405 g_return_if_fail (sheet != NULL);
7406 g_return_if_fail (GTK_IS_SHEET (sheet));
7408 if(!urange)
7409 range = sheet->range;
7410 else
7411 range = *urange;
7413 for (i=range.row0; i<=range.rowi; i++)
7414 for (j=range.col0; j<=range.coli; j++){
7415 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7416 attributes.is_visible=visible;
7417 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7420 if(!GTK_SHEET_IS_FROZEN(sheet))
7421 gtk_sheet_range_draw(sheet, &range);
7425 void
7426 gtk_sheet_range_set_border(GtkSheet *sheet, const GtkSheetRange *urange, gint mask,
7427 guint width, gint line_style)
7429 gint i, j;
7430 GtkSheetCellAttr attributes;
7431 GtkSheetRange range;
7433 g_return_if_fail (sheet != NULL);
7434 g_return_if_fail (GTK_IS_SHEET (sheet));
7436 if(!urange)
7437 range = sheet->range;
7438 else
7439 range = *urange;
7441 for (i=range.row0; i<=range.rowi; i++)
7442 for (j=range.col0; j<=range.coli; j++){
7443 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7444 attributes.border.mask = mask;
7445 attributes.border.width = width;
7446 attributes.border.line_style=line_style;
7447 attributes.border.cap_style=GDK_CAP_NOT_LAST;
7448 attributes.border.join_style=GDK_JOIN_MITER;
7449 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7452 range.row0--;
7453 range.col0--;
7454 range.rowi++;
7455 range.coli++;
7457 if(!GTK_SHEET_IS_FROZEN(sheet))
7458 gtk_sheet_range_draw(sheet, &range);
7462 void
7463 gtk_sheet_range_set_border_color(GtkSheet *sheet, const GtkSheetRange *urange, const GdkColor *color)
7465 gint i, j;
7466 GtkSheetCellAttr attributes;
7467 GtkSheetRange range;
7469 g_return_if_fail (sheet != NULL);
7470 g_return_if_fail (GTK_IS_SHEET (sheet));
7472 if(!urange)
7473 range = sheet->range;
7474 else
7475 range = *urange;
7477 for (i=range.row0; i<=range.rowi; i++)
7478 for (j=range.col0; j<=range.coli; j++){
7479 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7480 attributes.border.color = *color;
7481 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7484 if(!GTK_SHEET_IS_FROZEN(sheet))
7485 gtk_sheet_range_draw(sheet, &range);
7489 /* TODO: Should this really store the font pointer instead of the font value.
7492 #if 0
7493 /* SDB says: Remove this . . . . . */
7494 void
7495 gtk_sheet_range_set_font(GtkSheet *sheet, const GtkSheetRange *urange, GdkFont *font)
7497 gint i, j;
7498 gint font_height;
7499 GtkSheetCellAttr attributes;
7500 GtkSheetRange range;
7502 g_return_if_fail (sheet != NULL);
7503 g_return_if_fail (GTK_IS_SHEET (sheet));
7505 if(!urange)
7506 range = sheet->range;
7507 else
7508 range = *urange;
7510 gtk_sheet_freeze(sheet);
7512 for (i=range.row0; i<=range.rowi; i++)
7513 for (j=range.col0; j<=range.coli; j++){
7514 gtk_sheet_get_attributes(sheet, i, j, &attributes);
7515 attributes.font = font; /* TODO: See comment above this function.*/
7516 font_height=attributes.font->ascent +
7517 2 * attributes.font->descent + 2*CELLOFFSET;
7518 if(font_height > sheet->row[i].height){
7519 sheet->row[i].height = font_height;
7520 gtk_sheet_recalc_top_ypixels(sheet, i);
7523 gtk_sheet_set_cell_attributes(sheet, i, j, attributes);
7526 gtk_sheet_thaw(sheet);
7528 #endif
7530 static void
7531 gtk_sheet_set_cell_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr attributes)
7533 GtkSheetCell **cell;
7535 if(row > sheet->maxrow || col >sheet->maxcol) return;
7537 CheckBounds(sheet, row, col);
7539 cell = &sheet->data[row][col];
7541 if(*cell==NULL){
7542 (*cell) = gtk_sheet_cell_new();
7543 (*cell)->row = row;
7544 (*cell)->col = col;
7547 if((*cell)->attributes == NULL)
7548 (*cell)->attributes = g_new(GtkSheetCellAttr, 1);
7550 *((*cell)->attributes) = attributes;
7553 gboolean
7554 gtk_sheet_get_attributes(GtkSheet *sheet, gint row, gint col, GtkSheetCellAttr *attributes)
7556 GtkSheetCell **cell = NULL;
7558 g_return_val_if_fail (sheet != NULL, FALSE);
7559 g_return_val_if_fail (GTK_IS_SHEET (sheet), FALSE);
7561 if(row < 0 || col < 0) return FALSE;
7563 if(row > sheet->maxallocrow || col > sheet->maxalloccol){
7564 init_attributes(sheet, col, attributes);
7565 return FALSE;
7568 if(row <= sheet->maxallocrow && col <= sheet->maxalloccol){
7569 if(sheet->data[row] && sheet->data[row][col])
7570 cell = &sheet->data[row][col];
7571 if(cell == NULL || *cell == NULL){
7572 init_attributes(sheet, col, attributes);
7573 return FALSE;
7574 } else
7575 if((*cell)->attributes == NULL){
7576 init_attributes(sheet, col, attributes);
7577 return FALSE;
7578 }else{
7579 *attributes = *(sheet->data[row][col]->attributes);
7580 if(sheet->column[col].justification != GTK_JUSTIFY_FILL)
7581 attributes->justification = sheet->column[col].justification;
7585 return TRUE;
7588 static void
7589 init_attributes(GtkSheet *sheet, gint col, GtkSheetCellAttr *attributes)
7591 /* DEFAULT VALUES */
7592 attributes->foreground = GTK_WIDGET(sheet)->style->black;
7593 attributes->background = sheet->bg_color;
7594 if(!GTK_WIDGET_REALIZED(GTK_WIDGET(sheet))){
7595 GdkColormap *colormap;
7596 colormap=gdk_colormap_get_system();
7597 gdk_color_black(colormap, &attributes->foreground);
7598 attributes->background = sheet->bg_color;
7600 attributes->justification = sheet->column[col].justification;
7601 attributes->border.width = 0;
7602 attributes->border.line_style = GDK_LINE_SOLID;
7603 attributes->border.cap_style = GDK_CAP_NOT_LAST;
7604 attributes->border.join_style = GDK_JOIN_MITER;
7605 attributes->border.mask = 0;
7606 attributes->border.color = GTK_WIDGET(sheet)->style->black;
7607 attributes->is_editable = TRUE;
7608 attributes->is_visible = TRUE;
7609 attributes->font = GTK_WIDGET(sheet)->style->font;
7613 /**********************************************************************
7614 * Memory allocation routines:
7615 * AddRow & AddColumn allocate memory for GtkSheetColumn & GtkSheetRow structs.
7616 * InsertRow
7617 * InsertColumn
7618 * DeleteRow
7619 * DeleteColumn
7620 * GrowSheet allocates memory for the sheet cells contents using an array of
7621 * pointers. Alternative to this could be a linked list or a hash table.
7622 * CheckBounds checks whether the given cell is currently allocated or not.
7623 * If not, it calls to GrowSheet.
7624 **********************************************************************/
7626 static gint
7627 AddColumn(GtkSheet *tbl, gint ncols)
7629 gint i;
7631 if(ncols == -1 && tbl->maxcol == 0)
7633 ncols = 1;
7635 else
7637 tbl->maxcol += ncols;
7638 tbl->column = (GtkSheetColumn *)g_realloc(tbl->column,(tbl->maxcol+1)*
7639 sizeof(GtkSheetColumn));
7642 for(i=tbl->maxcol-ncols+1; i<= tbl->maxcol; i++){
7643 tbl->column[i].width=DEFAULT_COLUMN_WIDTH;
7644 tbl->column[i].button.label=NULL;
7645 tbl->column[i].button.child=NULL;
7646 tbl->column[i].button.state=GTK_STATE_NORMAL;
7647 tbl->column[i].button.justification=GTK_JUSTIFY_CENTER;
7648 tbl->column[i].button.label_visible = TRUE;
7649 tbl->column[i].name=NULL;
7650 tbl->column[i].is_visible=TRUE;
7651 tbl->column[i].is_sensitive=TRUE;
7652 tbl->column[i].left_text_column=i;
7653 tbl->column[i].right_text_column=i;
7654 tbl->column[i].justification=GTK_JUSTIFY_FILL;
7655 if(i>0)
7657 tbl->column[i].left_text_column=tbl->column[i-1].left_text_column;
7658 tbl->column[i].left_xpixel=tbl->column[i-1].left_xpixel +
7659 tbl->column[i-1].width;
7661 else
7663 tbl->column[i].left_xpixel=tbl->row_title_area.width;
7664 if(!GTK_SHEET_ROW_TITLES_VISIBLE(tbl))
7665 tbl->column[i].left_xpixel=0;
7668 return TRUE;
7671 static gint
7672 AddRow(GtkSheet *tbl, gint nrows)
7674 gint i;
7676 if(nrows == -1 && tbl->maxrow == 0)
7678 nrows = 1;
7680 else
7682 tbl->maxrow += nrows;
7683 tbl->row = (GtkSheetRow *)g_realloc(tbl->row,(tbl->maxrow+1)*
7684 sizeof(GtkSheetRow));
7687 for(i=tbl->maxrow-nrows+1; i<= tbl->maxrow; i++){
7688 tbl->row[i].height=DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7689 tbl->row[i].button.label=NULL;
7690 tbl->row[i].button.child=NULL;
7691 tbl->row[i].button.state=GTK_STATE_NORMAL;
7692 tbl->row[i].button.justification=GTK_JUSTIFY_CENTER;
7693 tbl->row[i].button.label_visible = TRUE;
7694 tbl->row[i].name=NULL;
7695 tbl->row[i].is_visible=TRUE;
7696 tbl->row[i].is_sensitive=TRUE;
7697 if(i>0)
7698 tbl->row[i].top_ypixel=tbl->row[i-1].top_ypixel+tbl->row[i-1].height;
7699 else
7701 tbl->row[i].top_ypixel=tbl->column_title_area.height;
7702 if(!GTK_SHEET_COL_TITLES_VISIBLE(tbl))
7703 tbl->row[i].top_ypixel=0;
7706 return TRUE;
7709 static gint
7710 InsertRow(GtkSheet *tbl, gint row, gint nrows)
7712 GtkSheetCell **pp;
7713 gint i,j;
7714 GtkSheetCell **auxdata;
7715 GtkSheetRow auxrow;
7717 AddRow(tbl,nrows);
7719 for(i=tbl->maxrow; i>=row+nrows; i--){
7720 auxrow = tbl->row[i];
7721 tbl->row[i]=tbl->row[i-nrows];
7722 tbl->row[i].is_visible=tbl->row[i-nrows].is_visible;
7723 tbl->row[i].is_sensitive=tbl->row[i-nrows].is_sensitive;
7724 if(auxrow.is_visible)
7725 tbl->row[i].top_ypixel+=nrows*DEFAULT_ROW_HEIGHT(GTK_WIDGET(tbl));
7726 tbl->row[i-nrows]=auxrow;
7729 if(row <= tbl->maxallocrow){
7731 GrowSheet(tbl,nrows,0);
7733 for(i=tbl->maxallocrow; i>=row+nrows; i--){
7734 auxdata = tbl->data[i];
7735 tbl->data[i]=tbl->data[i-nrows];
7737 pp= tbl->data[i];
7738 for(j=0; j<=tbl->maxalloccol; j++,pp++){
7739 if(*pp!=(GtkSheetCell *)NULL)
7740 (*pp)->row=i;
7743 tbl->data[i-nrows]=auxdata;
7746 gtk_sheet_recalc_top_ypixels(tbl, 0);
7747 return TRUE;
7750 static gint
7751 InsertColumn(GtkSheet *tbl, gint col, gint ncols)
7753 gint i,j;
7754 GtkSheetColumn auxcol;
7756 AddColumn(tbl,ncols);
7758 for(i=tbl->maxcol; i>=col+ncols; i--){
7759 auxcol = tbl->column[i];
7760 tbl->column[i]=tbl->column[i-ncols];
7761 tbl->column[i].is_visible=tbl->column[i-ncols].is_visible;
7762 tbl->column[i].is_sensitive=tbl->column[i-ncols].is_sensitive;
7763 tbl->column[i].left_text_column=tbl->column[i-ncols].left_text_column;
7764 tbl->column[i].right_text_column=tbl->column[i-ncols].right_text_column;
7765 tbl->column[i].justification=tbl->column[i-ncols].justification;
7766 if(auxcol.is_visible) tbl->column[i].left_xpixel+=ncols*DEFAULT_COLUMN_WIDTH;
7767 tbl->column[i-ncols]=auxcol;
7770 if(col <= tbl->maxalloccol){
7772 GrowSheet(tbl,0,ncols);
7774 for(i=0; i<=tbl->maxallocrow; i++){
7775 for(j=tbl->maxalloccol; j>=col+ncols; j--){
7776 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
7777 tbl->data[i][j]=tbl->data[i][j-ncols];
7778 if(tbl->data[i][j]) tbl->data[i][j]->col=j;
7779 tbl->data[i][j-ncols]=NULL;
7783 gtk_sheet_recalc_left_xpixels(tbl, 0);
7784 return TRUE;
7787 static gint
7788 DeleteRow(GtkSheet *tbl, gint row, gint nrows)
7790 GtkSheetCell **auxdata = NULL;
7791 gint i,j;
7793 if(nrows <= 0 || row > tbl->maxrow) return TRUE;
7795 nrows=MIN(nrows,tbl->maxrow-row+1);
7797 for(i=row; i<row+nrows; i++){
7798 if(tbl->row[i].name){
7799 g_free(tbl->row[i].name);
7800 tbl->row[i].name = NULL;
7802 if(tbl->row[i].button.label){
7803 g_free(tbl->row[i].button.label);
7804 tbl->row[i].button.label = NULL;
7808 for(i=row; i<=tbl->maxrow-nrows; i++){
7809 if(i+nrows <= tbl->maxrow){
7810 tbl->row[i]=tbl->row[i+nrows];
7814 if(row <= tbl->maxallocrow){
7816 for(i=row; i<=tbl->maxrow-nrows; i++){
7817 if(i<=tbl->maxallocrow){
7818 auxdata=tbl->data[i];
7819 for(j=0; j<=tbl->maxalloccol; j++){
7820 gtk_sheet_real_cell_clear(tbl, i, j, TRUE);
7823 if(i+nrows<=tbl->maxallocrow){
7824 tbl->data[i]=tbl->data[i+nrows];
7825 tbl->data[i+nrows]=auxdata;
7826 for(j=0; j<=tbl->maxalloccol; j++){
7827 if(tbl->data[i][j]) tbl->data[i][j]->row=i;
7832 for(i=tbl->maxrow-nrows+1; i<=tbl->maxallocrow; i++){
7833 if(i > 0 && tbl->data[i]){
7834 g_free(tbl->data[i]);
7835 tbl->data[i] = NULL;
7839 tbl->maxallocrow-=MIN(nrows,tbl->maxallocrow-row+1);
7840 tbl->maxallocrow = MIN(tbl->maxallocrow, tbl->maxrow);
7844 tbl->maxrow-=nrows;
7845 gtk_sheet_recalc_top_ypixels(tbl, 0);
7846 return TRUE;
7849 static gint
7850 DeleteColumn(GtkSheet *tbl, gint column, gint ncols)
7852 gint i,j;
7853 GtkSheetColumn auxcol;
7855 ncols = MIN(ncols,tbl->maxcol-column+1);
7857 if(ncols <= 0 || column > tbl->maxcol) return TRUE;
7859 for(i=column; i<column+ncols; i++){
7860 auxcol=tbl->column[i];
7861 if(tbl->column[i].name){
7862 g_free(tbl->column[i].name);
7863 tbl->column[i].name = NULL;
7865 if(tbl->column[i].button.label){
7866 g_free(tbl->column[i].button.label);
7867 tbl->column[i].button.label = NULL;
7871 for(i=column; i<=tbl->maxcol-ncols; i++){
7872 if(i+ncols <= tbl->maxcol){
7873 tbl->column[i]=tbl->column[i+ncols];
7877 if(column <= tbl->maxalloccol){
7879 for(i=column; i<=tbl->maxcol-ncols; i++){
7880 if(i<=tbl->maxalloccol){
7881 for(j=0; j<=tbl->maxallocrow; j++){
7882 gtk_sheet_real_cell_clear(tbl, j, i, TRUE);
7883 if(i+ncols <= tbl->maxalloccol){
7884 tbl->data[j][i] = tbl->data[j][i+ncols];
7885 tbl->data[j][i+ncols] = NULL;
7886 if(tbl->data[j][i]) tbl->data[j][i]->col=i;
7893 tbl->maxalloccol-=MIN(ncols,tbl->maxalloccol-column+1);
7894 tbl->maxalloccol = MIN(tbl->maxalloccol, tbl->maxcol);
7896 tbl->maxcol-=ncols;
7897 gtk_sheet_recalc_left_xpixels(tbl, 0);
7898 return TRUE;
7901 static gint
7902 GrowSheet(GtkSheet *tbl, gint newrows, gint newcols)
7904 gint i,j;
7905 gint inirow, inicol;
7907 inirow = tbl->maxallocrow + 1;
7908 inicol = tbl->maxalloccol + 1;
7910 tbl->maxalloccol = tbl->maxalloccol + newcols;
7911 tbl->maxallocrow = tbl->maxallocrow + newrows;
7913 if(newrows>0){
7914 tbl->data = (GtkSheetCell***)
7915 g_realloc(tbl->data,(tbl->maxallocrow+1)*sizeof(GtkSheetCell **)+sizeof(double));
7917 for(i=inirow; i <= tbl->maxallocrow; i++){
7918 tbl->data[i] = (GtkSheetCell **) \
7919 g_malloc((tbl->maxcol+1)*sizeof(GtkSheetCell *)+sizeof(double));
7920 for(j=0; j<inicol; j++) {
7921 tbl->data[i][j] = NULL;
7927 if(newcols>0){
7928 for(i=0; i <= tbl->maxallocrow; i++) {
7929 tbl->data[i] = (GtkSheetCell **) \
7930 g_realloc(tbl->data[i],(tbl->maxalloccol+1)*sizeof(GtkSheetCell *)+sizeof(double));
7931 for(j=inicol; j <= tbl->maxalloccol; j++) {
7932 tbl->data[i][j] = NULL;
7937 return(0);
7940 static gint
7941 CheckBounds(GtkSheet *tbl, gint row, gint col)
7943 gint newrows=0,newcols=0;
7945 if(col>tbl->maxalloccol) newcols=col-tbl->maxalloccol;
7946 if(row>tbl->maxallocrow) newrows=row-tbl->maxallocrow;
7947 if(newrows>0 || newcols>0) GrowSheet(tbl, newrows, newcols);
7948 return(0);
7951 /********************************************************************
7952 * Container Functions:
7953 * gtk_sheet_add
7954 * gtk_sheet_put
7955 * gtk_sheet_attach
7956 * gtk_sheet_remove
7957 * gtk_sheet_move_child
7958 * gtk_sheet_position_child
7959 * gtk_sheet_position_children
7960 * gtk_sheet_realize_child
7961 * gtk_sheet_get_child_at
7962 ********************************************************************/
7964 GtkSheetChild *
7965 gtk_sheet_put(GtkSheet *sheet, GtkWidget *child, gint x, gint y)
7967 GtkRequisition child_requisition;
7968 GtkSheetChild *child_info;
7970 g_return_val_if_fail(sheet != NULL, NULL);
7971 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
7972 g_return_val_if_fail(child != NULL, NULL);
7973 g_return_val_if_fail(child->parent == NULL, NULL);
7975 child_info = g_new (GtkSheetChild, 1);
7976 child_info->widget = child;
7977 child_info->x = x;
7978 child_info->y = y;
7979 child_info->window = NULL;
7980 child_info->attached_to_cell = FALSE;
7982 sheet->children = g_list_append(sheet->children, child_info);
7984 gtk_widget_set_parent (child, GTK_WIDGET(sheet));
7986 gtk_widget_size_request(child, &child_requisition);
7988 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
7991 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
7992 !GTK_WIDGET_REALIZED(child))
7993 gtk_sheet_realize_child(sheet, child_info);
7995 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
7996 !GTK_WIDGET_MAPPED(child))
7997 gtk_widget_map(child);
8000 gtk_sheet_position_child(sheet, child_info);
8002 /* This will avoid drawing on the titles */
8004 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)))
8006 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
8007 gdk_window_show(sheet->row_title_window);
8008 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
8009 gdk_window_show(sheet->column_title_window);
8012 return (child_info);
8015 void
8016 gtk_sheet_attach (GtkSheet *sheet,
8017 GtkWidget *widget,
8018 gint row, gint col,
8019 gfloat x_align, gfloat y_align)
8021 GdkRectangle area;
8022 GtkSheetChild *child;
8024 if(row < 0 || col < 0){
8025 gtk_sheet_button_attach(sheet, widget, row, col, x_align, y_align);
8026 return;
8029 gtk_sheet_get_cell_area(sheet, row, col, &area);
8031 child = gtk_sheet_put(sheet, widget, area.x, area.y);
8033 child->attached_to_cell = TRUE;
8034 child->row = row;
8035 child->col = col;
8036 child->x_align = x_align;
8037 child->y_align = y_align;
8040 void
8041 gtk_sheet_button_attach (GtkSheet *sheet,
8042 GtkWidget *widget,
8043 gint row, gint col,
8044 gfloat x_align, gfloat y_align)
8046 GtkSheetButton *button;
8047 GtkSheetChild *child;
8048 GtkRequisition button_requisition;
8050 if(row >= 0 && col >= 0) return;
8051 if(row < 0 && col < 0) return;
8053 child = g_new (GtkSheetChild, 1);
8054 child->widget = widget;
8055 child->x = 0;
8056 child->y = 0;
8057 child->window = NULL;
8058 child->attached_to_cell = TRUE;
8059 child->row = row;
8060 child->col = col;
8061 child->x_align = x_align;
8062 child->y_align = y_align;
8064 if(row == -1){
8065 button = &sheet->column[col].button;
8066 button->child = child;
8068 else
8070 button = &sheet->row[row].button;
8071 button->child = child;
8074 sheet->children = g_list_append(sheet->children, child);
8076 gtk_widget_set_parent (widget, GTK_WIDGET(sheet));
8077 gtk_sheet_button_size_request(sheet, button, &button_requisition);
8079 if(row == -1){
8080 if(button_requisition.height > sheet->column_title_area.height)
8081 sheet->column_title_area.height = button_requisition.height;
8082 if(button_requisition.width > sheet->column[col].width)
8083 sheet->column[col].width = button_requisition.width;
8086 if(col == -1){
8087 if(button_requisition.width > sheet->row_title_area.width)
8088 sheet->row_title_area.width = button_requisition.width;
8089 if(button_requisition.height > sheet->row[row].height)
8090 sheet->row[row].height = button_requisition.height;
8093 if (GTK_WIDGET_VISIBLE(GTK_WIDGET(sheet)))
8096 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8097 !GTK_WIDGET_REALIZED(widget))
8098 gtk_sheet_realize_child(sheet, child);
8100 if(GTK_WIDGET_MAPPED(GTK_WIDGET(sheet)) &&
8101 !GTK_WIDGET_MAPPED(widget))
8102 gtk_widget_map(widget);
8105 if(row == -1) size_allocate_column_title_buttons(sheet);
8106 if(col == -1) size_allocate_row_title_buttons(sheet);
8111 static void
8112 label_size_request(GtkSheet *sheet, gchar *label, GtkRequisition *req)
8114 gchar *words;
8115 gchar word[1000];
8116 gint n = 0;
8117 gint row_height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet)) - 2*CELLOFFSET + 2;
8119 req->height = 0;
8120 req->width = 0;
8121 words=label;
8123 while(words && *words != '\0'){
8124 if(*words == '\n' || *(words+1) == '\0'){
8125 req->height += row_height;
8127 word[n] = '\0';
8128 req->width = MAX( req->width, gdk_string_width (GTK_WIDGET (sheet)->style->font, word) );
8129 n = 0;
8130 } else {
8131 word[n++] = *words;
8133 words++;
8136 if(n > 0) req->height -= 2;
8141 static void
8142 gtk_sheet_button_size_request (GtkSheet *sheet,
8143 GtkSheetButton *button,
8144 GtkRequisition *button_requisition)
8146 GtkRequisition requisition;
8147 GtkRequisition label_requisition;
8149 /* Taken from 2.2 */
8150 if(GTK_SHEET_AUTORESIZE(sheet) && button->label && strlen(button->label) > 0){
8151 label_size_request(sheet, button->label, &label_requisition);
8152 label_requisition.width += 2*CELLOFFSET;
8153 label_requisition.height += 2*CELLOFFSET;
8154 } else {
8155 label_requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8156 label_requisition.width = COLUMN_MIN_WIDTH;
8159 if(button->child)
8161 gtk_widget_size_request(button->child->widget, &requisition);
8162 /* taken from 2.2 */
8163 requisition.width += 2; /* 2*button->child->xpadding; */
8164 requisition.height += 2; /* 2*button->child->ypadding; */
8165 requisition.width += 2*sheet->button->style->klass->xthickness;
8166 requisition.height += 2*sheet->button->style->klass->ythickness;
8167 } else {
8168 requisition.height = DEFAULT_ROW_HEIGHT(GTK_WIDGET(sheet));
8169 requisition.width = COLUMN_MIN_WIDTH;
8172 *button_requisition = requisition;
8174 button_requisition->width += sheet->button->style->klass->xthickness;
8175 button_requisition->height += sheet->button->style->klass->ythickness;
8178 void
8179 gtk_sheet_move_child(GtkSheet *sheet, GtkWidget *widget, gint x, gint y)
8181 GtkSheetChild *child;
8182 GList *children;
8184 g_return_if_fail(sheet != NULL);
8185 g_return_if_fail(GTK_IS_SHEET(sheet));
8187 children = sheet->children;
8188 while(children)
8190 child = children->data;
8192 if(child->widget == widget){
8193 child->x = x;
8194 child->y = y;
8195 child->row = ROW_FROM_YPIXEL(sheet, y);
8196 child->col = COLUMN_FROM_XPIXEL(sheet, x);
8197 gtk_sheet_position_child(sheet, child);
8198 return;
8201 children = children->next;
8204 g_warning("Widget must be a GtkSheet child");
8208 static void
8209 gtk_sheet_position_child(GtkSheet *sheet, GtkSheetChild *child)
8211 GtkRequisition child_requisition;
8212 gint xoffset = 0;
8213 gint yoffset = 0;
8214 gint x = 0, y = 0;
8215 GdkRectangle area;
8217 gtk_widget_get_child_requisition(child->widget, &child_requisition);
8219 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
8220 yoffset = sheet->column_title_area.height;
8222 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
8223 xoffset = sheet->row_title_area.width;
8225 if(child->attached_to_cell){
8227 child->x = COLUMN_LEFT_XPIXEL(sheet, child->col);
8228 child->y = ROW_TOP_YPIXEL(sheet, child->row);
8230 if(GTK_SHEET_ROW_TITLES_VISIBLE(sheet))
8231 child->x-=sheet->row_title_area.width;
8232 if(GTK_SHEET_COL_TITLES_VISIBLE(sheet))
8233 child->y-=sheet->column_title_area.height;
8235 width = sheet->column[child->col].width;
8236 height = sheet->row[child->row].height;
8239 gtk_sheet_get_cell_area(sheet, child->row, child->col, &area);
8240 child->x = area.x;
8241 child->y = area.y;
8242 child->x += (area.width - child_requisition.width) * child->x_align;
8243 child->y += (area.height - child_requisition.height) * child->y_align;
8244 x = child->widget->allocation.x = child->x + xoffset;
8245 y = child->widget->allocation.y = child->y + yoffset;
8247 else
8249 x = child->widget->allocation.x = child->x + sheet->hoffset + xoffset;
8250 x = child->widget->allocation.x = child->x + xoffset;
8251 y = child->widget->allocation.y = child->y + sheet->voffset + yoffset;
8252 y = child->widget->allocation.y = child->y + yoffset;
8255 child->widget->allocation.width = child_requisition.width;
8256 child->widget->allocation.height = child_requisition.height;
8258 if(GTK_WIDGET_NO_WINDOW(child->widget))
8260 child->widget->allocation.x = 0;
8261 child->widget->allocation.y = 0;
8264 if(GTK_WIDGET_REALIZED(GTK_WIDGET(sheet)) &&
8265 GTK_WIDGET_MAPPED(child->widget))
8267 gtk_widget_size_allocate(child->widget,
8268 &child->widget->allocation);
8269 if(GTK_WIDGET_NO_WINDOW(child->widget) && child->window)
8271 gdk_window_move_resize(child->window,
8272 x, y,
8273 child->widget->allocation.width,
8274 child->widget->allocation.height);
8275 gtk_widget_draw(child->widget, NULL);
8281 static void
8282 gtk_sheet_position_children(GtkSheet *sheet)
8284 GList *children;
8285 GtkSheetChild *child;
8287 children = sheet->children;
8289 while(children)
8291 child = (GtkSheetChild *)children->data;
8293 if(child->col !=-1 && child->row != -1)
8294 gtk_sheet_position_child(sheet, child);
8296 if(child->row == -1){
8297 if(child->col < MIN_VISIBLE_COLUMN(sheet) ||
8298 child->col > MAX_VISIBLE_COLUMN(sheet))
8299 gtk_sheet_child_hide(child);
8300 else
8301 gtk_sheet_child_show(child);
8303 if(child->col == -1){
8304 if(child->row < MIN_VISIBLE_ROW(sheet) ||
8305 child->row > MAX_VISIBLE_ROW(sheet))
8306 gtk_sheet_child_hide(child);
8307 else
8308 gtk_sheet_child_show(child);
8311 children = children->next;
8316 static void
8317 gtk_sheet_remove (GtkContainer *container, GtkWidget *widget)
8319 GtkSheet *sheet;
8320 GList *children;
8321 GtkSheetChild *child = 0;
8323 g_return_if_fail(container != NULL);
8324 g_return_if_fail(GTK_IS_SHEET(container));
8326 sheet = GTK_SHEET(container);
8328 children = sheet->children;
8330 while(children)
8332 child = (GtkSheetChild *)children->data;
8334 if(child->widget == widget) break;
8336 children = children->next;
8339 if (children)
8341 if(child->row == -1)
8342 sheet->row[child->col].button.child = NULL;
8344 if(child->col == -1)
8345 sheet->column[child->row].button.child = NULL;
8347 if(child->window) {
8348 gdk_window_hide(child->window);
8349 gdk_window_unref(child->window);
8352 gtk_widget_unparent (widget);
8353 child->widget = NULL;
8355 sheet->children = g_list_remove_link (sheet->children, children);
8356 g_list_free_1 (children);
8361 static void
8362 gtk_sheet_realize_child(GtkSheet *sheet, GtkSheetChild *child)
8364 gint attributes_mask;
8365 GtkWidget *widget;
8367 widget = GTK_WIDGET(sheet);
8369 if (GTK_WIDGET_NO_WINDOW (child->widget))
8371 GdkWindowAttr attributes;
8373 gint x = child->x - sheet->hoffset;
8374 gint y = child->y - sheet->voffset;
8376 attributes.window_type = GDK_WINDOW_CHILD;
8377 attributes.x = x;
8378 attributes.y = y;
8379 attributes.width = child->widget->requisition.width;
8380 attributes.height = child->widget->requisition.height;
8381 attributes.wclass = GDK_INPUT_OUTPUT;
8382 attributes.visual = gtk_widget_get_visual (widget);
8383 attributes.colormap = gtk_widget_get_colormap (widget);
8384 attributes.event_mask = GDK_EXPOSURE_MASK;
8386 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
8388 if(child->row == -1)
8389 child->window = gdk_window_new (sheet->column_title_window,
8390 &attributes, attributes_mask);
8391 else if(child->col == -1)
8392 child->window = gdk_window_new (sheet->row_title_window,
8393 &attributes, attributes_mask);
8394 else
8395 child->window = gdk_window_new (widget->window,
8396 &attributes, attributes_mask);
8398 if(GTK_IS_PIXMAP(child->widget)){
8399 gdk_window_shape_combine_mask(child->window,
8400 GTK_PIXMAP(child->widget)->mask,
8401 0, 0);
8404 gdk_window_set_user_data (child->window, widget);
8406 if (child->window)
8407 gtk_style_set_background (widget->style,
8408 child->window,
8409 GTK_STATE_NORMAL);
8411 gtk_widget_set_parent_window(child->widget, child->window);
8412 gdk_window_show(child->window);
8416 gtk_widget_realize(child->widget);
8422 GtkSheetChild *
8423 gtk_sheet_get_child_at(GtkSheet *sheet, gint row, gint col)
8425 GList *children;
8426 GtkSheetChild *child = 0;
8428 g_return_val_if_fail(sheet != NULL, NULL);
8429 g_return_val_if_fail(GTK_IS_SHEET(sheet), NULL);
8431 children = sheet->children;
8433 while(children)
8435 child = (GtkSheetChild *)children->data;
8437 if(child->attached_to_cell)
8438 if(child->row == row && child->col == col) break;
8440 children = children->next;
8443 if(children) return child;
8445 return NULL;
8448 static void
8449 gtk_sheet_child_hide(GtkSheetChild *child)
8451 g_return_if_fail(child != NULL);
8452 gtk_widget_hide(child->widget);
8453 if(child->window)
8454 gdk_window_hide(child->window);
8457 static void
8458 gtk_sheet_child_show(GtkSheetChild *child)
8460 g_return_if_fail(child != NULL);
8462 gtk_widget_show(child->widget);
8463 if(child->window)
8464 gdk_window_show(child->window);